Mercurial > libervia-backend
annotate tests/unit/test_ap-gateway.py @ 3751:073f386a191a
core (memory/disco): fix hard encoded value in `findServiceEntity`
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 13 May 2022 17:56:40 +0200 |
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" |