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:
parent
fca541a2f1
commit
4d3f5f1afa
1 changed files with 211 additions and 10 deletions
|
|
@ -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']
|
||||
|
|
|
|||
Loading…
Reference in a new issue