irctest/irctest/server_tests/test_labeled_responses.py

641 lines
21 KiB
Python
Raw Normal View History

2018-02-10 22:56:30 +00:00
"""
<https://ircv3.net/specs/extensions/labeled-response.html>
"""
2018-12-28 18:43:01 +00:00
import re
2018-02-10 22:56:30 +00:00
from irctest import cases
2021-02-22 18:02:13 +00:00
2018-02-10 22:56:30 +00:00
class LabeledResponsesTestCase(cases.BaseServerTestCase, cases.OptionalityHelper):
2021-02-22 18:02:13 +00:00
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledPrivmsgResponsesToMultipleClients(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
2021-02-22 18:02:13 +00:00
self.connectClient(
"carl",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(3)
2021-02-22 18:02:13 +00:00
self.connectClient(
"alice",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(4)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345 PRIVMSG bar,carl,alice :hi")
2018-02-10 22:56:30 +00:00
m = self.getMessage(1)
m2 = self.getMessage(2)
m3 = self.getMessage(3)
m4 = self.getMessage(4)
# ensure the label isn't sent to recipients
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m2,
command="PRIVMSG",
fail_msg="No PRIVMSG received by target 1 after sending one out",
)
self.assertNotIn(
"label",
m2.tags,
m2,
fail_msg="When sending a PRIVMSG with a label, the target users shouldn't receive the label (only the sending user should): {msg}",
)
self.assertMessageEqual(
m3,
command="PRIVMSG",
fail_msg="No PRIVMSG received by target 1 after sending one out",
)
self.assertNotIn(
"label",
m3.tags,
m3,
fail_msg="When sending a PRIVMSG with a label, the target users shouldn't receive the label (only the sending user should): {msg}",
)
self.assertMessageEqual(
m4,
command="PRIVMSG",
fail_msg="No PRIVMSG received by target 1 after sending one out",
)
self.assertNotIn(
"label",
m4.tags,
m4,
fail_msg="When sending a PRIVMSG with a label, the target users shouldn't receive the label (only the sending user should): {msg}",
)
self.assertMessageEqual(
m, command="BATCH", fail_msg="No BATCH echo received after sending one out"
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledPrivmsgResponsesToClient(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345 PRIVMSG bar :hi")
2018-02-10 22:56:30 +00:00
m = self.getMessage(1)
m2 = self.getMessage(2)
# ensure the label isn't sent to recipient
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m2,
command="PRIVMSG",
fail_msg="No PRIVMSG received by the target after sending one out",
)
self.assertNotIn(
"label",
m2.tags,
m2,
fail_msg="When sending a PRIVMSG with a label, the target user shouldn't receive the label (only the sending user should): {msg}",
)
self.assertMessageEqual(
m,
command="PRIVMSG",
fail_msg="No PRIVMSG echo received after sending one out",
)
self.assertIn(
"label",
m.tags,
m,
fail_msg="When sending a PRIVMSG with a label, the echo'd message didn't contain the label at all: {msg}",
)
self.assertEqual(
m.tags["label"],
"12345",
m,
fail_msg="Echo'd PRIVMSG to a client did not contain the same label we sent it with(should be '12345'): {msg}",
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledPrivmsgResponsesToChannel(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
# join channels
2021-02-22 18:02:13 +00:00
self.sendLine(1, "JOIN #test")
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(2, "JOIN #test")
2018-02-10 22:56:30 +00:00
self.getMessages(2)
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(
1, "@label=12345;+draft/reply=123;+draft/react=l😃l PRIVMSG #test :hi"
)
2018-02-10 22:56:30 +00:00
ms = self.getMessage(1)
mt = self.getMessage(2)
# ensure the label isn't sent to recipient
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
mt,
command="PRIVMSG",
fail_msg="No PRIVMSG received by the target after sending one out",
)
self.assertNotIn(
"label",
mt.tags,
mt,
fail_msg="When sending a PRIVMSG with a label, the target user shouldn't receive the label (only the sending user should): {msg}",
)
2018-02-10 22:56:30 +00:00
# ensure sender correctly receives msg
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
ms, command="PRIVMSG", fail_msg="Got a message back that wasn't a PRIVMSG"
)
self.assertIn(
"label",
ms.tags,
ms,
fail_msg="When sending a PRIVMSG with a label, the source user should receive the label but didn't: {msg}",
)
self.assertEqual(
ms.tags["label"],
"12345",
ms,
fail_msg="Echo'd label doesn't match the label we sent (should be '12345'): {msg}",
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledPrivmsgResponsesToSelf(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345 PRIVMSG foo :hi")
2018-02-10 22:56:30 +00:00
m1 = self.getMessage(1)
m2 = self.getMessage(1)
number_of_labels = 0
for m in [m1, m2]:
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m,
command="PRIVMSG",
fail_msg="Got a message back that wasn't a PRIVMSG",
)
if "label" in m.tags:
2018-02-10 22:56:30 +00:00
number_of_labels += 1
2021-02-22 18:02:13 +00:00
self.assertEqual(
m.tags["label"],
"12345",
m,
fail_msg="Echo'd label doesn't match the label we sent (should be '12345'): {msg}",
)
self.assertEqual(
number_of_labels,
1,
m1,
fail_msg="When sending a PRIVMSG to self with echo-message, we only expect one message to contain the label. Instead, {} messages had the label".format(
number_of_labels
),
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledNoticeResponsesToClient(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345 NOTICE bar :hi")
2018-02-10 22:56:30 +00:00
m = self.getMessage(1)
m2 = self.getMessage(2)
# ensure the label isn't sent to recipient
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m2,
command="NOTICE",
fail_msg="No NOTICE received by the target after sending one out",
)
self.assertNotIn(
"label",
m2.tags,
m2,
fail_msg="When sending a NOTICE with a label, the target user shouldn't receive the label (only the sending user should): {msg}",
)
self.assertMessageEqual(
m,
command="NOTICE",
fail_msg="No NOTICE echo received after sending one out",
)
self.assertIn(
"label",
m.tags,
m,
fail_msg="When sending a NOTICE with a label, the echo'd message didn't contain the label at all: {msg}",
)
self.assertEqual(
m.tags["label"],
"12345",
m,
fail_msg="Echo'd NOTICE to a client did not contain the same label we sent it with(should be '12345'): {msg}",
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledNoticeResponsesToChannel(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
# join channels
2021-02-22 18:02:13 +00:00
self.sendLine(1, "JOIN #test")
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(2, "JOIN #test")
2018-02-10 22:56:30 +00:00
self.getMessages(2)
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(
1, "@label=12345;+draft/reply=123;+draft/react=l😃l NOTICE #test :hi"
)
2018-02-10 22:56:30 +00:00
ms = self.getMessage(1)
mt = self.getMessage(2)
# ensure the label isn't sent to recipient
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
mt,
command="NOTICE",
fail_msg="No NOTICE received by the target after sending one out",
)
self.assertNotIn(
"label",
mt.tags,
mt,
fail_msg="When sending a NOTICE with a label, the target user shouldn't receive the label (only the sending user should): {msg}",
)
2018-02-10 22:56:30 +00:00
# ensure sender correctly receives msg
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
ms, command="NOTICE", fail_msg="Got a message back that wasn't a NOTICE"
)
self.assertIn(
"label",
ms.tags,
ms,
fail_msg="When sending a NOTICE with a label, the source user should receive the label but didn't: {msg}",
)
self.assertEqual(
ms.tags["label"],
"12345",
ms,
fail_msg="Echo'd label doesn't match the label we sent (should be '12345'): {msg}",
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledNoticeResponsesToSelf(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345 NOTICE foo :hi")
2018-02-10 22:56:30 +00:00
m1 = self.getMessage(1)
m2 = self.getMessage(1)
number_of_labels = 0
for m in [m1, m2]:
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m, command="NOTICE", fail_msg="Got a message back that wasn't a NOTICE"
)
if "label" in m.tags:
2018-02-10 22:56:30 +00:00
number_of_labels += 1
2021-02-22 18:02:13 +00:00
self.assertEqual(
m.tags["label"],
"12345",
m,
fail_msg="Echo'd label doesn't match the label we sent (should be '12345'): {msg}",
)
self.assertEqual(
number_of_labels,
1,
m1,
fail_msg="When sending a NOTICE to self with echo-message, we only expect one message to contain the label. Instead, {} messages had the label".format(
number_of_labels
),
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledTagMsgResponsesToClient(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response", "message-tags"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response", "message-tags"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345;+draft/reply=123;+draft/react=l😃l TAGMSG bar")
2018-02-10 22:56:30 +00:00
m = self.getMessage(1)
m2 = self.getMessage(2)
# ensure the label isn't sent to recipient
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m2,
command="TAGMSG",
fail_msg="No TAGMSG received by the target after sending one out",
)
self.assertNotIn(
"label",
m2.tags,
m2,
fail_msg="When sending a TAGMSG with a label, the target user shouldn't receive the label (only the sending user should): {msg}",
)
self.assertIn(
"+draft/reply",
m2.tags,
m2,
fail_msg="Reply tag wasn't present on the target user's TAGMSG: {msg}",
)
self.assertEqual(
m2.tags["+draft/reply"],
"123",
m2,
fail_msg="Reply tag wasn't the same on the target user's TAGMSG: {msg}",
)
self.assertIn(
"+draft/react",
m2.tags,
m2,
fail_msg="React tag wasn't present on the target user's TAGMSG: {msg}",
)
self.assertEqual(
m2.tags["+draft/react"],
"l😃l",
m2,
fail_msg="React tag wasn't the same on the target user's TAGMSG: {msg}",
)
self.assertMessageEqual(
m,
command="TAGMSG",
fail_msg="No TAGMSG echo received after sending one out",
)
self.assertIn(
"label",
m.tags,
m,
fail_msg="When sending a TAGMSG with a label, the echo'd message didn't contain the label at all: {msg}",
)
self.assertEqual(
m.tags["label"],
"12345",
m,
fail_msg="Echo'd TAGMSG to a client did not contain the same label we sent it with(should be '12345'): {msg}",
)
self.assertIn(
"+draft/reply",
m.tags,
m,
fail_msg="Reply tag wasn't present on the source user's TAGMSG: {msg}",
)
self.assertEqual(
m2.tags["+draft/reply"],
"123",
m,
fail_msg="Reply tag wasn't the same on the source user's TAGMSG: {msg}",
)
self.assertIn(
"+draft/react",
m.tags,
m,
fail_msg="React tag wasn't present on the source user's TAGMSG: {msg}",
)
self.assertEqual(
m2.tags["+draft/react"],
"l😃l",
m,
fail_msg="React tag wasn't the same on the source user's TAGMSG: {msg}",
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledTagMsgResponsesToChannel(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response", "message-tags"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "echo-message", "labeled-response", "message-tags"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(2)
# join channels
2021-02-22 18:02:13 +00:00
self.sendLine(1, "JOIN #test")
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(2, "JOIN #test")
2018-02-10 22:56:30 +00:00
self.getMessages(2)
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345;+draft/reply=123;+draft/react=l😃l TAGMSG #test")
2018-02-10 22:56:30 +00:00
ms = self.getMessage(1)
mt = self.getMessage(2)
# ensure the label isn't sent to recipient
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
mt,
command="TAGMSG",
fail_msg="No TAGMSG received by the target after sending one out",
)
self.assertNotIn(
"label",
mt.tags,
mt,
fail_msg="When sending a TAGMSG with a label, the target user shouldn't receive the label (only the sending user should): {msg}",
)
2018-02-10 22:56:30 +00:00
# ensure sender correctly receives msg
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
ms, command="TAGMSG", fail_msg="Got a message back that wasn't a TAGMSG"
)
self.assertIn(
"label",
ms.tags,
ms,
fail_msg="When sending a TAGMSG with a label, the source user should receive the label but didn't: {msg}",
)
self.assertEqual(
ms.tags["label"],
"12345",
ms,
fail_msg="Echo'd label doesn't match the label we sent (should be '12345'): {msg}",
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-02-10 22:56:30 +00:00
def testLabeledTagMsgResponsesToSelf(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"foo",
capabilities=["batch", "echo-message", "labeled-response", "message-tags"],
skip_if_cap_nak=True,
)
2018-02-10 22:56:30 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345;+draft/reply=123;+draft/react=l😃l TAGMSG foo")
2018-02-10 22:56:30 +00:00
m1 = self.getMessage(1)
m2 = self.getMessage(1)
number_of_labels = 0
for m in [m1, m2]:
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(
m, command="TAGMSG", fail_msg="Got a message back that wasn't a TAGMSG"
)
if "label" in m.tags:
2018-02-10 22:56:30 +00:00
number_of_labels += 1
2021-02-22 18:02:13 +00:00
self.assertEqual(
m.tags["label"],
"12345",
m,
fail_msg="Echo'd label doesn't match the label we sent (should be '12345'): {msg}",
)
self.assertEqual(
number_of_labels,
1,
m1,
fail_msg="When sending a TAGMSG to self with echo-message, we only expect one message to contain the label. Instead, {} messages had the label".format(
number_of_labels
),
)
@cases.SpecificationSelector.requiredBySpecification("IRCv3.2")
2018-12-28 18:43:01 +00:00
def testBatchedJoinMessages(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "labeled-response", "message-tags", "server-time"],
skip_if_cap_nak=True,
)
2018-12-28 18:43:01 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=12345 JOIN #xyz")
2018-12-28 18:43:01 +00:00
m = self.getMessages(1)
# we expect at least join and names lines, which must be batched
self.assertGreaterEqual(len(m), 3)
# valid BATCH start line:
batch_start = m[0]
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(batch_start, command="BATCH")
2018-12-28 18:43:01 +00:00
self.assertEqual(len(batch_start.params), 2)
2021-02-22 18:02:13 +00:00
self.assertTrue(
batch_start.params[0].startswith("+"),
"batch start param must begin with +, got %s" % (batch_start.params[0],),
)
2018-12-28 18:43:01 +00:00
batch_id = batch_start.params[0][1:]
# batch id MUST be alphanumerics and hyphens
2021-02-22 18:02:13 +00:00
self.assertTrue(
re.match(r"^[A-Za-z0-9\-]+$", batch_id) is not None,
"batch id must be alphanumerics and hyphens, got %r" % (batch_id,),
)
self.assertEqual(batch_start.params[1], "labeled-response")
self.assertEqual(batch_start.tags.get("label"), "12345")
2018-12-28 18:43:01 +00:00
# valid BATCH end line
batch_end = m[-1]
2021-02-22 18:02:13 +00:00
self.assertMessageEqual(batch_end, command="BATCH", params=["-" + batch_id])
2018-12-28 18:43:01 +00:00
# messages must have the BATCH tag
for message in m[1:-1]:
2021-02-22 18:02:13 +00:00
self.assertEqual(message.tags.get("batch"), batch_id)
2018-12-28 18:43:01 +00:00
2021-02-22 18:02:13 +00:00
@cases.SpecificationSelector.requiredBySpecification("Oragono")
2018-12-28 18:43:01 +00:00
def testNoBatchForSingleMessage(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "labeled-response", "message-tags", "server-time"],
)
2018-12-28 18:43:01 +00:00
self.getMessages(1)
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=98765 PING adhoctestline")
2018-12-28 18:43:01 +00:00
# no BATCH should be initiated for a one-line response, it should just be labeled
ms = self.getMessages(1)
self.assertEqual(len(ms), 1)
m = ms[0]
2021-02-22 18:02:13 +00:00
self.assertEqual(m.command, "PONG")
self.assertEqual(m.params[-1], "adhoctestline")
2018-12-28 18:43:01 +00:00
# check the label
2021-02-22 18:02:13 +00:00
self.assertEqual(m.tags.get("label"), "98765")
2019-02-21 03:48:48 +00:00
2021-02-22 18:02:13 +00:00
@cases.SpecificationSelector.requiredBySpecification("Oragono")
2019-02-21 03:48:48 +00:00
def testEmptyBatchForNoResponse(self):
2021-02-22 18:02:13 +00:00
self.connectClient(
"bar",
capabilities=["batch", "labeled-response", "message-tags", "server-time"],
)
2019-02-21 03:48:48 +00:00
self.getMessages(1)
# PONG never receives a response
2021-02-22 18:02:13 +00:00
self.sendLine(1, "@label=98765 PONG adhoctestline")
2019-02-21 03:48:48 +00:00
2020-01-28 02:12:33 +00:00
# labeled-response: "Servers MUST respond with a labeled
2019-06-13 06:11:26 +00:00
# `ACK` message when a client sends a labeled command that normally
# produces no response."
2019-02-21 03:48:48 +00:00
ms = self.getMessages(1)
2019-06-13 06:11:26 +00:00
self.assertEqual(len(ms), 1)
ack = ms[0]
2019-02-21 03:48:48 +00:00
2021-02-22 18:02:13 +00:00
self.assertEqual(ack.command, "ACK")
self.assertEqual(ack.tags.get("label"), "98765")