diff tests/unit/test_ap-gateway.py @ 3837:56720561f45f

test (unit/AP gateway): tests for XMPP reference/mention <=> AP mention conversion: this patch add 5 tests: - 2 to mention AP mention to XMPP conversion, with direct addressing or using "tag" field - 2 to test automatic mention parsing of body - 1 to test XEP-0372 Reference to AP mention conversion rel 369
author Goffi <goffi@goffi.org>
date Sun, 10 Jul 2022 16:15:09 +0200
parents 81c79b7cafa7
children 8c01d8ab9447
line wrap: on
line diff
--- a/tests/unit/test_ap-gateway.py	Sun Jul 10 16:15:09 2022 +0200
+++ b/tests/unit/test_ap-gateway.py	Sun Jul 10 16:15:09 2022 +0200
@@ -20,6 +20,7 @@
 from unittest.mock import MagicMock, AsyncMock, patch, DEFAULT
 from urllib import parse
 from functools import partial
+from typing import Dict, Union
 
 import pytest
 from pytest_twisted import ensureDeferred as ed
@@ -42,6 +43,7 @@
 from sat.plugins.plugin_xep_0465 import NS_PPS
 from sat.tools.utils import xmpp_date
 from sat.tools import xml_tools
+from sat.tools.common import uri as xmpp_uri
 from sat.plugins.plugin_comp_ap_gateway import TYPE_ACTOR
 from sat.memory.sqla_mapping import SubscriptionState
 
@@ -391,6 +393,16 @@
     return ret_items, {"rsm": rsm_resp.toDict(), "complete": True}
 
 
+async def mock_getPubsubNode(client, service, node, with_subscriptions=False, **kwargs):
+    """Mock storage's getPubsubNode
+
+    return an MagicMock with subscription attribute set to empty list
+    """
+    fake_cached_node = MagicMock()
+    fake_cached_node.subscriptions = []
+    return fake_cached_node
+
+
 def getVirtualClient(jid):
     client = MagicMock()
     client.jid = jid
@@ -415,6 +427,7 @@
     gateway.local_only = True
     gateway.public_url = PUBLIC_URL
     gateway.ap_path = '_ap'
+    gateway.auto_mentions = True
     gateway.base_ap_url = parse.urljoin(
         f"https://{gateway.public_url}",
         f"{gateway.ap_path}/"
@@ -1142,3 +1155,198 @@
         # only the first nickname should be used
         assert actor_data["name"] == "nick1"
         assert actor_data["summary"] == "test description"
+
+    @ed
+    async def test_direct_addressing_mention_to_reference(self, ap_gateway, monkeypatch):
+        """AP mentions by direct addressing are converted to XEP-0372 references"""
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
+        monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
+
+        xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
+
+        direct_addr_mention = {
+            'attributedTo': TEST_AP_ACTOR_ID,
+            'cc': [],
+            'content': '<p>test mention by direct addressing</p>',
+            'id': f'{TEST_AP_ACTOR_ID}/statuses/direct_addr_123',
+            'published': '2022-05-20T08:14:39Z',
+            'to': [ap_const.NS_AP_PUBLIC, xmpp_actor_id],
+            'type': 'Note'
+        }
+        client = ap_gateway.client.getVirtualClient(
+            ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
+        )
+        monkeypatch.setattr(client, "sendMessage", MagicMock())
+
+        with patch.object(ap_gateway._refs, "sendReference") as sendReference:
+            await ap_gateway.newAPItem(
+                client, None, ap_gateway._m.namespace, direct_addr_mention
+            )
+
+        assert sendReference.call_count == 1
+        assert sendReference.call_args.kwargs["to_jid"] == TEST_JID
+
+        local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
+        expected_anchor = xmpp_uri.buildXMPPUri(
+            "pubsub",
+            path=local_actor_jid.full(),
+            node=ap_gateway._m.namespace,
+            item=direct_addr_mention["id"]
+        )
+
+        assert sendReference.call_args.kwargs["anchor"] == expected_anchor
+
+    @ed
+    async def test_tag_mention_to_reference(self, ap_gateway, monkeypatch):
+        """AP mentions in "tag" field are converted to XEP-0372 references"""
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
+        monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
+
+        xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
+
+        direct_addr_mention = {
+            'attributedTo': TEST_AP_ACTOR_ID,
+            'cc': [],
+            'content': '<p>test mention by tag</p>',
+            'id': f'{TEST_AP_ACTOR_ID}/statuses/tag_123',
+            'published': '2022-05-20T08:14:39Z',
+            'to': [ap_const.NS_AP_PUBLIC],
+            "tag": [
+                {
+                    "type": "Mention",
+                    "href": xmpp_actor_id,
+                    "name": f"@{TEST_JID}'"
+                }
+            ],
+            'type': 'Note'
+        }
+        client = ap_gateway.client.getVirtualClient(
+            ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
+        )
+        monkeypatch.setattr(client, "sendMessage", MagicMock())
+
+        with patch.object(ap_gateway._refs, "sendReference") as sendReference:
+            await ap_gateway.newAPItem(
+                client, None, ap_gateway._m.namespace, direct_addr_mention
+            )
+
+        assert sendReference.call_count == 1
+        assert sendReference.call_args.kwargs["to_jid"] == TEST_JID
+
+        local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
+        expected_anchor = xmpp_uri.buildXMPPUri(
+            "pubsub",
+            path=local_actor_jid.full(),
+            node=ap_gateway._m.namespace,
+            item=direct_addr_mention["id"]
+        )
+
+        assert sendReference.call_args.kwargs["anchor"] == expected_anchor
+
+    @ed
+    async def test_auto_mentions(self, ap_gateway, monkeypatch):
+        """Check that mentions in body are converted to AP mentions"""
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
+        monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
+
+        mb_data = {
+            "author_jid": TEST_JID.full(),
+            "content": f"mention of @{TEST_AP_ACCOUNT}",
+            "service": TEST_JID.full(),
+            "node": ap_gateway._m.namespace
+        }
+        ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=True)
+
+        ap_object = ap_item["object"]
+        assert TEST_AP_ACTOR_ID in ap_object["to"]
+        expected_mention = {
+            "type": ap_const.TYPE_MENTION,
+            "href": TEST_AP_ACTOR_ID,
+            "name": f"@{TEST_AP_ACCOUNT}"
+        }
+        assert expected_mention in ap_object["tag"]
+
+    @ed
+    async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch):
+        """Check that no mention is send when the message is not public"""
+        # this is the same test as test_auto_mentions above, except that public is not set
+        # in mbdata2APitem
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
+        monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
+
+        mb_data = {
+            "author_jid": TEST_JID.full(),
+            "content": f"mention of @{TEST_AP_ACCOUNT}",
+            "service": TEST_JID.full(),
+            "node": ap_gateway._m.namespace
+        }
+        ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=False)
+
+        ap_object = ap_item["object"]
+        assert "to" not in ap_object
+        assert "tag" not in ap_object
+
+    @ed
+    async def test_xmpp_reference_to_ap_mention(self, ap_gateway, monkeypatch):
+        """Check that XEP-0372 references are converted to AP mention"""
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
+        monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
+        monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
+
+        local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
+        item_elt = XMPP_ITEMS[0]
+        anchor = xmpp_uri.buildXMPPUri(
+            "pubsub",
+            path=TEST_JID.full(),
+            node=ap_gateway._m.namespace,
+            item=item_elt["id"]
+        )
+
+        ref_data: Dict[str, Union[str, int, dict]] = {
+            "uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()),
+            "type_": "mention",
+            "anchor": anchor
+        }
+        reference_elt = ap_gateway._refs.buildRefElement(**ref_data)
+
+        # we now update ref_data to look like what is received in the trigger
+
+        ref_data["parsed_uri"] = xmpp_uri.parseXMPPUri(ref_data["uri"])
+        ref_data["parsed_anchor"] = xmpp_uri.parseXMPPUri(ref_data["anchor"])
+
+        # "type" is a builtin function, thus "type_" is used in buildRefElement, but in
+        # ref_data is "type" without underscore
+        ref_data["type"] = ref_data["type_"]
+        del ref_data["type_"]
+
+        message_elt = domish.Element((None, "message"))
+        message_elt.addChild(reference_elt)
+
+        with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
+            # getItems returns a sqla_mapping.PubsubItem, thus we need to fake it and set
+            # the item_elt we want to use in its "data" attribute
+            mock_pubsub_item = MagicMock
+            mock_pubsub_item.data = item_elt
+            getItems.return_value = ([mock_pubsub_item], {})
+            with patch.object(ap_gateway, "signAndPost") as signAndPost:
+                signAndPost.return_value.code = 202
+                await ap_gateway._onReferenceReceived(ap_gateway.client, message_elt, ref_data)
+
+        # when reference is received, the referencing item must be sent to referenced
+        # actor, and they must be in "to" field and in "tag"
+        assert signAndPost.call_count == 1
+        send_ap_item = signAndPost.call_args.args[-1]
+        ap_object = send_ap_item["object"]
+        assert TEST_AP_ACTOR_ID in ap_object["to"]
+        expected_mention = {
+            "type": ap_const.TYPE_MENTION,
+            "href": TEST_AP_ACTOR_ID,
+            # we don't have a prefixing "@" here, because it's not needed in referencing
+            # item with XMPP
+            "name": f"{TEST_AP_ACCOUNT}"
+        }
+        assert expected_mention in ap_object["tag"]