From 4468a3fc5fe7145de396974c4d5fafa44c4d25f6 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 20 Oct 2025 17:47:25 +0100 Subject: [PATCH 01/18] Convert Sytest `Name/topic keys are correct` to Complement --- tests/csapi/public_rooms_test.go | 188 +++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 tests/csapi/public_rooms_test.go diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go new file mode 100644 index 00000000..e6e228e8 --- /dev/null +++ b/tests/csapi/public_rooms_test.go @@ -0,0 +1,188 @@ +package csapi_tests + +import ( + "net/http" + "testing" + "time" + + "github.com/tidwall/gjson" + + "github.com/matrix-org/complement" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/helpers" + "github.com/matrix-org/complement/match" + "github.com/matrix-org/complement/must" +) + +func TestPublicRooms(t *testing.T) { + deployment := complement.Deploy(t, 1) + defer deployment.Destroy(t) + + t.Run("parallel", func(t *testing.T) { + // sytest: Name/topic keys are correct + t.Run("Name/topic keys are correct", func(t *testing.T) { + t.Parallel() + authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) + + // Define room configurations matching the Sytest + roomConfigs := []struct { + alias string + name string + topic string + }{ + {"publicroomalias_no_name", "", ""}, + {"publicroomalias_with_name", "name_1", ""}, + {"publicroomalias_with_topic", "", "topic_1"}, + {"publicroomalias_with_name_topic", "name_2", "topic_2"}, + {"publicroom_with_unicode_chars_name", "un nom français", ""}, + {"publicroom_with_unicode_chars_topic", "", "un topic à la française"}, + {"publicroom_with_unicode_chars_name_topic", "un nom français", "un topic à la française"}, + } + + // Create all rooms with their configurations + createdRooms := make(map[string]struct { + roomID string + name string + topic string + }) + + for _, config := range roomConfigs { + roomOptions := map[string]interface{}{ + "visibility": "public", + "room_alias_name": config.alias, + } + + if config.name != "" { + roomOptions["name"] = config.name + } + if config.topic != "" { + roomOptions["topic"] = config.topic + } + + roomID := authedClient.MustCreateRoom(t, roomOptions) + createdRooms[config.alias] = struct { + roomID string + name string + topic string + }{ + roomID: roomID, + name: config.name, + topic: config.topic, + } + t.Logf("Created room %s with alias %s", roomID, config.alias) + } + + // Poll /publicRooms until all our rooms appear with correct data + authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, + client.WithRetryUntil(15*time.Second, func(res *http.Response) bool { + body := must.ParseJSON(t, res.Body) + + must.MatchGJSON( + t, + body, + match.JSONKeyPresent("chunk"), + match.JSONKeyTypeEqual("chunk", gjson.JSON), + ) + + chunk := body.Get("chunk") + if !chunk.IsArray() { + t.Logf("chunk is not an array") + return false + } + + // Track which rooms we've correctly found + foundRooms := make(map[string]bool) + + // Check each room in the public rooms list + for _, roomData := range chunk.Array() { + // Verify required keys are present + must.MatchGJSON( + t, + roomData, + match.JSONKeyPresent("world_readable"), + match.JSONKeyPresent("guest_can_join"), + match.JSONKeyPresent("num_joined_members"), + ) + + canonicalAlias := roomData.Get("canonical_alias").Str + name := roomData.Get("name").Str + topic := roomData.Get("topic").Str + numMembers := roomData.Get("num_joined_members").Int() + + // Skip rooms that aren't ours + if canonicalAlias == "" { + continue + } + + // Find which of our rooms this matches + var matchedAlias string + for alias := range createdRooms { + expectedAlias := "#" + alias + ":hs1" + if canonicalAlias == expectedAlias { + matchedAlias = alias + break + } + } + + if matchedAlias == "" { + continue // Not one of our rooms + } + + roomConfig := createdRooms[matchedAlias] + + // Verify member count + if numMembers != 1 { + t.Logf("Room %s has %d members, expected 1", matchedAlias, numMembers) + return false + } + + // Verify name field + if roomConfig.name != "" { + if name != roomConfig.name { + t.Logf("Room %s has name '%s', expected '%s'", matchedAlias, name, roomConfig.name) + return false + } + } else { + if name != "" { + t.Logf("Room %s has unexpected name '%s', expected no name", matchedAlias, name) + return false + } + } + + // Verify topic field + if roomConfig.topic != "" { + if topic != roomConfig.topic { + t.Logf("Room %s has topic '%s', expected '%s'", matchedAlias, topic, roomConfig.topic) + return false + } + } else { + if topic != "" { + t.Logf("Room %s has unexpected topic '%s', expected no topic", matchedAlias, topic) + return false + } + } + + // Mark this room as correctly found + foundRooms[matchedAlias] = true + t.Logf("Successfully validated room %s", matchedAlias) + } + + // Check if we found all our rooms + if len(foundRooms) != len(createdRooms) { + missing := []string{} + for alias := range createdRooms { + if !foundRooms[alias] { + missing = append(missing, alias) + } + } + t.Logf("Missing rooms in public list: %v (found %d/%d)", missing, len(foundRooms), len(createdRooms)) + return false + } + + t.Logf("All %d rooms found with correct name/topic data", len(foundRooms)) + return true + }), + ) + }) + }) +} From 835ba9ae43d514cb761e37e8288aa70dc94481fb Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 20 Oct 2025 18:31:56 +0100 Subject: [PATCH 02/18] Regenerate the list of converted sytests in the README --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 63c31e7e..79ba75c2 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ update-ca-certificates ## Sytest parity -As of 10 February 2023: +As of 20 October 2025: ``` $ go build ./cmd/sytest-coverage $ ./sytest-coverage -v @@ -507,7 +507,13 @@ $ ./sytest-coverage -v ✓ Can get rooms/{roomId}/members 30rooms/60version_upgrade 0/19 tests -30rooms/70publicroomslist 0/5 tests +30rooms/70publicroomslist 1/5 tests + × Asking for a remote rooms list, but supplying the local server's name, returns the local rooms list + × Can get remote public room list + × Can paginate public room list + × Can search public room list + ✓ Name/topic keys are correct + 31sync/01filter 2/2 tests ✓ Can create filter ✓ Can download filter @@ -707,5 +713,5 @@ $ ./sytest-coverage -v 90jira/SYN-516 0/1 tests 90jira/SYN-627 0/1 tests -TOTAL: 220/610 tests converted +TOTAL: 221/610 tests converted ``` From 0ef2cf7061d678097d1fef81977c8c8e3f8c2da2 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 29 Oct 2025 12:59:34 +0000 Subject: [PATCH 03/18] Update sytest coverage list --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 79ba75c2..6a0b2cf5 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ update-ca-certificates ## Sytest parity -As of 20 October 2025: +As of 29 October 2025: ``` $ go build ./cmd/sytest-coverage $ ./sytest-coverage -v @@ -507,11 +507,11 @@ $ ./sytest-coverage -v ✓ Can get rooms/{roomId}/members 30rooms/60version_upgrade 0/19 tests -30rooms/70publicroomslist 1/5 tests +30rooms/70publicroomslist 2/5 tests × Asking for a remote rooms list, but supplying the local server's name, returns the local rooms list × Can get remote public room list × Can paginate public room list - × Can search public room list + ✓ Can search public room list ✓ Name/topic keys are correct 31sync/01filter 2/2 tests @@ -713,5 +713,5 @@ $ ./sytest-coverage -v 90jira/SYN-516 0/1 tests 90jira/SYN-627 0/1 tests -TOTAL: 221/610 tests converted +TOTAL: 222/610 tests converted ``` From f31eeffa462b6b4d17ec2c276611e02266cc3c57 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 29 Oct 2025 13:05:19 +0000 Subject: [PATCH 04/18] Wait for `SyncUnitTimeout` instead of 15s arbitrarily As 15s would be quite long to wait until the test failed. --- tests/csapi/public_rooms_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 623f182b..38e86f27 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -127,7 +127,7 @@ func TestPublicRooms(t *testing.T) { // Poll /publicRooms until all our rooms appear with correct data authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, - client.WithRetryUntil(15*time.Second, func(res *http.Response) bool { + client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { body := must.ParseJSON(t, res.Body) must.MatchGJSON( From 2d2a8ab339c939f2775676fdf9fc352c071bd2e4 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 29 Oct 2025 14:07:02 +0000 Subject: [PATCH 05/18] Batch up all errors of a room before logging This allows us to collect all incorrect data about a room and print it. A side-effect is that one doesn't need to re-run the tests to see all the broken fields. In addition, the `must.MatchGJSON` was changed to a `should`, which now re-polls `/publicRooms`. This prevents the test from exiting early upon receiving an entry that's missing some keys. --- tests/csapi/public_rooms_test.go | 44 ++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 38e86f27..87848f70 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -1,6 +1,7 @@ package csapi_tests import ( + "fmt" "net/http" "testing" "time" @@ -12,6 +13,7 @@ import ( "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/match" "github.com/matrix-org/complement/must" + "github.com/matrix-org/complement/should" ) func TestPublicRooms(t *testing.T) { @@ -148,14 +150,21 @@ func TestPublicRooms(t *testing.T) { // Check each room in the public rooms list for _, roomData := range chunk.Array() { - // Verify required keys are present - must.MatchGJSON( - t, + // Verify required keys are present. This applies to any room we see. + err := should.MatchGJSON( roomData, match.JSONKeyPresent("world_readable"), match.JSONKeyPresent("guest_can_join"), match.JSONKeyPresent("num_joined_members"), ) + if err != nil { + // This room is missing required keys, log and try again. + roomId := roomData.Get("room_id").Str + t.Logf("Room %s data missing required keys: %s", roomId, err.Error()) + return false + } + + validationErrors := make([]error, 0) canonicalAlias := roomData.Get("canonical_alias").Str name := roomData.Get("name").Str @@ -185,38 +194,47 @@ func TestPublicRooms(t *testing.T) { // Verify member count if numMembers != 1 { - t.Logf("Room %s has %d members, expected 1", matchedAlias, numMembers) - return false + err = fmt.Errorf("Room %s has %d members, expected 1", matchedAlias, numMembers) + validationErrors = append(validationErrors, err) } // Verify name field if roomConfig.name != "" { if name != roomConfig.name { - t.Logf("Room %s has name '%s', expected '%s'", matchedAlias, name, roomConfig.name) - return false + err = fmt.Errorf("Room %s has name '%s', expected '%s'", matchedAlias, name, roomConfig.name) + validationErrors = append(validationErrors, err) } } else { if name != "" { - t.Logf("Room %s has unexpected name '%s', expected no name", matchedAlias, name) - return false + err = fmt.Errorf("Room %s has unexpected name '%s', expected no name", matchedAlias, name) + validationErrors = append(validationErrors, err) } } // Verify topic field if roomConfig.topic != "" { if topic != roomConfig.topic { - t.Logf("Room %s has topic '%s', expected '%s'", matchedAlias, topic, roomConfig.topic) - return false + err = fmt.Errorf("Room %s has topic '%s', expected '%s'", matchedAlias, topic, roomConfig.topic) + validationErrors = append(validationErrors, err) } } else { if topic != "" { - t.Logf("Room %s has unexpected topic '%s', expected no topic", matchedAlias, topic) - return false + err = fmt.Errorf("Room %s has unexpected topic '%s', expected no topic", matchedAlias, topic) + validationErrors = append(validationErrors, err) + } + } + + if len(validationErrors) > 0 { + for _, e := range validationErrors { + t.Logf("Validation error for room %s: %s", matchedAlias, e.Error()) } + + return false } // Mark this room as correctly found foundRooms[matchedAlias] = true + t.Logf("Successfully validated room %s", matchedAlias) } From 843789b9657ba1b89ac58bb99ba7bdb075fd9f3c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 29 Oct 2025 14:11:22 +0000 Subject: [PATCH 06/18] Use `GetFullyQualifiedHomeserverName` --- tests/csapi/public_rooms_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 87848f70..cadabbed 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -19,6 +19,7 @@ import ( func TestPublicRooms(t *testing.T) { deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) + hostname := deployment.GetFullyQualifiedHomeserverName(t, "hs1") t.Run("parallel", func(t *testing.T) { // sytest: Can search public room list @@ -179,7 +180,7 @@ func TestPublicRooms(t *testing.T) { // Find which of our rooms this matches var matchedAlias string for alias := range createdRooms { - expectedAlias := "#" + alias + ":hs1" + expectedAlias := "#" + alias + ":" + string(hostname) if canonicalAlias == expectedAlias { matchedAlias = alias break From 1f20acf6d8e2f39d07668ca7db2e6fae29e141f3 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 29 Oct 2025 14:17:33 +0000 Subject: [PATCH 07/18] Print out unexpected rooms if we found any --- tests/csapi/public_rooms_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index cadabbed..bc61e9f2 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -149,8 +149,13 @@ func TestPublicRooms(t *testing.T) { // Track which rooms we've correctly found foundRooms := make(map[string]bool) + // Keep track of any rooms that we didn't expect to see. + unexpectedRooms := make([]string, 0) + // Check each room in the public rooms list for _, roomData := range chunk.Array() { + roomId := roomData.Get("room_id").Str + // Verify required keys are present. This applies to any room we see. err := should.MatchGJSON( roomData, @@ -160,7 +165,6 @@ func TestPublicRooms(t *testing.T) { ) if err != nil { // This room is missing required keys, log and try again. - roomId := roomData.Get("room_id").Str t.Logf("Room %s data missing required keys: %s", roomId, err.Error()) return false } @@ -174,6 +178,7 @@ func TestPublicRooms(t *testing.T) { // Skip rooms that aren't ours if canonicalAlias == "" { + unexpectedRooms = append(unexpectedRooms, roomId) continue } @@ -248,6 +253,10 @@ func TestPublicRooms(t *testing.T) { } } t.Logf("Missing rooms in public list: %v (found %d/%d)", missing, len(foundRooms), len(createdRooms)) + + if len(unexpectedRooms) > 0 { + t.Logf("Also found unexpected rooms: %v", unexpectedRooms) + } return false } From 2d9a22cb43765ee178c648b58128d57974ce9720 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 30 Oct 2025 12:31:16 +0000 Subject: [PATCH 08/18] foundRooms -> validatedRooms A more accurate name for it. --- tests/csapi/public_rooms_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index bc61e9f2..4d8e7494 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -147,7 +147,7 @@ func TestPublicRooms(t *testing.T) { } // Track which rooms we've correctly found - foundRooms := make(map[string]bool) + validatedRooms := make(map[string]bool) // Keep track of any rooms that we didn't expect to see. unexpectedRooms := make([]string, 0) @@ -239,20 +239,20 @@ func TestPublicRooms(t *testing.T) { } // Mark this room as correctly found - foundRooms[matchedAlias] = true + validatedRooms[matchedAlias] = true t.Logf("Successfully validated room %s", matchedAlias) } - // Check if we found all our rooms - if len(foundRooms) != len(createdRooms) { + // Check if we found and validated all of our rooms + if len(validatedRooms) != len(createdRooms) { missing := []string{} for alias := range createdRooms { - if !foundRooms[alias] { + if !validatedRooms[alias] { missing = append(missing, alias) } } - t.Logf("Missing rooms in public list: %v (found %d/%d)", missing, len(foundRooms), len(createdRooms)) + t.Logf("Missing rooms in public list: %v (found %d/%d)", missing, len(validatedRooms), len(createdRooms)) if len(unexpectedRooms) > 0 { t.Logf("Also found unexpected rooms: %v", unexpectedRooms) @@ -260,7 +260,7 @@ func TestPublicRooms(t *testing.T) { return false } - t.Logf("All %d rooms found with correct name/topic data", len(foundRooms)) + t.Logf("All %d rooms found with correct name/topic data", len(validatedRooms)) return true }), ) From 6958458acd8dce18f9c4d5f33919ed42b60ccaf3 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 30 Oct 2025 16:02:03 +0000 Subject: [PATCH 09/18] Convert to a separate test per room data config This is indeed much easier to follow, and less book-keeping. --- tests/csapi/public_rooms_test.go | 278 +++++++++++++------------------ 1 file changed, 119 insertions(+), 159 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 4d8e7494..09d99331 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -43,22 +43,8 @@ func TestPublicRooms(t *testing.T) { }, }), client.WithRetryUntil(15*time.Second, func(res *http.Response) bool { - body := must.ParseJSON(t, res.Body) + results := parsePublicRoomsResponse(t, res) - must.MatchGJSON( - t, - body, - match.JSONKeyPresent("chunk"), - match.JSONKeyTypeEqual("chunk", gjson.JSON), - ) - - chunk := body.Get("chunk") - if !chunk.IsArray() { - t.Logf("chunk is not an array") - return false - } - - results := chunk.Array() if len(results) != 1 { t.Logf("expected a single search result, got %d", len(results)) return false @@ -80,7 +66,7 @@ func TestPublicRooms(t *testing.T) { t.Parallel() authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) - // Define room configurations matching the Sytest + // Define room configurations roomConfigs := []struct { alias string name string @@ -95,175 +81,149 @@ func TestPublicRooms(t *testing.T) { {"publicroom_with_unicode_chars_name_topic", "un nom français", "un topic à la française"}, } - // Create all rooms with their configurations - createdRooms := make(map[string]struct { - roomID string - name string - topic string - }) + for _, roomConfig := range roomConfigs { + t.Run(fmt.Sprintf("Creating room with alias %s", roomConfig.alias), func(t *testing.T) { + expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, hostname) - for _, config := range roomConfigs { - roomOptions := map[string]interface{}{ - "visibility": "public", - "room_alias_name": config.alias, - } - - if config.name != "" { - roomOptions["name"] = config.name - } - if config.topic != "" { - roomOptions["topic"] = config.topic - } - - roomID := authedClient.MustCreateRoom(t, roomOptions) - createdRooms[config.alias] = struct { - roomID string - name string - topic string - }{ - roomID: roomID, - name: config.name, - topic: config.topic, - } - t.Logf("Created room %s with alias %s", roomID, config.alias) - } - - // Poll /publicRooms until all our rooms appear with correct data - authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, - client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { - body := must.ParseJSON(t, res.Body) - - must.MatchGJSON( - t, - body, - match.JSONKeyPresent("chunk"), - match.JSONKeyTypeEqual("chunk", gjson.JSON), - ) + // Create the room + roomOptions := map[string]interface{}{ + "visibility": "public", + "room_alias_name": roomConfig.alias, + } - chunk := body.Get("chunk") - if !chunk.IsArray() { - t.Logf("chunk is not an array") - return false + if roomConfig.name != "" { + roomOptions["name"] = roomConfig.name + } + if roomConfig.topic != "" { + roomOptions["topic"] = roomConfig.topic } - // Track which rooms we've correctly found - validatedRooms := make(map[string]bool) + roomID := authedClient.MustCreateRoom(t, roomOptions) + t.Logf("Created room %s with alias %s", roomID, roomConfig.alias) + + // Poll /publicRooms until the room appears with the correct data // Keep track of any rooms that we didn't expect to see. unexpectedRooms := make([]string, 0) - // Check each room in the public rooms list - for _, roomData := range chunk.Array() { - roomId := roomData.Get("room_id").Str - - // Verify required keys are present. This applies to any room we see. - err := should.MatchGJSON( - roomData, - match.JSONKeyPresent("world_readable"), - match.JSONKeyPresent("guest_can_join"), - match.JSONKeyPresent("num_joined_members"), - ) - if err != nil { - // This room is missing required keys, log and try again. - t.Logf("Room %s data missing required keys: %s", roomId, err.Error()) - return false - } + var discoveredRoomData gjson.Result + authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, + client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { + results := parsePublicRoomsResponse(t, res) + + // Check each room in the public rooms list + for _, roomData := range results { + discoveredRoomID := roomData.Get("room_id").Str + if discoveredRoomID != roomID { + // Not our room, skip. + unexpectedRooms = append(unexpectedRooms, discoveredRoomID) + continue + } + + // We found our room. Stop calling /publicRooms and validate the response. + discoveredRoomData = roomData + } - validationErrors := make([]error, 0) + if !discoveredRoomData.Exists() { + t.Logf("Room %s not found in public rooms list, trying again...", roomID) + return false + } - canonicalAlias := roomData.Get("canonical_alias").Str - name := roomData.Get("name").Str - topic := roomData.Get("topic").Str - numMembers := roomData.Get("num_joined_members").Int() + return true + }), + ) - // Skip rooms that aren't ours - if canonicalAlias == "" { - unexpectedRooms = append(unexpectedRooms, roomId) - continue - } + t.Logf("Warning: Found unexpected rooms in public rooms list: %v", unexpectedRooms) - // Find which of our rooms this matches - var matchedAlias string - for alias := range createdRooms { - expectedAlias := "#" + alias + ":" + string(hostname) - if canonicalAlias == expectedAlias { - matchedAlias = alias - break - } - } + // Verify required keys are present in the room data. + err := should.MatchGJSON( + discoveredRoomData, + match.JSONKeyPresent("world_readable"), + match.JSONKeyPresent("guest_can_join"), + match.JSONKeyPresent("num_joined_members"), + ) + if err != nil { + // The room is missing required keys, and + // it's unlikely to get them after + // calling the method again. Let's bail out. + t.Fatalf("Room %s data missing required keys: %s, data: %v", roomID, err.Error(), discoveredRoomData) + } - if matchedAlias == "" { - continue // Not one of our rooms - } + // Keep track of all validation errors, rather than bailing out on the first one. + validationErrors := make([]error, 0) - roomConfig := createdRooms[matchedAlias] + // Verify canonical alias + canonicalAlias := discoveredRoomData.Get("canonical_alias").Str + if canonicalAlias != expectedCanonicalAlias { + err = fmt.Errorf("Room %s has canonical alias '%s', expected '%s'", roomID, canonicalAlias, expectedCanonicalAlias) + validationErrors = append(validationErrors, err) + } - // Verify member count - if numMembers != 1 { - err = fmt.Errorf("Room %s has %d members, expected 1", matchedAlias, numMembers) + // Verify member count + numMembers := discoveredRoomData.Get("num_joined_members").Int() + if numMembers != 1 { + err = fmt.Errorf("Room %s has %d members, expected 1", roomID, numMembers) + validationErrors = append(validationErrors, err) + } + + // Verify name field, if there is one to verify + name := discoveredRoomData.Get("name").Str + if roomConfig.name != "" { + if name != roomConfig.name { + err = fmt.Errorf("Room %s has name '%s', expected '%s'", roomID, name, roomConfig.name) validationErrors = append(validationErrors, err) } - - // Verify name field - if roomConfig.name != "" { - if name != roomConfig.name { - err = fmt.Errorf("Room %s has name '%s', expected '%s'", matchedAlias, name, roomConfig.name) - validationErrors = append(validationErrors, err) - } - } else { - if name != "" { - err = fmt.Errorf("Room %s has unexpected name '%s', expected no name", matchedAlias, name) - validationErrors = append(validationErrors, err) - } + } else { + if name != "" { + err = fmt.Errorf("Room %s has unexpected name '%s', expected no name", roomID, name) + validationErrors = append(validationErrors, err) } + } - // Verify topic field - if roomConfig.topic != "" { - if topic != roomConfig.topic { - err = fmt.Errorf("Room %s has topic '%s', expected '%s'", matchedAlias, topic, roomConfig.topic) - validationErrors = append(validationErrors, err) - } - } else { - if topic != "" { - err = fmt.Errorf("Room %s has unexpected topic '%s', expected no topic", matchedAlias, topic) - validationErrors = append(validationErrors, err) - } + // Verify topic field, if there is one to verify + topic := discoveredRoomData.Get("topic").Str + if roomConfig.topic != "" { + if topic != roomConfig.topic { + err = fmt.Errorf("Room %s has topic '%s', expected '%s'", roomID, topic, roomConfig.topic) + validationErrors = append(validationErrors, err) } - - if len(validationErrors) > 0 { - for _, e := range validationErrors { - t.Logf("Validation error for room %s: %s", matchedAlias, e.Error()) - } - - return false + } else { + if topic != "" { + err = fmt.Errorf("Room %s has unexpected topic '%s', expected no topic", roomID, topic) + validationErrors = append(validationErrors, err) } - - // Mark this room as correctly found - validatedRooms[matchedAlias] = true - - t.Logf("Successfully validated room %s", matchedAlias) } - // Check if we found and validated all of our rooms - if len(validatedRooms) != len(createdRooms) { - missing := []string{} - for alias := range createdRooms { - if !validatedRooms[alias] { - missing = append(missing, alias) - } + if len(validationErrors) > 0 { + for _, e := range validationErrors { + t.Errorf("Validation error for room %s: %s", roomID, e.Error()) } - t.Logf("Missing rooms in public list: %v (found %d/%d)", missing, len(validatedRooms), len(createdRooms)) - if len(unexpectedRooms) > 0 { - t.Logf("Also found unexpected rooms: %v", unexpectedRooms) - } - return false + t.Fail() } - - t.Logf("All %d rooms found with correct name/topic data", len(validatedRooms)) - return true - }), - ) + }) + } }) }) } + +func parsePublicRoomsResponse(t *testing.T, res *http.Response) []gjson.Result { + body := must.ParseJSON(t, res.Body) + + must.MatchGJSON( + t, + body, + match.JSONKeyPresent("chunk"), + match.JSONKeyTypeEqual("chunk", gjson.JSON), + ) + + chunk := body.Get("chunk") + if !chunk.Exists() { + t.Fatalf("`chunk` field on public rooms response does not exist, got body: %v", body) + } + if !chunk.IsArray() { + t.Fatalf("`chunk` field on public rooms response is not an array, got: %v", chunk) + } + + return chunk.Array() +} From 9e08bc7568799a5a5d3597feda8bf564ae425999 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 30 Oct 2025 16:08:13 +0000 Subject: [PATCH 10/18] Remove the room from the public rooms list at test's end Otherwise we were (correctly) seeing the warning about unexpected rooms in every time other than the first. --- tests/csapi/public_rooms_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 09d99331..42131e59 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -87,6 +87,7 @@ func TestPublicRooms(t *testing.T) { // Create the room roomOptions := map[string]interface{}{ + // Add the room to the public rooms list. "visibility": "public", "room_alias_name": roomConfig.alias, } @@ -201,6 +202,16 @@ func TestPublicRooms(t *testing.T) { t.Fail() } + + // Remove the room from the public rooms list to avoid polluting other tests. + authedClient.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, + client.WithJSONBody(t, map[string]interface{}{ + "visibility": "private", + }), + ) }) } }) From e79b3466fe083c122b7c726fa895ae0c8e22bdf5 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:02:14 +0000 Subject: [PATCH 11/18] Mark `parsePublicRoomsResponse` as a test helper function Co-authored-by: Eric Eastwood --- tests/csapi/public_rooms_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 42131e59..1540e1d5 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -219,6 +219,7 @@ func TestPublicRooms(t *testing.T) { } func parsePublicRoomsResponse(t *testing.T, res *http.Response) []gjson.Result { + t.Helper() body := must.ParseJSON(t, res.Body) must.MatchGJSON( From c7ee1d837a9be9964aed48b415f449bf83de7165 Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:02:35 +0000 Subject: [PATCH 12/18] Replace arbitrary timeout with `authedClient.SyncUntilTimeout` Co-authored-by: Eric Eastwood --- tests/csapi/public_rooms_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 1540e1d5..5a20950a 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -42,7 +42,7 @@ func TestPublicRooms(t *testing.T) { "generic_search_term": "wombles", }, }), - client.WithRetryUntil(15*time.Second, func(res *http.Response) bool { + client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { results := parsePublicRoomsResponse(t, res) if len(results) != 1 { From 59f9f0e71ea813428427c4d130047bead70e1313 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 5 Nov 2025 16:13:29 +0000 Subject: [PATCH 13/18] hostname -> server_name Better name for the variable. --- tests/csapi/public_rooms_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 5a20950a..9f12172b 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -19,7 +19,7 @@ import ( func TestPublicRooms(t *testing.T) { deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) - hostname := deployment.GetFullyQualifiedHomeserverName(t, "hs1") + server_name := deployment.GetFullyQualifiedHomeserverName(t, "hs1") t.Run("parallel", func(t *testing.T) { // sytest: Can search public room list @@ -83,7 +83,7 @@ func TestPublicRooms(t *testing.T) { for _, roomConfig := range roomConfigs { t.Run(fmt.Sprintf("Creating room with alias %s", roomConfig.alias), func(t *testing.T) { - expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, hostname) + expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, server_name) // Create the room roomOptions := map[string]interface{}{ From a395212212ca34ff741c36c6fc3c782aec749a5c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 5 Nov 2025 16:13:39 +0000 Subject: [PATCH 14/18] Only log unexpected rooms if there are any --- tests/csapi/public_rooms_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 9f12172b..4c94a247 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -134,7 +134,9 @@ func TestPublicRooms(t *testing.T) { }), ) - t.Logf("Warning: Found unexpected rooms in public rooms list: %v", unexpectedRooms) + if len(unexpectedRooms) > 0 { + t.Logf("Warning: Found unexpected rooms in public rooms list: %v", unexpectedRooms) + } // Verify required keys are present in the room data. err := should.MatchGJSON( From d24405d465cfe67e499fd706d53d7b59ec8da9e1 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 5 Nov 2025 16:15:55 +0000 Subject: [PATCH 15/18] Remove duplicate `chunk` checks --- tests/csapi/public_rooms_test.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 4c94a247..5ae64187 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -224,13 +224,6 @@ func parsePublicRoomsResponse(t *testing.T, res *http.Response) []gjson.Result { t.Helper() body := must.ParseJSON(t, res.Body) - must.MatchGJSON( - t, - body, - match.JSONKeyPresent("chunk"), - match.JSONKeyTypeEqual("chunk", gjson.JSON), - ) - chunk := body.Get("chunk") if !chunk.Exists() { t.Fatalf("`chunk` field on public rooms response does not exist, got body: %v", body) From 83723e73fc274d9011bf6079a9bf3591d1dbd40c Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 5 Nov 2025 16:38:07 +0000 Subject: [PATCH 16/18] Remove room at the end of "Can search public room list" --- tests/csapi/public_rooms_test.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 5ae64187..8f9a7fb5 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -4,7 +4,6 @@ import ( "fmt" "net/http" "testing" - "time" "github.com/tidwall/gjson" @@ -59,6 +58,16 @@ func TestPublicRooms(t *testing.T) { return true }), ) + + // Remove the room from the public rooms list to avoid polluting other tests. + authedClient.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, + client.WithJSONBody(t, map[string]interface{}{ + "visibility": "private", + }), + ) }) // sytest: Name/topic keys are correct From 9ab045cbbd2fb9e9c67053fb8ac8226f428c573b Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Wed, 5 Nov 2025 16:38:44 +0000 Subject: [PATCH 17/18] unparallel public rooms tests --- tests/csapi/public_rooms_test.go | 374 +++++++++++++++---------------- 1 file changed, 185 insertions(+), 189 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 8f9a7fb5..8959feb5 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -20,212 +20,208 @@ func TestPublicRooms(t *testing.T) { defer deployment.Destroy(t) server_name := deployment.GetFullyQualifiedHomeserverName(t, "hs1") - t.Run("parallel", func(t *testing.T) { - // sytest: Can search public room list - t.Run("Can search public room list", func(t *testing.T) { - t.Parallel() - authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) - - roomID := authedClient.MustCreateRoom(t, map[string]any{ - "visibility": "public", - "name": "Test Name", - "topic": "Test Topic Wombles", - }) - - authedClient.MustDo( - t, - "POST", - []string{"_matrix", "client", "v3", "publicRooms"}, - client.WithJSONBody(t, map[string]any{ - "filter": map[string]any{ - "generic_search_term": "wombles", - }, - }), - client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { - results := parsePublicRoomsResponse(t, res) - - if len(results) != 1 { - t.Logf("expected a single search result, got %d", len(results)) - return false - } - - foundRoomID := results[0].Get("room_id").Str - if foundRoomID != roomID { - t.Logf("expected room_id %s in search results, got %s", roomID, foundRoomID) - return false - } - - return true - }), - ) - - // Remove the room from the public rooms list to avoid polluting other tests. - authedClient.MustDo( - t, - "PUT", - []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, - client.WithJSONBody(t, map[string]interface{}{ - "visibility": "private", - }), - ) + // sytest: Can search public room list + t.Run("Can search public room list", func(t *testing.T) { + authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) + + roomID := authedClient.MustCreateRoom(t, map[string]any{ + "visibility": "public", + "name": "Test Name", + "topic": "Test Topic Wombles", }) - // sytest: Name/topic keys are correct - t.Run("Name/topic keys are correct", func(t *testing.T) { - t.Parallel() - authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) - - // Define room configurations - roomConfigs := []struct { - alias string - name string - topic string - }{ - {"publicroomalias_no_name", "", ""}, - {"publicroomalias_with_name", "name_1", ""}, - {"publicroomalias_with_topic", "", "topic_1"}, - {"publicroomalias_with_name_topic", "name_2", "topic_2"}, - {"publicroom_with_unicode_chars_name", "un nom français", ""}, - {"publicroom_with_unicode_chars_topic", "", "un topic à la française"}, - {"publicroom_with_unicode_chars_name_topic", "un nom français", "un topic à la française"}, - } - - for _, roomConfig := range roomConfigs { - t.Run(fmt.Sprintf("Creating room with alias %s", roomConfig.alias), func(t *testing.T) { - expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, server_name) - - // Create the room - roomOptions := map[string]interface{}{ - // Add the room to the public rooms list. - "visibility": "public", - "room_alias_name": roomConfig.alias, - } - - if roomConfig.name != "" { - roomOptions["name"] = roomConfig.name - } - if roomConfig.topic != "" { - roomOptions["topic"] = roomConfig.topic - } - - roomID := authedClient.MustCreateRoom(t, roomOptions) - t.Logf("Created room %s with alias %s", roomID, roomConfig.alias) - - // Poll /publicRooms until the room appears with the correct data - - // Keep track of any rooms that we didn't expect to see. - unexpectedRooms := make([]string, 0) - - var discoveredRoomData gjson.Result - authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, - client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { - results := parsePublicRoomsResponse(t, res) - - // Check each room in the public rooms list - for _, roomData := range results { - discoveredRoomID := roomData.Get("room_id").Str - if discoveredRoomID != roomID { - // Not our room, skip. - unexpectedRooms = append(unexpectedRooms, discoveredRoomID) - continue - } - - // We found our room. Stop calling /publicRooms and validate the response. - discoveredRoomData = roomData - } + authedClient.MustDo( + t, + "POST", + []string{"_matrix", "client", "v3", "publicRooms"}, + client.WithJSONBody(t, map[string]any{ + "filter": map[string]any{ + "generic_search_term": "wombles", + }, + }), + client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { + results := parsePublicRoomsResponse(t, res) + + if len(results) != 1 { + t.Logf("expected a single search result, got %d", len(results)) + return false + } + + foundRoomID := results[0].Get("room_id").Str + if foundRoomID != roomID { + t.Logf("expected room_id %s in search results, got %s", roomID, foundRoomID) + return false + } + + return true + }), + ) + + // Remove the room from the public rooms list to avoid polluting other tests. + authedClient.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, + client.WithJSONBody(t, map[string]interface{}{ + "visibility": "private", + }), + ) + }) - if !discoveredRoomData.Exists() { - t.Logf("Room %s not found in public rooms list, trying again...", roomID) - return false + // sytest: Name/topic keys are correct + t.Run("Name/topic keys are correct", func(t *testing.T) { + authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) + + // Define room configurations + roomConfigs := []struct { + alias string + name string + topic string + }{ + {"publicroomalias_no_name", "", ""}, + {"publicroomalias_with_name", "name_1", ""}, + {"publicroomalias_with_topic", "", "topic_1"}, + {"publicroomalias_with_name_topic", "name_2", "topic_2"}, + {"publicroom_with_unicode_chars_name", "un nom français", ""}, + {"publicroom_with_unicode_chars_topic", "", "un topic à la française"}, + {"publicroom_with_unicode_chars_name_topic", "un nom français", "un topic à la française"}, + } + + for _, roomConfig := range roomConfigs { + t.Run(fmt.Sprintf("Creating room with alias %s", roomConfig.alias), func(t *testing.T) { + expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, server_name) + + // Create the room + roomOptions := map[string]interface{}{ + // Add the room to the public rooms list. + "visibility": "public", + "room_alias_name": roomConfig.alias, + } + + if roomConfig.name != "" { + roomOptions["name"] = roomConfig.name + } + if roomConfig.topic != "" { + roomOptions["topic"] = roomConfig.topic + } + + roomID := authedClient.MustCreateRoom(t, roomOptions) + t.Logf("Created room %s with alias %s", roomID, roomConfig.alias) + + // Poll /publicRooms until the room appears with the correct data + + // Keep track of any rooms that we didn't expect to see. + unexpectedRooms := make([]string, 0) + + var discoveredRoomData gjson.Result + authedClient.MustDo(t, "GET", []string{"_matrix", "client", "v3", "publicRooms"}, + client.WithRetryUntil(authedClient.SyncUntilTimeout, func(res *http.Response) bool { + results := parsePublicRoomsResponse(t, res) + + // Check each room in the public rooms list + for _, roomData := range results { + discoveredRoomID := roomData.Get("room_id").Str + if discoveredRoomID != roomID { + // Not our room, skip. + unexpectedRooms = append(unexpectedRooms, discoveredRoomID) + continue } - return true - }), - ) - - if len(unexpectedRooms) > 0 { - t.Logf("Warning: Found unexpected rooms in public rooms list: %v", unexpectedRooms) - } - - // Verify required keys are present in the room data. - err := should.MatchGJSON( - discoveredRoomData, - match.JSONKeyPresent("world_readable"), - match.JSONKeyPresent("guest_can_join"), - match.JSONKeyPresent("num_joined_members"), - ) - if err != nil { - // The room is missing required keys, and - // it's unlikely to get them after - // calling the method again. Let's bail out. - t.Fatalf("Room %s data missing required keys: %s, data: %v", roomID, err.Error(), discoveredRoomData) - } + // We found our room. Stop calling /publicRooms and validate the response. + discoveredRoomData = roomData + } - // Keep track of all validation errors, rather than bailing out on the first one. - validationErrors := make([]error, 0) + if !discoveredRoomData.Exists() { + t.Logf("Room %s not found in public rooms list, trying again...", roomID) + return false + } - // Verify canonical alias - canonicalAlias := discoveredRoomData.Get("canonical_alias").Str - if canonicalAlias != expectedCanonicalAlias { - err = fmt.Errorf("Room %s has canonical alias '%s', expected '%s'", roomID, canonicalAlias, expectedCanonicalAlias) + return true + }), + ) + + if len(unexpectedRooms) > 0 { + t.Logf("Warning: Found unexpected rooms in public rooms list: %v", unexpectedRooms) + } + + // Verify required keys are present in the room data. + err := should.MatchGJSON( + discoveredRoomData, + match.JSONKeyPresent("world_readable"), + match.JSONKeyPresent("guest_can_join"), + match.JSONKeyPresent("num_joined_members"), + ) + if err != nil { + // The room is missing required keys, and + // it's unlikely to get them after + // calling the method again. Let's bail out. + t.Fatalf("Room %s data missing required keys: %s, data: %v", roomID, err.Error(), discoveredRoomData) + } + + // Keep track of all validation errors, rather than bailing out on the first one. + validationErrors := make([]error, 0) + + // Verify canonical alias + canonicalAlias := discoveredRoomData.Get("canonical_alias").Str + if canonicalAlias != expectedCanonicalAlias { + err = fmt.Errorf("Room %s has canonical alias '%s', expected '%s'", roomID, canonicalAlias, expectedCanonicalAlias) + validationErrors = append(validationErrors, err) + } + + // Verify member count + numMembers := discoveredRoomData.Get("num_joined_members").Int() + if numMembers != 1 { + err = fmt.Errorf("Room %s has %d members, expected 1", roomID, numMembers) + validationErrors = append(validationErrors, err) + } + + // Verify name field, if there is one to verify + name := discoveredRoomData.Get("name").Str + if roomConfig.name != "" { + if name != roomConfig.name { + err = fmt.Errorf("Room %s has name '%s', expected '%s'", roomID, name, roomConfig.name) validationErrors = append(validationErrors, err) } - - // Verify member count - numMembers := discoveredRoomData.Get("num_joined_members").Int() - if numMembers != 1 { - err = fmt.Errorf("Room %s has %d members, expected 1", roomID, numMembers) + } else { + if name != "" { + err = fmt.Errorf("Room %s has unexpected name '%s', expected no name", roomID, name) validationErrors = append(validationErrors, err) } + } - // Verify name field, if there is one to verify - name := discoveredRoomData.Get("name").Str - if roomConfig.name != "" { - if name != roomConfig.name { - err = fmt.Errorf("Room %s has name '%s', expected '%s'", roomID, name, roomConfig.name) - validationErrors = append(validationErrors, err) - } - } else { - if name != "" { - err = fmt.Errorf("Room %s has unexpected name '%s', expected no name", roomID, name) - validationErrors = append(validationErrors, err) - } + // Verify topic field, if there is one to verify + topic := discoveredRoomData.Get("topic").Str + if roomConfig.topic != "" { + if topic != roomConfig.topic { + err = fmt.Errorf("Room %s has topic '%s', expected '%s'", roomID, topic, roomConfig.topic) + validationErrors = append(validationErrors, err) } - - // Verify topic field, if there is one to verify - topic := discoveredRoomData.Get("topic").Str - if roomConfig.topic != "" { - if topic != roomConfig.topic { - err = fmt.Errorf("Room %s has topic '%s', expected '%s'", roomID, topic, roomConfig.topic) - validationErrors = append(validationErrors, err) - } - } else { - if topic != "" { - err = fmt.Errorf("Room %s has unexpected topic '%s', expected no topic", roomID, topic) - validationErrors = append(validationErrors, err) - } + } else { + if topic != "" { + err = fmt.Errorf("Room %s has unexpected topic '%s', expected no topic", roomID, topic) + validationErrors = append(validationErrors, err) } + } - if len(validationErrors) > 0 { - for _, e := range validationErrors { - t.Errorf("Validation error for room %s: %s", roomID, e.Error()) - } - - t.Fail() + if len(validationErrors) > 0 { + for _, e := range validationErrors { + t.Errorf("Validation error for room %s: %s", roomID, e.Error()) } - // Remove the room from the public rooms list to avoid polluting other tests. - authedClient.MustDo( - t, - "PUT", - []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, - client.WithJSONBody(t, map[string]interface{}{ - "visibility": "private", - }), - ) - }) - } - }) + t.Fail() + } + + // Remove the room from the public rooms list to avoid polluting other tests. + authedClient.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, + client.WithJSONBody(t, map[string]interface{}{ + "visibility": "private", + }), + ) + }) + } }) } From ce9288f2daf428552deb7e1d7fe5d442d20a23e1 Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Mon, 10 Nov 2025 10:07:53 +0000 Subject: [PATCH 18/18] `defer` right after creating the room This will be a no-op if the room was already private. --- tests/csapi/public_rooms_test.go | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/csapi/public_rooms_test.go b/tests/csapi/public_rooms_test.go index 8959feb5..c48b68e5 100644 --- a/tests/csapi/public_rooms_test.go +++ b/tests/csapi/public_rooms_test.go @@ -18,7 +18,7 @@ import ( func TestPublicRooms(t *testing.T) { deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) - server_name := deployment.GetFullyQualifiedHomeserverName(t, "hs1") + hs1ServerName := deployment.GetFullyQualifiedHomeserverName(t, "hs1") // sytest: Can search public room list t.Run("Can search public room list", func(t *testing.T) { @@ -30,6 +30,16 @@ func TestPublicRooms(t *testing.T) { "topic": "Test Topic Wombles", }) + // Remove the room from the public rooms list to avoid polluting other tests. + defer authedClient.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, + client.WithJSONBody(t, map[string]interface{}{ + "visibility": "private", + }), + ) + authedClient.MustDo( t, "POST", @@ -56,16 +66,6 @@ func TestPublicRooms(t *testing.T) { return true }), ) - - // Remove the room from the public rooms list to avoid polluting other tests. - authedClient.MustDo( - t, - "PUT", - []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, - client.WithJSONBody(t, map[string]interface{}{ - "visibility": "private", - }), - ) }) // sytest: Name/topic keys are correct @@ -89,7 +89,7 @@ func TestPublicRooms(t *testing.T) { for _, roomConfig := range roomConfigs { t.Run(fmt.Sprintf("Creating room with alias %s", roomConfig.alias), func(t *testing.T) { - expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, server_name) + expectedCanonicalAlias := fmt.Sprintf("#%s:%s", roomConfig.alias, hs1ServerName) // Create the room roomOptions := map[string]interface{}{ @@ -108,6 +108,16 @@ func TestPublicRooms(t *testing.T) { roomID := authedClient.MustCreateRoom(t, roomOptions) t.Logf("Created room %s with alias %s", roomID, roomConfig.alias) + // Remove the room from the public rooms list to avoid polluting other tests. + defer authedClient.MustDo( + t, + "PUT", + []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, + client.WithJSONBody(t, map[string]interface{}{ + "visibility": "private", + }), + ) + // Poll /publicRooms until the room appears with the correct data // Keep track of any rooms that we didn't expect to see. @@ -210,16 +220,6 @@ func TestPublicRooms(t *testing.T) { t.Fail() } - - // Remove the room from the public rooms list to avoid polluting other tests. - authedClient.MustDo( - t, - "PUT", - []string{"_matrix", "client", "v3", "directory", "list", "room", roomID}, - client.WithJSONBody(t, map[string]interface{}{ - "visibility": "private", - }), - ) }) } })