From 5f07025a4ae95cf023b7bfecf8ce705abe3ead4a Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Fri, 25 Dec 2015 22:47:11 +0100 Subject: [PATCH] Add basic MONITOR tests. --- irctest/cases.py | 12 ++- irctest/client_mock.py | 2 + irctest/server_tests/test_monitor.py | 139 +++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 irctest/server_tests/test_monitor.py diff --git a/irctest/cases.py b/irctest/cases.py index c260f6b..b26f310 100644 --- a/irctest/cases.py +++ b/irctest/cases.py @@ -34,7 +34,7 @@ class _IrcTestCase(unittest.TestCase): print('---- new test ----') def assertMessageEqual(self, msg, subcommand=None, subparams=None, target=None, nick=None, fail_msg=None, extra_format=(), - **kwargs): + strip_first_param=False, **kwargs): """Helper for partially comparing a message. Takes the message as first arguments, and comparisons to be made @@ -44,6 +44,8 @@ class _IrcTestCase(unittest.TestCase): `subparams`, and `target` are given.""" fail_msg = fail_msg or '{msg}' for (key, value) in kwargs.items(): + if strip_first_param and key == 'params': + value = value[1:] self.assertEqual(getattr(msg, key), value, msg, fail_msg, extra_format=extra_format) if nick: @@ -215,6 +217,7 @@ class BaseServerTestCase(_IrcTestCase): invalid_metadata_keys = frozenset() def setUp(self): super().setUp() + self.server_support = {} self.find_hostname_and_port() self.controller.run(self.hostname, self.port, password=self.password, valid_metadata_keys=self.valid_metadata_keys, @@ -326,6 +329,13 @@ class BaseServerTestCase(_IrcTestCase): m = self.getMessage(client) if m.command == 'PONG': break + elif m.command == '005': + for param in m.params[1:-1]: + if '=' in param: + (key, value) = param.split('=') + else: + (key, value) = (param, None) + self.server_support[key] = value def joinClient(self, client, channel): self.sendLine(client, 'JOIN {}'.format(channel)) diff --git a/irctest/client_mock.py b/irctest/client_mock.py index 91a79dd..1a85bea 100644 --- a/irctest/client_mock.py +++ b/irctest/client_mock.py @@ -50,6 +50,8 @@ class ClientMock: print('{:.3f} waiting…'.format(time.time())) time.sleep(0.1) continue + except ConnectionResetError: + raise ConnectionResetError() else: if not new_data: # Connection closed diff --git a/irctest/server_tests/test_monitor.py b/irctest/server_tests/test_monitor.py new file mode 100644 index 0000000..3f15b24 --- /dev/null +++ b/irctest/server_tests/test_monitor.py @@ -0,0 +1,139 @@ +""" + +""" + +from irctest import cases +from irctest.basecontrollers import NotImplementedByController + +class EchoMessageTestCase(cases.BaseServerTestCase): + def check_server_support(self): + if 'MONITOR' not in self.server_support: + raise NotImplementedByController('MONITOR') + + def assertMononline(self, client, nick, m=None): + if not m: + m = self.getMessage(client) + self.assertMessageEqual(m, command='730', # RPL_MONOFFLINE + fail_msg='Sent non-730 (RPL_MONONLINE) message after ' + 'monitored nick “{}” connected: {msg}', + extra_format=(nick,)) + self.assertEqual(len(m.params), 2, m, + fail_msg='Invalid number of params of RPL_MONONLINE: {msg}') + self.assertEqual(m.params[1].split('!')[0], 'bar', + fail_msg='730 (RPL_MONONLINE) with bad target after “{}” ' + 'connects: {msg}', + extra_format=(nick,)) + + def assertMonoffline(self, client, nick, m=None): + if not m: + m = self.getMessage(client) + self.assertMessageEqual(m, command='731', # RPL_MONOFFLINE + fail_msg='Did not reply with 731 (RPL_MONOFFLINE) to ' + '“MONITOR + {}”, while “{}” is offline: {msg}', + extra_format=(nick, nick)) + self.assertEqual(len(m.params), 2, m, + fail_msg='Invalid number of params of RPL_MONOFFLINE: {msg}') + self.assertEqual(m.params[1].split('!')[0], 'bar', + fail_msg='731 (RPL_MONOFFLINE) reply to “MONITOR + {}” ' + 'with bad target: {msg}', + extra_format=(nick,)) + + @cases.SpecificationSelector.requiredBySpecification('IRCv3.2') + def testMonitorOneDisconnected(self): + """“If any of the targets being added are online, the server will + generate RPL_MONONLINE numerics listing those targets that are + online.” + -- + """ + self.connectClient('foo') + self.check_server_support() + self.sendLine(1, 'MONITOR + bar') + self.assertMonoffline(1, 'bar') + self.connectClient('bar') + self.assertMononline(1, 'bar') + self.sendLine(2, 'QUIT :bye') + try: + self.getMessages(2) + except ConnectionResetError: + pass + self.assertMonoffline(1, 'bar') + + @cases.SpecificationSelector.requiredBySpecification('IRCv3.2') + def testMonitorOneConnection(self): + self.connectClient('foo') + self.check_server_support() + self.sendLine(1, 'MONITOR + bar') + self.getMessages(1) + self.connectClient('bar') + self.assertMononline(1, 'bar') + + @cases.SpecificationSelector.requiredBySpecification('IRCv3.2') + def testMonitorOneConnected(self): + """“If any of the targets being added are offline, the server will + generate RPL_MONOFFLINE numerics listing those targets that are + online.” + -- + """ + self.connectClient('foo') + self.check_server_support() + self.connectClient('bar') + self.sendLine(1, 'MONITOR + bar') + self.assertMononline(1, 'bar') + self.sendLine(2, 'QUIT :bye') + try: + self.getMessages(2) + except ConnectionResetError: + pass + self.assertMonoffline(1, 'bar') + + @cases.SpecificationSelector.requiredBySpecification('IRCv3.2') + def testMonitorOneConnection(self): + self.connectClient('foo') + self.check_server_support() + self.connectClient('bar') + self.sendLine(1, 'MONITOR + bar') + self.assertMononline(1, 'bar') + self.sendLine(2, 'QUIT :bye') + try: + self.getMessages(2) + except ConnectionResetError: + pass + self.assertMonoffline(1, 'bar') + self.connectClient('bar') + self.assertMononline(1, 'bar') + + @cases.SpecificationSelector.requiredBySpecification('IRCv3.2') + def testMonitorConnectedAndDisconnected(self): + """“If any of the targets being added are online, the server will + generate RPL_MONONLINE numerics listing those targets that are + online. + + If any of the targets being added are offline, the server will + generate RPL_MONOFFLINE numerics listing those targets that are + online.” + -- + """ + self.connectClient('foo') + self.check_server_support() + self.connectClient('bar') + self.sendLine(1, 'MONITOR + bar,baz') + m1 = self.getMessage(1) + m2 = self.getMessage(1) + commands = {m1.command, m2.command} + self.assertEqual(commands, {'730', '731'}, + fail_msg='Did not send one 730 (RPL_MONONLINE) and one ' + '731 (RPL_MONOFFLINE) after “MONITOR + bar,baz” when “bar” ' + 'is online and “baz” is offline. Sent this instead: {}', + extra_format=((m1, m2))) + if m1.command == '731': + (m1, m2) = (m2, m1) + self.assertEqual(len(m1.params), 2, m1, + fail_msg='Invalid number of params of RPL_MONONLINE: {msg}') + self.assertEqual(len(m2.params), 2, m2, + fail_msg='Invalid number of params of RPL_MONONLINE: {msg}') + self.assertEqual(m1.params[1].split('!')[0], 'bar', m1, + fail_msg='730 (RPL_MONONLINE) with bad target after ' + '“MONITOR + bar,baz” and “bar” is connected: {msg}') + self.assertEqual(m2.params[1].split('!')[0], 'baz', m2, + fail_msg='731 (RPL_MONOFFLINE) with bad target after ' + '“MONITOR + bar,baz” and “baz” is disconnected: {msg}')