comparison 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
comparison
equal deleted inserted replaced
3836:e183f1fbfa8d 3837:56720561f45f
18 18
19 from copy import deepcopy 19 from copy import deepcopy
20 from unittest.mock import MagicMock, AsyncMock, patch, DEFAULT 20 from unittest.mock import MagicMock, AsyncMock, patch, DEFAULT
21 from urllib import parse 21 from urllib import parse
22 from functools import partial 22 from functools import partial
23 from typing import Dict, Union
23 24
24 import pytest 25 import pytest
25 from pytest_twisted import ensureDeferred as ed 26 from pytest_twisted import ensureDeferred as ed
26 from twisted.internet import defer 27 from twisted.internet import defer
27 from twisted.words.protocols.jabber import jid 28 from twisted.words.protocols.jabber import jid
40 from sat.plugins.plugin_xep_0422 import NS_FASTEN 41 from sat.plugins.plugin_xep_0422 import NS_FASTEN
41 from sat.plugins.plugin_xep_0424 import NS_MESSAGE_RETRACT 42 from sat.plugins.plugin_xep_0424 import NS_MESSAGE_RETRACT
42 from sat.plugins.plugin_xep_0465 import NS_PPS 43 from sat.plugins.plugin_xep_0465 import NS_PPS
43 from sat.tools.utils import xmpp_date 44 from sat.tools.utils import xmpp_date
44 from sat.tools import xml_tools 45 from sat.tools import xml_tools
46 from sat.tools.common import uri as xmpp_uri
45 from sat.plugins.plugin_comp_ap_gateway import TYPE_ACTOR 47 from sat.plugins.plugin_comp_ap_gateway import TYPE_ACTOR
46 from sat.memory.sqla_mapping import SubscriptionState 48 from sat.memory.sqla_mapping import SubscriptionState
47 49
48 50
49 TEST_BASE_URL = "https://example.org" 51 TEST_BASE_URL = "https://example.org"
389 count=len(ret_items) 391 count=len(ret_items)
390 ) 392 )
391 return ret_items, {"rsm": rsm_resp.toDict(), "complete": True} 393 return ret_items, {"rsm": rsm_resp.toDict(), "complete": True}
392 394
393 395
396 async def mock_getPubsubNode(client, service, node, with_subscriptions=False, **kwargs):
397 """Mock storage's getPubsubNode
398
399 return an MagicMock with subscription attribute set to empty list
400 """
401 fake_cached_node = MagicMock()
402 fake_cached_node.subscriptions = []
403 return fake_cached_node
404
405
394 def getVirtualClient(jid): 406 def getVirtualClient(jid):
395 client = MagicMock() 407 client = MagicMock()
396 client.jid = jid 408 client.jid = jid
397 return client 409 return client
398 410
413 client.getVirtualClient = getVirtualClient 425 client.getVirtualClient = getVirtualClient
414 gateway.client = client 426 gateway.client = client
415 gateway.local_only = True 427 gateway.local_only = True
416 gateway.public_url = PUBLIC_URL 428 gateway.public_url = PUBLIC_URL
417 gateway.ap_path = '_ap' 429 gateway.ap_path = '_ap'
430 gateway.auto_mentions = True
418 gateway.base_ap_url = parse.urljoin( 431 gateway.base_ap_url = parse.urljoin(
419 f"https://{gateway.public_url}", 432 f"https://{gateway.public_url}",
420 f"{gateway.ap_path}/" 433 f"{gateway.ap_path}/"
421 ) 434 )
422 gateway.server = HTTPServer(gateway) 435 gateway.server = HTTPServer(gateway)
1140 ) 1153 )
1141 1154
1142 # only the first nickname should be used 1155 # only the first nickname should be used
1143 assert actor_data["name"] == "nick1" 1156 assert actor_data["name"] == "nick1"
1144 assert actor_data["summary"] == "test description" 1157 assert actor_data["summary"] == "test description"
1158
1159 @ed
1160 async def test_direct_addressing_mention_to_reference(self, ap_gateway, monkeypatch):
1161 """AP mentions by direct addressing are converted to XEP-0372 references"""
1162 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
1163 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
1164 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1165
1166 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
1167
1168 direct_addr_mention = {
1169 'attributedTo': TEST_AP_ACTOR_ID,
1170 'cc': [],
1171 'content': '<p>test mention by direct addressing</p>',
1172 'id': f'{TEST_AP_ACTOR_ID}/statuses/direct_addr_123',
1173 'published': '2022-05-20T08:14:39Z',
1174 'to': [ap_const.NS_AP_PUBLIC, xmpp_actor_id],
1175 'type': 'Note'
1176 }
1177 client = ap_gateway.client.getVirtualClient(
1178 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1179 )
1180 monkeypatch.setattr(client, "sendMessage", MagicMock())
1181
1182 with patch.object(ap_gateway._refs, "sendReference") as sendReference:
1183 await ap_gateway.newAPItem(
1184 client, None, ap_gateway._m.namespace, direct_addr_mention
1185 )
1186
1187 assert sendReference.call_count == 1
1188 assert sendReference.call_args.kwargs["to_jid"] == TEST_JID
1189
1190 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1191 expected_anchor = xmpp_uri.buildXMPPUri(
1192 "pubsub",
1193 path=local_actor_jid.full(),
1194 node=ap_gateway._m.namespace,
1195 item=direct_addr_mention["id"]
1196 )
1197
1198 assert sendReference.call_args.kwargs["anchor"] == expected_anchor
1199
1200 @ed
1201 async def test_tag_mention_to_reference(self, ap_gateway, monkeypatch):
1202 """AP mentions in "tag" field are converted to XEP-0372 references"""
1203 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
1204 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
1205 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1206
1207 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost())
1208
1209 direct_addr_mention = {
1210 'attributedTo': TEST_AP_ACTOR_ID,
1211 'cc': [],
1212 'content': '<p>test mention by tag</p>',
1213 'id': f'{TEST_AP_ACTOR_ID}/statuses/tag_123',
1214 'published': '2022-05-20T08:14:39Z',
1215 'to': [ap_const.NS_AP_PUBLIC],
1216 "tag": [
1217 {
1218 "type": "Mention",
1219 "href": xmpp_actor_id,
1220 "name": f"@{TEST_JID}'"
1221 }
1222 ],
1223 'type': 'Note'
1224 }
1225 client = ap_gateway.client.getVirtualClient(
1226 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1227 )
1228 monkeypatch.setattr(client, "sendMessage", MagicMock())
1229
1230 with patch.object(ap_gateway._refs, "sendReference") as sendReference:
1231 await ap_gateway.newAPItem(
1232 client, None, ap_gateway._m.namespace, direct_addr_mention
1233 )
1234
1235 assert sendReference.call_count == 1
1236 assert sendReference.call_args.kwargs["to_jid"] == TEST_JID
1237
1238 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1239 expected_anchor = xmpp_uri.buildXMPPUri(
1240 "pubsub",
1241 path=local_actor_jid.full(),
1242 node=ap_gateway._m.namespace,
1243 item=direct_addr_mention["id"]
1244 )
1245
1246 assert sendReference.call_args.kwargs["anchor"] == expected_anchor
1247
1248 @ed
1249 async def test_auto_mentions(self, ap_gateway, monkeypatch):
1250 """Check that mentions in body are converted to AP mentions"""
1251 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
1252 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
1253 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1254
1255 mb_data = {
1256 "author_jid": TEST_JID.full(),
1257 "content": f"mention of @{TEST_AP_ACCOUNT}",
1258 "service": TEST_JID.full(),
1259 "node": ap_gateway._m.namespace
1260 }
1261 ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=True)
1262
1263 ap_object = ap_item["object"]
1264 assert TEST_AP_ACTOR_ID in ap_object["to"]
1265 expected_mention = {
1266 "type": ap_const.TYPE_MENTION,
1267 "href": TEST_AP_ACTOR_ID,
1268 "name": f"@{TEST_AP_ACCOUNT}"
1269 }
1270 assert expected_mention in ap_object["tag"]
1271
1272 @ed
1273 async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch):
1274 """Check that no mention is send when the message is not public"""
1275 # this is the same test as test_auto_mentions above, except that public is not set
1276 # in mbdata2APitem
1277 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
1278 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
1279 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1280
1281 mb_data = {
1282 "author_jid": TEST_JID.full(),
1283 "content": f"mention of @{TEST_AP_ACCOUNT}",
1284 "service": TEST_JID.full(),
1285 "node": ap_gateway._m.namespace
1286 }
1287 ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=False)
1288
1289 ap_object = ap_item["object"]
1290 assert "to" not in ap_object
1291 assert "tag" not in ap_object
1292
1293 @ed
1294 async def test_xmpp_reference_to_ap_mention(self, ap_gateway, monkeypatch):
1295 """Check that XEP-0372 references are converted to AP mention"""
1296 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get)
1297 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
1298 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
1299
1300 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT)
1301 item_elt = XMPP_ITEMS[0]
1302 anchor = xmpp_uri.buildXMPPUri(
1303 "pubsub",
1304 path=TEST_JID.full(),
1305 node=ap_gateway._m.namespace,
1306 item=item_elt["id"]
1307 )
1308
1309 ref_data: Dict[str, Union[str, int, dict]] = {
1310 "uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()),
1311 "type_": "mention",
1312 "anchor": anchor
1313 }
1314 reference_elt = ap_gateway._refs.buildRefElement(**ref_data)
1315
1316 # we now update ref_data to look like what is received in the trigger
1317
1318 ref_data["parsed_uri"] = xmpp_uri.parseXMPPUri(ref_data["uri"])
1319 ref_data["parsed_anchor"] = xmpp_uri.parseXMPPUri(ref_data["anchor"])
1320
1321 # "type" is a builtin function, thus "type_" is used in buildRefElement, but in
1322 # ref_data is "type" without underscore
1323 ref_data["type"] = ref_data["type_"]
1324 del ref_data["type_"]
1325
1326 message_elt = domish.Element((None, "message"))
1327 message_elt.addChild(reference_elt)
1328
1329 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems:
1330 # getItems returns a sqla_mapping.PubsubItem, thus we need to fake it and set
1331 # the item_elt we want to use in its "data" attribute
1332 mock_pubsub_item = MagicMock
1333 mock_pubsub_item.data = item_elt
1334 getItems.return_value = ([mock_pubsub_item], {})
1335 with patch.object(ap_gateway, "signAndPost") as signAndPost:
1336 signAndPost.return_value.code = 202
1337 await ap_gateway._onReferenceReceived(ap_gateway.client, message_elt, ref_data)
1338
1339 # when reference is received, the referencing item must be sent to referenced
1340 # actor, and they must be in "to" field and in "tag"
1341 assert signAndPost.call_count == 1
1342 send_ap_item = signAndPost.call_args.args[-1]
1343 ap_object = send_ap_item["object"]
1344 assert TEST_AP_ACTOR_ID in ap_object["to"]
1345 expected_mention = {
1346 "type": ap_const.TYPE_MENTION,
1347 "href": TEST_AP_ACTOR_ID,
1348 # we don't have a prefixing "@" here, because it's not needed in referencing
1349 # item with XMPP
1350 "name": f"{TEST_AP_ACCOUNT}"
1351 }
1352 assert expected_mention in ap_object["tag"]