Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 0faf7dd

Browse files
committed
Add test script.
1 parent 083bb40 commit 0faf7dd

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed

thread_test.py

+190
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
import json
2+
from time import monotonic, sleep
3+
4+
import requests
5+
6+
HOMESERVER = "http://localhost:8080"
7+
8+
USER_1_TOK = "syt_dGVzdGVy_AywuFarQjsYrHuPkOUvg_25XLNK"
9+
USER_1_HEADERS = {"Authorization": f"Bearer {USER_1_TOK}"}
10+
11+
USER_2_TOK = "syt_b3RoZXI_jtiTnwtlBjMGMixlHIBM_4cxesB"
12+
USER_2_HEADERS = {"Authorization": f"Bearer {USER_2_TOK}"}
13+
14+
15+
def _check_for_status(result):
16+
# Similar to raise_for_status, but prints the error.
17+
if 400 <= result.status_code:
18+
error_msg = result.json()
19+
result.raise_for_status()
20+
print(error_msg)
21+
exit(0)
22+
23+
24+
def _sync_and_show(room_id):
25+
print("Syncing . . .")
26+
result = requests.get(
27+
f"{HOMESERVER}/_matrix/client/v3/sync",
28+
headers=USER_1_HEADERS,
29+
params={
30+
"filter": json.dumps(
31+
{
32+
"room": {
33+
"timeline": {"limit": 30, "unread_thread_notifications": True}
34+
}
35+
}
36+
)
37+
},
38+
)
39+
_check_for_status(result)
40+
sync_response = result.json()
41+
42+
room = sync_response["rooms"]["join"][room_id]
43+
44+
# Find read receipts (this assumes non-overlapping).
45+
read_receipts = {} # thread -> event ID -> users
46+
for event in room["ephemeral"]["events"]:
47+
if event["type"] != "m.receipt":
48+
continue
49+
50+
for event_id, content in event["content"].items():
51+
for mxid, receipt in content["m.read"].items():
52+
print(mxid, receipt)
53+
# Just care about the localpart of the MXID.
54+
mxid = mxid.split(":", 1)[0]
55+
read_receipts.setdefault(receipt.get("thread_id"), {}).setdefault(
56+
event_id, []
57+
).append(mxid)
58+
59+
print(room["unread_notifications"])
60+
print(room.get("unread_thread_notifications"))
61+
print()
62+
63+
# Convert events to their threads.
64+
threads = {}
65+
for event in room["timeline"]["events"]:
66+
if event["type"] != "m.room.message":
67+
continue
68+
69+
event_id = event["event_id"]
70+
71+
parent_id = event["content"].get("m.relates_to", {}).get("event_id")
72+
if parent_id:
73+
threads[parent_id][1].append(event)
74+
else:
75+
threads[event_id] = (event, [])
76+
77+
for root_event_id, (root, thread) in threads.items():
78+
msg = root["content"]["body"]
79+
print(f"{root_event_id}: {msg}")
80+
81+
for event in thread:
82+
thread_event_id = event["event_id"]
83+
84+
msg = event["content"]["body"]
85+
print(f"\t{thread_event_id}: {msg}")
86+
87+
if thread_event_id in read_receipts.get(root_event_id, {}):
88+
user_ids = ", ".join(read_receipts[root_event_id][thread_event_id])
89+
print(f"\t^--------- {user_ids} ---------^")
90+
91+
if root_event_id in read_receipts[None]:
92+
user_ids = ", ".join(read_receipts[None][root_event_id])
93+
print(f"^--------- {user_ids} ---------^")
94+
95+
print()
96+
print()
97+
98+
99+
def _send_event(room_id, body, thread_id=None):
100+
content = {
101+
"msgtype": "m.text",
102+
"body": body,
103+
}
104+
if thread_id:
105+
content["m.relates_to"] = {
106+
"rel_type": "m.thread",
107+
"event_id": thread_id,
108+
}
109+
110+
# Send a msg to the room.
111+
result = requests.put(
112+
f"{HOMESERVER}/_matrix/client/v3/rooms/{room_id}/send/m.room.message/msg{monotonic()}",
113+
json=content,
114+
headers=USER_2_HEADERS,
115+
)
116+
_check_for_status(result)
117+
return result.json()["event_id"]
118+
119+
120+
def main():
121+
# Create a new room as user 2, add a bunch of messages.
122+
result = requests.post(
123+
f"{HOMESERVER}/_matrix/client/v3/createRoom",
124+
json={"visibility": "public", "name": f"Thread Read Receipts ({monotonic()})"},
125+
headers=USER_2_HEADERS,
126+
)
127+
_check_for_status(result)
128+
room_id = result.json()["room_id"]
129+
130+
# Second user joins the room.
131+
result = requests.post(
132+
f"{HOMESERVER}/_matrix/client/v3/rooms/{room_id}/join", headers=USER_1_HEADERS
133+
)
134+
_check_for_status(result)
135+
136+
# Sync user 1.
137+
_sync_and_show(room_id)
138+
139+
# User 2 sends some messages.
140+
event_ids = []
141+
142+
def _send_and_append(body, thread_id=None):
143+
event_id = _send_event(room_id, body, thread_id)
144+
event_ids.append(event_id)
145+
return event_id
146+
147+
for msg in range(5):
148+
root_message_id = _send_and_append(f"Message {msg}")
149+
for msg in range(10):
150+
if msg % 2:
151+
_send_and_append(f"More message {msg}")
152+
else:
153+
_send_and_append(f"Thread Message {msg}", root_message_id)
154+
155+
# User 2 sends a read receipt.
156+
print("@second reads main timeline")
157+
result = requests.post(
158+
f"{HOMESERVER}/_matrix/client/v3/rooms/{room_id}/receipt/m.read/{event_ids[3]}",
159+
headers=USER_2_HEADERS,
160+
json={},
161+
)
162+
_check_for_status(result)
163+
164+
_sync_and_show(room_id)
165+
166+
# User 1 sends a read receipt.
167+
print("@test reads main timeline")
168+
result = requests.post(
169+
f"{HOMESERVER}/_matrix/client/v3/rooms/{room_id}/receipt/m.read/{event_ids[-5]}",
170+
headers=USER_1_HEADERS,
171+
json={},
172+
)
173+
_check_for_status(result)
174+
175+
_sync_and_show(room_id)
176+
177+
# User 1 sends another read receipt.
178+
print("@test reads thread")
179+
result = requests.post(
180+
f"{HOMESERVER}/_matrix/client/v3/rooms/{room_id}/receipt/m.read/{event_ids[-4]}/{root_message_id}",
181+
headers=USER_1_HEADERS,
182+
json={},
183+
)
184+
_check_for_status(result)
185+
186+
_sync_and_show(room_id)
187+
188+
189+
if __name__ == "__main__":
190+
main()

0 commit comments

Comments
 (0)