From da005d7d2492bf31c4bdeb46108240766c69d0ad Mon Sep 17 00:00:00 2001 From: Val Lorentz Date: Mon, 21 Feb 2022 21:43:22 +0100 Subject: [PATCH] Add tests for WHOX. (#131) --- irctest/cases.py | 17 ++-- irctest/numerics.py | 1 + irctest/server_tests/who.py | 162 +++++++++++++++++++++++++++++++++++- irctest/specifications.py | 1 + pytest.ini | 1 + 5 files changed, 172 insertions(+), 10 deletions(-) diff --git a/irctest/cases.py b/irctest/cases.py index 49a1b81..f4caa9d 100644 --- a/irctest/cases.py +++ b/irctest/cases.py @@ -647,6 +647,16 @@ class BaseServerTestCase( else: raise + def authenticateClient( + self, client: TClientName, account: str, password: str + ) -> None: + self.sendLine(client, "AUTHENTICATE PLAIN") + m = self.getRegistrationMessage(client) + self.assertMessageMatch(m, command="AUTHENTICATE", params=["+"]) + self.sendLine(client, sasl_plain_blob(account, password)) + m = self.getRegistrationMessage(client) + self.assertIn(m.command, ["900", "903"], str(m)) + def connectClient( self, nick: str, @@ -670,12 +680,7 @@ class BaseServerTestCase( if password is not None: if "sasl" not in (capabilities or ()): raise ValueError("Used 'password' option without sasl capbilitiy") - self.sendLine(client, "AUTHENTICATE PLAIN") - m = self.getRegistrationMessage(client) - self.assertMessageMatch(m, command="AUTHENTICATE", params=["+"]) - self.sendLine(client, sasl_plain_blob(account or nick, password)) - m = self.getRegistrationMessage(client) - self.assertIn(m.command, ["900", "903"], str(m)) + self.authenticateClient(client, account or nick, password) self.sendLine(client, "NICK {}".format(nick)) self.sendLine(client, "USER %s * * :Realname" % (ident,)) diff --git a/irctest/numerics.py b/irctest/numerics.py index 6193243..28006fe 100644 --- a/irctest/numerics.py +++ b/irctest/numerics.py @@ -86,6 +86,7 @@ RPL_ENDOFEXCEPTLIST = "349" RPL_VERSION = "351" RPL_WHOREPLY = "352" RPL_NAMREPLY = "353" +RPL_WHOSPCRPL = "354" RPL_LINKS = "364" RPL_ENDOFLINKS = "365" RPL_ENDOFNAMES = "366" diff --git a/irctest/server_tests/who.py b/irctest/server_tests/who.py index bfb8cb4..c526b0d 100644 --- a/irctest/server_tests/who.py +++ b/irctest/server_tests/who.py @@ -2,8 +2,8 @@ import re import pytest -from irctest import cases -from irctest.numerics import RPL_ENDOFWHO, RPL_WHOREPLY, RPL_YOUREOPER +from irctest import cases, runner +from irctest.numerics import RPL_ENDOFWHO, RPL_WHOREPLY, RPL_WHOSPCRPL, RPL_YOUREOPER from irctest.patma import ANYSTR, InsensitiveStr, StrRe @@ -15,15 +15,22 @@ def realname_regexp(realname): ) -class WhoTestCase(cases.BaseServerTestCase, cases.OptionalityHelper): - def _init(self): +class BaseWhoTestCase: + def _init(self, auth=False): self.nick = "coolNick" self.username = "myusernam" # may be truncated if longer than this self.realname = "My UniqueReal Name" self.addClient() + if auth: + self.controller.registerUser(self, "coolAcct", "sesame") + self.requestCapabilities(1, ["sasl"], skip_if_cap_nak=True) + self.authenticateClient(1, "coolAcct", "sesame") self.sendLine(1, f"NICK {self.nick}") self.sendLine(1, f"USER {self.username} 0 * :{self.realname}") + if auth: + self.sendLine(1, "CAP END") + self.getRegistrationMessage(1) self.skipToWelcome(1) self.sendLine(1, "JOIN #chan") @@ -69,6 +76,8 @@ class WhoTestCase(cases.BaseServerTestCase, cases.OptionalityHelper): ], ) + +class WhoTestCase(BaseWhoTestCase, cases.BaseServerTestCase, cases.OptionalityHelper): @cases.mark_specifications("Modern") def testWhoStar(self): self._init() @@ -323,3 +332,148 @@ class WhoTestCase(cases.BaseServerTestCase, cases.OptionalityHelper): command=RPL_ENDOFWHO, params=["otherNick", InsensitiveStr(mask), ANYSTR], ) + + @cases.mark_specifications("IRCv3") + @cases.mark_isupport("WHOX") + def testWhoxFull(self): + """https://github.com/ircv3/ircv3-specifications/pull/482""" + self._testWhoxFull("%tcuihsnfdlaor,123") + + @cases.mark_specifications("IRCv3") + @cases.mark_isupport("WHOX") + def testWhoxFullReversed(self): + """https://github.com/ircv3/ircv3-specifications/pull/482""" + self._testWhoxFull("%" + "".join(reversed("tcuihsnfdlaor")) + ",123") + + def _testWhoxFull(self, chars): + self._init() + if "WHOX" not in self.server_support: + raise runner.IsupportTokenNotSupported("WHOX") + + self.sendLine(2, f"WHO coolNick {chars}") + messages = self.getMessages(2) + + self.assertEqual(len(messages), 2, "Unexpected number of messages") + + (reply, end) = messages + + self.assertMessageMatch( + reply, + command=RPL_WHOSPCRPL, + params=[ + "otherNick", + "123", + StrRe(r"(#chan|\*)"), + StrRe("~?myusernam"), + ANYSTR, + ANYSTR, + "My.Little.Server", + "coolNick", + StrRe("H@?"), + ANYSTR, # hopcount + StrRe("[0-9]"), # seconds idle + "0", # account name + ANYSTR, # op level + "My UniqueReal Name", + ], + ) + + self.assertMessageMatch( + end, + command=RPL_ENDOFWHO, + params=["otherNick", InsensitiveStr("coolNick"), ANYSTR], + ) + + def testWhoxToken(self): + """https://github.com/ircv3/ircv3-specifications/pull/482""" + self._init() + if "WHOX" not in self.server_support: + raise runner.IsupportTokenNotSupported("WHOX") + + self.sendLine(2, "WHO coolNick %tn,321") + messages = self.getMessages(2) + + self.assertEqual(len(messages), 2, "Unexpected number of messages") + + (reply, end) = messages + + self.assertMessageMatch( + reply, + command=RPL_WHOSPCRPL, + params=[ + "otherNick", + "321", + "coolNick", + ], + ) + + self.assertMessageMatch( + end, + command=RPL_ENDOFWHO, + params=["otherNick", InsensitiveStr("coolNick"), ANYSTR], + ) + + +@cases.mark_services +class WhoServicesTestCase( + BaseWhoTestCase, cases.BaseServerTestCase, cases.OptionalityHelper +): + @cases.mark_specifications("IRCv3") + @cases.mark_isupport("WHOX") + def testWhoxAccount(self): + self._init(auth=True) + if "WHOX" not in self.server_support: + raise runner.IsupportTokenNotSupported("WHOX") + + self.sendLine(2, "WHO coolNick %na") + messages = self.getMessages(2) + + self.assertEqual(len(messages), 2, "Unexpected number of messages") + + (reply, end) = messages + + self.assertMessageMatch( + reply, + command=RPL_WHOSPCRPL, + params=[ + "otherNick", + "coolNick", + "coolAcct", + ], + ) + + self.assertMessageMatch( + end, + command=RPL_ENDOFWHO, + params=["otherNick", InsensitiveStr("coolNick"), ANYSTR], + ) + + @cases.mark_specifications("IRCv3") + @cases.mark_isupport("WHOX") + def testWhoxNoAccount(self): + self._init(auth=False) + if "WHOX" not in self.server_support: + raise runner.IsupportTokenNotSupported("WHOX") + + self.sendLine(2, "WHO coolNick %na") + messages = self.getMessages(2) + + self.assertEqual(len(messages), 2, "Unexpected number of messages") + + (reply, end) = messages + + self.assertMessageMatch( + reply, + command=RPL_WHOSPCRPL, + params=[ + "otherNick", + "coolNick", + "0", + ], + ) + + self.assertMessageMatch( + end, + command=RPL_ENDOFWHO, + params=["otherNick", InsensitiveStr("coolNick"), ANYSTR], + ) diff --git a/irctest/specifications.py b/irctest/specifications.py index 71a5bcf..745895a 100644 --- a/irctest/specifications.py +++ b/irctest/specifications.py @@ -53,6 +53,7 @@ class IsupportTokens(enum.Enum): MONITOR = "MONITOR" STATUSMSG = "STATUSMSG" TARGMAX = "TARGMAX" + WHOX = "WHOX" @classmethod def from_name(cls, name: str) -> IsupportTokens: diff --git a/pytest.ini b/pytest.ini index 221add7..6774b93 100644 --- a/pytest.ini +++ b/pytest.ini @@ -35,5 +35,6 @@ markers = MONITOR STATUSMSG TARGMAX + WHOX python_classes = *TestCase Test*