Mercurial > libervia-backend
annotate tests/unit/test_ap-gateway.py @ 3743:54c249ec35ce
core (memory/migration): ignore FTS table when autogenerating script for migration:
SQLite Full-Text Search stable are not associated to Python object and can't be detected
by Alembic. To avoid the generation of unwanted drop commands, they are now ignored when
autogenerating migration scripts.
rel 364
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 22 Mar 2022 17:00:42 +0100 |
parents | 04ecc8eeb81a |
children | f31113777881 |
rev | line source |
---|---|
3733 | 1 #!/usr/bin/env python3 |
2 | |
3 # Libervia: an XMPP client | |
4 # Copyright (C) 2009-2022 Jérôme Poisson (goffi@goffi.org) | |
5 | |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 from copy import deepcopy | |
20 from unittest.mock import MagicMock, patch | |
21 from urllib import parse | |
22 | |
23 import pytest | |
24 from pytest_twisted import ensureDeferred as ed | |
25 from twisted.words.protocols.jabber import jid | |
26 from twisted.web.server import Request | |
27 from wokkel import rsm, pubsub | |
28 | |
29 from sat.core import exceptions | |
30 from sat.plugins import plugin_comp_ap_gateway | |
31 from sat.plugins.plugin_comp_ap_gateway.http_server import HTTPServer | |
32 from sat.tools.utils import xmpp_date | |
33 from sat.tools import xml_tools | |
34 | |
35 | |
36 TEST_BASE_URL = "https://example.org" | |
37 TEST_USER = "test_user" | |
38 TEST_AP_ACCOUNT = f"{TEST_USER}@example.org" | |
39 | |
40 AP_REQUESTS = { | |
41 f"{TEST_BASE_URL}/.well-known/webfinger?" | |
42 f"resource=acct:{parse.quote(TEST_AP_ACCOUNT)}": { | |
43 "aliases": [ | |
44 f"{TEST_BASE_URL}/@{TEST_USER}", | |
45 f"{TEST_BASE_URL}/users/{TEST_USER}" | |
46 ], | |
47 "links": [ | |
48 { | |
49 "href": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
50 "rel": "self", | |
51 "type": "application/activity+json" | |
52 }, | |
53 ], | |
54 "subject": f"acct:{TEST_AP_ACCOUNT}" | |
55 }, | |
56 | |
57 f"{TEST_BASE_URL}/users/{TEST_USER}": { | |
58 "@context": [ | |
59 "https://www.w3.org/ns/activitystreams", | |
60 ], | |
61 "endpoints": { | |
62 "sharedInbox": f"{TEST_BASE_URL}/inbox" | |
63 }, | |
64 "followers": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
65 "following": f"{TEST_BASE_URL}/users/{TEST_USER}/following", | |
66 "id": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
67 "inbox": f"{TEST_BASE_URL}/users/{TEST_USER}/inbox", | |
68 "name": "", | |
69 "outbox": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", | |
70 "preferredUsername": f"{TEST_USER}", | |
71 "type": "Person", | |
72 "url": f"{TEST_BASE_URL}/@{TEST_USER}" | |
73 }, | |
74 | |
75 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox": { | |
76 "@context": "https://www.w3.org/ns/activitystreams", | |
77 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", | |
78 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", | |
79 "last": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", | |
80 "totalItems": 4, | |
81 "type": "OrderedCollection" | |
82 }, | |
83 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true": { | |
84 "@context": [ | |
85 "https://www.w3.org/ns/activitystreams", | |
86 ], | |
87 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", | |
88 "orderedItems": [ | |
89 { | |
90 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
91 "cc": [ | |
92 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
93 ], | |
94 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/1/activity", | |
95 "object": { | |
96 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
97 "cc": [ | |
98 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
99 ], | |
100 "content": "<p>test message 1</p>", | |
101 "contentMap": { | |
102 "en": "<p>test message 1</p>" | |
103 }, | |
104 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/1", | |
105 "inReplyTo": None, | |
106 "published": "2021-12-16T17:28:03Z", | |
107 "sensitive": False, | |
108 "summary": None, | |
109 "tag": [], | |
110 "to": [ | |
111 "https://www.w3.org/ns/activitystreams#Public" | |
112 ], | |
113 "type": "Note", | |
114 "url": f"{TEST_BASE_URL}/@{TEST_USER}/1" | |
115 }, | |
116 "published": "2021-12-16T17:28:03Z", | |
117 "to": [ | |
118 "https://www.w3.org/ns/activitystreams#Public" | |
119 ], | |
120 "type": "Create" | |
121 }, | |
122 { | |
123 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
124 "cc": [ | |
125 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
126 ], | |
127 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/2/activity", | |
128 "object": { | |
129 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
130 "cc": [ | |
131 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
132 ], | |
133 "content": "<p>test message 2</p>", | |
134 "contentMap": { | |
135 "en": "<p>test message 2</p>" | |
136 }, | |
137 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/2", | |
138 "inReplyTo": None, | |
139 "published": "2021-12-16T17:27:03Z", | |
140 "sensitive": False, | |
141 "summary": None, | |
142 "tag": [], | |
143 "to": [ | |
144 "https://www.w3.org/ns/activitystreams#Public" | |
145 ], | |
146 "type": "Note", | |
147 "url": f"{TEST_BASE_URL}/@{TEST_USER}/2" | |
148 }, | |
149 "published": "2021-12-16T17:27:03Z", | |
150 "to": [ | |
151 "https://www.w3.org/ns/activitystreams#Public" | |
152 ], | |
153 "type": "Create" | |
154 }, | |
155 { | |
156 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
157 "cc": [ | |
158 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
159 ], | |
160 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/3/activity", | |
161 "object": { | |
162 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
163 "cc": [ | |
164 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
165 ], | |
166 "content": "<p>test message 3</p>", | |
167 "contentMap": { | |
168 "en": "<p>test message 3</p>" | |
169 }, | |
170 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/3", | |
171 "inReplyTo": None, | |
172 "published": "2021-12-16T17:26:03Z", | |
173 "sensitive": False, | |
174 "summary": None, | |
175 "tag": [], | |
176 "to": [ | |
177 "https://www.w3.org/ns/activitystreams#Public" | |
178 ], | |
179 "type": "Note", | |
180 "url": f"{TEST_BASE_URL}/@{TEST_USER}/3" | |
181 }, | |
182 "published": "2021-12-16T17:26:03Z", | |
183 "to": [ | |
184 "https://www.w3.org/ns/activitystreams#Public" | |
185 ], | |
186 "type": "Create" | |
187 }, | |
188 { | |
189 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
190 "cc": [ | |
191 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
192 ], | |
193 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/4/activity", | |
194 "object": { | |
195 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | |
196 "cc": [ | |
197 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | |
198 ], | |
199 "content": "<p>test message 4</p>", | |
200 "contentMap": { | |
201 "en": "<p>test message 4</p>" | |
202 }, | |
203 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/4", | |
204 "inReplyTo": None, | |
205 "published": "2021-12-16T17:25:03Z", | |
206 "sensitive": False, | |
207 "summary": None, | |
208 "tag": [], | |
209 "to": [ | |
210 "https://www.w3.org/ns/activitystreams#Public" | |
211 ], | |
212 "type": "Note", | |
213 "url": f"{TEST_BASE_URL}/@{TEST_USER}/4" | |
214 }, | |
215 "published": "2021-12-16T17:25:03Z", | |
216 "to": [ | |
217 "https://www.w3.org/ns/activitystreams#Public" | |
218 ], | |
219 "type": "Create" | |
220 }, | |
221 ], | |
222 "partOf": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", | |
223 "prev": None, | |
224 "type": "OrderedCollectionPage" | |
225 } | |
226 | |
227 } | |
228 | |
229 XMPP_ITEM_TPL = """ | |
230 <item id='{id}' publisher='{publisher_jid}'> | |
231 <entry xmlns='http://www.w3.org/2005/Atom' xml:lang='en'> | |
232 <title type='xhtml'> | |
233 <div xmlns='http://www.w3.org/1999/xhtml'> | |
234 <p> | |
235 XMPP item {id} | |
236 </p> | |
237 </div> | |
238 </title> | |
239 <title type='text'> | |
240 XMPP item {id} | |
241 </title> | |
242 <author> | |
243 <name> | |
244 test_user | |
245 </name> | |
246 <uri> | |
247 xmpp:{publisher_jid} | |
248 </uri> | |
249 </author> | |
250 <updated> | |
251 {updated} | |
252 </updated> | |
253 <published> | |
254 {published} | |
255 </published> | |
256 <id> | |
257 xmpp:{publisher_jid}?;node=urn%3Axmpp%3Amicroblog%3A0;item={id} | |
258 </id> | |
259 </entry> | |
260 </item> | |
261 """ | |
262 | |
263 ITEM_BASE_TS = 1643385499 | |
264 XMPP_ITEMS = [ | |
265 xml_tools.parse( | |
266 "".join( | |
267 l.strip() for l in XMPP_ITEM_TPL.format( | |
268 id=i, | |
269 publisher_jid="some_user@test.example", | |
270 updated=xmpp_date(ITEM_BASE_TS + i * 60), | |
271 published=xmpp_date(ITEM_BASE_TS + i * 60), | |
272 ).split("\n") | |
273 ), | |
274 namespace=pubsub.NS_PUBSUB | |
275 ) | |
276 for i in range(1, 5) | |
277 ] | |
278 | |
279 async def mock_ap_get(url): | |
280 return deepcopy(AP_REQUESTS[url]) | |
281 | |
282 | |
283 async def mock_treq_json(data): | |
284 return dict(data) | |
285 | |
286 | |
287 async def mock_getItems(*args, **kwargs): | |
288 rsm_resp = rsm.RSMResponse( | |
289 first=XMPP_ITEMS[0]["id"], | |
290 last=XMPP_ITEMS[-1]["id"], | |
291 index=0, | |
292 count=len(XMPP_ITEMS) | |
293 ) | |
294 return XMPP_ITEMS, {"rsm": rsm_resp.toDict(), "complete": True} | |
295 | |
296 | |
297 @pytest.fixture(scope="session") | |
298 def ap_gateway(host): | |
299 gateway = plugin_comp_ap_gateway.APGateway(host) | |
300 gateway.initialised = True | |
301 client = MagicMock() | |
302 client.jid = jid.JID("ap.test.example") | |
303 client.host = "test.example" | |
304 gateway.client = client | |
305 gateway.local_only = True | |
306 gateway.public_url = "test.example" | |
307 gateway.ap_path = '_ap' | |
308 gateway.base_ap_url = parse.urljoin( | |
309 f"https://{gateway.public_url}", | |
310 f"{gateway.ap_path}/" | |
311 ) | |
312 gateway.server = HTTPServer(gateway) | |
313 return gateway | |
314 | |
315 | |
316 class TestActivityPubGateway: | |
317 | |
318 @ed | |
319 async def test_jid_and_node_convert_to_ap_handle(self, ap_gateway): | |
320 """JID and pubsub node are converted correctly to an AP actor handle""" | |
321 get_account = ap_gateway.getAPAccountFromJidAndNode | |
322 | |
323 # local jid | |
324 assert await get_account( | |
325 jid_ = jid.JID("simple@test.example"), | |
326 node = None | |
327 ) == "simple@test.example" | |
328 | |
329 # non local jid | |
330 assert await get_account( | |
331 jid_ = jid.JID("simple@example.org"), | |
332 node = None | |
333 ) == "___simple.40example.2eorg@ap.test.example" | |
334 | |
335 # local jid with non microblog node | |
336 assert await get_account( | |
337 jid_ = jid.JID("simple@test.example"), | |
338 node = "some_other_node" | |
339 ) == "some_other_node---simple@test.example" | |
340 | |
341 # local pubsub node | |
342 with patch.object(ap_gateway, "isPubsub") as isPubsub: | |
343 isPubsub.return_value = True | |
344 assert await get_account( | |
345 jid_ = jid.JID("pubsub.test.example"), | |
346 node = "some_node" | |
347 ) == "some_node@pubsub.test.example" | |
348 | |
349 # non local pubsub node | |
350 with patch.object(ap_gateway, "isPubsub") as isPubsub: | |
351 isPubsub.return_value = True | |
352 assert await get_account( | |
353 jid_ = jid.JID("pubsub.example.org"), | |
354 node = "some_node" | |
355 ) == "___some_node.40pubsub.2eexample.2eorg@ap.test.example" | |
356 | |
357 @ed | |
358 async def test_ap_handle_convert_to_jid_and_node(self, ap_gateway, monkeypatch): | |
359 """AP actor handle convert correctly to JID and pubsub node""" | |
360 get_jid_node = ap_gateway.getJIDAndNode | |
361 | |
362 # for following assertion, host is not a pubsub service | |
363 with patch.object(ap_gateway, "isPubsub") as isPubsub: | |
364 isPubsub.return_value = False | |
365 | |
366 # simple local jid | |
367 assert await get_jid_node( | |
368 "toto@test.example" | |
369 ) == (jid.JID("toto@test.example"), None) | |
370 | |
371 # simple external jid | |
372 | |
373 ## with "local_only" set, it should raise an exception | |
374 with pytest.raises(exceptions.PermissionError): | |
375 await get_jid_node("toto@example.org") | |
376 | |
377 ## with "local_only" unset, it should work | |
378 with monkeypatch.context() as m: | |
379 m.setattr(ap_gateway, "local_only", False, raising=True) | |
380 assert await get_jid_node( | |
381 "toto@example.org" | |
382 ) == (jid.JID("toto@example.org"), None) | |
383 | |
384 # explicit node | |
385 assert await get_jid_node( | |
386 "tata---toto@test.example" | |
387 ) == (jid.JID("toto@test.example"), "tata") | |
388 | |
389 # for following assertion, host is a pubsub service | |
390 with patch.object(ap_gateway, "isPubsub") as isPubsub: | |
391 isPubsub.return_value = True | |
392 | |
393 # simple local node | |
394 assert await get_jid_node( | |
395 "toto@pubsub.test.example" | |
396 ) == (jid.JID("pubsub.test.example"), "toto") | |
397 | |
398 # encoded local node | |
399 assert await get_jid_node( | |
400 "___urn.3axmpp.3amicroblog.3a0@pubsub.test.example" | |
401 ) == (jid.JID("pubsub.test.example"), "urn:xmpp:microblog:0") | |
402 | |
403 @ed | |
404 async def test_ap_to_pubsub_conversion(self, ap_gateway, monkeypatch): | |
405 """AP requests are converted to pubsub""" | |
406 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) | |
407 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json) | |
408 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) | |
409 | |
3735
04ecc8eeb81a
tests (ap-gateway): fix use of outbox URL to get items
Goffi <goffi@goffi.org>
parents:
3733
diff
changeset
|
410 actor_data = await ap_gateway.getAPActorDataFromId(TEST_AP_ACCOUNT) |
04ecc8eeb81a
tests (ap-gateway): fix use of outbox URL to get items
Goffi <goffi@goffi.org>
parents:
3733
diff
changeset
|
411 outbox = await ap_gateway.apGetObject(actor_data, "outbox") |
04ecc8eeb81a
tests (ap-gateway): fix use of outbox URL to get items
Goffi <goffi@goffi.org>
parents:
3733
diff
changeset
|
412 items, rsm_resp = await ap_gateway.getAPItems(outbox, 2) |
3733 | 413 |
414 assert rsm_resp.count == 4 | |
415 assert rsm_resp.index == 0 | |
416 assert rsm_resp.first == "https://example.org/users/test_user/statuses/4" | |
417 assert rsm_resp.last == "https://example.org/users/test_user/statuses/3" | |
418 | |
419 assert items[0].entry.title.toXml() == ( | |
420 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
421 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 4</p></div>" | |
422 "</title>" | |
423 ) | |
424 author_uri = str( | |
425 [e for e in items[0].entry.author.elements() if e.name == "uri"][0] | |
426 ) | |
427 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" | |
428 assert str(items[0].entry.published) == "2021-12-16T17:25:03Z" | |
429 | |
430 assert items[1].entry.title.toXml() == ( | |
431 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
432 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 3</p></div>" | |
433 "</title>" | |
434 ) | |
435 author_uri = str( | |
436 [e for e in items[1].entry.author.elements() if e.name == "uri"][0] | |
437 ) | |
438 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" | |
439 assert str(items[1].entry.published) == "2021-12-16T17:26:03Z" | |
440 | |
441 items, rsm_resp = await ap_gateway.getAPItems( | |
3735
04ecc8eeb81a
tests (ap-gateway): fix use of outbox URL to get items
Goffi <goffi@goffi.org>
parents:
3733
diff
changeset
|
442 outbox, |
3733 | 443 max_items=2, |
444 after_id="https://example.org/users/test_user/statuses/3", | |
445 ) | |
446 | |
447 assert rsm_resp.count == 4 | |
448 assert rsm_resp.index == 2 | |
449 assert rsm_resp.first == "https://example.org/users/test_user/statuses/2" | |
450 assert rsm_resp.last == "https://example.org/users/test_user/statuses/1" | |
451 | |
452 assert items[0].entry.title.toXml() == ( | |
453 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
454 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 2</p></div>" | |
455 "</title>" | |
456 ) | |
457 author_uri = str( | |
458 [e for e in items[0].entry.author.elements() if e.name == "uri"][0] | |
459 ) | |
460 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" | |
461 assert str(items[0].entry.published) == "2021-12-16T17:27:03Z" | |
462 | |
463 assert items[1].entry.title.toXml() == ( | |
464 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
465 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 1</p></div>" | |
466 "</title>" | |
467 ) | |
468 author_uri = str( | |
469 [e for e in items[1].entry.author.elements() if e.name == "uri"][0] | |
470 ) | |
471 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" | |
472 assert str(items[1].entry.published) == "2021-12-16T17:28:03Z" | |
473 | |
474 items, rsm_resp = await ap_gateway.getAPItems( | |
3735
04ecc8eeb81a
tests (ap-gateway): fix use of outbox URL to get items
Goffi <goffi@goffi.org>
parents:
3733
diff
changeset
|
475 outbox, |
3733 | 476 max_items=1, |
477 start_index=2 | |
478 ) | |
479 | |
480 assert rsm_resp.count == 4 | |
481 assert rsm_resp.index == 2 | |
482 assert rsm_resp.first == "https://example.org/users/test_user/statuses/2" | |
483 assert rsm_resp.last == "https://example.org/users/test_user/statuses/2" | |
484 assert len(items) == 1 | |
485 | |
486 assert items[0].entry.title.toXml() == ( | |
487 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
488 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 2</p></div>" | |
489 "</title>" | |
490 ) | |
491 assert str(items[0].entry.published) == "2021-12-16T17:27:03Z" | |
492 | |
493 items, rsm_resp = await ap_gateway.getAPItems( | |
3735
04ecc8eeb81a
tests (ap-gateway): fix use of outbox URL to get items
Goffi <goffi@goffi.org>
parents:
3733
diff
changeset
|
494 outbox, |
3733 | 495 max_items=3, |
496 chronological_pagination=False | |
497 ) | |
498 assert rsm_resp.count == 4 | |
499 assert rsm_resp.index == 1 | |
500 assert rsm_resp.first == "https://example.org/users/test_user/statuses/3" | |
501 assert rsm_resp.last == "https://example.org/users/test_user/statuses/1" | |
502 assert len(items) == 3 | |
503 assert items[0].entry.title.toXml() == ( | |
504 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
505 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 3</p></div>" | |
506 "</title>" | |
507 ) | |
508 assert items[2].entry.title.toXml() == ( | |
509 "<title xmlns='http://www.w3.org/2005/Atom' type='xhtml'>" | |
510 "<div xmlns='http://www.w3.org/1999/xhtml'><p>test message 1</p></div>" | |
511 "</title>" | |
512 ) | |
513 | |
514 def ap_request_params(self, ap_gateway, type_=None, url=None, query_data=None): | |
515 """Generate parameters for HTTPAPGServer's AP*Request | |
516 | |
517 @param type_: one of the AP query type (e.g. "outbox") | |
518 @param url: URL to query (mutually exclusif with type_) | |
519 @param query_data: query data as returned by parse.parse_qs | |
520 @return dict with kw params to use | |
521 """ | |
522 assert type_ and url is None or url and type_ is None | |
523 if type_ is not None: | |
524 path = f"_ap/{type_}/some_user%40test.example" | |
525 else: | |
526 url_parsed = parse.urlparse(url) | |
527 path = url_parsed.path.lstrip("/") | |
528 type_ = path.split("/")[1] | |
529 if query_data is None: | |
530 query_data = parse.parse_qs(url_parsed.query) | |
531 | |
532 if query_data: | |
533 uri = f"{path}?{parse.urlencode(query_data, doseq=True)}" | |
534 else: | |
535 uri = path | |
536 | |
537 test_jid = jid.JID("some_user@test.example") | |
538 request = Request(MagicMock()) | |
539 request.path = path.encode() | |
540 request.uri = uri.encode() | |
541 ap_url = parse.urljoin( | |
542 f"https://{ap_gateway.public_url}", | |
543 path | |
544 ) | |
545 kwargs = { | |
546 "request": request, | |
547 "account_jid": test_jid, | |
548 "node": None, | |
549 "ap_account": test_jid.full(), | |
550 "ap_url": ap_url, | |
551 } | |
552 if type_ == "outbox" and query_data: | |
553 kwargs["query_data"] = query_data | |
554 return kwargs | |
555 | |
556 @ed | |
557 async def test_pubsub_to_ap_conversion(self, ap_gateway, monkeypatch): | |
558 """Pubsub nodes are converted to AP collections""" | |
559 monkeypatch.setattr(ap_gateway._p, "getItems", mock_getItems) | |
560 outbox = await ap_gateway.server.resource.APOutboxRequest( | |
561 **self.ap_request_params(ap_gateway, "outbox") | |
562 ) | |
563 assert outbox["@context"] == "https://www.w3.org/ns/activitystreams" | |
564 assert outbox["id"] == "https://test.example/_ap/outbox/some_user%40test.example" | |
565 assert outbox["totalItems"] == len(XMPP_ITEMS) | |
566 assert outbox["type"] == "OrderedCollection" | |
567 assert outbox["first"] | |
568 assert outbox["last"] | |
569 | |
570 first_page = await ap_gateway.server.resource.APOutboxPageRequest( | |
571 **self.ap_request_params(ap_gateway, url=outbox["first"]) | |
572 ) | |
573 assert first_page["@context"] == "https://www.w3.org/ns/activitystreams" | |
574 assert first_page["id"] == "https://test.example/_ap/outbox/some_user%40test.example?page=first" | |
575 assert first_page["type"] == "OrderedCollectionPage" | |
576 assert first_page["partOf"] == outbox["id"] | |
577 assert len(first_page["orderedItems"]) == len(XMPP_ITEMS) | |
578 first_item = first_page["orderedItems"][0] | |
579 assert first_item["@context"] == "https://www.w3.org/ns/activitystreams" | |
580 assert first_item["id"] == "https://test.example/_ap/item/some_user%40test.example/4" | |
581 assert first_item["actor"] == "https://test.example/_ap/actor/some_user%40test.example" | |
582 assert first_item["type"] == "Create" | |
583 first_item_obj = first_item["object"] | |
584 assert first_item_obj["id"] == first_item["id"] | |
585 assert first_item_obj["type"] == "Note" | |
586 assert first_item_obj["published"] == "2022-01-28T16:02:19Z" | |
587 assert first_item_obj["attributedTo"] == first_item["actor"] | |
588 assert first_item_obj["content"] == "<div><p>XMPP item 4</p></div>" | |
589 assert first_item_obj["to"] == "https://www.w3.org/ns/activitystreams#Public" |