Skip to content

Commit b0d2f8e

Browse files
authored
Add basic tests for the /threads endpoint. (#502)
Basic tests for MSC3856.
1 parent d762275 commit b0d2f8e

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

tests/csapi/room_threads_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package csapi_tests
2+
3+
import (
4+
"net/http"
5+
"testing"
6+
7+
"github.com/tidwall/gjson"
8+
9+
"github.com/matrix-org/complement/internal/b"
10+
"github.com/matrix-org/complement/internal/client"
11+
"github.com/matrix-org/complement/internal/match"
12+
"github.com/matrix-org/complement/internal/must"
13+
"github.com/matrix-org/complement/runtime"
14+
)
15+
16+
// A tuple of thread ID + latest event ID to match against.
17+
func threadKey(threadID, latestEventID string) string {
18+
return threadID + "|" + latestEventID
19+
}
20+
21+
func checkResults(t *testing.T, body []byte, expected []string) {
22+
t.Helper()
23+
24+
values := gjson.GetBytes(body, "chunk")
25+
var result []string
26+
for _, v := range values.Array() {
27+
result = append(result, threadKey(v.Get("event_id").Str, v.Get("unsigned.m\\.relations.m\\.thread.latest_event.event_id").Str))
28+
}
29+
must.HaveInOrder(t, result, expected)
30+
}
31+
32+
// Test the /threads endpoint.
33+
func TestThreadsEndpoint(t *testing.T) {
34+
runtime.SkipIf(t, runtime.Dendrite) // not supported
35+
deployment := Deploy(t, b.BlueprintAlice)
36+
defer deployment.Destroy(t)
37+
38+
alice := deployment.Client(t, "hs1", "@alice:hs1")
39+
roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"})
40+
_, token := alice.MustSync(t, client.SyncReq{})
41+
42+
// Create 2 threads in the room.
43+
res := alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-1"}, client.WithJSONBody(t, map[string]interface{}{
44+
"msgtype": "m.text",
45+
"body": "Thread 1 Root",
46+
}))
47+
threadID1 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id")
48+
49+
res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-2"}, client.WithJSONBody(t, map[string]interface{}{
50+
"msgtype": "m.text",
51+
"body": "Thraed 2 Root",
52+
}))
53+
threadID2 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id")
54+
55+
// Add threaded replies.
56+
res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-3"}, client.WithJSONBody(t, map[string]interface{}{
57+
"msgtype": "m.text",
58+
"body": "Thread 1 Reply",
59+
"m.relates_to": map[string]interface{}{
60+
"event_id": threadID1,
61+
"rel_type": "m.thread",
62+
},
63+
}))
64+
replyID1 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id")
65+
66+
res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-4"}, client.WithJSONBody(t, map[string]interface{}{
67+
"msgtype": "m.text",
68+
"body": "Thread 2 Reply",
69+
"m.relates_to": map[string]interface{}{
70+
"event_id": threadID2,
71+
"rel_type": "m.thread",
72+
},
73+
}))
74+
replyID2 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id")
75+
76+
// sync until the server has processed it
77+
alice.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool {
78+
return r.Get("event_id").Str == replyID2
79+
}))
80+
81+
// Request the threads.
82+
res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "threads"})
83+
body := must.MatchResponse(t, res, match.HTTPResponse{
84+
StatusCode: http.StatusOK,
85+
})
86+
87+
// Ensure the threads were properly ordered.
88+
checkResults(t, body, []string{threadKey(threadID2, replyID2), threadKey(threadID1, replyID1)})
89+
90+
// Update thread 1 and ensure it gets updated.
91+
res = alice.MustDoFunc(t, "PUT", []string{"_matrix", "client", "v3", "rooms", roomID, "send", "m.room.message", "txn-5"}, client.WithJSONBody(t, map[string]interface{}{
92+
"msgtype": "m.text",
93+
"body": "Thread 1 Reply 2",
94+
"m.relates_to": map[string]interface{}{
95+
"event_id": threadID1,
96+
"rel_type": "m.thread",
97+
},
98+
}))
99+
replyID3 := client.GetJSONFieldStr(t, client.ParseJSON(t, res), "event_id")
100+
101+
// sync until the server has processed it
102+
alice.MustSyncUntil(t, client.SyncReq{Since: token}, client.SyncTimelineHas(roomID, func(r gjson.Result) bool {
103+
return r.Get("event_id").Str == replyID3
104+
}))
105+
106+
res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v1", "rooms", roomID, "threads"})
107+
body = must.MatchResponse(t, res, match.HTTPResponse{
108+
StatusCode: http.StatusOK,
109+
})
110+
111+
// Ensure the threads were properly ordered.
112+
checkResults(t, body, []string{threadKey(threadID1, replyID3), threadKey(threadID2, replyID2)})
113+
}

0 commit comments

Comments
 (0)