Mercurial > libervia-backend
comparison tests/unit/test_ap-gateway.py @ 3907:755920bd30da
tests (unit/AP gateway): fix tests:
rel 372
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 22 Sep 2022 00:01:48 +0200 |
parents | 989df1047c3c |
children | d43b197735d1 |
comparison
equal
deleted
inserted
replaced
3906:d8baf92cb921 | 3907:755920bd30da |
---|---|
60 AP_REQUESTS = { | 60 AP_REQUESTS = { |
61 f"{TEST_BASE_URL}/.well-known/webfinger?" | 61 f"{TEST_BASE_URL}/.well-known/webfinger?" |
62 f"resource=acct:{parse.quote(TEST_AP_ACCOUNT)}": { | 62 f"resource=acct:{parse.quote(TEST_AP_ACCOUNT)}": { |
63 "aliases": [ | 63 "aliases": [ |
64 f"{TEST_BASE_URL}/@{TEST_USER}", | 64 f"{TEST_BASE_URL}/@{TEST_USER}", |
65 f"{TEST_BASE_URL}/users/{TEST_USER}" | 65 f"{TEST_BASE_URL}/users/{TEST_USER}", |
66 ], | 66 ], |
67 "links": [ | 67 "links": [ |
68 { | 68 { |
69 "href": f"{TEST_BASE_URL}/users/{TEST_USER}", | 69 "href": f"{TEST_BASE_URL}/users/{TEST_USER}", |
70 "rel": "self", | 70 "rel": "self", |
71 "type": "application/activity+json" | 71 "type": "application/activity+json", |
72 }, | 72 }, |
73 ], | 73 ], |
74 "subject": f"acct:{TEST_AP_ACCOUNT}" | 74 "subject": f"acct:{TEST_AP_ACCOUNT}", |
75 }, | 75 }, |
76 | |
77 f"{TEST_BASE_URL}/users/{TEST_USER}": { | 76 f"{TEST_BASE_URL}/users/{TEST_USER}": { |
78 "@context": [ | 77 "@context": [ |
79 "https://www.w3.org/ns/activitystreams", | 78 "https://www.w3.org/ns/activitystreams", |
80 ], | 79 ], |
81 "endpoints": { | 80 "endpoints": {"sharedInbox": f"{TEST_BASE_URL}/inbox"}, |
82 "sharedInbox": f"{TEST_BASE_URL}/inbox" | |
83 }, | |
84 "followers": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 81 "followers": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
85 "following": f"{TEST_BASE_URL}/users/{TEST_USER}/following", | 82 "following": f"{TEST_BASE_URL}/users/{TEST_USER}/following", |
86 "id": f"{TEST_BASE_URL}/users/{TEST_USER}", | 83 "id": f"{TEST_BASE_URL}/users/{TEST_USER}", |
87 "inbox": f"{TEST_BASE_URL}/users/{TEST_USER}/inbox", | 84 "inbox": f"{TEST_BASE_URL}/users/{TEST_USER}/inbox", |
88 "name": "test_user nickname", | 85 "name": "test_user nickname", |
89 "summary": "<p>test account</p>", | 86 "summary": "<p>test account</p>", |
90 "outbox": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", | 87 "outbox": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", |
91 "preferredUsername": f"{TEST_USER}", | 88 "preferredUsername": f"{TEST_USER}", |
92 "type": "Person", | 89 "type": "Person", |
93 "url": f"{TEST_BASE_URL}/@{TEST_USER}" | 90 "url": f"{TEST_BASE_URL}/@{TEST_USER}", |
94 }, | 91 }, |
95 f"{TEST_BASE_URL}/.well-known/webfinger?" | 92 f"{TEST_BASE_URL}/.well-known/webfinger?" |
96 f"resource=acct:{parse.quote('ext_user@example.org')}": { | 93 f"resource=acct:{parse.quote('ext_user@example.org')}": { |
97 "aliases": [ | 94 "aliases": [f"{TEST_BASE_URL}/@ext_user", f"{TEST_BASE_URL}/users/ext_user"], |
98 f"{TEST_BASE_URL}/@ext_user", | |
99 f"{TEST_BASE_URL}/users/ext_user" | |
100 ], | |
101 "links": [ | 95 "links": [ |
102 { | 96 { |
103 "href": f"{TEST_BASE_URL}/users/ext_user", | 97 "href": f"{TEST_BASE_URL}/users/ext_user", |
104 "rel": "self", | 98 "rel": "self", |
105 "type": "application/activity+json" | 99 "type": "application/activity+json", |
106 }, | 100 }, |
107 ], | 101 ], |
108 "subject": f"acct:ext_user@example.org" | 102 "subject": f"acct:ext_user@example.org", |
109 }, | 103 }, |
110 f"{TEST_BASE_URL}/users/ext_user": { | 104 f"{TEST_BASE_URL}/users/ext_user": { |
111 "@context": [ | 105 "@context": [ |
112 "https://www.w3.org/ns/activitystreams", | 106 "https://www.w3.org/ns/activitystreams", |
113 ], | 107 ], |
114 "endpoints": { | 108 "endpoints": {"sharedInbox": f"{TEST_BASE_URL}/inbox"}, |
115 "sharedInbox": f"{TEST_BASE_URL}/inbox" | |
116 }, | |
117 "followers": f"{TEST_BASE_URL}/users/ext_user/followers", | 109 "followers": f"{TEST_BASE_URL}/users/ext_user/followers", |
118 "following": f"{TEST_BASE_URL}/users/ext_user/following", | 110 "following": f"{TEST_BASE_URL}/users/ext_user/following", |
119 "id": f"{TEST_BASE_URL}/users/ext_user", | 111 "id": f"{TEST_BASE_URL}/users/ext_user", |
120 "inbox": f"{TEST_BASE_URL}/users/ext_user/inbox", | 112 "inbox": f"{TEST_BASE_URL}/users/ext_user/inbox", |
121 "name": "", | 113 "name": "", |
122 "outbox": f"{TEST_BASE_URL}/users/ext_user/outbox", | 114 "outbox": f"{TEST_BASE_URL}/users/ext_user/outbox", |
123 "preferredUsername": f"ext_user", | 115 "preferredUsername": f"ext_user", |
124 "type": "Person", | 116 "type": "Person", |
125 "url": f"{TEST_BASE_URL}/@ext_user" | 117 "url": f"{TEST_BASE_URL}/@ext_user", |
126 }, | 118 }, |
127 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox": { | 119 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox": { |
128 "@context": "https://www.w3.org/ns/activitystreams", | 120 "@context": "https://www.w3.org/ns/activitystreams", |
129 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", | 121 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", |
130 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", | 122 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", |
131 "last": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", | 123 "last": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true", |
132 "totalItems": 4, | 124 "totalItems": 4, |
133 "type": "OrderedCollection" | 125 "type": "OrderedCollection", |
134 }, | 126 }, |
135 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true": { | 127 f"{TEST_BASE_URL}/users/{TEST_USER}/outbox?page=true": { |
136 "@context": [ | 128 "@context": [ |
137 "https://www.w3.org/ns/activitystreams", | 129 "https://www.w3.org/ns/activitystreams", |
138 ], | 130 ], |
148 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | 140 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", |
149 "cc": [ | 141 "cc": [ |
150 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 142 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
151 ], | 143 ], |
152 "content": "<p>test message 1</p>", | 144 "content": "<p>test message 1</p>", |
153 "contentMap": { | 145 "contentMap": {"en": "<p>test message 1</p>"}, |
154 "en": "<p>test message 1</p>" | |
155 }, | |
156 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/1", | 146 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/1", |
157 "inReplyTo": None, | 147 "inReplyTo": None, |
158 "published": "2021-12-16T17:28:03Z", | 148 "published": "2021-12-16T17:28:03Z", |
159 "sensitive": False, | 149 "sensitive": False, |
160 "summary": None, | 150 "summary": None, |
161 "tag": [], | 151 "tag": [], |
162 "to": [ | 152 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
163 "https://www.w3.org/ns/activitystreams#Public" | |
164 ], | |
165 "type": "Note", | 153 "type": "Note", |
166 "url": f"{TEST_BASE_URL}/@{TEST_USER}/1" | 154 "url": f"{TEST_BASE_URL}/@{TEST_USER}/1", |
167 }, | 155 }, |
168 "published": "2021-12-16T17:28:03Z", | 156 "published": "2021-12-16T17:28:03Z", |
169 "to": [ | 157 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
170 "https://www.w3.org/ns/activitystreams#Public" | 158 "type": "Create", |
171 ], | |
172 "type": "Create" | |
173 }, | 159 }, |
174 { | 160 { |
175 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | 161 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", |
176 "cc": [ | 162 "cc": [ |
177 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 163 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
181 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | 167 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", |
182 "cc": [ | 168 "cc": [ |
183 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 169 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
184 ], | 170 ], |
185 "content": "<p>test message 2</p>", | 171 "content": "<p>test message 2</p>", |
186 "contentMap": { | 172 "contentMap": {"en": "<p>test message 2</p>"}, |
187 "en": "<p>test message 2</p>" | |
188 }, | |
189 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/2", | 173 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/2", |
190 "inReplyTo": None, | 174 "inReplyTo": None, |
191 "published": "2021-12-16T17:27:03Z", | 175 "published": "2021-12-16T17:27:03Z", |
192 "sensitive": False, | 176 "sensitive": False, |
193 "summary": None, | 177 "summary": None, |
194 "tag": [], | 178 "tag": [], |
195 "to": [ | 179 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
196 "https://www.w3.org/ns/activitystreams#Public" | |
197 ], | |
198 "type": "Note", | 180 "type": "Note", |
199 "url": f"{TEST_BASE_URL}/@{TEST_USER}/2" | 181 "url": f"{TEST_BASE_URL}/@{TEST_USER}/2", |
200 }, | 182 }, |
201 "published": "2021-12-16T17:27:03Z", | 183 "published": "2021-12-16T17:27:03Z", |
202 "to": [ | 184 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
203 "https://www.w3.org/ns/activitystreams#Public" | 185 "type": "Create", |
204 ], | |
205 "type": "Create" | |
206 }, | 186 }, |
207 { | 187 { |
208 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | 188 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", |
209 "cc": [ | 189 "cc": [ |
210 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 190 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
214 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | 194 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", |
215 "cc": [ | 195 "cc": [ |
216 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 196 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
217 ], | 197 ], |
218 "content": "<p>test message 3</p>", | 198 "content": "<p>test message 3</p>", |
219 "contentMap": { | 199 "contentMap": {"en": "<p>test message 3</p>"}, |
220 "en": "<p>test message 3</p>" | |
221 }, | |
222 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/3", | 200 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/3", |
223 "inReplyTo": None, | 201 "inReplyTo": None, |
224 "published": "2021-12-16T17:26:03Z", | 202 "published": "2021-12-16T17:26:03Z", |
225 "sensitive": False, | 203 "sensitive": False, |
226 "summary": None, | 204 "summary": None, |
227 "tag": [], | 205 "tag": [], |
228 "to": [ | 206 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
229 "https://www.w3.org/ns/activitystreams#Public" | |
230 ], | |
231 "type": "Note", | 207 "type": "Note", |
232 "url": f"{TEST_BASE_URL}/@{TEST_USER}/3" | 208 "url": f"{TEST_BASE_URL}/@{TEST_USER}/3", |
233 }, | 209 }, |
234 "published": "2021-12-16T17:26:03Z", | 210 "published": "2021-12-16T17:26:03Z", |
235 "to": [ | 211 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
236 "https://www.w3.org/ns/activitystreams#Public" | 212 "type": "Create", |
237 ], | |
238 "type": "Create" | |
239 }, | 213 }, |
240 { | 214 { |
241 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", | 215 "actor": f"{TEST_BASE_URL}/users/{TEST_USER}", |
242 "cc": [ | 216 "cc": [ |
243 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 217 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
247 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", | 221 "attributedTo": f"{TEST_BASE_URL}/users/{TEST_USER}", |
248 "cc": [ | 222 "cc": [ |
249 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 223 f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
250 ], | 224 ], |
251 "content": "<p>test message 4</p>", | 225 "content": "<p>test message 4</p>", |
252 "contentMap": { | 226 "contentMap": {"en": "<p>test message 4</p>"}, |
253 "en": "<p>test message 4</p>" | |
254 }, | |
255 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/4", | 227 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/statuses/4", |
256 "inReplyTo": None, | 228 "inReplyTo": None, |
257 "published": "2021-12-16T17:25:03Z", | 229 "published": "2021-12-16T17:25:03Z", |
258 "sensitive": False, | 230 "sensitive": False, |
259 "summary": None, | 231 "summary": None, |
260 "tag": [], | 232 "tag": [], |
261 "to": [ | 233 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
262 "https://www.w3.org/ns/activitystreams#Public" | |
263 ], | |
264 "type": "Note", | 234 "type": "Note", |
265 "url": f"{TEST_BASE_URL}/@{TEST_USER}/4" | 235 "url": f"{TEST_BASE_URL}/@{TEST_USER}/4", |
266 }, | 236 }, |
267 "published": "2021-12-16T17:25:03Z", | 237 "published": "2021-12-16T17:25:03Z", |
268 "to": [ | 238 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
269 "https://www.w3.org/ns/activitystreams#Public" | 239 "type": "Create", |
270 ], | |
271 "type": "Create" | |
272 }, | 240 }, |
273 ], | 241 ], |
274 "partOf": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", | 242 "partOf": f"{TEST_BASE_URL}/users/{TEST_USER}/outbox", |
275 "prev": None, | 243 "prev": None, |
276 "type": "OrderedCollectionPage" | 244 "type": "OrderedCollectionPage", |
277 }, | 245 }, |
278 f"{TEST_BASE_URL}/users/{TEST_USER}/following": { | 246 f"{TEST_BASE_URL}/users/{TEST_USER}/following": { |
279 "@context": "https://www.w3.org/ns/activitystreams", | 247 "@context": "https://www.w3.org/ns/activitystreams", |
280 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1", | 248 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1", |
281 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following", | 249 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following", |
282 "totalItems": 2, | 250 "totalItems": 2, |
283 "type": "OrderedCollection" | 251 "type": "OrderedCollection", |
284 }, | 252 }, |
285 f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1": { | 253 f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1": { |
286 "@context": "https://www.w3.org/ns/activitystreams", | 254 "@context": "https://www.w3.org/ns/activitystreams", |
287 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1", | 255 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/following?page=1", |
288 "orderedItems": [ | 256 "orderedItems": [ |
289 f"{TEST_BASE_URL}/users/ext_user", | 257 f"{TEST_BASE_URL}/users/ext_user", |
290 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}", | 258 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}", |
291 ], | 259 ], |
292 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/following", | 260 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/following", |
293 "totalItems": 2, | 261 "totalItems": 2, |
294 "type": "OrderedCollectionPage" | 262 "type": "OrderedCollectionPage", |
295 }, | 263 }, |
296 f"{TEST_BASE_URL}/users/{TEST_USER}/followers": { | 264 f"{TEST_BASE_URL}/users/{TEST_USER}/followers": { |
297 "@context": "https://www.w3.org/ns/activitystreams", | 265 "@context": "https://www.w3.org/ns/activitystreams", |
298 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1", | 266 "first": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1", |
299 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", | 267 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers", |
300 "totalItems": 2, | 268 "totalItems": 2, |
301 "type": "OrderedCollection" | 269 "type": "OrderedCollection", |
302 }, | 270 }, |
303 f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1": { | 271 f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1": { |
304 "@context": "https://www.w3.org/ns/activitystreams", | 272 "@context": "https://www.w3.org/ns/activitystreams", |
305 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1", | 273 "id": f"{TEST_BASE_URL}/users/{TEST_USER}/followers?page=1", |
306 "orderedItems": [ | 274 "orderedItems": [ |
307 f"{TEST_BASE_URL}/users/ext_user", | 275 f"{TEST_BASE_URL}/users/ext_user", |
308 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}", | 276 f"https://{PUBLIC_URL}/_ap/{TYPE_ACTOR}/local_user%40{PUBLIC_URL}", |
309 ], | 277 ], |
310 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/followers", | 278 "partOf": "{TEST_BASE_URL}/users/{TEST_USER}/followers", |
311 "totalItems": 2, | 279 "totalItems": 2, |
312 "type": "OrderedCollectionPage" | 280 "type": "OrderedCollectionPage", |
313 }, | 281 }, |
314 | |
315 } | 282 } |
316 | 283 |
317 XMPP_ITEM_TPL = """ | 284 XMPP_ITEM_TPL = """ |
318 <item id='{id}' publisher='{publisher_jid}'> | 285 <item id='{id}' publisher='{publisher_jid}'> |
319 <entry xmlns='http://www.w3.org/2005/Atom' xml:lang='en'> | 286 <entry xmlns='http://www.w3.org/2005/Atom' xml:lang='en'> |
350 | 317 |
351 ITEM_BASE_TS = 1643385499 | 318 ITEM_BASE_TS = 1643385499 |
352 XMPP_ITEMS = [ | 319 XMPP_ITEMS = [ |
353 xml_tools.parse( | 320 xml_tools.parse( |
354 "".join( | 321 "".join( |
355 l.strip() for l in XMPP_ITEM_TPL.format( | 322 l.strip() |
323 for l in XMPP_ITEM_TPL.format( | |
356 id=i, | 324 id=i, |
357 publisher_jid="some_user@test.example", | 325 publisher_jid="some_user@test.example", |
358 updated=xmpp_date(ITEM_BASE_TS + i * 60), | 326 updated=xmpp_date(ITEM_BASE_TS + i * 60), |
359 published=xmpp_date(ITEM_BASE_TS + i * 60), | 327 published=xmpp_date(ITEM_BASE_TS + i * 60), |
360 ).split("\n") | 328 ).split("\n") |
361 ), | 329 ), |
362 namespace=pubsub.NS_PUBSUB | 330 namespace=pubsub.NS_PUBSUB, |
363 ) | 331 ) |
364 for i in range(1, 5) | 332 for i in range(1, 5) |
365 ] | 333 ] |
366 | 334 |
367 TEST_USER_DATA = AP_REQUESTS[f"{TEST_BASE_URL}/users/{TEST_USER}"] | 335 TEST_USER_DATA = AP_REQUESTS[f"{TEST_BASE_URL}/users/{TEST_USER}"] |
392 tested_node = kwargs.pop("tested_node", None) | 360 tested_node = kwargs.pop("tested_node", None) |
393 if tested_node is not None and node != tested_node: | 361 if tested_node is not None and node != tested_node: |
394 raise StanzaError("item-not-found") | 362 raise StanzaError("item-not-found") |
395 ret_items = kwargs.pop("ret_items", XMPP_ITEMS) | 363 ret_items = kwargs.pop("ret_items", XMPP_ITEMS) |
396 rsm_resp = rsm.RSMResponse( | 364 rsm_resp = rsm.RSMResponse( |
397 first=ret_items[0]["id"], | 365 first=ret_items[0]["id"], last=ret_items[-1]["id"], index=0, count=len(ret_items) |
398 last=ret_items[-1]["id"], | |
399 index=0, | |
400 count=len(ret_items) | |
401 ) | 366 ) |
402 return ret_items, {"rsm": rsm_resp.toDict(), "complete": True} | 367 return ret_items, {"rsm": rsm_resp.toDict(), "complete": True} |
403 | 368 |
404 | 369 |
405 async def mock_getPubsubNode(client, service, node, with_subscriptions=False, **kwargs): | 370 async def mock_getPubsubNode(client, service, node, with_subscriptions=False, **kwargs): |
438 client = mockClient(jid.JID("ap.test.example")) | 403 client = mockClient(jid.JID("ap.test.example")) |
439 client.getVirtualClient = getVirtualClient | 404 client.getVirtualClient = getVirtualClient |
440 gateway.client = client | 405 gateway.client = client |
441 gateway.local_only = True | 406 gateway.local_only = True |
442 gateway.public_url = PUBLIC_URL | 407 gateway.public_url = PUBLIC_URL |
443 gateway.ap_path = '_ap' | 408 gateway.ap_path = "_ap" |
444 gateway.auto_mentions = True | 409 gateway.auto_mentions = True |
445 gateway.base_ap_url = parse.urljoin( | 410 gateway.base_ap_url = parse.urljoin( |
446 f"https://{gateway.public_url}", | 411 f"https://{gateway.public_url}", f"{gateway.ap_path}/" |
447 f"{gateway.ap_path}/" | |
448 ) | 412 ) |
449 gateway.server = HTTPServer(gateway) | 413 gateway.server = HTTPServer(gateway) |
450 gateway.public_key_pem = None | 414 gateway.public_key_pem = None |
451 return gateway | 415 return gateway |
452 | 416 |
453 | 417 |
454 class TestActivityPubGateway: | 418 class TestActivityPubGateway: |
455 | |
456 def getTitleXHTML(self, item_elt: domish.Element) -> domish.Element: | 419 def getTitleXHTML(self, item_elt: domish.Element) -> domish.Element: |
457 return next( | 420 return next( |
458 t for t in item_elt.entry.elements(NS_ATOM, "title") | 421 t |
422 for t in item_elt.entry.elements(NS_ATOM, "title") | |
459 if t.getAttribute("type") == "xhtml" | 423 if t.getAttribute("type") == "xhtml" |
460 ) | 424 ) |
461 | |
462 | 425 |
463 @ed | 426 @ed |
464 async def test_jid_and_node_convert_to_ap_handle(self, ap_gateway): | 427 async def test_jid_and_node_convert_to_ap_handle(self, ap_gateway): |
465 """JID and pubsub node are converted correctly to an AP actor handle""" | 428 """JID and pubsub node are converted correctly to an AP actor handle""" |
466 get_account = ap_gateway.getAPAccountFromJidAndNode | 429 get_account = ap_gateway.getAPAccountFromJidAndNode |
467 | 430 |
468 # local jid | 431 # local jid |
469 assert await get_account( | 432 assert ( |
470 jid_ = jid.JID("simple@test.example"), | 433 await get_account(jid_=jid.JID("simple@test.example"), node=None) |
471 node = None | 434 == "simple@test.example" |
472 ) == "simple@test.example" | 435 ) |
473 | 436 |
474 # non local jid | 437 # non local jid |
475 assert await get_account( | 438 assert ( |
476 jid_ = jid.JID("simple@example.org"), | 439 await get_account(jid_=jid.JID("simple@example.org"), node=None) |
477 node = None | 440 == "___simple.40example.2eorg@ap.test.example" |
478 ) == "___simple.40example.2eorg@ap.test.example" | 441 ) |
479 | 442 |
480 # local jid with non microblog node | 443 # local jid with non microblog node |
481 assert await get_account( | 444 assert ( |
482 jid_ = jid.JID("simple@test.example"), | 445 await get_account(jid_=jid.JID("simple@test.example"), node="some_other_node") |
483 node = "some_other_node" | 446 == "some_other_node---simple@test.example" |
484 ) == "some_other_node---simple@test.example" | 447 ) |
485 | 448 |
486 # local pubsub node | 449 # local pubsub node |
487 with patch.object(ap_gateway, "isPubsub") as isPubsub: | 450 with patch.object(ap_gateway, "isPubsub") as isPubsub: |
488 isPubsub.return_value = True | 451 isPubsub.return_value = True |
489 assert await get_account( | 452 assert ( |
490 jid_ = jid.JID("pubsub.test.example"), | 453 await get_account(jid_=jid.JID("pubsub.test.example"), node="some_node") |
491 node = "some_node" | 454 == "some_node@pubsub.test.example" |
492 ) == "some_node@pubsub.test.example" | 455 ) |
493 | 456 |
494 # non local pubsub node | 457 # non local pubsub node |
495 with patch.object(ap_gateway, "isPubsub") as isPubsub: | 458 with patch.object(ap_gateway, "isPubsub") as isPubsub: |
496 isPubsub.return_value = True | 459 isPubsub.return_value = True |
497 assert await get_account( | 460 assert ( |
498 jid_ = jid.JID("pubsub.example.org"), | 461 await get_account(jid_=jid.JID("pubsub.example.org"), node="some_node") |
499 node = "some_node" | 462 == "___some_node.40pubsub.2eexample.2eorg@ap.test.example" |
500 ) == "___some_node.40pubsub.2eexample.2eorg@ap.test.example" | 463 ) |
501 | 464 |
502 @ed | 465 @ed |
503 async def test_ap_handle_convert_to_jid_and_node(self, ap_gateway, monkeypatch): | 466 async def test_ap_handle_convert_to_jid_and_node(self, ap_gateway, monkeypatch): |
504 """AP actor handle convert correctly to JID and pubsub node""" | 467 """AP actor handle convert correctly to JID and pubsub node""" |
505 get_jid_node = ap_gateway.getJIDAndNode | 468 get_jid_node = ap_gateway.getJIDAndNode |
507 # for following assertion, host is not a pubsub service | 470 # for following assertion, host is not a pubsub service |
508 with patch.object(ap_gateway, "isPubsub") as isPubsub: | 471 with patch.object(ap_gateway, "isPubsub") as isPubsub: |
509 isPubsub.return_value = False | 472 isPubsub.return_value = False |
510 | 473 |
511 # simple local jid | 474 # simple local jid |
512 assert await get_jid_node( | 475 assert await get_jid_node("toto@test.example") == ( |
513 "toto@test.example" | 476 jid.JID("toto@test.example"), |
514 ) == (jid.JID("toto@test.example"), None) | 477 None, |
478 ) | |
515 | 479 |
516 # simple external jid | 480 # simple external jid |
517 | 481 |
518 ## with "local_only" set, it should raise an exception | 482 ## with "local_only" set, it should raise an exception |
519 with pytest.raises(exceptions.PermissionError): | 483 with pytest.raises(exceptions.PermissionError): |
520 await get_jid_node("toto@example.org") | 484 await get_jid_node("toto@example.org") |
521 | 485 |
522 ## with "local_only" unset, it should work | 486 ## with "local_only" unset, it should work |
523 with monkeypatch.context() as m: | 487 with monkeypatch.context() as m: |
524 m.setattr(ap_gateway, "local_only", False, raising=True) | 488 m.setattr(ap_gateway, "local_only", False, raising=True) |
525 assert await get_jid_node( | 489 assert await get_jid_node("toto@example.org") == ( |
526 "toto@example.org" | 490 jid.JID("toto@example.org"), |
527 ) == (jid.JID("toto@example.org"), None) | 491 None, |
492 ) | |
528 | 493 |
529 # explicit node | 494 # explicit node |
530 assert await get_jid_node( | 495 assert await get_jid_node("tata---toto@test.example") == ( |
531 "tata---toto@test.example" | 496 jid.JID("toto@test.example"), |
532 ) == (jid.JID("toto@test.example"), "tata") | 497 "tata", |
498 ) | |
533 | 499 |
534 # for following assertion, host is a pubsub service | 500 # for following assertion, host is a pubsub service |
535 with patch.object(ap_gateway, "isPubsub") as isPubsub: | 501 with patch.object(ap_gateway, "isPubsub") as isPubsub: |
536 isPubsub.return_value = True | 502 isPubsub.return_value = True |
537 | 503 |
538 # simple local node | 504 # simple local node |
539 assert await get_jid_node( | 505 assert await get_jid_node("toto@pubsub.test.example") == ( |
540 "toto@pubsub.test.example" | 506 jid.JID("pubsub.test.example"), |
541 ) == (jid.JID("pubsub.test.example"), "toto") | 507 "toto", |
508 ) | |
542 | 509 |
543 # encoded local node | 510 # encoded local node |
544 assert await get_jid_node( | 511 assert await get_jid_node( |
545 "___urn.3axmpp.3amicroblog.3a0@pubsub.test.example" | 512 "___urn.3axmpp.3amicroblog.3a0@pubsub.test.example" |
546 ) == (jid.JID("pubsub.test.example"), "urn:xmpp:microblog:0") | 513 ) == (jid.JID("pubsub.test.example"), "urn:xmpp:microblog:0") |
618 [e for e in items[1].entry.author.elements() if e.name == "uri"][0] | 585 [e for e in items[1].entry.author.elements() if e.name == "uri"][0] |
619 ) | 586 ) |
620 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" | 587 assert author_uri == "xmpp:test_user\\40example.org@ap.test.example" |
621 assert str(items[1].entry.published) == "2021-12-16T17:28:03Z" | 588 assert str(items[1].entry.published) == "2021-12-16T17:28:03Z" |
622 | 589 |
623 items, rsm_resp = await ap_gateway.getAPItems( | 590 items, rsm_resp = await ap_gateway.getAPItems(outbox, max_items=1, start_index=2) |
624 outbox, | |
625 max_items=1, | |
626 start_index=2 | |
627 ) | |
628 | 591 |
629 assert rsm_resp.count == 4 | 592 assert rsm_resp.count == 4 |
630 assert rsm_resp.index == 2 | 593 assert rsm_resp.index == 2 |
631 assert rsm_resp.first == "https://example.org/users/test_user/statuses/2" | 594 assert rsm_resp.first == "https://example.org/users/test_user/statuses/2" |
632 assert rsm_resp.last == "https://example.org/users/test_user/statuses/2" | 595 assert rsm_resp.last == "https://example.org/users/test_user/statuses/2" |
639 "</title>" | 602 "</title>" |
640 ) | 603 ) |
641 assert str(items[0].entry.published) == "2021-12-16T17:27:03Z" | 604 assert str(items[0].entry.published) == "2021-12-16T17:27:03Z" |
642 | 605 |
643 items, rsm_resp = await ap_gateway.getAPItems( | 606 items, rsm_resp = await ap_gateway.getAPItems( |
644 outbox, | 607 outbox, max_items=3, chronological_pagination=False |
645 max_items=3, | |
646 chronological_pagination=False | |
647 ) | 608 ) |
648 assert rsm_resp.count == 4 | 609 assert rsm_resp.count == 4 |
649 assert rsm_resp.index == 1 | 610 assert rsm_resp.index == 1 |
650 assert rsm_resp.first == "https://example.org/users/test_user/statuses/3" | 611 assert rsm_resp.first == "https://example.org/users/test_user/statuses/3" |
651 assert rsm_resp.last == "https://example.org/users/test_user/statuses/1" | 612 assert rsm_resp.last == "https://example.org/users/test_user/statuses/1" |
668 ap_gateway, | 629 ap_gateway, |
669 type_: Optional[str] = None, | 630 type_: Optional[str] = None, |
670 url: Optional[str] = None, | 631 url: Optional[str] = None, |
671 doc: Optional[Any] = None, | 632 doc: Optional[Any] = None, |
672 query_data: Optional[dict] = None, | 633 query_data: Optional[dict] = None, |
673 signing_actor: Optional[str] = None | 634 signing_actor: Optional[str] = None, |
674 ) -> Dict[str, Any]: | 635 ) -> Dict[str, Any]: |
675 """Generate parameters for HTTPAPGServer's AP*Request | 636 """Generate parameters for HTTPAPGServer's AP*Request |
676 | 637 |
677 @param type_: one of the AP query type (e.g. "outbox") | 638 @param type_: one of the AP query type (e.g. "outbox") |
678 @param url: URL to query (mutually exclusif with type_) | 639 @param url: URL to query (mutually exclusif with type_) |
701 request.path = path.encode() | 662 request.path = path.encode() |
702 request.uri = uri.encode() | 663 request.uri = uri.encode() |
703 if doc is not None: | 664 if doc is not None: |
704 request.content = io.BytesIO(json.dumps(doc).encode()) | 665 request.content = io.BytesIO(json.dumps(doc).encode()) |
705 | 666 |
706 ap_url = parse.urljoin( | 667 ap_url = parse.urljoin(f"https://{ap_gateway.public_url}", path) |
707 f"https://{ap_gateway.public_url}", | |
708 path | |
709 ) | |
710 kwargs = { | 668 kwargs = { |
711 "request": request, | 669 "request": request, |
712 "account_jid": test_jid, | 670 "account_jid": test_jid, |
713 "node": None, | 671 "node": None, |
714 "ap_account": test_jid.full(), | 672 "ap_account": test_jid.full(), |
715 "ap_url": ap_url, | 673 "ap_url": ap_url, |
716 "signing_actor": signing_actor | 674 "signing_actor": signing_actor, |
717 } | 675 } |
718 if type_ == "outbox" and query_data: | 676 if type_ == "outbox" and query_data: |
719 kwargs["query_data"] = query_data | 677 kwargs["query_data"] = query_data |
720 # signing_actor is not used for page requests | 678 # signing_actor is not used for page requests |
721 del kwargs["signing_actor"] | 679 del kwargs["signing_actor"] |
726 """Pubsub nodes are converted to AP collections""" | 684 """Pubsub nodes are converted to AP collections""" |
727 monkeypatch.setattr(ap_gateway._p, "getItems", mock_getItems) | 685 monkeypatch.setattr(ap_gateway._p, "getItems", mock_getItems) |
728 outbox = await ap_gateway.server.resource.APOutboxRequest( | 686 outbox = await ap_gateway.server.resource.APOutboxRequest( |
729 **self.ap_request_params(ap_gateway, "outbox") | 687 **self.ap_request_params(ap_gateway, "outbox") |
730 ) | 688 ) |
731 assert outbox["@context"] == "https://www.w3.org/ns/activitystreams" | 689 assert outbox["@context"] == ["https://www.w3.org/ns/activitystreams"] |
732 assert outbox["id"] == "https://test.example/_ap/outbox/some_user%40test.example" | 690 assert outbox["id"] == "https://test.example/_ap/outbox/some_user%40test.example" |
733 assert outbox["totalItems"] == len(XMPP_ITEMS) | 691 assert outbox["totalItems"] == len(XMPP_ITEMS) |
734 assert outbox["type"] == "OrderedCollection" | 692 assert outbox["type"] == "OrderedCollection" |
735 assert outbox["first"] | 693 assert outbox["first"] |
736 assert outbox["last"] | 694 assert outbox["last"] |
737 | 695 |
738 first_page = await ap_gateway.server.resource.APOutboxPageRequest( | 696 first_page = await ap_gateway.server.resource.APOutboxPageRequest( |
739 **self.ap_request_params(ap_gateway, url=outbox["first"]) | 697 **self.ap_request_params(ap_gateway, url=outbox["first"]) |
740 ) | 698 ) |
741 assert first_page["@context"] == "https://www.w3.org/ns/activitystreams" | 699 assert first_page["@context"] == ["https://www.w3.org/ns/activitystreams"] |
742 assert first_page["id"] == "https://test.example/_ap/outbox/some_user%40test.example?page=first" | 700 assert ( |
701 first_page["id"] | |
702 == "https://test.example/_ap/outbox/some_user%40test.example?page=first" | |
703 ) | |
743 assert first_page["type"] == "OrderedCollectionPage" | 704 assert first_page["type"] == "OrderedCollectionPage" |
744 assert first_page["partOf"] == outbox["id"] | 705 assert first_page["partOf"] == outbox["id"] |
745 assert len(first_page["orderedItems"]) == len(XMPP_ITEMS) | 706 assert len(first_page["orderedItems"]) == len(XMPP_ITEMS) |
746 first_item = first_page["orderedItems"][0] | 707 first_item = first_page["orderedItems"][0] |
747 assert first_item["@context"] == "https://www.w3.org/ns/activitystreams" | 708 assert first_item["@context"] == ["https://www.w3.org/ns/activitystreams"] |
748 assert first_item["id"] == "https://test.example/_ap/item/some_user%40test.example/4" | 709 assert ( |
749 assert first_item["actor"] == "https://test.example/_ap/actor/some_user%40test.example" | 710 first_item["id"] == "https://test.example/_ap/item/some_user%40test.example/4" |
711 ) | |
712 assert ( | |
713 first_item["actor"] | |
714 == "https://test.example/_ap/actor/some_user%40test.example" | |
715 ) | |
750 assert first_item["type"] == "Create" | 716 assert first_item["type"] == "Create" |
751 first_item_obj = first_item["object"] | 717 first_item_obj = first_item["object"] |
752 assert first_item_obj["id"] == first_item["id"] | 718 assert first_item_obj["id"] == first_item["id"] |
753 assert first_item_obj["type"] == "Note" | 719 assert first_item_obj["type"] == "Note" |
754 assert first_item_obj["published"] == "2022-01-28T16:02:19Z" | 720 assert first_item_obj["published"] == "2022-01-28T16:02:19Z" |
767 jid.JID("toto@example.org"), | 733 jid.JID("toto@example.org"), |
768 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), | 734 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), |
769 ap_gateway._pps.subscriptions_node, | 735 ap_gateway._pps.subscriptions_node, |
770 None, | 736 None, |
771 None, | 737 None, |
772 None | 738 None, |
773 ) | 739 ) |
774 assert len(items) == 2 | 740 assert len(items) == 2 |
775 for idx, entity in enumerate(( | 741 for idx, entity in enumerate( |
776 "local_user@test.example", | 742 ("local_user@test.example", "ext_user\\40example.org@ap.test.example") |
777 "ext_user\\40example.org@ap.test.example" | 743 ): |
778 )): | |
779 subscription_elt = next(items[idx].elements(NS_PPS, "subscription"), None) | 744 subscription_elt = next(items[idx].elements(NS_PPS, "subscription"), None) |
780 assert subscription_elt is not None | 745 assert subscription_elt is not None |
781 assert subscription_elt["node"] == ap_gateway._m.namespace | 746 assert subscription_elt["node"] == ap_gateway._m.namespace |
782 assert subscription_elt["service"] == entity | 747 assert subscription_elt["service"] == entity |
783 | 748 |
792 jid.JID("toto@example.org"), | 757 jid.JID("toto@example.org"), |
793 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), | 758 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), |
794 ap_gateway._pps.getPublicSubscribersNode(ap_gateway._m.namespace), | 759 ap_gateway._pps.getPublicSubscribersNode(ap_gateway._m.namespace), |
795 None, | 760 None, |
796 None, | 761 None, |
797 None | 762 None, |
798 ) | 763 ) |
799 assert len(items) == 2 | 764 assert len(items) == 2 |
800 for idx, entity in enumerate(( | 765 for idx, entity in enumerate( |
801 "local_user@test.example", | 766 ("local_user@test.example", "ext_user\\40example.org@ap.test.example") |
802 "ext_user\\40example.org@ap.test.example" | 767 ): |
803 )): | |
804 subscriber_elt = next(items[idx].elements(NS_PPS, "subscriber"), None) | 768 subscriber_elt = next(items[idx].elements(NS_PPS, "subscriber"), None) |
805 assert subscriber_elt is not None | 769 assert subscriber_elt is not None |
806 assert subscriber_elt["jid"] == entity | 770 assert subscriber_elt["jid"] == entity |
807 | 771 |
808 @ed | 772 @ed |
809 async def test_pps_to_following(self, ap_gateway, monkeypatch): | 773 async def test_pps_to_following(self, ap_gateway, monkeypatch): |
810 """Public Pubsub Subscription subscriptions are converted to AP following items""" | 774 """Public Pubsub Subscription subscriptions are converted to AP following items""" |
811 subscriptions = [ | 775 subscriptions = [ |
812 pubsub.Item( | 776 pubsub.Item( |
813 id="subscription_1", | 777 id="subscription_1", |
814 payload = ap_gateway._pps.buildSubscriptionElt( | 778 payload=ap_gateway._pps.buildSubscriptionElt( |
815 ap_gateway._m.namespace, | 779 ap_gateway._m.namespace, jid.JID("local_user@test.example") |
816 jid.JID("local_user@test.example") | 780 ), |
817 ) | |
818 ), | 781 ), |
819 pubsub.Item( | 782 pubsub.Item( |
820 id="subscription_2", | 783 id="subscription_2", |
821 payload = ap_gateway._pps.buildSubscriptionElt( | 784 payload=ap_gateway._pps.buildSubscriptionElt( |
822 ap_gateway._m.namespace, | 785 ap_gateway._m.namespace, |
823 jid.JID("ext_user\\40example.org@ap.test.example") | 786 jid.JID("ext_user\\40example.org@ap.test.example"), |
824 ) | 787 ), |
825 ) | 788 ), |
826 ] | 789 ] |
827 monkeypatch.setattr(ap_gateway._p, "getItems", partial( | 790 monkeypatch.setattr( |
828 mock_getItems, | 791 ap_gateway._p, "getItems", partial(mock_getItems, ret_items=subscriptions) |
829 ret_items=subscriptions | 792 ) |
830 )) | |
831 following = await ap_gateway.server.resource.APFollowingRequest( | 793 following = await ap_gateway.server.resource.APFollowingRequest( |
832 **self.ap_request_params(ap_gateway, "following") | 794 **self.ap_request_params(ap_gateway, "following") |
833 ) | 795 ) |
834 assert following["@context"] == "https://www.w3.org/ns/activitystreams" | 796 assert following["@context"] == ["https://www.w3.org/ns/activitystreams"] |
835 assert following["id"] == "https://test.example/_ap/following/some_user%40test.example" | 797 assert ( |
798 following["id"] | |
799 == "https://test.example/_ap/following/some_user%40test.example" | |
800 ) | |
836 assert following["totalItems"] == len(subscriptions) | 801 assert following["totalItems"] == len(subscriptions) |
837 assert following["type"] == "OrderedCollection" | 802 assert following["type"] == "OrderedCollection" |
838 assert following.get("first") | 803 assert following.get("first") |
839 | 804 |
840 first_page = following["first"] | 805 first_page = following["first"] |
841 assert first_page["type"] == "OrderedCollectionPage" | 806 assert first_page["type"] == "OrderedCollectionPage" |
842 assert len(first_page["orderedItems"]) == len(subscriptions) | 807 assert len(first_page["orderedItems"]) == len(subscriptions) |
843 items = first_page["orderedItems"] | 808 items = first_page["orderedItems"] |
844 assert items == ['local_user@test.example', 'ext_user@example.org'] | 809 assert items == ["local_user@test.example", "ext_user@example.org"] |
845 | 810 |
846 @ed | 811 @ed |
847 async def test_pps_to_followers(self, ap_gateway, monkeypatch): | 812 async def test_pps_to_followers(self, ap_gateway, monkeypatch): |
848 """Public Pubsub Subscription subscribers are converted to AP followers""" | 813 """Public Pubsub Subscription subscribers are converted to AP followers""" |
849 subscribers = [ | 814 subscribers = [ |
850 pubsub.Item( | 815 pubsub.Item( |
851 id="subscriber_1", | 816 id="subscriber_1", |
852 payload = ap_gateway._pps.buildSubscriberElt( | 817 payload=ap_gateway._pps.buildSubscriberElt( |
853 jid.JID("local_user@test.example") | 818 jid.JID("local_user@test.example") |
854 ) | 819 ), |
855 ), | 820 ), |
856 pubsub.Item( | 821 pubsub.Item( |
857 id="subscriber_2", | 822 id="subscriber_2", |
858 payload = ap_gateway._pps.buildSubscriberElt( | 823 payload=ap_gateway._pps.buildSubscriberElt( |
859 jid.JID("ext_user\\40example.org@ap.test.example") | 824 jid.JID("ext_user\\40example.org@ap.test.example") |
860 ) | 825 ), |
861 ) | 826 ), |
862 ] | 827 ] |
863 monkeypatch.setattr(ap_gateway._p, "getItems", partial( | 828 monkeypatch.setattr( |
864 mock_getItems, | 829 ap_gateway._p, "getItems", partial(mock_getItems, ret_items=subscribers) |
865 ret_items=subscribers | 830 ) |
866 )) | |
867 followers = await ap_gateway.server.resource.APFollowersRequest( | 831 followers = await ap_gateway.server.resource.APFollowersRequest( |
868 **self.ap_request_params(ap_gateway, "followers") | 832 **self.ap_request_params(ap_gateway, "followers") |
869 ) | 833 ) |
870 assert followers["@context"] == "https://www.w3.org/ns/activitystreams" | 834 assert followers["@context"] == ["https://www.w3.org/ns/activitystreams"] |
871 assert followers["id"] == "https://test.example/_ap/followers/some_user%40test.example" | 835 assert ( |
836 followers["id"] | |
837 == "https://test.example/_ap/followers/some_user%40test.example" | |
838 ) | |
872 assert followers["totalItems"] == len(subscribers) | 839 assert followers["totalItems"] == len(subscribers) |
873 assert followers["type"] == "OrderedCollection" | 840 assert followers["type"] == "OrderedCollection" |
874 assert followers.get("first") | 841 assert followers.get("first") |
875 | 842 |
876 first_page = followers["first"] | 843 first_page = followers["first"] |
877 assert first_page["type"] == "OrderedCollectionPage" | 844 assert first_page["type"] == "OrderedCollectionPage" |
878 assert len(first_page["orderedItems"]) == len(subscribers) | 845 assert len(first_page["orderedItems"]) == len(subscribers) |
879 items = first_page["orderedItems"] | 846 items = first_page["orderedItems"] |
880 assert items == ['local_user@test.example', 'ext_user@example.org'] | 847 assert items == ["local_user@test.example", "ext_user@example.org"] |
881 | 848 |
882 @ed | 849 @ed |
883 async def test_xmpp_message_to_ap_direct_message(self, ap_gateway, monkeypatch): | 850 async def test_xmpp_message_to_ap_direct_message(self, ap_gateway, monkeypatch): |
884 """XMPP message are sent as AP direct message""" | 851 """XMPP message are sent as AP direct message""" |
885 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) | 852 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) |
888 mess_data = { | 855 mess_data = { |
889 "from": TEST_JID, | 856 "from": TEST_JID, |
890 "to": ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), | 857 "to": ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), |
891 "type": "chat", | 858 "type": "chat", |
892 "message": {"": "This is a test message."}, | 859 "message": {"": "This is a test message."}, |
893 "extra": { | 860 "extra": {"origin-id": "123"}, |
894 "origin-id": "123" | |
895 } | |
896 } | 861 } |
897 with patch.object(ap_gateway, "signAndPost") as signAndPost: | 862 with patch.object(ap_gateway, "signAndPost") as signAndPost: |
898 await ap_gateway.onMessage(ap_gateway.client, mess_data) | 863 await ap_gateway.onMessage(ap_gateway.client, mess_data) |
899 url, actor_id, doc = signAndPost.call_args[0] | 864 url, actor_id, doc = signAndPost.call_args[0] |
900 assert url == "https://example.org/users/test_user/inbox" | 865 assert url == "https://example.org/users/test_user/inbox" |
901 assert actor_id == "https://test.example/_ap/actor/some_user%40test.example" | 866 assert actor_id == "https://test.example/_ap/actor/some_user%40test.example" |
902 obj = doc["object"] | 867 obj = doc["object"] |
903 assert doc["@context"] == "https://www.w3.org/ns/activitystreams" | 868 assert doc["@context"] == ["https://www.w3.org/ns/activitystreams"] |
904 assert doc["actor"] == "https://test.example/_ap/actor/some_user%40test.example" | 869 assert doc["actor"] == "https://test.example/_ap/actor/some_user%40test.example" |
905 assert obj["type"] == "Note" | 870 assert obj["type"] == "Note" |
906 assert obj["content"] == "This is a test message." | 871 assert obj["content"] == "This is a test message." |
907 assert obj["attributedTo"] == ( | 872 assert obj["attributedTo"] == ( |
908 "https://test.example/_ap/actor/some_user%40test.example" | 873 "https://test.example/_ap/actor/some_user%40test.example" |
924 # we have to patch DeferredList to not wait forever | 889 # we have to patch DeferredList to not wait forever |
925 monkeypatch.setattr(defer, "DeferredList", AsyncMock()) | 890 monkeypatch.setattr(defer, "DeferredList", AsyncMock()) |
926 | 891 |
927 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) | 892 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) |
928 direct_ap_message = { | 893 direct_ap_message = { |
929 'attributedTo': TEST_AP_ACTOR_ID, | 894 "attributedTo": TEST_AP_ACTOR_ID, |
930 'cc': [], | 895 "cc": [], |
931 'content': '<p>test direct message</p>', | 896 "content": "<p>test direct message</p>", |
932 'contentMap': {'en': '<p>test direct message</p>'}, | 897 "contentMap": {"en": "<p>test direct message</p>"}, |
933 'id': f'{TEST_AP_ACTOR_ID}/statuses/123', | 898 "id": f"{TEST_AP_ACTOR_ID}/statuses/123", |
934 'published': '2022-05-20T08:14:39Z', | 899 "published": "2022-05-20T08:14:39Z", |
935 'to': [xmpp_actor_id], | 900 "to": [xmpp_actor_id], |
936 'type': 'Note', | 901 "type": "Note", |
937 } | 902 } |
938 client = ap_gateway.client.getVirtualClient( | 903 client = ap_gateway.client.getVirtualClient( |
939 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) | 904 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) |
940 ) | 905 ) |
941 with patch.object(client, "sendMessage") as sendMessage: | 906 with patch.object(client, "sendMessage") as sendMessage: |
961 items_event = pubsub.ItemsEvent( | 926 items_event = pubsub.ItemsEvent( |
962 sender=TEST_JID, | 927 sender=TEST_JID, |
963 recipient=ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), | 928 recipient=ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), |
964 nodeIdentifier=ap_gateway._m.namespace, | 929 nodeIdentifier=ap_gateway._m.namespace, |
965 items=[retract_elt], | 930 items=[retract_elt], |
966 headers={} | 931 headers={}, |
967 ) | 932 ) |
968 with patch.object(ap_gateway, "signAndPost") as signAndPost: | 933 with patch.object(ap_gateway, "signAndPost") as signAndPost: |
969 signAndPost.return_value = FakeTReqPostResponse() | 934 signAndPost.return_value = FakeTReqPostResponse() |
970 # we simulate the reception of a retract event | 935 # we simulate the reception of a retract event |
971 await ap_gateway._itemsReceived(ap_gateway.client, items_event) | 936 await ap_gateway._itemsReceived(ap_gateway.client, items_event) |
991 ap_item = { | 956 ap_item = { |
992 "@context": "https://www.w3.org/ns/activitystreams", | 957 "@context": "https://www.w3.org/ns/activitystreams", |
993 "actor": TEST_AP_ACTOR_ID, | 958 "actor": TEST_AP_ACTOR_ID, |
994 "id": "https://test.example/retract_123", | 959 "id": "https://test.example/retract_123", |
995 "type": "Delete", | 960 "type": "Delete", |
996 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", | 961 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", "type": "Tombstone"}, |
997 "type": "Tombstone"}, | 962 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
998 "to": ["https://www.w3.org/ns/activitystreams#Public"] | |
999 } | 963 } |
1000 with patch.multiple( | 964 with patch.multiple( |
1001 ap_gateway.host.memory.storage, | 965 ap_gateway.host.memory.storage, |
1002 get=DEFAULT, | 966 get=DEFAULT, |
1003 getPubsubNode=DEFAULT, | 967 getPubsubNode=DEFAULT, |
1004 deletePubsubItems=DEFAULT, | 968 deletePubsubItems=DEFAULT, |
1005 ) as mock_objs: | 969 ) as mock_objs: |
1006 mock_objs["get"].return_value=None | 970 mock_objs["get"].return_value = None |
1007 cached_node = MagicMock() | 971 cached_node = MagicMock() |
1008 mock_objs["getPubsubNode"].return_value=cached_node | 972 mock_objs["getPubsubNode"].return_value = cached_node |
1009 subscription = MagicMock() | 973 subscription = MagicMock() |
1010 subscription.state = SubscriptionState.SUBSCRIBED | 974 subscription.state = SubscriptionState.SUBSCRIBED |
1011 subscription.subscriber = TEST_JID | 975 subscription.subscriber = TEST_JID |
1012 cached_node.subscriptions = [subscription] | 976 cached_node.subscriptions = [subscription] |
1013 with patch.object( | 977 with patch.object( |
1016 # we simulate a received Delete activity | 980 # we simulate a received Delete activity |
1017 await ap_gateway.newAPDeleteItem( | 981 await ap_gateway.newAPDeleteItem( |
1018 client=client, | 982 client=client, |
1019 destinee=None, | 983 destinee=None, |
1020 node=ap_gateway._m.namespace, | 984 node=ap_gateway._m.namespace, |
1021 item=ap_item | 985 item=ap_item, |
1022 ) | 986 ) |
1023 | 987 |
1024 # item is deleted from database | 988 # item is deleted from database |
1025 deletePubsubItems = mock_objs["deletePubsubItems"] | 989 deletePubsubItems = mock_objs["deletePubsubItems"] |
1026 assert deletePubsubItems.call_count == 1 | 990 assert deletePubsubItems.call_count == 1 |
1064 fake_fastened_elts = MagicMock() | 1028 fake_fastened_elts = MagicMock() |
1065 fake_fastened_elts.id = origin_id | 1029 fake_fastened_elts.id = origin_id |
1066 # we simulate the reception of a retract event using the message element that | 1030 # we simulate the reception of a retract event using the message element that |
1067 # we generated above | 1031 # we generated above |
1068 await ap_gateway._onMessageRetract( | 1032 await ap_gateway._onMessageRetract( |
1069 ap_gateway.client, | 1033 ap_gateway.client, message_retract_elt, retract_elt, fake_fastened_elts |
1070 message_retract_elt, | |
1071 retract_elt, | |
1072 fake_fastened_elts | |
1073 ) | 1034 ) |
1074 url, actor_id, doc = signAndPost.call_args[0] | 1035 url, actor_id, doc = signAndPost.call_args[0] |
1075 | 1036 |
1076 # the AP delete activity must have been sent through signAndPost | 1037 # the AP delete activity must have been sent through signAndPost |
1077 # we check its values | 1038 # we check its values |
1106 ap_item = { | 1067 ap_item = { |
1107 "@context": "https://www.w3.org/ns/activitystreams", | 1068 "@context": "https://www.w3.org/ns/activitystreams", |
1108 "actor": TEST_AP_ACTOR_ID, | 1069 "actor": TEST_AP_ACTOR_ID, |
1109 "id": "https://test.example/retract_123", | 1070 "id": "https://test.example/retract_123", |
1110 "type": "Delete", | 1071 "type": "Delete", |
1111 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", | 1072 "object": {"id": f"{TEST_AP_ACTOR_ID}/item/123", "type": "Tombstone"}, |
1112 "type": "Tombstone"}, | 1073 "to": ["https://www.w3.org/ns/activitystreams#Public"], |
1113 "to": ["https://www.w3.org/ns/activitystreams#Public"] | |
1114 } | 1074 } |
1115 with patch.object(ap_gateway.host.memory.storage, "get") as storage_get: | 1075 with patch.object(ap_gateway.host.memory.storage, "get") as storage_get: |
1116 fake_history = MagicMock() | 1076 fake_history = MagicMock() |
1117 fake_history.source_jid = client.jid | 1077 fake_history.source_jid = client.jid |
1118 fake_history.dest_jid = TEST_JID | 1078 fake_history.dest_jid = TEST_JID |
1119 fake_history.origin_id = ap_item["id"] | 1079 fake_history.origin_id = ap_item["id"] |
1120 storage_get.return_value = fake_history | 1080 storage_get.return_value = fake_history |
1121 # we simulate a received Delete activity | 1081 # we simulate a received Delete activity |
1122 await ap_gateway.newAPDeleteItem( | 1082 await ap_gateway.newAPDeleteItem( |
1123 client=client, | 1083 client=client, destinee=None, node=ap_gateway._m.namespace, item=ap_item |
1124 destinee=None, | |
1125 node=ap_gateway._m.namespace, | |
1126 item=ap_item | |
1127 ) | 1084 ) |
1128 | 1085 |
1129 # item is deleted from database | 1086 # item is deleted from database |
1130 assert retractDBHistory.call_count == 1 | 1087 assert retractDBHistory.call_count == 1 |
1131 assert retractDBHistory.call_args.args[0] == client | 1088 assert retractDBHistory.call_args.args[0] == client |
1155 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), | 1112 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT), |
1156 # VCard4 node | 1113 # VCard4 node |
1157 ap_gateway._v.node, | 1114 ap_gateway._v.node, |
1158 None, | 1115 None, |
1159 None, | 1116 None, |
1160 None | 1117 None, |
1161 ) | 1118 ) |
1162 assert len(items) == 1 | 1119 assert len(items) == 1 |
1163 vcard_elt = next(items[0].elements(ap_gateway._v.namespace, "vcard")) | 1120 vcard_elt = next(items[0].elements(ap_gateway._v.namespace, "vcard")) |
1164 vcard = ap_gateway._v.vcard2Dict(vcard_elt) | 1121 vcard = ap_gateway._v.vcard2Dict(vcard_elt) |
1165 assert "test_user nickname" in vcard["nicknames"] | 1122 assert "test_user nickname" in vcard["nicknames"] |
1170 """XMPP identity is converted to AP actor metadata""" | 1127 """XMPP identity is converted to AP actor metadata""" |
1171 # XXX: XMPP identity is normally an amalgam of metadata from several | 1128 # XXX: XMPP identity is normally an amalgam of metadata from several |
1172 # XEPs/locations (vCard4, vcard-tmp, etc) | 1129 # XEPs/locations (vCard4, vcard-tmp, etc) |
1173 with patch.object(ap_gateway._i, "getIdentity") as getIdentity: | 1130 with patch.object(ap_gateway._i, "getIdentity") as getIdentity: |
1174 getIdentity.return_value = { | 1131 getIdentity.return_value = { |
1175 "nicknames": ["nick1", "nick2"], | 1132 "nicknames": ["nick1", "nick2"], |
1176 "description": "test description" | 1133 "description": "test description", |
1177 } | 1134 } |
1178 actor_data = await ap_gateway.server.resource.APActorRequest( | 1135 actor_data = await ap_gateway.server.resource.APActorRequest( |
1179 **self.ap_request_params(ap_gateway, ap_const.TYPE_ACTOR) | 1136 **self.ap_request_params(ap_gateway, ap_const.TYPE_ACTOR) |
1180 ) | 1137 ) |
1181 | 1138 |
1191 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) | 1148 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) |
1192 | 1149 |
1193 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) | 1150 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) |
1194 | 1151 |
1195 direct_addr_mention = { | 1152 direct_addr_mention = { |
1196 'attributedTo': TEST_AP_ACTOR_ID, | 1153 "attributedTo": TEST_AP_ACTOR_ID, |
1197 'cc': [], | 1154 "cc": [], |
1198 'content': '<p>test mention by direct addressing</p>', | 1155 "content": "<p>test mention by direct addressing</p>", |
1199 'id': f'{TEST_AP_ACTOR_ID}/statuses/direct_addr_123', | 1156 "id": f"{TEST_AP_ACTOR_ID}/statuses/direct_addr_123", |
1200 'published': '2022-05-20T08:14:39Z', | 1157 "published": "2022-05-20T08:14:39Z", |
1201 'to': [ap_const.NS_AP_PUBLIC, xmpp_actor_id], | 1158 "to": [ap_const.NS_AP_PUBLIC, xmpp_actor_id], |
1202 'type': 'Note' | 1159 "type": "Note", |
1203 } | 1160 } |
1204 client = ap_gateway.client.getVirtualClient( | 1161 client = ap_gateway.client.getVirtualClient( |
1205 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) | 1162 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) |
1206 ) | 1163 ) |
1207 monkeypatch.setattr(client, "sendMessage", MagicMock()) | 1164 monkeypatch.setattr(client, "sendMessage", MagicMock()) |
1217 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) | 1174 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) |
1218 expected_anchor = xmpp_uri.buildXMPPUri( | 1175 expected_anchor = xmpp_uri.buildXMPPUri( |
1219 "pubsub", | 1176 "pubsub", |
1220 path=local_actor_jid.full(), | 1177 path=local_actor_jid.full(), |
1221 node=ap_gateway._m.namespace, | 1178 node=ap_gateway._m.namespace, |
1222 item=direct_addr_mention["id"] | 1179 item=direct_addr_mention["id"], |
1223 ) | 1180 ) |
1224 | 1181 |
1225 assert sendReference.call_args.kwargs["anchor"] == expected_anchor | 1182 assert sendReference.call_args.kwargs["anchor"] == expected_anchor |
1226 | 1183 |
1227 @ed | 1184 @ed |
1232 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) | 1189 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) |
1233 | 1190 |
1234 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) | 1191 xmpp_actor_id = ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) |
1235 | 1192 |
1236 direct_addr_mention = { | 1193 direct_addr_mention = { |
1237 'attributedTo': TEST_AP_ACTOR_ID, | 1194 "attributedTo": TEST_AP_ACTOR_ID, |
1238 'cc': [], | 1195 "cc": [], |
1239 'content': '<p>test mention by tag</p>', | 1196 "content": "<p>test mention by tag</p>", |
1240 'id': f'{TEST_AP_ACTOR_ID}/statuses/tag_123', | 1197 "id": f"{TEST_AP_ACTOR_ID}/statuses/tag_123", |
1241 'published': '2022-05-20T08:14:39Z', | 1198 "published": "2022-05-20T08:14:39Z", |
1242 'to': [ap_const.NS_AP_PUBLIC], | 1199 "to": [ap_const.NS_AP_PUBLIC], |
1243 "tag": [ | 1200 "tag": [{"type": "Mention", "href": xmpp_actor_id, "name": f"@{TEST_JID}'"}], |
1244 { | 1201 "type": "Note", |
1245 "type": "Mention", | |
1246 "href": xmpp_actor_id, | |
1247 "name": f"@{TEST_JID}'" | |
1248 } | |
1249 ], | |
1250 'type': 'Note' | |
1251 } | 1202 } |
1252 client = ap_gateway.client.getVirtualClient( | 1203 client = ap_gateway.client.getVirtualClient( |
1253 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) | 1204 ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) |
1254 ) | 1205 ) |
1255 monkeypatch.setattr(client, "sendMessage", MagicMock()) | 1206 monkeypatch.setattr(client, "sendMessage", MagicMock()) |
1265 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) | 1216 local_actor_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) |
1266 expected_anchor = xmpp_uri.buildXMPPUri( | 1217 expected_anchor = xmpp_uri.buildXMPPUri( |
1267 "pubsub", | 1218 "pubsub", |
1268 path=local_actor_jid.full(), | 1219 path=local_actor_jid.full(), |
1269 node=ap_gateway._m.namespace, | 1220 node=ap_gateway._m.namespace, |
1270 item=direct_addr_mention["id"] | 1221 item=direct_addr_mention["id"], |
1271 ) | 1222 ) |
1272 | 1223 |
1273 assert sendReference.call_args.kwargs["anchor"] == expected_anchor | 1224 assert sendReference.call_args.kwargs["anchor"] == expected_anchor |
1274 | 1225 |
1275 @ed | 1226 @ed |
1281 | 1232 |
1282 mb_data = { | 1233 mb_data = { |
1283 "author_jid": TEST_JID.full(), | 1234 "author_jid": TEST_JID.full(), |
1284 "content": f"mention of @{TEST_AP_ACCOUNT}", | 1235 "content": f"mention of @{TEST_AP_ACCOUNT}", |
1285 "service": TEST_JID.full(), | 1236 "service": TEST_JID.full(), |
1286 "node": ap_gateway._m.namespace | 1237 "node": ap_gateway._m.namespace, |
1287 } | 1238 } |
1288 ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=True) | 1239 ap_item = await ap_gateway.mb_data_2_ap_item( |
1240 ap_gateway.client, mb_data, public=True | |
1241 ) | |
1289 | 1242 |
1290 ap_object = ap_item["object"] | 1243 ap_object = ap_item["object"] |
1291 assert TEST_AP_ACTOR_ID in ap_object["to"] | 1244 assert TEST_AP_ACTOR_ID in ap_object["to"] |
1292 expected_mention = { | 1245 expected_mention = { |
1293 "type": ap_const.TYPE_MENTION, | 1246 "type": ap_const.TYPE_MENTION, |
1294 "href": TEST_AP_ACTOR_ID, | 1247 "href": TEST_AP_ACTOR_ID, |
1295 "name": f"@{TEST_AP_ACCOUNT}" | 1248 "name": f"@{TEST_AP_ACCOUNT}", |
1296 } | 1249 } |
1297 assert expected_mention in ap_object["tag"] | 1250 assert expected_mention in ap_object["tag"] |
1298 | 1251 |
1299 @ed | 1252 @ed |
1300 async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch): | 1253 async def test_no_auto_mentions_when_not_public(self, ap_gateway, monkeypatch): |
1301 """Check that no mention is send when the message is not public""" | 1254 """Check that no mention is send when the message is not public""" |
1302 # this is the same test as test_auto_mentions above, except that public is not set | 1255 # this is the same test as test_auto_mentions above, except that public is not set |
1303 # in mbdata2APitem | 1256 # in mb_data_2_ap_item |
1304 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) | 1257 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "get", mock_ap_get) |
1305 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json) | 1258 monkeypatch.setattr(plugin_comp_ap_gateway.treq, "json_content", mock_treq_json) |
1306 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) | 1259 monkeypatch.setattr(ap_gateway, "apGet", mock_ap_get) |
1307 | 1260 |
1308 mb_data = { | 1261 mb_data = { |
1309 "author_jid": TEST_JID.full(), | 1262 "author_jid": TEST_JID.full(), |
1310 "content": f"mention of @{TEST_AP_ACCOUNT}", | 1263 "content": f"mention of @{TEST_AP_ACCOUNT}", |
1311 "service": TEST_JID.full(), | 1264 "service": TEST_JID.full(), |
1312 "node": ap_gateway._m.namespace | 1265 "node": ap_gateway._m.namespace, |
1313 } | 1266 } |
1314 ap_item = await ap_gateway.mbdata2APitem(ap_gateway.client, mb_data, public=False) | 1267 ap_item = await ap_gateway.mb_data_2_ap_item( |
1268 ap_gateway.client, mb_data, public=False | |
1269 ) | |
1315 | 1270 |
1316 ap_object = ap_item["object"] | 1271 ap_object = ap_item["object"] |
1317 assert "to" not in ap_object | 1272 assert "to" not in ap_object |
1318 assert "tag" not in ap_object | 1273 assert "tag" not in ap_object |
1319 | 1274 |
1328 item_elt = XMPP_ITEMS[0] | 1283 item_elt = XMPP_ITEMS[0] |
1329 anchor = xmpp_uri.buildXMPPUri( | 1284 anchor = xmpp_uri.buildXMPPUri( |
1330 "pubsub", | 1285 "pubsub", |
1331 path=TEST_JID.full(), | 1286 path=TEST_JID.full(), |
1332 node=ap_gateway._m.namespace, | 1287 node=ap_gateway._m.namespace, |
1333 item=item_elt["id"] | 1288 item=item_elt["id"], |
1334 ) | 1289 ) |
1335 | 1290 |
1336 ref_data: Dict[str, Union[str, int, dict]] = { | 1291 ref_data: Dict[str, Union[str, int, dict]] = { |
1337 "uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()), | 1292 "uri": xmpp_uri.buildXMPPUri(None, path=local_actor_jid.full()), |
1338 "type_": "mention", | 1293 "type_": "mention", |
1339 "anchor": anchor | 1294 "anchor": anchor, |
1340 } | 1295 } |
1341 reference_elt = ap_gateway._refs.buildRefElement(**ref_data) | 1296 reference_elt = ap_gateway._refs.buildRefElement(**ref_data) |
1342 | 1297 |
1343 # we now update ref_data to look like what is received in the trigger | 1298 # we now update ref_data to look like what is received in the trigger |
1344 | 1299 |
1359 mock_pubsub_item = MagicMock | 1314 mock_pubsub_item = MagicMock |
1360 mock_pubsub_item.data = item_elt | 1315 mock_pubsub_item.data = item_elt |
1361 getItems.return_value = ([mock_pubsub_item], {}) | 1316 getItems.return_value = ([mock_pubsub_item], {}) |
1362 with patch.object(ap_gateway, "signAndPost") as signAndPost: | 1317 with patch.object(ap_gateway, "signAndPost") as signAndPost: |
1363 signAndPost.return_value.code = 202 | 1318 signAndPost.return_value.code = 202 |
1364 await ap_gateway._onReferenceReceived(ap_gateway.client, message_elt, ref_data) | 1319 await ap_gateway._onReferenceReceived( |
1320 ap_gateway.client, message_elt, ref_data | |
1321 ) | |
1365 | 1322 |
1366 # when reference is received, the referencing item must be sent to referenced | 1323 # when reference is received, the referencing item must be sent to referenced |
1367 # actor, and they must be in "to" field and in "tag" | 1324 # actor, and they must be in "to" field and in "tag" |
1368 assert signAndPost.call_count == 1 | 1325 assert signAndPost.call_count == 1 |
1369 send_ap_item = signAndPost.call_args.args[-1] | 1326 send_ap_item = signAndPost.call_args.args[-1] |
1372 expected_mention = { | 1329 expected_mention = { |
1373 "type": ap_const.TYPE_MENTION, | 1330 "type": ap_const.TYPE_MENTION, |
1374 "href": TEST_AP_ACTOR_ID, | 1331 "href": TEST_AP_ACTOR_ID, |
1375 # we don't have a prefixing "@" here, because it's not needed in referencing | 1332 # we don't have a prefixing "@" here, because it's not needed in referencing |
1376 # item with XMPP | 1333 # item with XMPP |
1377 "name": f"{TEST_AP_ACCOUNT}" | 1334 "name": f"{TEST_AP_ACCOUNT}", |
1378 } | 1335 } |
1379 assert expected_mention in ap_object["tag"] | 1336 assert expected_mention in ap_object["tag"] |
1380 | 1337 |
1381 @ed | 1338 @ed |
1382 async def test_xmpp_repeat_to_ap_announce(self, ap_gateway, monkeypatch): | 1339 async def test_xmpp_repeat_to_ap_announce(self, ap_gateway, monkeypatch): |
1391 ap_item = TEST_AP_ITEMS[0] | 1348 ap_item = TEST_AP_ITEMS[0] |
1392 ap_item_url = xmpp_uri.buildXMPPUri( | 1349 ap_item_url = xmpp_uri.buildXMPPUri( |
1393 "pubsub", | 1350 "pubsub", |
1394 path=recipient_jid.full(), | 1351 path=recipient_jid.full(), |
1395 node=ap_gateway._m.namespace, | 1352 node=ap_gateway._m.namespace, |
1396 item=ap_item["id"] | 1353 item=ap_item["id"], |
1397 ) | 1354 ) |
1398 item_elt = xml_tools.parse(f""" | 1355 item_elt = xml_tools.parse( |
1356 f""" | |
1399 <item id="123" publisher="{TEST_JID}/res.123"> | 1357 <item id="123" publisher="{TEST_JID}/res.123"> |
1400 <entry xmlns="http://www.w3.org/2005/Atom"> | 1358 <entry xmlns="http://www.w3.org/2005/Atom"> |
1401 <title type="text">test message 1</title> | 1359 <title type="text">test message 1</title> |
1402 <title type="xhtml"> | 1360 <title type="xhtml"> |
1403 <div xmlns="http://www.w3.org/1999/xhtml"> | 1361 <div xmlns="http://www.w3.org/1999/xhtml"> |
1412 <published>2022-07-21T14:38:53Z</published> | 1370 <published>2022-07-21T14:38:53Z</published> |
1413 <id>{ap_item["id"]}</id> | 1371 <id>{ap_item["id"]}</id> |
1414 <link href="{ap_item_url}" rel="via"/> | 1372 <link href="{ap_item_url}" rel="via"/> |
1415 </entry> | 1373 </entry> |
1416 </item> | 1374 </item> |
1417 """) | 1375 """ |
1376 ) | |
1418 item_elt.uri = pubsub.NS_PUBSUB_EVENT | 1377 item_elt.uri = pubsub.NS_PUBSUB_EVENT |
1419 | 1378 |
1420 with patch.object(ap_gateway, "signAndPost") as signAndPost: | 1379 with patch.object(ap_gateway, "signAndPost") as signAndPost: |
1421 signAndPost.return_value.code = 202 | 1380 signAndPost.return_value.code = 202 |
1422 await ap_gateway.convertAndPostItems( | 1381 await ap_gateway.convertAndPostItems( |
1423 ap_gateway.client, | 1382 ap_gateway.client, |
1424 TEST_AP_ACCOUNT, | 1383 TEST_AP_ACCOUNT, |
1425 TEST_JID, | 1384 TEST_JID, |
1426 ap_gateway._m.namespace, | 1385 ap_gateway._m.namespace, |
1427 [item_elt] | 1386 [item_elt], |
1428 ) | 1387 ) |
1429 | 1388 |
1430 assert signAndPost.called | 1389 assert signAndPost.called |
1431 url, actor_id, doc = signAndPost.call_args.args | 1390 url, actor_id, doc = signAndPost.call_args.args |
1432 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] | 1391 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] |
1450 ) | 1409 ) |
1451 announce = { | 1410 announce = { |
1452 "@context": "https://www.w3.org/ns/activitystreams", | 1411 "@context": "https://www.w3.org/ns/activitystreams", |
1453 "type": "Announce", | 1412 "type": "Announce", |
1454 "actor": TEST_AP_ACTOR_ID, | 1413 "actor": TEST_AP_ACTOR_ID, |
1455 "cc": [ | 1414 "cc": [xmpp_actor_id, TEST_USER_DATA["followers"]], |
1456 xmpp_actor_id, | |
1457 TEST_USER_DATA["followers"] | |
1458 ], | |
1459 "id": "https://example.org/announce/123", | 1415 "id": "https://example.org/announce/123", |
1460 "object": xmpp_item_url, | 1416 "object": xmpp_item_url, |
1461 "published": "2022-07-22T09:24:12Z", | 1417 "published": "2022-07-22T09:24:12Z", |
1462 "to": [ap_const.NS_AP_PUBLIC] | 1418 "to": [ap_const.NS_AP_PUBLIC], |
1463 } | 1419 } |
1464 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: | 1420 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: |
1465 mock_pubsub_item = MagicMock | 1421 mock_pubsub_item = MagicMock |
1466 mock_pubsub_item.data = xmpp_item | 1422 mock_pubsub_item.data = xmpp_item |
1467 getItems.return_value = ([mock_pubsub_item], {}) | 1423 getItems.return_value = ([mock_pubsub_item], {}) |
1468 with patch.object( | 1424 with patch.object( |
1469 ap_gateway.host.memory.storage, | 1425 ap_gateway.host.memory.storage, "cachePubsubItems" |
1470 "cachePubsubItems") as cachePubsubItems: | 1426 ) as cachePubsubItems: |
1471 await ap_gateway.server.resource.handleAnnounceActivity( | 1427 await ap_gateway.server.resource.handleAnnounceActivity( |
1472 Request(MagicMock()), | 1428 Request(MagicMock()), announce, None, None, None, "", TEST_AP_ACTOR_ID |
1473 announce, | |
1474 None, | |
1475 None, | |
1476 None, | |
1477 "", | |
1478 TEST_AP_ACTOR_ID | |
1479 ) | 1429 ) |
1480 | 1430 |
1481 assert cachePubsubItems.called | 1431 assert cachePubsubItems.called |
1482 # the microblog data put in cache correspond to the item sent to subscribers | 1432 # the microblog data put in cache correspond to the item sent to subscribers |
1483 __, __, __, [mb_data] = cachePubsubItems.call_args.args | 1433 __, __, __, [mb_data] = cachePubsubItems.call_args.args |
1487 assert repeated["by"] == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT).full() | 1437 assert repeated["by"] == ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT).full() |
1488 xmpp_item_xmpp_url = xmpp_uri.buildXMPPUri( | 1438 xmpp_item_xmpp_url = xmpp_uri.buildXMPPUri( |
1489 "pubsub", | 1439 "pubsub", |
1490 path=TEST_JID.full(), | 1440 path=TEST_JID.full(), |
1491 node=ap_gateway._m.namespace, | 1441 node=ap_gateway._m.namespace, |
1492 item=xmpp_item["id"] | 1442 item=xmpp_item["id"], |
1493 ) | 1443 ) |
1494 assert repeated["uri"] == xmpp_item_xmpp_url | 1444 assert repeated["uri"] == xmpp_item_xmpp_url |
1495 | 1445 |
1496 @ed | 1446 @ed |
1497 async def test_xmpp_attachment_noticed_to_ap_like(self, ap_gateway, monkeypatch): | 1447 async def test_xmpp_attachment_noticed_to_ap_like(self, ap_gateway, monkeypatch): |
1502 | 1452 |
1503 recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) | 1453 recipient_jid = ap_gateway.getLocalJIDFromAccount(TEST_AP_ACCOUNT) |
1504 # noticed item | 1454 # noticed item |
1505 ap_item = TEST_AP_ITEMS[0] | 1455 ap_item = TEST_AP_ITEMS[0] |
1506 attachment_node = ap_gateway._pa.getAttachmentNodeName( | 1456 attachment_node = ap_gateway._pa.getAttachmentNodeName( |
1507 recipient_jid, | 1457 recipient_jid, ap_gateway._m.namespace, ap_item["id"] |
1508 ap_gateway._m.namespace, | 1458 ) |
1509 ap_item["id"] | 1459 item_elt = xml_tools.parse( |
1510 ) | 1460 f""" |
1511 item_elt = xml_tools.parse(f""" | |
1512 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}"> | 1461 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}"> |
1513 <attachments xmlns="urn:xmpp:pubsub-attachments:1"> | 1462 <attachments xmlns="urn:xmpp:pubsub-attachments:1"> |
1514 <noticed timestamp="2022-07-22T12:29:45Z"/> | 1463 <noticed timestamp="2022-07-22T12:29:45Z"/> |
1515 </attachments> | 1464 </attachments> |
1516 </item> | 1465 </item> |
1517 """) | 1466 """ |
1467 ) | |
1518 item_elt.uri = pubsub.NS_PUBSUB_EVENT | 1468 item_elt.uri = pubsub.NS_PUBSUB_EVENT |
1519 items_event = pubsub.ItemsEvent( | 1469 items_event = pubsub.ItemsEvent( |
1520 TEST_JID, | 1470 TEST_JID, recipient_jid, attachment_node, [item_elt], {} |
1521 recipient_jid, | |
1522 attachment_node, | |
1523 [item_elt], | |
1524 {} | |
1525 ) | 1471 ) |
1526 | 1472 |
1527 with patch.object(ap_gateway, "signAndPost") as signAndPost: | 1473 with patch.object(ap_gateway, "signAndPost") as signAndPost: |
1528 signAndPost.return_value.code = 202 | 1474 signAndPost.return_value.code = 202 |
1529 await ap_gateway._itemsReceived( | 1475 await ap_gateway._itemsReceived(ap_gateway.client, items_event) |
1530 ap_gateway.client, | |
1531 items_event | |
1532 ) | |
1533 | 1476 |
1534 assert signAndPost.called | 1477 assert signAndPost.called |
1535 url, actor_id, doc = signAndPost.call_args.args | 1478 url, actor_id, doc = signAndPost.call_args.args |
1536 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] | 1479 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] |
1537 assert actor_id == ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) | 1480 assert actor_id == ap_gateway.buildAPURL(ap_const.TYPE_ACTOR, TEST_JID.userhost()) |
1554 ) | 1497 ) |
1555 like = { | 1498 like = { |
1556 "@context": "https://www.w3.org/ns/activitystreams", | 1499 "@context": "https://www.w3.org/ns/activitystreams", |
1557 "type": "Like", | 1500 "type": "Like", |
1558 "actor": TEST_AP_ACTOR_ID, | 1501 "actor": TEST_AP_ACTOR_ID, |
1559 "cc": [ | 1502 "cc": [xmpp_actor_id, TEST_USER_DATA["followers"]], |
1560 xmpp_actor_id, | |
1561 TEST_USER_DATA["followers"] | |
1562 ], | |
1563 "id": "https://example.org/like/123", | 1503 "id": "https://example.org/like/123", |
1564 "object": xmpp_item_url, | 1504 "object": xmpp_item_url, |
1565 "published": "2022-07-22T09:24:12Z", | 1505 "published": "2022-07-22T09:24:12Z", |
1566 "to": [ap_const.NS_AP_PUBLIC] | 1506 "to": [ap_const.NS_AP_PUBLIC], |
1567 } | 1507 } |
1568 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: | 1508 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: |
1569 getItems.return_value = ([], {}) | 1509 getItems.return_value = ([], {}) |
1570 with patch.object(ap_gateway._p, "sendItems") as sendItems: | 1510 with patch.object(ap_gateway._p, "sendItems") as sendItems: |
1571 await ap_gateway.server.resource.APInboxRequest( | 1511 await ap_gateway.server.resource.APInboxRequest( |
1572 **self.ap_request_params( | 1512 **self.ap_request_params( |
1573 ap_gateway, | 1513 ap_gateway, "inbox", doc=like, signing_actor=TEST_AP_ACTOR_ID |
1574 "inbox", | |
1575 doc=like, | |
1576 signing_actor=TEST_AP_ACTOR_ID | |
1577 ) | 1514 ) |
1578 ) | 1515 ) |
1579 | 1516 |
1580 assert sendItems.called | 1517 assert sendItems.called |
1581 si_client, si_service, si_node, [si_item] = sendItems.call_args.args | 1518 si_client, si_service, si_node, [si_item] = sendItems.call_args.args |
1601 ap_item = TEST_AP_ITEMS[0] | 1538 ap_item = TEST_AP_ITEMS[0] |
1602 ap_item_url = xmpp_uri.buildXMPPUri( | 1539 ap_item_url = xmpp_uri.buildXMPPUri( |
1603 "pubsub", | 1540 "pubsub", |
1604 path=recipient_jid.full(), | 1541 path=recipient_jid.full(), |
1605 node=ap_gateway._m.namespace, | 1542 node=ap_gateway._m.namespace, |
1606 item=ap_item["id"] | 1543 item=ap_item["id"], |
1607 ) | 1544 ) |
1608 attachment_node = ap_gateway._pa.getAttachmentNodeName( | 1545 attachment_node = ap_gateway._pa.getAttachmentNodeName( |
1609 recipient_jid, | 1546 recipient_jid, ap_gateway._m.namespace, ap_item["id"] |
1610 ap_gateway._m.namespace, | |
1611 ap_item["id"] | |
1612 ) | 1547 ) |
1613 reactions = ["🦁", "🥜", "🎻"] | 1548 reactions = ["🦁", "🥜", "🎻"] |
1614 item_elt = xml_tools.parse(f""" | 1549 item_elt = xml_tools.parse( |
1550 f""" | |
1615 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}"> | 1551 <item id="{TEST_JID.userhost()}" published="{TEST_JID.userhostJID()}"> |
1616 <attachments xmlns="urn:xmpp:pubsub-attachments:1"> | 1552 <attachments xmlns="urn:xmpp:pubsub-attachments:1"> |
1617 <reactions timestamp="2022-08-31T12:17:23Z"> | 1553 <reactions timestamp="2022-08-31T12:17:23Z"> |
1618 <reaction>{reactions[0]}</reaction> | 1554 <reaction>{reactions[0]}</reaction> |
1619 <reaction>{reactions[1]}</reaction> | 1555 <reaction>{reactions[1]}</reaction> |
1620 <reaction>{reactions[2]}</reaction> | 1556 <reaction>{reactions[2]}</reaction> |
1621 </reactions> | 1557 </reactions> |
1622 </attachments> | 1558 </attachments> |
1623 </item> | 1559 </item> |
1624 """) | 1560 """ |
1561 ) | |
1625 item_elt.uri = pubsub.NS_PUBSUB_EVENT | 1562 item_elt.uri = pubsub.NS_PUBSUB_EVENT |
1626 items_event = pubsub.ItemsEvent( | 1563 items_event = pubsub.ItemsEvent( |
1627 TEST_JID, | 1564 TEST_JID, recipient_jid, attachment_node, [item_elt], {} |
1628 recipient_jid, | |
1629 attachment_node, | |
1630 [item_elt], | |
1631 {} | |
1632 ) | 1565 ) |
1633 | 1566 |
1634 with patch.object(ap_gateway, "signAndPost") as signAndPost: | 1567 with patch.object(ap_gateway, "signAndPost") as signAndPost: |
1635 signAndPost.return_value.code = 202 | 1568 signAndPost.return_value.code = 202 |
1636 await ap_gateway._itemsReceived( | 1569 await ap_gateway._itemsReceived(ap_gateway.client, items_event) |
1637 ap_gateway.client, | |
1638 items_event | |
1639 ) | |
1640 | 1570 |
1641 assert signAndPost.call_count == 3 | 1571 assert signAndPost.call_count == 3 |
1642 for idx, call_args in enumerate(signAndPost.call_args_list): | 1572 for idx, call_args in enumerate(signAndPost.call_args_list): |
1643 url, actor_id, doc = call_args.args | 1573 url, actor_id, doc = call_args.args |
1644 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] | 1574 assert url == TEST_USER_DATA["endpoints"]["sharedInbox"] |
1670 ) | 1600 ) |
1671 like = { | 1601 like = { |
1672 "@context": "https://www.w3.org/ns/activitystreams", | 1602 "@context": "https://www.w3.org/ns/activitystreams", |
1673 "type": "EmojiReact", | 1603 "type": "EmojiReact", |
1674 "actor": TEST_AP_ACTOR_ID, | 1604 "actor": TEST_AP_ACTOR_ID, |
1675 "cc": [ | 1605 "cc": [xmpp_actor_id, TEST_USER_DATA["followers"]], |
1676 xmpp_actor_id, | |
1677 TEST_USER_DATA["followers"] | |
1678 ], | |
1679 "id": "https://example.org/like/123", | 1606 "id": "https://example.org/like/123", |
1680 "object": xmpp_item_url, | 1607 "object": xmpp_item_url, |
1681 "content": "🐅", | 1608 "content": "🐅", |
1682 "published": "2022-07-22T09:24:12Z", | 1609 "published": "2022-07-22T09:24:12Z", |
1683 "to": [ap_const.NS_AP_PUBLIC] | 1610 "to": [ap_const.NS_AP_PUBLIC], |
1684 } | 1611 } |
1685 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: | 1612 with patch.object(ap_gateway.host.memory.storage, "getItems") as getItems: |
1686 getItems.return_value = ([], {}) | 1613 getItems.return_value = ([], {}) |
1687 with patch.object(ap_gateway._p, "sendItems") as sendItems: | 1614 with patch.object(ap_gateway._p, "sendItems") as sendItems: |
1688 await ap_gateway.server.resource.APInboxRequest( | 1615 await ap_gateway.server.resource.APInboxRequest( |
1689 **self.ap_request_params( | 1616 **self.ap_request_params( |
1690 ap_gateway, | 1617 ap_gateway, "inbox", doc=like, signing_actor=TEST_AP_ACTOR_ID |
1691 "inbox", | |
1692 doc=like, | |
1693 signing_actor=TEST_AP_ACTOR_ID | |
1694 ) | 1618 ) |
1695 ) | 1619 ) |
1696 | 1620 |
1697 assert sendItems.called | 1621 assert sendItems.called |
1698 si_client, si_service, si_node, [si_item] = sendItems.call_args.args | 1622 si_client, si_service, si_node, [si_item] = sendItems.call_args.args |