Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 5da410e

Browse files
authoredJun 12, 2025··
Add (Must)GetStateEventContent (#786)
It's used in enough places to warrant being a helper function.
1 parent 5daf877 commit 5da410e

8 files changed

+87
-167
lines changed
 

‎client/client.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,21 @@ func (c *CSAPI) SendRedaction(t ct.TestLike, roomID string, content map[string]i
367367
return c.Do(t, "PUT", paths, WithJSONBody(t, content))
368368
}
369369

370+
// MustGetStateEvent returns the event content for the given state event. Fails the test if the state event does not exist.
371+
func (c *CSAPI) MustGetStateEventContent(t ct.TestLike, roomID, eventType, stateKey string) (content gjson.Result) {
372+
t.Helper()
373+
res := c.GetStateEventContent(t, roomID, eventType, stateKey)
374+
mustRespond2xx(t, res)
375+
body := ParseJSON(t, res)
376+
return gjson.ParseBytes(body)
377+
}
378+
379+
// GetStateEvent returns the event content for the given state event. Use this form to detect absence via 404.
380+
func (c *CSAPI) GetStateEventContent(t ct.TestLike, roomID, eventType, stateKey string) *http.Response {
381+
t.Helper()
382+
return c.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", eventType, stateKey})
383+
}
384+
370385
// MustSendTyping marks this user as typing until the timeout is reached. If isTyping is false, timeout is ignored.
371386
func (c *CSAPI) MustSendTyping(t ct.TestLike, roomID string, isTyping bool, timeoutMillis int) {
372387
res := c.SendTyping(t, roomID, isTyping, timeoutMillis)
@@ -834,6 +849,7 @@ func (c *CSAPI) SendToDeviceMessages(t ct.TestLike, evType string, messages map[
834849
}
835850

836851
func mustRespond2xx(t ct.TestLike, res *http.Response) {
852+
t.Helper()
837853
if res.StatusCode >= 200 && res.StatusCode < 300 {
838854
return // 2xx
839855
}

‎tests/csapi/apidoc_room_create_test.go

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,8 @@ func TestRoomCreate(t *testing.T) {
5959
"topic": "Test Room",
6060
"preset": "public_chat",
6161
})
62-
res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.topic"})
63-
must.MatchResponse(t, res, match.HTTPResponse{
64-
StatusCode: 200,
65-
JSON: []match.JSON{
66-
match.JSONKeyEqual("topic", "Test Room"),
67-
},
68-
})
62+
content := alice.MustGetStateEventContent(t, roomID, "m.room.topic", "")
63+
must.MatchGJSON(t, content, match.JSONKeyEqual("topic", "Test Room"))
6964
})
7065
// sytest: POST /createRoom makes a room with a name
7166
t.Run("POST /createRoom makes a room with a name", func(t *testing.T) {
@@ -74,13 +69,8 @@ func TestRoomCreate(t *testing.T) {
7469
"name": "Test Room",
7570
"preset": "public_chat",
7671
})
77-
res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"})
78-
must.MatchResponse(t, res, match.HTTPResponse{
79-
StatusCode: 200,
80-
JSON: []match.JSON{
81-
match.JSONKeyEqual("name", "Test Room"),
82-
},
83-
})
72+
content := alice.MustGetStateEventContent(t, roomID, "m.room.name", "")
73+
must.MatchGJSON(t, content, match.JSONKeyEqual("name", "Test Room"))
8474
})
8575
// sytest: POST /createRoom creates a room with the given version
8676
t.Run("POST /createRoom creates a room with the given version", func(t *testing.T) {
@@ -89,13 +79,8 @@ func TestRoomCreate(t *testing.T) {
8979
"room_version": "2",
9080
"preset": "public_chat",
9181
})
92-
res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.create"})
93-
must.MatchResponse(t, res, match.HTTPResponse{
94-
StatusCode: 200,
95-
JSON: []match.JSON{
96-
match.JSONKeyEqual("room_version", "2"),
97-
},
98-
})
82+
content := alice.MustGetStateEventContent(t, roomID, "m.room.create", "")
83+
must.MatchGJSON(t, content, match.JSONKeyEqual("room_version", "2"))
9984
})
10085
// sytest: POST /createRoom makes a private room with invites
10186
t.Run("POST /createRoom makes a private room with invites", func(t *testing.T) {

‎tests/csapi/apidoc_room_members_test.go

Lines changed: 10 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,8 @@ func TestRoomMembers(t *testing.T) {
158158
})
159159

160160
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID))
161-
res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID})
162-
163-
must.MatchResponse(t, res, match.HTTPResponse{
164-
JSON: []match.JSON{
165-
match.JSONKeyEqual("foo", "bar"),
166-
match.JSONKeyEqual("membership", "join"),
167-
},
168-
})
161+
content := alice.MustGetStateEventContent(t, roomID, "m.room.member", bob.UserID)
162+
must.MatchGJSON(t, content, match.JSONKeyEqual("membership", "join"), match.JSONKeyEqual("foo", "bar"))
169163
})
170164
// sytest: POST /join/:room_alias can join a room with custom content
171165
t.Run("POST /join/:room_alias can join a room with custom content", func(t *testing.T) {
@@ -187,14 +181,8 @@ func TestRoomMembers(t *testing.T) {
187181
})
188182

189183
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID))
190-
res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID})
191-
192-
must.MatchResponse(t, res, match.HTTPResponse{
193-
JSON: []match.JSON{
194-
match.JSONKeyEqual("foo", "bar"),
195-
match.JSONKeyEqual("membership", "join"),
196-
},
197-
})
184+
content := alice.MustGetStateEventContent(t, roomID, "m.room.member", bob.UserID)
185+
must.MatchGJSON(t, content, match.JSONKeyEqual("membership", "join"), match.JSONKeyEqual("foo", "bar"))
198186
})
199187

200188
// sytest: POST /rooms/:room_id/ban can ban a user
@@ -222,12 +210,8 @@ func TestRoomMembers(t *testing.T) {
222210
return ev.Get("content.membership").Str == "ban"
223211
}))
224212
// verify bob is banned
225-
res = alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID})
226-
must.MatchResponse(t, res, match.HTTPResponse{
227-
JSON: []match.JSON{
228-
match.JSONKeyEqual("membership", "ban"),
229-
},
230-
})
213+
content := alice.MustGetStateEventContent(t, roomID, "m.room.member", bob.UserID)
214+
must.MatchGJSON(t, content, match.JSONKeyEqual("membership", "ban"))
231215
})
232216

233217
// sytest: POST /rooms/:room_id/invite can send an invite
@@ -236,12 +220,8 @@ func TestRoomMembers(t *testing.T) {
236220
roomID := alice.MustCreateRoom(t, map[string]interface{}{})
237221
alice.MustInviteRoom(t, roomID, bob.UserID)
238222
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncInvitedTo(bob.UserID, roomID))
239-
res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID})
240-
must.MatchResponse(t, res, match.HTTPResponse{
241-
JSON: []match.JSON{
242-
match.JSONKeyEqual("membership", "invite"),
243-
},
244-
})
223+
content := alice.MustGetStateEventContent(t, roomID, "m.room.member", bob.UserID)
224+
must.MatchGJSON(t, content, match.JSONKeyEqual("membership", "invite"))
245225
})
246226

247227
// sytest: POST /rooms/:room_id/leave can leave a room
@@ -254,13 +234,8 @@ func TestRoomMembers(t *testing.T) {
254234
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID))
255235
bob.MustLeaveRoom(t, roomID)
256236
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncLeftFrom(bob.UserID, roomID))
257-
258-
res := alice.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", bob.UserID})
259-
must.MatchResponse(t, res, match.HTTPResponse{
260-
JSON: []match.JSON{
261-
match.JSONKeyEqual("membership", "leave"),
262-
},
263-
})
237+
content := alice.MustGetStateEventContent(t, roomID, "m.room.member", bob.UserID)
238+
must.MatchGJSON(t, content, match.JSONKeyEqual("membership", "leave"))
264239
})
265240
})
266241
}

‎tests/csapi/power_levels_test.go

Lines changed: 36 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -60,52 +60,47 @@ func TestPowerLevels(t *testing.T) {
6060
// sytest: GET /rooms/:room_id/state/m.room.power_levels can fetch levels
6161
t.Run("GET /rooms/:room_id/state/m.room.power_levels can fetch levels", func(t *testing.T) {
6262
// Test if the old state still exists
63-
res := alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"})
64-
6563
// note: before v10 we technically cannot assume that powerlevel integers are json numbers,
6664
// as they can be both strings and numbers.
6765
// However, for this test, we control the test environment,
6866
// and we will assume the server is sane and give us powerlevels as numbers,
6967
// and if it doesn't, that's an offense worthy of a frown.
68+
content := alice.MustGetStateEventContent(t, roomID, "m.room.power_levels", "")
69+
must.MatchGJSON(t, content,
70+
match.JSONKeyTypeEqual("ban", gjson.Number),
71+
match.JSONKeyTypeEqual("kick", gjson.Number),
72+
match.JSONKeyTypeEqual("redact", gjson.Number),
73+
match.JSONKeyTypeEqual("state_default", gjson.Number),
74+
match.JSONKeyTypeEqual("events_default", gjson.Number),
75+
match.JSONKeyTypeEqual("users_default", gjson.Number),
76+
77+
match.JSONMapEach("events", func(k, v gjson.Result) error {
78+
if v.Type != gjson.Number {
79+
return fmt.Errorf("key %s is not a number", k.Str)
80+
} else {
81+
return nil
82+
}
83+
}),
7084

71-
must.MatchResponse(t, res, match.HTTPResponse{
72-
StatusCode: 200,
73-
JSON: []match.JSON{
74-
match.JSONKeyTypeEqual("ban", gjson.Number),
75-
match.JSONKeyTypeEqual("kick", gjson.Number),
76-
match.JSONKeyTypeEqual("redact", gjson.Number),
77-
match.JSONKeyTypeEqual("state_default", gjson.Number),
78-
match.JSONKeyTypeEqual("events_default", gjson.Number),
79-
match.JSONKeyTypeEqual("users_default", gjson.Number),
80-
81-
match.JSONMapEach("events", func(k, v gjson.Result) error {
82-
if v.Type != gjson.Number {
83-
return fmt.Errorf("key %s is not a number", k.Str)
84-
} else {
85-
return nil
86-
}
87-
}),
88-
89-
match.JSONMapEach("users", func(k, v gjson.Result) error {
90-
if v.Type != gjson.Number {
91-
return fmt.Errorf("key %s is not a number", k.Str)
92-
} else {
93-
return nil
94-
}
95-
}),
96-
97-
func(body gjson.Result) error {
98-
userDefault := int(body.Get("users_default").Num)
99-
thisUser := int(body.Get("users." + client.GjsonEscape(alice.UserID)).Num)
100-
101-
if thisUser > userDefault {
102-
return nil
103-
} else {
104-
return fmt.Errorf("expected room creator (%d) to have a higher-than-default powerlevel (which is %d)", thisUser, userDefault)
105-
}
106-
},
85+
match.JSONMapEach("users", func(k, v gjson.Result) error {
86+
if v.Type != gjson.Number {
87+
return fmt.Errorf("key %s is not a number", k.Str)
88+
} else {
89+
return nil
90+
}
91+
}),
92+
93+
func(body gjson.Result) error {
94+
userDefault := int(body.Get("users_default").Num)
95+
thisUser := int(body.Get("users." + client.GjsonEscape(alice.UserID)).Num)
96+
97+
if thisUser > userDefault {
98+
return nil
99+
} else {
100+
return fmt.Errorf("expected room creator (%d) to have a higher-than-default powerlevel (which is %d)", thisUser, userDefault)
101+
}
107102
},
108-
})
103+
)
109104
})
110105

111106
// sytest: PUT /rooms/:room_id/state/m.room.power_levels can set levels
@@ -172,13 +167,7 @@ func TestPowerLevels(t *testing.T) {
172167
})
173168

174169
// Test if the old state still exists
175-
res = alice.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"})
176-
177-
must.MatchResponse(t, res, match.HTTPResponse{
178-
StatusCode: 200,
179-
JSON: []match.JSON{
180-
match.JSONKeyMissing("users"),
181-
},
182-
})
170+
content := alice.MustGetStateEventContent(t, roomID, "m.room.power_levels", "")
171+
must.MatchGJSON(t, content, match.JSONKeyMissing("users"))
183172
})
184173
}

‎tests/csapi/room_leave_test.go

Lines changed: 8 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -128,28 +128,12 @@ func TestLeftRoomFixture(t *testing.T) {
128128
// sytest: Can get rooms/{roomId}/state for a departed room (SPEC-216)
129129
t.Run("Can get rooms/{roomId}/state for a departed room", func(t *testing.T) {
130130
// Bob gets the old state
131-
resp := bob.MustDo(
132-
t,
133-
"GET",
134-
[]string{"_matrix", "client", "v3", "rooms", roomID, "state", madeUpStateKey},
135-
)
136-
must.MatchResponse(t, resp, match.HTTPResponse{
137-
JSON: []match.JSON{
138-
match.JSONKeyEqual("body", beforeMadeUpState),
139-
},
140-
})
131+
content := bob.MustGetStateEventContent(t, roomID, madeUpStateKey, "")
132+
must.MatchGJSON(t, content, match.JSONKeyEqual("body", beforeMadeUpState))
141133

142134
// ...While Alice gets the new state
143-
resp = alice.MustDo(
144-
t,
145-
"GET",
146-
[]string{"_matrix", "client", "v3", "rooms", roomID, "state", madeUpStateKey},
147-
)
148-
must.MatchResponse(t, resp, match.HTTPResponse{
149-
JSON: []match.JSON{
150-
match.JSONKeyEqual("body", afterMadeUpState),
151-
},
152-
})
135+
content = alice.MustGetStateEventContent(t, roomID, madeUpStateKey, "")
136+
must.MatchGJSON(t, content, match.JSONKeyEqual("body", afterMadeUpState))
153137
})
154138

155139
// sytest: Can get rooms/{roomId}/members for a departed room (SPEC-216)
@@ -205,28 +189,12 @@ func TestLeftRoomFixture(t *testing.T) {
205189
// sytest: Can get 'm.room.name' state for a departed room (SPEC-216)
206190
t.Run("Can get 'm.room.name' state for a departed room", func(t *testing.T) {
207191
// Bob gets the old name
208-
resp := bob.MustDo(
209-
t,
210-
"GET",
211-
[]string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"},
212-
)
213-
must.MatchResponse(t, resp, match.HTTPResponse{
214-
JSON: []match.JSON{
215-
match.JSONKeyEqual("name", beforeRoomName),
216-
},
217-
})
192+
content := bob.MustGetStateEventContent(t, roomID, "m.room.name", "")
193+
must.MatchGJSON(t, content, match.JSONKeyEqual("name", beforeRoomName))
218194

219195
// ...While Alice gets the new name
220-
resp = alice.MustDo(
221-
t,
222-
"GET",
223-
[]string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.name"},
224-
)
225-
must.MatchResponse(t, resp, match.HTTPResponse{
226-
JSON: []match.JSON{
227-
match.JSONKeyEqual("name", afterRoomName),
228-
},
229-
})
196+
content = alice.MustGetStateEventContent(t, roomID, "m.room.name", "")
197+
must.MatchGJSON(t, content, match.JSONKeyEqual("name", afterRoomName))
230198
})
231199

232200
// sytest: Getting messages going forward is limited for a departed room (SPEC-216)

‎tests/csapi/rooms_invite_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -176,12 +176,7 @@ func verifyState(t *testing.T, res gjson.Result, roomID string, cl *client.CSAPI
176176
eventContent := event.Get("content." + field).Str
177177
eventStateKey := event.Get("state_key").Str
178178

179-
res := cl.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", eventType, eventStateKey})
180-
181-
must.MatchResponse(t, res, match.HTTPResponse{
182-
JSON: []match.JSON{
183-
match.JSONKeyEqual(field, eventContent),
184-
},
185-
})
179+
content := cl.MustGetStateEventContent(t, roomID, eventType, eventStateKey)
180+
must.MatchGJSON(t, content, match.JSONKeyEqual(field, eventContent))
186181
}
187182
}

‎tests/federation_acl_test.go

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,11 @@ func TestACLs(t *testing.T) {
108108
must.ContainSubset(t, events, []string{sentinelEventID})
109109

110110
// Validate the ACL event is actually in the rooms state
111-
res := user.Do(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.server_acl"})
112-
must.MatchResponse(t, res, match.HTTPResponse{
113-
StatusCode: 200,
114-
JSON: []match.JSON{
115-
match.JSONKeyEqual("allow", []string{"*"}),
116-
match.JSONKeyEqual("deny", []string{"hs2"}),
117-
match.JSONKeyEqual("allow_ip_literals", true),
118-
},
119-
})
111+
content := user.MustGetStateEventContent(t, roomID, "m.room.server_acl", "")
112+
must.MatchGJSON(t, content,
113+
match.JSONKeyEqual("allow", []string{"*"}),
114+
match.JSONKeyEqual("deny", []string{"hs2"}),
115+
match.JSONKeyEqual("allow_ip_literals", true),
116+
)
120117
}
121118
}

‎tests/federation_room_join_test.go

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -357,15 +357,10 @@ func TestBannedUserCannotSendJoin(t *testing.T) {
357357
}
358358

359359
// Alice checks the room state to check that charlie isn't a member
360-
res := alice.MustDo(
361-
t,
362-
"GET",
363-
[]string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.member", charlie},
360+
content := alice.MustGetStateEventContent(t, roomID, "m.room.member", charlie)
361+
must.MatchGJSON(t, content,
362+
match.JSONKeyEqual("membership", "ban"),
364363
)
365-
stateResp := must.ParseJSON(t, res.Body)
366-
res.Body.Close()
367-
membership := must.GetJSONFieldStr(t, stateResp, "membership")
368-
must.Equal(t, membership, "ban", "membership of charlie")
369364
}
370365

371366
// This test checks that we cannot submit anything via /v1/send_join except a join.

0 commit comments

Comments
 (0)
Please sign in to comment.