smodusermc commited on
Commit
51bbfca
·
verified ·
1 Parent(s): f0f1cc3

Update tests/test_e2e.py

Browse files
Files changed (1) hide show
  1. tests/test_e2e.py +143 -2
tests/test_e2e.py CHANGED
@@ -198,9 +198,9 @@ async def main():
198
  await bob.send({"type": "load_messages", "conversation_id": 1, "limit": 100})
199
  bl = await bob.expect("messages_loaded")
200
  check(all(m["id"] != dmsg["id"] for m in bl["messages"]), "deleted msg absent from history")
201
- # double delete is idempotent-ish (404)
202
  r = await http.delete(f"{BASE}/api/messages/{dmsg['id']}", headers={"X-Auth-Token": alice.token})
203
- check(r.status_code == 404, "second delete 404 (no crash)")
204
  # deleting someone else's message forbidden
205
  r = await http.delete(f"{BASE}/api/messages/{mid}", headers={"X-Auth-Token": bob.token})
206
  check(r.status_code == 404 or r.status_code == 403, "can't delete others' msg", r.text[:100])
@@ -325,6 +325,147 @@ async def main():
325
  allmsg = (await alice.expect("messages_loaded"))["messages"]
326
  check(sum(1 for m in allmsg if m["content"] == "dedupe me") == 1, "no duplicate messages stored")
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  # ---- auth edge ----
329
  r = await http.get(BASE + "/api/auth/verify", headers={"X-Auth-Token": "bogus"})
330
  check(r.status_code == 401, "bad token rejected")
 
198
  await bob.send({"type": "load_messages", "conversation_id": 1, "limit": 100})
199
  bl = await bob.expect("messages_loaded")
200
  check(all(m["id"] != dmsg["id"] for m in bl["messages"]), "deleted msg absent from history")
201
+ # double delete is idempotent (200 "already_deleted")
202
  r = await http.delete(f"{BASE}/api/messages/{dmsg['id']}", headers={"X-Auth-Token": alice.token})
203
+ check(r.status_code == 200, "second delete is a no-op (no crash)")
204
  # deleting someone else's message forbidden
205
  r = await http.delete(f"{BASE}/api/messages/{mid}", headers={"X-Auth-Token": bob.token})
206
  check(r.status_code == 404 or r.status_code == 403, "can't delete others' msg", r.text[:100])
 
325
  allmsg = (await alice.expect("messages_loaded"))["messages"]
326
  check(sum(1 for m in allmsg if m["content"] == "dedupe me") == 1, "no duplicate messages stored")
327
 
328
+ # ---- group chats, invites, blocking and renaming ----
329
+ await alice.drain(0.4)
330
+ await bob.drain(0.4)
331
+ r = await http.post(f"{BASE}/api/conversations/group?name=Group Test&member_ids={bob.user['id']}",
332
+ headers={"X-Auth-Token": alice.token})
333
+ check(r.status_code == 200, "group create ok", r.text[:200])
334
+ group = r.json()["conversation"]
335
+ gid = group["id"]
336
+ check(group["is_group"] is True and group["role"] == "owner", "creator is group owner")
337
+
338
+ # bob receives a pending invite and must accept before chatting
339
+ pending = await bob.expect("conversation_updated", 6)
340
+ check(pending["conversation"]["id"] == gid and pending["conversation"]["is_pending"],
341
+ "bob gets pending group invite")
342
+ r = await http.post(f"{BASE}/api/conversations/{gid}/accept", headers={"X-Auth-Token": bob.token})
343
+ check(r.status_code == 200 and r.json()["conversation"]["is_pending"] is False,
344
+ "bob accepts invite")
345
+ await alice.drain(0.3)
346
+ await bob.drain(0.3)
347
+
348
+ # rename the group; everyone else sees it
349
+ r = await http.patch(f"{BASE}/api/conversations/{gid}?name=Renamed Group",
350
+ headers={"X-Auth-Token": alice.token})
351
+ check(r.status_code == 200 and r.json()["conversation"]["custom_name"] == "Renamed Group",
352
+ "group rename ok")
353
+ renamed = await bob.expect("conversation_updated", 6)
354
+ check(renamed["conversation"]["custom_name"] == "Renamed Group", "bob sees renamed group")
355
+
356
+ # non-owner leaves; owner can delete afterwards
357
+ r = await http.delete(f"{BASE}/api/conversations/{gid}", headers={"X-Auth-Token": bob.token})
358
+ check(r.status_code == 200 and r.json()["status"] == "left", "group member can leave")
359
+ r = await http.delete(f"{BASE}/api/conversations/{gid}", headers={"X-Auth-Token": alice.token})
360
+ check(r.status_code == 200 and r.json()["status"] == "deleted", "owner can delete group")
361
+
362
+ # ---- group invites stay acceptable and pending users cannot act ----
363
+ charlie = Client("charlie")
364
+ r = await http.post(f"{BASE}/api/auth/signup?username=charlie&password=password123&display_name=Charlie")
365
+ check(r.status_code == 200, "signup charlie", r.text[:200])
366
+ charlie.token = r.json()["token"]
367
+ charlie.user = r.json()["user"]
368
+
369
+ await alice.drain(0.3)
370
+ await bob.drain(0.3)
371
+ r = await http.post(
372
+ f"{BASE}/api/conversations/group?name=Invite Group&member_ids={bob.user['id']},{charlie.user['id']}",
373
+ headers={"X-Auth-Token": alice.token})
374
+ check(r.status_code == 200, "group with two invitees created", r.text[:200])
375
+ g2id = r.json()["conversation"]["id"]
376
+
377
+ pend = await bob.expect("conversation_updated", 6)
378
+ check(pend["conversation"]["id"] == g2id and pend["conversation"]["is_pending"],
379
+ "second group invite arrives as pending")
380
+
381
+ # A pending invitee cannot leave, rename, send, or add members.
382
+ r = await http.delete(f"{BASE}/api/conversations/{g2id}", headers={"X-Auth-Token": bob.token})
383
+ check(r.status_code == 403, "pending user cannot leave", r.text[:120])
384
+ r = await http.patch(f"{BASE}/api/conversations/{g2id}?name=Nope", headers={"X-Auth-Token": bob.token})
385
+ check(r.status_code == 403, "pending user cannot rename", r.text[:120])
386
+ await bob.send({"type": "send_message", "conversation_id": g2id,
387
+ "content": "should not send", "client_id": "pending-send"})
388
+ send_err = await bob.expect("error", 6)
389
+ check(send_err.get("code") == "FORBIDDEN", "pending user cannot send", send_err.get("message", ""))
390
+ r = await http.post(f"{BASE}/api/conversations/{g2id}/members?member_ids={alice.user['id']}",
391
+ headers={"X-Auth-Token": bob.token})
392
+ check(r.status_code == 403, "pending user cannot add members", r.text[:120])
393
+
394
+ # Rejecting removes the pending row.
395
+ r = await http.post(f"{BASE}/api/conversations/{g2id}/reject", headers={"X-Auth-Token": bob.token})
396
+ check(r.status_code == 200 and r.json()["status"] == "rejected", "pending user can reject invite")
397
+
398
+ # A future re-invite must go through acceptance again.
399
+ await alice.drain(0.3)
400
+ await bob.drain(0.3)
401
+ r = await http.post(f"{BASE}/api/conversations/{g2id}/members?member_ids={bob.user['id']}",
402
+ headers={"X-Auth-Token": alice.token})
403
+ check(r.status_code == 200, "owner can re-invite after reject", r.text[:200])
404
+ re_pend = await bob.expect("conversation_updated", 6)
405
+ check(re_pend["conversation"]["id"] == g2id and re_pend["conversation"]["is_pending"],
406
+ "re-invite needs acceptance again")
407
+ r = await http.post(f"{BASE}/api/conversations/{g2id}/accept", headers={"X-Auth-Token": bob.token})
408
+ check(r.status_code == 200 and r.json()["conversation"]["is_pending"] is False,
409
+ "bob accepts the re-invite")
410
+ r = await http.post(f"{BASE}/api/conversations/{g2id}/accept", headers={"X-Auth-Token": charlie.token})
411
+ check(r.status_code == 200 and r.json()["conversation"]["is_pending"] is False,
412
+ "charlie accepts its own invite independently")
413
+ await alice.drain(0.3)
414
+ await bob.drain(0.3)
415
+
416
+ # Owner can also delete a group that still has pending/unopened invites.
417
+ r = await http.delete(f"{BASE}/api/conversations/{g2id}", headers={"X-Auth-Token": alice.token})
418
+ check(r.status_code == 200 and r.json()["status"] == "deleted", "owner can delete group with invites")
419
+
420
+ # blocking hides all existing chats but does not delete them
421
+ pre_block = await http.get(f"{BASE}/api/conversations", headers={"X-Auth-Token": alice.token})
422
+ check(any(c["id"] == dmid for c in pre_block.json()["conversations"]), "dm exists before block")
423
+ r = await http.post(f"{BASE}/api/users/{bob.user['id']}/block",
424
+ headers={"X-Auth-Token": alice.token})
425
+ check(r.status_code == 200, "alice blocks bob")
426
+ blocked_event = await bob.expect("block_changed", 6)
427
+ check(blocked_event["blocked"] is True and blocked_event["blocker_id"] == alice.user["id"],
428
+ "blocked user is notified")
429
+ r = await http.get(f"{BASE}/api/conversations", headers={"X-Auth-Token": alice.token})
430
+ check(all(c["id"] != dmid for c in r.json()["conversations"]), "blocked dm hidden for blocker")
431
+ r = await http.get(f"{BASE}/api/conversations", headers={"X-Auth-Token": bob.token})
432
+ check(all(c["id"] != dmid for c in r.json()["conversations"]), "blocked dm hidden for blocked user")
433
+ r = await http.post(f"{BASE}/api/conversations/dm?user_id={alice.user['id']}",
434
+ headers={"X-Auth-Token": bob.token})
435
+ check(r.status_code == 403, "blocked user cannot start new dm")
436
+
437
+ # the global room must stay usable while a pair is blocked
438
+ await alice.drain(0.3)
439
+ await bob.drain(0.3)
440
+ await alice.send({"type": "send_message", "content": "global while blocked",
441
+ "conversation_id": 1, "client_id": "gblock1"})
442
+ echo = await alice.expect("new_message")
443
+ check(echo["message"]["content"] == "global while blocked",
444
+ "blocker can still use the global room")
445
+ got = await wait_events([bob], "new_message")
446
+ check(any(m["message"].get("content") == "global while blocked" for m in got["bob"]),
447
+ "blocked user still receives global-room messages", str(got["bob"][:1]))
448
+ await alice.drain(0.2)
449
+ await bob.drain(0.2)
450
+ await bob.send({"type": "send_message", "content": "from blocked user in global",
451
+ "conversation_id": 1, "client_id": "gblock2"})
452
+ echo = await bob.expect("new_message")
453
+ check(echo["message"]["content"] == "from blocked user in global",
454
+ "blocked user can still send in the global room")
455
+ got = await wait_events([alice], "new_message")
456
+ check(any(m["message"].get("content") == "from blocked user in global" for m in got["alice"]),
457
+ "blocker still receives messages from blocked user in global room", str(got["alice"][:1]))
458
+
459
+ # unblock restores the hidden chat (still stored, never deleted)
460
+ r = await http.delete(f"{BASE}/api/users/{bob.user['id']}/block",
461
+ headers={"X-Auth-Token": alice.token})
462
+ check(r.status_code == 200, "unblock ok")
463
+ await alice.drain(0.3)
464
+ await bob.drain(0.3)
465
+ after = await http.get(f"{BASE}/api/conversations", headers={"X-Auth-Token": alice.token})
466
+ check(any(c["id"] == dmid for c in after.json()["conversations"]),
467
+ "hidden dm returns after unblock")
468
+
469
  # ---- auth edge ----
470
  r = await http.get(BASE + "/api/auth/verify", headers={"X-Auth-Token": "bogus"})
471
  check(r.status_code == 401, "bad token rejected")