tests (unit/ap-gateway): tests for following/followers <=> PPS:

AP following/followers collections to XMPP Public Pubsub Subscriptions conversion is
checked in both directions.

rel 365
This commit is contained in:
Goffi 2022-05-13 19:29:17 +02:00
commit 4d3f5f1afa

View file

@ -17,8 +17,9 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from copy import deepcopy
from unittest.mock import MagicMock, patch
from unittest.mock import MagicMock, AsyncMock, patch
from urllib import parse
from functools import partial
import pytest
from pytest_twisted import ensureDeferred as ed
@ -29,13 +30,16 @@ from wokkel import rsm, pubsub
from sat.core import exceptions
from sat.plugins import plugin_comp_ap_gateway
from sat.plugins.plugin_comp_ap_gateway.http_server import HTTPServer
from sat.plugins.plugin_xep_0465 import NS_PPS
from sat.tools.utils import xmpp_date
from sat.tools import xml_tools
from sat.plugins.plugin_comp_ap_gateway import TYPE_ACTOR
TEST_BASE_URL = "https://example.org"
TEST_USER = "test_user"
TEST_AP_ACCOUNT = f"{TEST_USER}@example.org"
PUBLIC_URL = "test.example"
AP_REQUESTS = {
f"{TEST_BASE_URL}/.well-known/webfinger?"
@ -71,7 +75,38 @@ AP_REQUESTS = {
"type": "Person",
"url": f"{TEST_BASE_URL}/@{TEST_USER}"
},
f"{TEST_BASE_URL}/.well-known/webfinger?"
f"resource=acct:{parse.quote('ext_user@example.org')}": {
"aliases": [
f"{TEST_BASE_URL}/@ext_user",
f"{TEST_BASE_URL}/users/ext_user"
],
"links": [
{
"href": f"{TEST_BASE_URL}/users/ext_user",
"rel": "self",
"type": "application/activity+json"
},
],
"subject": f"acct:ext_user@example.org"
},
f"{TEST_BASE_URL}/users/ext_user": {
"@context": [
"https://www.w3.org/ns/activitystreams",
],
"endpoints": {
"sharedInbox": f"{TEST_BASE_URL}/inbox"
},
"followers": f"{TEST_BASE_URL}/users/ext_user/followers",
"following": f"{TEST_BASE_URL}/users/ext_user/following",
"id": f"{TEST_BASE_URL}/users/ext_user",
"inbox": f"{TEST_BASE_URL}/users/ext_user/inbox",
"name": "",
"outbox": f"{TEST_BASE_URL}/users/ext_user/outbox",
"preferredUsername": f"ext_user",
"type": "Person",
"url": f"{TEST_BASE_URL}/@ext_user"
},
f"{TEST_BASE_URL}/users/{TEST_USER}/outbox": {
"@context": "https://www.w3.org/ns/activitystreams",
"first": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true",
@ -222,7 +257,43 @@ AP_REQUESTS = {
"partOf": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox",
"prev": None,
"type": "OrderedCollectionPage"
}
},
f"{TEST_BASE_URL}/users/{TEST_USER}/following": {
"@context": "https://www.w3.org/ns/activitystreams",
"first": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1",
"id": f"{TEST_BASE_URL}/users/{TEST_USER}/following",
"totalItems": 2,
"type": "OrderedCollection"
},
f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1": {
"@context": "https://www.w3.org/ns/activitystreams",
"id": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1",
"orderedItems": [
f"{TEST_BASE_URL}/users/ext_user",
f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}",
],
"partOf": "{TEST_BASE_URL}/users/{TEST_USER}/following",
"totalItems": 2,
"type": "OrderedCollectionPage"
},
f"{TEST_BASE_URL}/users/{TEST_USER}/followers": {
"@context": "https://www.w3.org/ns/activitystreams",
"first": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1",
"id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers",
"totalItems": 2,
"type": "OrderedCollection"
},
f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1": {
"@context": "https://www.w3.org/ns/activitystreams",
"id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1",
"orderedItems": [
f"{TEST_BASE_URL}/users/ext_user",
f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}",
],
"partOf": "{TEST_BASE_URL}/users/{TEST_USER}/followers",
"totalItems": 2,
"type": "OrderedCollectionPage"
},
}
@ -276,6 +347,7 @@ XMPP_ITEMS = [
for i in range(1, 5)
]
async def mock_ap_get(url):
return deepcopy(AP_REQUESTS[url])
@ -285,25 +357,28 @@ async def mock_treq_json(data):
async def mock_getItems(*args, **kwargs):
ret_items = kwargs.pop("ret_items", XMPP_ITEMS)
rsm_resp = rsm.RSMResponse(
first=XMPP_ITEMS[0]["id"],
last=XMPP_ITEMS[-1]["id"],
first=ret_items[0]["id"],
last=ret_items[-1]["id"],
index=0,
count=len(XMPP_ITEMS)
count=len(ret_items)
)
return XMPP_ITEMS, {"rsm": rsm_resp.toDict(), "complete": True}
return ret_items, {"rsm": rsm_resp.toDict(), "complete": True}
@pytest.fixture(scope="session")
def ap_gateway(host):
gateway = plugin_comp_ap_gateway.APGateway(host)
gateway.initialised = True
gateway.isPubsub = AsyncMock()
gateway.isPubsub.return_value = False
client = MagicMock()
client.jid = jid.JID("ap.test.example")
client.host = "test.example"
gateway.client = client
gateway.local_only = True
gateway.public_url = "test.example"
gateway.public_url = PUBLIC_URL
gateway.ap_path = '_ap'
gateway.base_ap_url = parse.urljoin(
f"https://{gateway.public_url}",
@ -407,7 +482,7 @@ class TestActivityPubGateway:
monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json)
monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get)
actor_data = await ap_gateway.getAPActorDataFromId(TEST_AP_ACCOUNT)
actor_data = await ap_gateway.getAPActorDataFromAccount(TEST_AP_ACCOUNT)
outbox = await ap_gateway.apGetObject(actor_data, "outbox")
items, rsm_resp = await ap_gateway.getAPItems(outbox, 2)
@ -548,9 +623,12 @@ class TestActivityPubGateway:
"node": None,
"ap_account": test_jid.full(),
"ap_url": ap_url,
"signing_actor": None
}
if type_ == "outbox" and query_data:
kwargs["query_data"] = query_data
# signing_actor is not used for page requests
del kwargs["signing_actor"]
return kwargs
@ed
@ -586,4 +664,127 @@ class TestActivityPubGateway:
assert first_item_obj["published"] == "2022-01-28T16:02:19Z"
assert first_item_obj["attributedTo"] == first_item["actor"]
assert first_item_obj["content"] == "<div><p>XMPP item 4</p></div>"
assert first_item_obj["to"] == "https://www.w3.org/ns/activitystreams#Public"
assert first_item_obj["to"] == ["https://www.w3.org/ns/activitystreams#Public"]
@ed
async def test_following_to_pps(self, ap_gateway, monkeypatch):
"""AP following items are converted to Public Pubsub Subscription subscriptions"""
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)
items, __ = await ap_gateway.pubsub_service.items(
jid.JID("toto@example.org"),
ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
ap_gateway._pps.subscriptions_node,
None,
None,
None
)
assert len(items) == 2
for idx, entity in enumerate((
"local_user@test.example",
"ext_user\\40example.org@ap.test.example"
)):
subscription_elt = next(items[idx].elements(NS_PPS, "subscription"), None)
assert subscription_elt is not None
assert subscription_elt["node"] == ap_gateway._m.namespace
assert subscription_elt["service"] == entity
@ed
async def test_followers_to_pps(self, ap_gateway, monkeypatch):
"""AP followers items are converted to Public Pubsub Subscription subscribers"""
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)
items, __ = await ap_gateway.pubsub_service.items(
jid.JID("toto@example.org"),
ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT),
ap_gateway._pps.getPublicSubscribersNode(ap_gateway._m.namespace),
None,
None,
None
)
assert len(items) == 2
for idx, entity in enumerate((
"local_user@test.example",
"ext_user\\40example.org@ap.test.example"
)):
subscriber_elt = next(items[idx].elements(NS_PPS, "subscriber"), None)
assert subscriber_elt is not None
assert subscriber_elt["jid"] == entity
@ed
async def test_pps_to_following(self, ap_gateway, monkeypatch):
"""Public Pubsub Subscription subscriptions are converted to AP following items"""
subscriptions = [
pubsub.Item(
id="subscription_1",
payload = ap_gateway._pps.buildSubscriptionElt(
ap_gateway._m.namespace,
jid.JID("local_user@test.example")
)
),
pubsub.Item(
id="subscription_2",
payload = ap_gateway._pps.buildSubscriptionElt(
ap_gateway._m.namespace,
jid.JID("ext_user\\40example.org@ap.test.example")
)
)
]
monkeypatch.setattr(ap_gateway._p, "getItems", partial(
mock_getItems,
ret_items=subscriptions
))
following = await ap_gateway.server.resource.APFollowingRequest(
**self.ap_request_params(ap_gateway, "following")
)
assert following["@context"] == "https://www.w3.org/ns/activitystreams"
assert following["id"] == "https://test.example/_ap/following/some_user%40test.example"
assert following["totalItems"] == len(subscriptions)
assert following["type"] == "OrderedCollection"
assert following.get("first")
first_page = following["first"]
assert first_page["type"] == "OrderedCollectionPage"
assert len(first_page["orderedItems"]) == len(subscriptions)
items = first_page["orderedItems"]
assert items == ['local_user@test.example', 'ext_user@example.org']
@ed
async def test_pps_to_followers(self, ap_gateway, monkeypatch):
"""Public Pubsub Subscription subscribers are converted to AP followers"""
subscribers = [
pubsub.Item(
id="subscriber_1",
payload = ap_gateway._pps.buildSubscriberElt(
jid.JID("local_user@test.example")
)
),
pubsub.Item(
id="subscriber_2",
payload = ap_gateway._pps.buildSubscriberElt(
jid.JID("ext_user\\40example.org@ap.test.example")
)
)
]
monkeypatch.setattr(ap_gateway._p, "getItems", partial(
mock_getItems,
ret_items=subscribers
))
followers = await ap_gateway.server.resource.APFollowersRequest(
**self.ap_request_params(ap_gateway, "followers")
)
assert followers["@context"] == "https://www.w3.org/ns/activitystreams"
assert followers["id"] == "https://test.example/_ap/followers/some_user%40test.example"
assert followers["totalItems"] == len(subscribers)
assert followers["type"] == "OrderedCollection"
assert followers.get("first")
first_page = followers["first"]
assert first_page["type"] == "OrderedCollectionPage"
assert len(first_page["orderedItems"]) == len(subscribers)
items = first_page["orderedItems"]
assert items == ['local_user@test.example', 'ext_user@example.org']