Awesome IRC bot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

175 lines
4.9 KiB

  1. import os
  2. import sys
  3. import pytest
  4. from threading import Thread
  5. from random import randint
  6. from pyircbot import PyIRCBot
  7. from pyircbot.pyircbot import PrimitiveBot
  8. from pyircbot.irccore import IRCEvent, UserPrefix, IRCCore
  9. from unittest.mock import MagicMock
  10. from tests.miniircd import Server as MiniIrcServer
  11. sys.path.append(os.path.join(os.path.dirname(__file__), "../pyircbot/modules/"))
  12. class FakeBaseBot(PrimitiveBot):
  13. """
  14. Class that simulates a bot base class. You need to add mocks for any methods you expect called, beyond privmsg.
  15. """
  16. def __init__(self, config):
  17. super().__init__(config)
  18. self.act_PRIVMSG = MagicMock()
  19. self._modules = []
  20. def feed_line(self, trailing, cmd="PRIVMSG", args=["#test"], sender=("chatter", "root", "cia.gov")):
  21. """
  22. Feed a message into the bot.
  23. """
  24. msg = IRCCore.packetAsObject(cmd,
  25. args,
  26. f"{sender[0]}!{sender[1]}@{sender[2]}", # hack
  27. trailing)
  28. for module_name, module in self.moduleInstances.items():# TODO dedupe this block across the various base classes
  29. for hook in module.irchooks:
  30. validation = hook.validator(msg, self)
  31. if validation:
  32. hook.method(msg, validation)
  33. def closeAllModules(self):
  34. for modname in self._modules:
  35. self.unloadmodule(modname)
  36. def loadmodule(self, module_name):
  37. super().loadmodule(module_name)
  38. self._modules.append(module_name)
  39. def unloadmodule(self, module_name):
  40. super().unloadmodule(module_name)
  41. self._modules.remove(module_name)
  42. def get_nick(self):
  43. return "testbot"
  44. @pytest.fixture
  45. def fakebot(tmpdir):
  46. # TODO copy data tree to isolated place so each fakebot() is isolated
  47. os.mkdir(os.path.join(tmpdir, "data"))
  48. bot = FakeBaseBot({"bot": {"datadir": tmpdir},
  49. "module_configs": {}})
  50. yield bot
  51. bot.closeAllModules()
  52. @pytest.fixture
  53. def ircserver():
  54. """
  55. Fixture providing an isolated IRC server.
  56. :return: tuple of (port, server_object)
  57. """
  58. port = randint(40000, 65000)
  59. class IRCOptions(object):
  60. channel_log_dir = None
  61. chroot = None
  62. daemon = None
  63. debug = None
  64. ipv6 = None
  65. listen = "127.0.0.1"
  66. log_count = 10
  67. log_file = None
  68. log_max_size = 10
  69. motd = None
  70. password = None
  71. password_file = None
  72. pid_file = None
  73. ports = [port]
  74. setuid = None
  75. ssl_pem_file = None
  76. state_dir = None
  77. verbose = None
  78. server = MiniIrcServer(IRCOptions)
  79. server_t = Thread(target=server.start, daemon=True)
  80. server_t.start()
  81. yield port, server
  82. server.stop()
  83. @pytest.fixture
  84. def livebot(ircserver, tmpdir):
  85. """
  86. A full-fledged bot connected to an irc server.
  87. """
  88. port, server = ircserver
  89. channel = "#test" + str(randint(100000, 1000000))
  90. nick = "testbot" + str(randint(100000, 1000000))
  91. config = {
  92. "bot": {
  93. "datadir": tmpdir,
  94. "rpcbind": "0.0.0.0",
  95. "rpcport": -1,
  96. "usermodules": []
  97. },
  98. "connection": {
  99. "servers": [
  100. ["localhost", port]
  101. ],
  102. "force_ipv6": False,
  103. "rate_limit": {
  104. "rate_max": 5.0,
  105. "rate_int": 1.1
  106. }
  107. },
  108. "modules": [
  109. "PingResponder",
  110. "Services"
  111. ],
  112. "module_configs": {
  113. "Services": {
  114. "user": {
  115. "nick": [
  116. nick,
  117. nick + "_",
  118. nick + "__"
  119. ],
  120. "password": "nickservpassword",
  121. "username": "pyircbot3",
  122. "hostname": "pyircbot3.domain.com",
  123. "realname": "pyircbot3"
  124. },
  125. "ident": {
  126. "enable": "no",
  127. "to": "nickserv",
  128. "command": "identify %(password)s",
  129. "ghost": "no",
  130. "ghost_to": "nickserv",
  131. "ghost_cmd": "ghost %(nick)s %(password)s"
  132. },
  133. "channels": [
  134. channel
  135. ],
  136. "privatechannels": {
  137. "to": "chanserv",
  138. "command": "invite %(channel)s",
  139. "list": []
  140. }
  141. }
  142. }
  143. }
  144. bot = PyIRCBot(config)
  145. bot_t = Thread(target=bot.run, daemon=True)
  146. # bot_t.start()
  147. yield port, server, bot, bot_t, channel, nick
  148. bot.kill(message="bye", forever=True)
  149. def pm(bot, line, nick="chatter"):
  150. bot.feed_line(line, args=['bot'], sender=(nick, "root", "cia.gov"))