From 585efb2c18a08b408ec6e15cb805e372bc392c02 Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 3 Dec 2017 17:54:00 -0800 Subject: [PATCH] Add E2E test --- pyircbot/irccore.py | 2 ++ pyircbot/pyircbot.py | 3 +- run-tests.sh | 2 +- tests/lib.py | 42 +++++++++++++++++++++++++- tests/miniircd.py | 1 + tests/test_pyircbot.py | 67 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 tests/test_pyircbot.py diff --git a/pyircbot/irccore.py b/pyircbot/irccore.py index 53ca481..4292240 100644 --- a/pyircbot/irccore.py +++ b/pyircbot/irccore.py @@ -199,6 +199,7 @@ class IRCCore(object): '255', '265', '266', + '331', '332', '333', '353', @@ -206,6 +207,7 @@ class IRCCore(object): '372', '375', '376', + '401', '422', '433', ] diff --git a/pyircbot/pyircbot.py b/pyircbot/pyircbot.py index f2570c5..05e561f 100644 --- a/pyircbot/pyircbot.py +++ b/pyircbot/pyircbot.py @@ -231,7 +231,8 @@ class PyIRCBot(PrimitiveBot): self.loop = asyncio.get_event_loop() """Reference to BotRPC thread""" - self.rpc = BotRPC(self) + if self.botconfig["bot"]["rpcport"] >= 0: + self.rpc = BotRPC(self) ratelimit = self.botconfig["connection"].get("rate_limit", None) or dict(rate_max=5.0, rate_int=1.1) diff --git a/run-tests.sh b/run-tests.sh index 50e3107..9bfc287 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -3,4 +3,4 @@ export PYTHONUNBUFFERED=1 export PYTHONPATH=. -py.test --cov=pyircbot --cov-report html -s tests/ +py.test --cov=pyircbot --cov-report html tests/ diff --git a/tests/lib.py b/tests/lib.py index e932919..d1e1667 100644 --- a/tests/lib.py +++ b/tests/lib.py @@ -1,9 +1,12 @@ import os import sys import pytest +from random import randint +from threading import Thread 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/")) @@ -36,6 +39,43 @@ class FakeBaseBot(PrimitiveBot): @pytest.fixture def fakebot(): + # TODO copy data tree to isolated place so each fakebot() is isolated bot = FakeBaseBot({"bot": {"datadir": "./examples/data/"}, "module_configs": {}}) - return bot + yield bot + + +@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() diff --git a/tests/miniircd.py b/tests/miniircd.py index b558d0f..f51cfb3 100755 --- a/tests/miniircd.py +++ b/tests/miniircd.py @@ -1080,5 +1080,6 @@ def main(argv): except KeyboardInterrupt: server.print_error("Interrupted.") + if __name__ == '__main__': main(sys.argv) diff --git a/tests/test_pyircbot.py b/tests/test_pyircbot.py new file mode 100644 index 0000000..f95b7b7 --- /dev/null +++ b/tests/test_pyircbot.py @@ -0,0 +1,67 @@ +import pytest +from tests.lib import * # NOQA - fixtures +from time import sleep, time +from pyircbot import IRCCore +import logging + + +logging.getLogger().setLevel(logging.DEBUG) + + +def wait_until(server, channel, nick, func, timeout): + start = time() + while time() < start + timeout: + v = func() + if v: + return v + sleep(0.02) + raise Exception("Function {} did not settle after {}s".format(func, timeout)) + + +def wait_until_joined(server, channel, nick, timeout=5.0): + def in_ch(): + if channel in server.channels: + members = [u.nickname for u in server.channels[channel].members] + if nick in members: + return members + return wait_until(server, channel, nick, in_ch, timeout=timeout) + + +def wait_until_absent(server, channel, nick, timeout=5.0): + def not_in_ch(): + if channel not in server.channels: + return True + members = [u.nickname for u in server.channels[channel].members] + if nick not in members: + return True + return wait_until(server, channel, nick, not_in_ch, timeout=timeout) + + +def test_connect_and_join(livebot): + port, server, bot, bot_t, channel, nick = livebot + bot_t.start() + assert nick in wait_until_joined(server, channel, nick) + + +@pytest.mark.slow +def test_hop_to_next_server(livebot): + port, server, bot, bot_t, channel, nick = livebot + bot.irc.servers = [["localhost", bot.irc.servers[0][1] + 1], bot.irc.servers[0]] # bad port, con refused on 1st srv + bot_t.start() + assert nick in wait_until_joined(server, channel, nick) + + +@pytest.mark.slow +def test_quit_reconnect(livebot): + port, server, bot, bot_t, channel, nick = livebot + bot.irc.reconnect_delay = 0.1 + bot_t.start() + wait_until_joined(server, channel, nick) + bot.act_QUIT("quitting") + wait_until_absent(server, channel, nick) + assert nick in wait_until_joined(server, channel, nick) + + +def test_bs(): + IRCCore.fulltrace() + IRCCore.trace()