def testWallopsPrivileges(self): """ https://github.com/ircdocs/modern-irc/pull/118 """ self.connectClient("nick1") self.sendLine(1, "WALLOPS :hi everyone") message = self.getMessage(1) if message.command == ERR_UNKNOWNCOMMAND: raise runner.NotImplementedByController("WALLOPS") self.assertMessageMatch(message, command=ERR_NOPRIVILEGES, params=["nick1", ANYSTR])
def testWallops(self): """ "The WALLOPS command is used to send a message to all currently connected users who have set the 'w' user mode for themselves." -- https://datatracker.ietf.org/doc/html/rfc2812#section-4.7 -- https://github.com/ircdocs/modern-irc/pull/118 "Servers MAY echo WALLOPS messages to their sender even if they don't have the 'w' user mode. Servers MAY send WALLOPS only to operators." -- https://github.com/ircdocs/modern-irc/pull/118 """ self.connectClient("nick1") self.connectClient("nick2") self.connectClient("nick3") self.sendLine(2, "MODE nick2 -w") self.getMessages(2) self.sendLine(3, "MODE nick3 +w") self.getMessages(3) self.sendLine(1, "OPER operuser operpassword") self.assertIn( RPL_YOUREOPER, [m.command for m in self.getMessages(1)], fail_msg="OPER failed", ) self.sendLine(1, "WALLOPS :hi everyone") messages = self.getMessages(1) if ERR_UNKNOWNCOMMAND in (message.command for message in messages): raise runner.NotImplementedByController("WALLOPS") for message in messages: self.assertMessageMatch( message, prefix=StrRe("nick1!.*"), command="WALLOPS", params=[StrRe(".*hi everyone")], ) messages = self.getMessages(3) if messages: self.assertMessageMatch( messages[0], prefix=StrRe("nick1!.*"), command="WALLOPS", params=[StrRe(".*hi everyone")], ) self.assertEqual(self.getMessages(2), [], fail_msg="Server sent WALLOPS to user without +w")
def testChannelsEquivalent(self, casemapping, name1, name2): self.connectClient("foo") self.connectClient("bar") if self.server_support["CASEMAPPING"] != casemapping: raise runner.NotImplementedByController( "Casemapping {} not implemented".format(casemapping) ) self.joinClient(1, name1) self.joinClient(2, name2) try: m = self.getMessage(1) self.assertMessageMatch(m, command="JOIN", nick="bar") except client_mock.NoMessageException: raise AssertionError( "Channel names {} and {} are not equivalent.".format(name1, name2) )
def testTargmax(self): """ "Format: TARGMAX=[<command>:[limit]{,<command>:[limit]}]" -- https://modern.ircdocs.horse/#targmax-parameter "TARGMAX=[cmd:[number][,cmd:[number][,...]]]" -- https://defs.ircdocs.horse/defs/isupport.html#targmax """ self.connectClient("foo") if "TARGMAX" not in self.server_support: raise runner.NotImplementedByController("TARGMAX") parts = self.server_support["TARGMAX"].split(",") for part in parts: self.assertTrue( re.match("[A-Z]+:[0-9]*", part), "Invalid TARGMAX key:value: %r", part )
def testDoubleKickMessages(self, multiple_targets): """“The server MUST NOT send KICK messages with multiple channels or users to clients. This is necessarily to maintain backward compatibility with old client software.” -- https://tools.ietf.org/html/rfc2812#section-3.2.8 "The server MUST NOT send KICK messages with multiple channels or users to clients. This is necessary to maintain backward compatibility with existing client software." -- https://modern.ircdocs.horse/#kick-message "Servers MAY limit the number of target users per `KICK` command via the [`TARGMAX` parameter of `RPL_ISUPPORT`](#targmax-parameter), and silently drop targets if the number of targets exceeds the limit." -- https://modern.ircdocs.horse/#kick-message "If the "TARGMAX" parameter is not advertised or a value is not sent then a client SHOULD assume that no commands except the "JOIN" and "PART" commands accept multiple parameters." -- https://defs.ircdocs.horse/defs/isupport.html#targmax "If this parameter is not advertised or a value is not sent then a client SHOULD assume that no commands except the `JOIN` and `PART` commands accept multiple parameters." -- https://github.com/ircdocs/modern-irc/pull/113 "If <limit> is not specified, then there is no maximum number of targets for that command." -- https://modern.ircdocs.horse/#targmax-parameter """ self.connectClient("foo") self.joinChannel(1, "#chan") self.connectClient("bar") self.joinChannel(2, "#chan") self.connectClient("baz") self.joinChannel(3, "#chan") self.connectClient("qux") self.joinChannel(4, "#chan") targmax = dict( item.split(":", 1) for item in self.server_support.get("TARGMAX", "").split(",") if item) if targmax.get("KICK", "1") == "1": raise runner.NotImplementedByController("Multi-target KICK") # TODO: check foo is an operator # Synchronize self.getMessages(1) self.getMessages(2) self.getMessages(3) self.getMessages(4) if multiple_targets: self.sendLine(1, "KICK #chan,#chan bar,baz :bye") else: self.sendLine(1, "KICK #chan bar,baz :bye") try: m = self.getMessage(1) if m.command == "482": raise runner.OptionalExtensionNotSupported( "Channel creators are not opped by default.") except client_mock.NoMessageException: # The RFCs do not say KICK must be echoed pass mgroup = self.getMessages(4) self.assertGreaterEqual(len(mgroup), 2, mgroup) m1, m2 = mgroup[:2] self.assertMessageMatch(m1, command="KICK", params=["#chan", ANYSTR, "bye"]) self.assertMessageMatch(m2, command="KICK", params=["#chan", ANYSTR, "bye"]) if (m1.params[1] == "bar" and m2.params[1] == "baz") or (m1.params[1] == "baz" and m2.params[1] == "bar"): ... # success else: raise AssertionError( "Middle params [{}, {}] are not correct.".format( m1.params[1], m2.params[1]))