lusers: Add a variant that ircu2 and snircd can pass + add stricter tests (#126)

This commit is contained in:
Val Lorentz 2022-01-15 00:19:58 +01:00 committed by GitHub
parent 88a8f8ad8d
commit 1371979ccd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 31 deletions

View File

@ -66,7 +66,7 @@ INSPIRCD_SELECTORS := \
# buffering tests fail because ircu2 discards the whole buffer on long lines (TODO: refine how we exclude these tests)
# testQuit and testQuitErrors fail because ircu2 does not send ERROR or QUIT
# lusers tests fail because they depend on Modern behavior, not just RFC2812 (TODO: update lusers tests to accept RFC2812-compliant implementations)
# lusers "full" tests fail because they depend on Modern behavior, not just RFC2812
# statusmsg tests fail because STATUSMSG is present in ISUPPORT, but it not actually supported as PRIVMSG target
# testKeyValidation[empty] fails because ircu2 returns ERR_NEEDMOREPARAMS on empty keys: https://github.com/UndernetIRC/ircu2/issues/13
# testKickDefaultComment fails because it uses the nick of the kickee rather than the kicker.
@ -78,7 +78,7 @@ IRCU2_SELECTORS := \
and not strict \
and not buffering \
and not testQuit \
and not lusers \
and not (lusers and full) \
and not statusmsg \
and not (testKeyValidation and empty) \
and not testKickDefaultComment \
@ -93,7 +93,7 @@ SNIRCD_SELECTORS := \
and not strict \
and not buffering \
and not testQuit \
and not lusers \
and not (lusers and full) \
and not statusmsg \
$(EXTRA_SELECTORS)

View File

@ -14,6 +14,7 @@ from irctest.numerics import (
RPL_LUSERUNKNOWN,
RPL_YOUREOPER,
)
from irctest.patma import ANYSTR, StrRe
# 3 numbers, delimited by spaces, possibly negative (eek)
LUSERCLIENT_REGEX = re.compile(r"^.*( [-0-9]* ).*( [-0-9]* ).*( [-0-9]* ).*$")
@ -50,10 +51,11 @@ class LusersTestCase(cases.BaseServerTestCase):
self.assertIn(lusers.LocalTotal, (total, None))
self.assertIn(lusers.LocalMax, (max_, None))
def getLusers(self, client):
def getLusers(self, client, allow_missing_265_266):
self.sendLine(client, "LUSERS")
messages = self.getMessages(client)
by_numeric = dict((msg.command, msg) for msg in messages)
self.assertEqual(len(by_numeric), len(messages), "Duplicated numerics")
result = LusersResult()
@ -73,12 +75,31 @@ class LusersTestCase(cases.BaseServerTestCase):
raise ValueError("corrupt reply for 251 RPL_LUSERCLIENT", luserclient_param)
if RPL_LUSEROP in by_numeric:
self.assertMessageMatch(
by_numeric[RPL_LUSEROP], params=[client, StrRe("[0-9]+"), ANYSTR]
)
result.Opers = int(by_numeric[RPL_LUSEROP].params[1])
if RPL_LUSERUNKNOWN in by_numeric:
self.assertMessageMatch(
by_numeric[RPL_LUSERUNKNOWN], params=[client, StrRe("[0-9]+"), ANYSTR]
)
result.Unregistered = int(by_numeric[RPL_LUSERUNKNOWN].params[1])
if RPL_LUSERCHANNELS in by_numeric:
self.assertMessageMatch(
by_numeric[RPL_LUSERCHANNELS], params=[client, StrRe("[0-9]+"), ANYSTR]
)
result.Channels = int(by_numeric[RPL_LUSERCHANNELS].params[1])
self.assertMessageMatch(by_numeric[RPL_LUSERCLIENT], params=[client, ANYSTR])
self.assertMessageMatch(by_numeric[RPL_LUSERME], params=[client, ANYSTR])
if (
allow_missing_265_266
and RPL_LOCALUSERS not in by_numeric
and RPL_GLOBALUSERS not in by_numeric
):
return
# FIXME: RPL_LOCALUSERS and RPL_GLOBALUSERS are only in Modern, not in RFC2812
localusers = by_numeric[RPL_LOCALUSERS]
globalusers = by_numeric[RPL_GLOBALUSERS]
@ -114,23 +135,39 @@ class BasicLusersTestCase(LusersTestCase):
@cases.mark_specifications("RFC2812")
def testLusers(self):
self.connectClient("bar", name="bar")
lusers = self.getLusers("bar")
self.getLusers("bar", True)
self.connectClient("qux", name="qux")
self.getLusers("qux", True)
self.sendLine("qux", "QUIT")
self.assertDisconnected("qux")
self.getLusers("bar", True)
@cases.mark_specifications("Modern")
def testLusersFull(self):
self.connectClient("bar", name="bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=1)
self.connectClient("qux", name="qux")
lusers = self.getLusers("qux")
lusers = self.getLusers("qux", False)
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
self.sendLine("qux", "QUIT")
self.assertDisconnected("qux")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=2)
class LusersUnregisteredTestCase(LusersTestCase):
@cases.mark_specifications("RFC2812")
def testLusers(self):
self.doLusersTest()
def testLusersRfc2812(self):
self.doLusersTest(True)
@cases.mark_specifications("Modern")
def testLusersFull(self):
self.doLusersTest(False)
def _synchronize(self, client_name):
"""Synchronizes using a PING, but accept ERR_NOTREGISTERED as a response."""
@ -145,34 +182,39 @@ class LusersUnregisteredTestCase(LusersTestCase):
"got neither PONG or ERR_NOTREGISTERED"
)
def doLusersTest(self):
def doLusersTest(self, allow_missing_265_266):
self.connectClient("bar", name="bar")
lusers = self.getLusers("bar")
self.assertLusersResult(lusers, unregistered=0, total=1, max_=1)
lusers = self.getLusers("bar", allow_missing_265_266)
if lusers:
self.assertLusersResult(lusers, unregistered=0, total=1, max_=1)
self.addClient("qux")
self.sendLine("qux", "NICK qux")
self._synchronize("qux")
lusers = self.getLusers("bar")
self.assertLusersResult(lusers, unregistered=1, total=1, max_=1)
lusers = self.getLusers("bar", allow_missing_265_266)
if lusers:
self.assertLusersResult(lusers, unregistered=1, total=1, max_=1)
self.addClient("bat")
self.sendLine("bat", "NICK bat")
self._synchronize("bat")
lusers = self.getLusers("bar")
self.assertLusersResult(lusers, unregistered=2, total=1, max_=1)
lusers = self.getLusers("bar", allow_missing_265_266)
if lusers:
self.assertLusersResult(lusers, unregistered=2, total=1, max_=1)
# complete registration on one client
self.sendLine("qux", "USER u s e r")
self.getRegistrationMessage("qux")
lusers = self.getLusers("bar")
self.assertLusersResult(lusers, unregistered=1, total=2, max_=2)
lusers = self.getLusers("bar", allow_missing_265_266)
if lusers:
self.assertLusersResult(lusers, unregistered=1, total=2, max_=2)
# QUIT the other without registering
self.sendLine("bat", "QUIT")
self.assertDisconnected("bat")
lusers = self.getLusers("bar")
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
lusers = self.getLusers("bar", allow_missing_265_266)
if lusers:
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
class LusersUnregisteredDefaultInvisibleTestCase(LusersUnregisteredTestCase):
@ -188,8 +230,8 @@ class LusersUnregisteredDefaultInvisibleTestCase(LusersUnregisteredTestCase):
@cases.mark_specifications("Ergo")
def testLusers(self):
self.doLusersTest()
lusers = self.getLusers("bar")
self.doLusersTest(False)
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
self.assertEqual(lusers.GlobalInvisible, 2)
self.assertEqual(lusers.GlobalVisible, 0)
@ -199,7 +241,7 @@ class LuserOpersTestCase(LusersTestCase):
@cases.mark_specifications("Ergo")
def testLuserOpers(self):
self.connectClient("bar", name="bar")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=1)
self.assertIn(lusers.Opers, (0, None))
@ -207,7 +249,7 @@ class LuserOpersTestCase(LusersTestCase):
self.sendLine("bar", "OPER operuser operpassword")
msgs = self.getMessages("bar")
self.assertIn(RPL_YOUREOPER, {msg.command for msg in msgs})
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=1)
self.assertEqual(lusers.Opers, 1)
@ -215,7 +257,7 @@ class LuserOpersTestCase(LusersTestCase):
self.connectClient("qux", name="qux")
self.sendLine("qux", "OPER operuser operpassword")
self.getMessages("qux")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
self.assertEqual(lusers.Opers, 2)
@ -223,14 +265,14 @@ class LuserOpersTestCase(LusersTestCase):
self.sendLine("bar", "MODE bar -o")
msgs = self.getMessages("bar")
self.assertIn("MODE", {msg.command for msg in msgs})
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
self.assertEqual(lusers.Opers, 1)
# remove oper by quit
self.sendLine("qux", "QUIT")
self.assertDisconnected("qux")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=2)
self.assertEqual(lusers.Opers, 0)
@ -247,13 +289,13 @@ class ErgoInvisibleDefaultTestCase(LusersTestCase):
@cases.mark_specifications("Ergo")
def testLusers(self):
self.connectClient("bar", name="bar")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=1)
self.assertEqual(lusers.GlobalInvisible, 1)
self.assertEqual(lusers.GlobalVisible, 0)
self.connectClient("qux", name="qux")
lusers = self.getLusers("qux")
lusers = self.getLusers("qux", False)
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
self.assertEqual(lusers.GlobalInvisible, 2)
self.assertEqual(lusers.GlobalVisible, 0)
@ -261,7 +303,7 @@ class ErgoInvisibleDefaultTestCase(LusersTestCase):
# remove +i with MODE
self.sendLine("bar", "MODE bar -i")
msgs = self.getMessages("bar")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertIn("MODE", {msg.command for msg in msgs})
self.assertLusersResult(lusers, unregistered=0, total=2, max_=2)
self.assertEqual(lusers.GlobalInvisible, 1)
@ -270,7 +312,7 @@ class ErgoInvisibleDefaultTestCase(LusersTestCase):
# disconnect invisible user
self.sendLine("qux", "QUIT")
self.assertDisconnected("qux")
lusers = self.getLusers("bar")
lusers = self.getLusers("bar", False)
self.assertLusersResult(lusers, unregistered=0, total=1, max_=2)
self.assertEqual(lusers.GlobalInvisible, 0)
self.assertEqual(lusers.GlobalVisible, 1)