Skip to content

Commit 7e5c85b

Browse files
Convert Sytest Name/topic keys are correct to Complement (#811)
Co-authored-by: Eric Eastwood <erice@element.io>
1 parent a60750f commit 7e5c85b

File tree

2 files changed

+221
-49
lines changed

2 files changed

+221
-49
lines changed

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ update-ca-certificates
252252

253253
## Sytest parity
254254

255-
As of 10 February 2023:
255+
As of 29 October 2025:
256256
```
257257
$ go build ./cmd/sytest-coverage
258258
$ ./sytest-coverage -v
@@ -507,7 +507,13 @@ $ ./sytest-coverage -v
507507
✓ Can get rooms/{roomId}/members
508508
509509
30rooms/60version_upgrade 0/19 tests
510-
30rooms/70publicroomslist 0/5 tests
510+
30rooms/70publicroomslist 2/5 tests
511+
× Asking for a remote rooms list, but supplying the local server's name, returns the local rooms list
512+
× Can get remote public room list
513+
× Can paginate public room list
514+
✓ Can search public room list
515+
✓ Name/topic keys are correct
516+
511517
31sync/01filter 2/2 tests
512518
✓ Can create filter
513519
✓ Can download filter
@@ -707,5 +713,5 @@ $ ./sytest-coverage -v
707713
90jira/SYN-516 0/1 tests
708714
90jira/SYN-627 0/1 tests
709715
710-
TOTAL: 220/610 tests converted
716+
TOTAL: 222/610 tests converted
711717
```

tests/csapi/public_rooms_test.go

Lines changed: 212 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package csapi_tests
22

33
import (
4+
"fmt"
45
"net/http"
56
"testing"
6-
"time"
77

88
"github.com/tidwall/gjson"
99

@@ -12,64 +12,230 @@ import (
1212
"github.com/matrix-org/complement/helpers"
1313
"github.com/matrix-org/complement/match"
1414
"github.com/matrix-org/complement/must"
15+
"github.com/matrix-org/complement/should"
1516
)
1617

1718
func TestPublicRooms(t *testing.T) {
1819
deployment := complement.Deploy(t, 1)
1920
defer deployment.Destroy(t)
21+
hs1ServerName := deployment.GetFullyQualifiedHomeserverName(t, "hs1")
2022

21-
t.Run("parallel", func(t *testing.T) {
22-
// sytest: Can search public room list
23-
t.Run("Can search public room list", func(t *testing.T) {
24-
t.Parallel()
25-
authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{})
23+
// sytest: Can search public room list
24+
t.Run("Can search public room list", func(t *testing.T) {
25+
authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{})
2626

27-
roomID := authedClient.MustCreateRoom(t, map[string]any{
28-
"visibility": "public",
29-
"name": "Test Name",
30-
"topic": "Test Topic Wombles",
31-
})
27+
roomID := authedClient.MustCreateRoom(t, map[string]any{
28+
"visibility": "public",
29+
"name": "Test Name",
30+
"topic": "Test Topic Wombles",
31+
})
32+
33+
// Remove the room from the public rooms list to avoid polluting other tests.
34+
defer authedClient.MustDo(
35+
t,
36+
"PUT",
37+
[]string{"_matrix", "client", "v3", "directory", "list", "room", roomID},
38+
client.WithJSONBody(t, map[string]interface{}{
39+
"visibility": "private",
40+
}),
41+
)
42+
43+
authedClient.MustDo(
44+
t,
45+
"POST",
46+
[]string{"_matrix", "client", "v3", "publicRooms"},
47+
client.WithJSONBody(t, map[string]any{
48+
"filter": map[string]any{
49+
"generic_search_term": "wombles",
50+
},
51+
}),
52+
client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool {
53+
results := parsePublicRoomsResponse(t, res)
54+
55+
if len(results) != 1 {
56+
t.Logf("expected a single search result, got %d", len(results))
57+
return false
58+
}
59+
60+
foundRoomID := results[0].Get("room_id").Str
61+
if foundRoomID != roomID {
62+
t.Logf("expected room_id %s in search results, got %s", roomID, foundRoomID)
63+
return false
64+
}
65+
66+
return true
67+
}),
68+
)
69+
})
70+
71+
// sytest: Name/topic keys are correct
72+
t.Run("Name/topic keys are correct", func(t *testing.T) {
73+
authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{})
74+
75+
// Define room configurations
76+
roomConfigs := []struct {
77+
alias string
78+
name string
79+
topic string
80+
}{
81+
{"publicroomalias_no_name", "", ""},
82+
{"publicroomalias_with_name", "name_1", ""},
83+
{"publicroomalias_with_topic", "", "topic_1"},
84+
{"publicroomalias_with_name_topic", "name_2", "topic_2"},
85+
{"publicroom_with_unicode_chars_name", "un nom français", ""},
86+
{"publicroom_with_unicode_chars_topic", "", "un topic à la française"},
87+
{"publicroom_with_unicode_chars_name_topic", "un nom français", "un topic à la française"},
88+
}
89+
90+
for _, roomConfig := range roomConfigs {
91+
t.Run(fmt.Sprintf("Creating room with alias %s", roomConfig.alias), func(t *testing.T) {
92+
expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, hs1ServerName)
93+
94+
// Create the room
95+
roomOptions := map[string]interface{}{
96+
// Add the room to the public rooms list.
97+
"visibility": "public",
98+
"room_alias_name": roomConfig.alias,
99+
}
100+
101+
if roomConfig.name != "" {
102+
roomOptions["name"] = roomConfig.name
103+
}
104+
if roomConfig.topic != "" {
105+
roomOptions["topic"] = roomConfig.topic
106+
}
107+
108+
roomID := authedClient.MustCreateRoom(t, roomOptions)
109+
t.Logf("Created room %s with alias %s", roomID, roomConfig.alias)
110+
111+
// Remove the room from the public rooms list to avoid polluting other tests.
112+
defer authedClient.MustDo(
113+
t,
114+
"PUT",
115+
[]string{"_matrix", "client", "v3", "directory", "list", "room", roomID},
116+
client.WithJSONBody(t, map[string]interface{}{
117+
"visibility": "private",
118+
}),
119+
)
120+
121+
// Poll /publicRooms until the room appears with the correct data
122+
123+
// Keep track of any rooms that we didn't expect to see.
124+
unexpectedRooms := make([]string, 0)
125+
126+
var discoveredRoomData gjson.Result
127+
authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"},
128+
client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool {
129+
results := parsePublicRoomsResponse(t, res)
32130

33-
authedClient.MustDo(
34-
t,
35-
"POST",
36-
[]string{"_matrix", "client", "v3", "publicRooms"},
37-
client.WithJSONBody(t, map[string]any{
38-
"filter": map[string]any{
39-
"generic_search_term": "wombles",
40-
},
41-
}),
42-
client.WithRetryUntil(15*time.Second, func(res *http.Response) bool {
43-
body := must.ParseJSON(t, res.Body)
44-
45-
must.MatchGJSON(
46-
t,
47-
body,
48-
match.JSONKeyPresent("chunk"),
49-
match.JSONKeyTypeEqual("chunk", gjson.JSON),
50-
)
51-
52-
chunk := body.Get("chunk")
53-
if !chunk.IsArray() {
54-
t.Logf("chunk is not an array")
55-
return false
131+
// Check each room in the public rooms list
132+
for _, roomData := range results {
133+
discoveredRoomID := roomData.Get("room_id").Str
134+
if discoveredRoomID != roomID {
135+
// Not our room, skip.
136+
unexpectedRooms = append(unexpectedRooms, discoveredRoomID)
137+
continue
138+
}
139+
140+
// We found our room. Stop calling /publicRooms and validate the response.
141+
discoveredRoomData = roomData
142+
}
143+
144+
if !discoveredRoomData.Exists() {
145+
t.Logf("Room %s not found in public rooms list, trying again...", roomID)
146+
return false
147+
}
148+
149+
return true
150+
}),
151+
)
152+
153+
if len(unexpectedRooms) > 0 {
154+
t.Logf("Warning: Found unexpected rooms in public rooms list: %v", unexpectedRooms)
155+
}
156+
157+
// Verify required keys are present in the room data.
158+
err := should.MatchGJSON(
159+
discoveredRoomData,
160+
match.JSONKeyPresent("world_readable"),
161+
match.JSONKeyPresent("guest_can_join"),
162+
match.JSONKeyPresent("num_joined_members"),
163+
)
164+
if err != nil {
165+
// The room is missing required keys, and
166+
// it's unlikely to get them after
167+
// calling the method again. Let's bail out.
168+
t.Fatalf("Room %s data missing required keys: %s, data: %v", roomID, err.Error(), discoveredRoomData)
169+
}
170+
171+
// Keep track of all validation errors, rather than bailing out on the first one.
172+
validationErrors := make([]error, 0)
173+
174+
// Verify canonical alias
175+
canonicalAlias := discoveredRoomData.Get("canonical_alias").Str
176+
if canonicalAlias != expectedCanonicalAlias {
177+
err = fmt.Errorf("Room %s has canonical alias '%s', expected '%s'", roomID, canonicalAlias, expectedCanonicalAlias)
178+
validationErrors = append(validationErrors, err)
179+
}
180+
181+
// Verify member count
182+
numMembers := discoveredRoomData.Get("num_joined_members").Int()
183+
if numMembers != 1 {
184+
err = fmt.Errorf("Room %s has %d members, expected 1", roomID, numMembers)
185+
validationErrors = append(validationErrors, err)
186+
}
187+
188+
// Verify name field, if there is one to verify
189+
name := discoveredRoomData.Get("name").Str
190+
if roomConfig.name != "" {
191+
if name != roomConfig.name {
192+
err = fmt.Errorf("Room %s has name '%s', expected '%s'", roomID, name, roomConfig.name)
193+
validationErrors = append(validationErrors, err)
56194
}
195+
} else {
196+
if name != "" {
197+
err = fmt.Errorf("Room %s has unexpected name '%s', expected no name", roomID, name)
198+
validationErrors = append(validationErrors, err)
199+
}
200+
}
57201

58-
results := chunk.Array()
59-
if len(results) != 1 {
60-
t.Logf("expected a single search result, got %d", len(results))
61-
return false
202+
// Verify topic field, if there is one to verify
203+
topic := discoveredRoomData.Get("topic").Str
204+
if roomConfig.topic != "" {
205+
if topic != roomConfig.topic {
206+
err = fmt.Errorf("Room %s has topic '%s', expected '%s'", roomID, topic, roomConfig.topic)
207+
validationErrors = append(validationErrors, err)
208+
}
209+
} else {
210+
if topic != "" {
211+
err = fmt.Errorf("Room %s has unexpected topic '%s', expected no topic", roomID, topic)
212+
validationErrors = append(validationErrors, err)
62213
}
214+
}
63215

64-
foundRoomID := results[0].Get("room_id").Str
65-
if foundRoomID != roomID {
66-
t.Logf("expected room_id %s in search results, got %s", roomID, foundRoomID)
67-
return false
216+
if len(validationErrors) > 0 {
217+
for _, e := range validationErrors {
218+
t.Errorf("Validation error for room %s: %s", roomID, e.Error())
68219
}
69220

70-
return true
71-
}),
72-
)
73-
})
221+
t.Fail()
222+
}
223+
})
224+
}
74225
})
75226
}
227+
228+
func parsePublicRoomsResponse(t *testing.T, res *http.Response) []gjson.Result {
229+
t.Helper()
230+
body := must.ParseJSON(t, res.Body)
231+
232+
chunk := body.Get("chunk")
233+
if !chunk.Exists() {
234+
t.Fatalf("`chunk` field on public rooms response does not exist, got body: %v", body)
235+
}
236+
if !chunk.IsArray() {
237+
t.Fatalf("`chunk` field on public rooms response is not an array, got: %v", chunk)
238+
}
239+
240+
return chunk.Array()
241+
}

0 commit comments

Comments
 (0)