Adapt metadata_2 to stdreplies, and run it on Unreal

Passes on 3968354247
This commit is contained in:
Valentin Lorentz 2023-04-15 14:44:58 +02:00
parent 604041aa13
commit e17ab347f4
3 changed files with 70 additions and 116 deletions

View File

@ -11,6 +11,7 @@ from irctest.basecontrollers import BaseServerController, DirectoryBasedControll
TEMPLATE_CONFIG = """
include "modules.default.conf";
loadmodule "third/metadata2";
include "operclass.default.conf";
{extras}
include "help/help.conf";

View File

@ -1,41 +1,23 @@
"""
`Deprecated IRCv3 Metadata <https://ircv3.net/specs/core/metadata-3.2>`_
`IRCv3 Metadata 2 <https://github.com/ircv3/ircv3-specifications/pull/501>`_
(not to be confused with the `deprecated IRCv3 Metadata
<https://ircv3.net/specs/core/metadata-3.2>`_)
"""
from irctest import cases
from irctest.patma import ANYSTR, StrRe
class MetadataTestCase(cases.BaseServerTestCase):
valid_metadata_keys = {"valid_key1", "valid_key2"}
invalid_metadata_keys = {"invalid_key1", "invalid_key2"}
@cases.mark_specifications("IRCv3", deprecated=True)
def testInIsupport(self):
"""“If METADATA is supported, it MUST be specified in RPL_ISUPPORT
using the METADATA key.
-- <http://ircv3.net/specs/core/metadata-3.2.html>
"""
self.addClient()
self.sendLine(1, "CAP LS 302")
self.getCapLs(1)
self.sendLine(1, "USER foo foo foo :foo")
self.sendLine(1, "NICK foo")
self.sendLine(1, "CAP END")
self.skipToWelcome(1)
m = self.getMessage(1)
while m.command != "005": # RPL_ISUPPORT
m = self.getMessage(1)
self.assertIn(
"METADATA",
{x.split("=")[0] for x in m.params[1:-1]},
fail_msg="{item} missing from RPL_ISUPPORT",
)
self.getMessages(1)
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.mark_specifications("IRCv3")
def testGetOneUnsetValid(self):
"""<http://ircv3.net/specs/core/metadata-3.2.html#metadata-get>"""
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
self.sendLine(1, "METADATA * GET valid_key1")
m = self.getMessage(1)
self.assertMessageMatch(
@ -45,25 +27,26 @@ class MetadataTestCase(cases.BaseServerTestCase):
"request to an unset valid METADATA key.",
)
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.mark_specifications("IRCv3")
def testGetTwoUnsetValid(self):
"""“Multiple keys may be given. The response will be either RPL_KEYVALUE,
ERR_KEYINVALID or ERR_NOMATCHINGKEY for every key in order.
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-get>
"""
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
self.sendLine(1, "METADATA * GET valid_key1 valid_key2")
m = self.getMessage(1)
self.assertMessageMatch(
m,
command="766", # ERR_NOMATCHINGKEY
fail_msg="Did not reply with 766 (ERR_NOMATCHINGKEY) to a "
command="766", # RPL_NOMATCHINGKEY
fail_msg="Did not reply with 766 (RPL_NOMATCHINGKEY) to a "
"request to two unset valid METADATA key: {msg}",
)
self.assertEqual(
m.params[1],
"valid_key1",
self.assertMessageMatch(
m,
params=["foo", "foo", "valid_key1", ANYSTR],
fail_msg="Response to “METADATA * GET valid_key1 valid_key2” "
"did not respond to valid_key1 first: {msg}",
)
@ -74,42 +57,45 @@ class MetadataTestCase(cases.BaseServerTestCase):
fail_msg="Did not reply with two 766 (ERR_NOMATCHINGKEY) to a "
"request to two unset valid METADATA key: {msg}",
)
self.assertEqual(
m.params[1],
"valid_key2",
self.assertMessageMatch(
m,
params=["foo", "foo", "valid_key2", ANYSTR],
fail_msg="Response to “METADATA * GET valid_key1 valid_key2” "
"did not respond to valid_key2 as second response: {msg}",
)
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.mark_specifications("IRCv3")
def testListNoSet(self):
"""“This subcommand MUST list all currently-set metadata keys along
with their values. The response will be zero or more RPL_KEYVALUE
events, following by RPL_METADATAEND event.
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-list>
"""
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
self.sendLine(1, "METADATA * LIST")
m = self.getMessage(1)
self.assertMessageMatch(
m,
command="762", # RPL_METADATAEND
fail_msg="Response to “METADATA * LIST” was not "
"762 (RPL_METADATAEND) but: {msg}",
params=["foo", ANYSTR],
)
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.mark_specifications("IRCv3")
def testListInvalidTarget(self):
"""“In case of invalid target RPL_METADATAEND MUST NOT be sent.”
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-list>
"""
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
self.sendLine(1, "METADATA foobar LIST")
m = self.getMessage(1)
self.assertMessageMatch(
m,
command="765", # ERR_TARGETINVALID
command="FAIL",
params=["METADATA", "INVALID_TARGET", "foobar", ANYSTR],
fail_msg="Response to “METADATA <invalid target> LIST” was "
"not 765 (ERR_TARGETINVALID) but: {msg}",
)
@ -117,115 +103,81 @@ class MetadataTestCase(cases.BaseServerTestCase):
self.assertNotIn(
"762",
commands,
fail_msg="Sent “METADATA <invalid target> LIST”, got 765 "
"(ERR_TARGETINVALID), and then 762 (RPL_METADATAEND)",
fail_msg="Sent “METADATA <invalid target> LIST”, got FAIL INVALID_TARGET, "
"and then 762 (RPL_METADATAEND)",
)
def assertSetValue(self, target, key, value, displayable_value=None):
if displayable_value is None:
displayable_value = value
def assertSetValue(self, target, key, value):
self.sendLine(1, "METADATA {} SET {} :{}".format(target, key, value))
m = self.getMessage(1)
if target == "*":
target = StrRe(r"(\*|foo)")
self.assertMessageMatch(
m,
self.getMessage(1),
command="761", # RPL_KEYVALUE
fail_msg="Did not reply with 761 (RPL_KEYVALUE) to a valid "
"“METADATA * SET {} :{}”: {msg}",
extra_format=(key, displayable_value),
)
self.assertEqual(
m.params[1],
"valid_key1",
m,
fail_msg="Second param of 761 after setting “{expects}” to "
"{}” is not “{expects}”: {msg}.",
extra_format=(displayable_value,),
)
self.assertEqual(
m.params[3],
value,
m,
fail_msg="Fourth param of 761 after setting “{0}” to "
"{1}” is not “{1}”: {msg}.",
extra_format=(key, displayable_value),
)
m = self.getMessage(1)
self.assertMessageMatch(
m,
command="762", # RPL_METADATAEND
fail_msg="Did not send RPL_METADATAEND after setting "
"a valid METADATA key.",
params=["foo", target, key, ANYSTR, value],
)
def assertGetValue(self, target, key, value, displayable_value=None):
self.sendLine(1, "METADATA * GET {}".format(key))
m = self.getMessage(1)
def assertGetValue(self, target, key, value):
self.sendLine(1, "METADATA {} GET {}".format(target, key))
if target == "*":
target = StrRe(r"(\*|foo)")
self.assertMessageMatch(
m,
self.getMessage(1),
command="761", # RPL_KEYVALUE
fail_msg="Did not reply with 761 (RPL_KEYVALUE) to a valid "
"“METADATA * GET” when the key is set is set: {msg}",
)
self.assertEqual(
m.params[1],
key,
m,
fail_msg="Second param of 761 after getting “{expects}"
"(which is set) is not “{expects}”: {msg}.",
)
self.assertEqual(
m.params[3],
value,
m,
fail_msg="Fourth param of 761 after getting “{0}"
"(which is set to “{1}”) is not ”{1}”: {msg}.",
extra_format=(key, displayable_value),
params=["foo", target, key, ANYSTR, value],
)
def assertSetGetValue(self, target, key, value, displayable_value=None):
self.assertSetValue(target, key, value, displayable_value)
self.assertGetValue(target, key, value, displayable_value)
def assertSetGetValue(self, target, key, value):
self.assertSetValue(target, key, value)
self.assertGetValue(target, key, value)
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.mark_specifications("IRCv3")
def testSetGetValid(self):
"""<http://ircv3.net/specs/core/metadata-3.2.html>"""
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
self.assertSetGetValue("*", "valid_key1", "myvalue")
@cases.mark_specifications("IRCv3", deprecated=True)
def testSetGetZeroCharInValue(self):
"""“Values are unrestricted, except that they MUST be UTF-8.”
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-restrictions>
"""
self.connectClient("foo")
self.assertSetGetValue("*", "valid_key1", "zero->\0<-zero", "zero->\\0<-zero")
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.mark_specifications("IRCv3")
def testSetGetHeartInValue(self):
"""“Values are unrestricted, except that they MUST be UTF-8.”
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-restrictions>
"""
heart = b"\xf0\x9f\x92\x9c".decode()
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
self.assertSetGetValue(
"*",
"valid_key1",
"->{}<-".format(heart),
"zero->{}<-zero".format(heart.encode()),
)
@cases.mark_specifications("IRCv3", deprecated=True)
@cases.xfailIfSoftware(
["UnrealIRCd"], "UnrealIRCd does not validate UTF-8 in metadata values"
)
@cases.mark_specifications("IRCv3")
def testSetInvalidUtf8(self):
"""“Values are unrestricted, except that they MUST be UTF-8.”
-- <http://ircv3.net/specs/core/metadata-3.2.html#metadata-restrictions>
"""
self.connectClient("foo")
self.connectClient(
"foo", capabilities=["draft/metadata-2", "batch"], skip_if_cap_nak=True
)
# Sending directly because it is not valid UTF-8 so Python would
# not like it
self.clients[1].conn.sendall(
b"METADATA * SET valid_key1 " b":invalid UTF-8 ->\xc3<-\r\n"
)
commands = {m.command for m in self.getMessages(1)}
try:
commands = {m.command for m in self.getMessages(1)}
except UnicodeDecodeError:
assert False, "Server sent invalid UTF-8"
self.assertNotIn(
"761",
commands, # RPL_KEYVALUE

View File

@ -27,6 +27,7 @@ markers =
extended-monitor
labeled-response
message-tags
metadata-2
draft/multiline
multi-prefix
server-time