pyircbot/tests/lib.py

175 lines
4.8 KiB
Python

import os
import sys
import pytest
from threading import Thread
from random import randint
from pyircbot import PyIRCBot
from pyircbot.pyircbot import PrimitiveBot
from pyircbot.irccore import IRCEvent, UserPrefix
from unittest.mock import MagicMock
from tests.miniircd import Server as MiniIrcServer
sys.path.append(os.path.join(os.path.dirname(__file__), "../pyircbot/modules/"))
class FakeBaseBot(PrimitiveBot):
"""
Class that simulates a bot base class. You need to add mocks for any methods you expect called, beyond privmsg.
"""
def __init__(self, config):
super().__init__(config)
self.act_PRIVMSG = MagicMock()
self._modules = []
def feed_line(self, trailing, cmd="PRIVMSG", args=["#test"], sender=("chatter", "root", "cia.gov")):
"""
Feed a message into the bot.
"""
msg = IRCEvent(cmd,
args,
UserPrefix(*sender),
trailing)
for module_name, module in self.moduleInstances.items():# TODO dedupe this block across the various base classes
for hook in module.irchooks:
validation = hook.validator(msg, self)
if validation:
hook.method(msg, validation)
def closeAllModules(self):
for modname in self._modules:
self.unloadmodule(modname)
def loadmodule(self, module_name):
super().loadmodule(module_name)
self._modules.append(module_name)
def unloadmodule(self, module_name):
super().unloadmodule(module_name)
self._modules.remove(module_name)
def get_nick(self):
return "testbot"
@pytest.fixture
def fakebot(tmpdir):
# TODO copy data tree to isolated place so each fakebot() is isolated
os.mkdir(os.path.join(tmpdir, "data"))
bot = FakeBaseBot({"bot": {"datadir": tmpdir},
"module_configs": {}})
yield bot
bot.closeAllModules()
@pytest.fixture
def ircserver():
"""
Fixture providing an isolated IRC server.
:return: tuple of (port, server_object)
"""
port = randint(40000, 65000)
class IRCOptions(object):
channel_log_dir = None
chroot = None
daemon = None
debug = None
ipv6 = None
listen = "127.0.0.1"
log_count = 10
log_file = None
log_max_size = 10
motd = None
password = None
password_file = None
pid_file = None
ports = [port]
setuid = None
ssl_pem_file = None
state_dir = None
verbose = None
server = MiniIrcServer(IRCOptions)
server_t = Thread(target=server.start, daemon=True)
server_t.start()
yield port, server
server.stop()
@pytest.fixture
def livebot(ircserver, tmpdir):
"""
A full-fledged bot connected to an irc server.
"""
port, server = ircserver
channel = "#test" + str(randint(100000, 1000000))
nick = "testbot" + str(randint(100000, 1000000))
config = {
"bot": {
"datadir": tmpdir,
"rpcbind": "0.0.0.0",
"rpcport": -1,
"usermodules": []
},
"connection": {
"servers": [
["localhost", port]
],
"force_ipv6": False,
"rate_limit": {
"rate_max": 5.0,
"rate_int": 1.1
}
},
"modules": [
"PingResponder",
"Services"
],
"module_configs": {
"Services": {
"user": {
"nick": [
nick,
nick + "_",
nick + "__"
],
"password": "nickservpassword",
"username": "pyircbot3",
"hostname": "pyircbot3.domain.com",
"realname": "pyircbot3"
},
"ident": {
"enable": "no",
"to": "nickserv",
"command": "identify %(password)s",
"ghost": "no",
"ghost_to": "nickserv",
"ghost_cmd": "ghost %(nick)s %(password)s"
},
"channels": [
channel
],
"privatechannels": {
"to": "chanserv",
"command": "invite %(channel)s",
"list": []
}
}
}
}
bot = PyIRCBot(config)
bot_t = Thread(target=bot.run, daemon=True)
# bot_t.start()
yield port, server, bot, bot_t, channel, nick
bot.kill(message="bye", forever=True)
def pm(bot, line, nick="chatter"):
bot.feed_line(line, args=['bot'], sender=(nick, "root", "cia.gov"))