Skip to content

Commit 397f96f

Browse files
Sytest: Add 10apidoc/36room-levels tests (#545)
1 parent 0c42078 commit 397f96f

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

sytest.ignored.list

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ Can quarantine media in rooms
1212
Shutdown room
1313
Can backfill purged history
1414

15+
# Dummy test that exists only to prove a capability
16+
# (in 10apidoc/36room-levels)
17+
Both GET and PUT work
18+
1519
# Tests deprecated endpoints
1620
Tags appear in the v1 /initialSync
1721
Tags appear in the v1 /events stream

tests/csapi/power_levels_test.go

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

33
import (
4+
"fmt"
45
"testing"
56

7+
"github.com/tidwall/gjson"
8+
69
"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"
713
)
814

915
// This test ensures that an authorised (PL 100) user is able to modify the users_default value
@@ -40,3 +46,137 @@ func TestDemotingUsersViaUsersDefault(t *testing.T) {
4046
},
4147
})
4248
}
49+
50+
func TestPowerLevels(t *testing.T) {
51+
deployment := Deploy(t, b.BlueprintAlice)
52+
defer deployment.Destroy(t)
53+
54+
alice := deployment.Client(t, "hs1", "@alice:hs1")
55+
56+
roomID := alice.CreateRoom(t, map[string]interface{}{})
57+
58+
// sytest: GET /rooms/:room_id/state/m.room.power_levels can fetch levels
59+
t.Run("GET /rooms/:room_id/state/m.room.power_levels can fetch levels", func(t *testing.T) {
60+
// Test if the old state still exists
61+
res := alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"})
62+
63+
// note: before v10 we technically cannot assume that powerlevel integers are json numbers,
64+
// as they can be both strings and numbers.
65+
// However, for this test, we control the test environment,
66+
// and we will assume the server is sane and give us powerlevels as numbers,
67+
// and if it doesn't, that's an offense worthy of a frown.
68+
69+
must.MatchResponse(t, res, match.HTTPResponse{
70+
StatusCode: 200,
71+
JSON: []match.JSON{
72+
match.JSONKeyTypeEqual("ban", gjson.Number),
73+
match.JSONKeyTypeEqual("kick", gjson.Number),
74+
match.JSONKeyTypeEqual("redact", gjson.Number),
75+
match.JSONKeyTypeEqual("state_default", gjson.Number),
76+
match.JSONKeyTypeEqual("events_default", gjson.Number),
77+
match.JSONKeyTypeEqual("users_default", gjson.Number),
78+
79+
match.JSONMapEach("events", func(k, v gjson.Result) error {
80+
if v.Type != gjson.Number {
81+
return fmt.Errorf("key %s is not a number", k.Str)
82+
} else {
83+
return nil
84+
}
85+
}),
86+
87+
match.JSONMapEach("users", func(k, v gjson.Result) error {
88+
if v.Type != gjson.Number {
89+
return fmt.Errorf("key %s is not a number", k.Str)
90+
} else {
91+
return nil
92+
}
93+
}),
94+
95+
func(body []byte) error {
96+
userDefault := int(gjson.GetBytes(body, "users_default").Num)
97+
thisUser := int(gjson.GetBytes(body, "users."+client.GjsonEscape(alice.UserID)).Num)
98+
99+
if thisUser > userDefault {
100+
return nil
101+
} else {
102+
return fmt.Errorf("expected room creator (%d) to have a higher-than-default powerlevel (which is %d)", thisUser, userDefault)
103+
}
104+
},
105+
},
106+
})
107+
})
108+
109+
// sytest: PUT /rooms/:room_id/state/m.room.power_levels can set levels
110+
t.Run("PUT /rooms/:room_id/state/m.room.power_levels can set levels", func(t *testing.T) {
111+
// note: these need to be floats to allow a roundtrip comparison
112+
PLContent := map[string]interface{}{
113+
"invite": 100.0,
114+
"users": map[string]interface{}{
115+
alice.UserID: 100.0,
116+
"@random-other-user:their.home": 20.0,
117+
},
118+
}
119+
120+
eventId := alice.SendEventSynced(t, roomID, b.Event{
121+
Type: "m.room.power_levels",
122+
StateKey: b.Ptr(""),
123+
Content: PLContent,
124+
})
125+
126+
res := alice.MustDoFunc(
127+
t,
128+
"GET",
129+
[]string{"_matrix", "client", "v3", "rooms", roomID, "event", eventId},
130+
)
131+
132+
must.MatchResponse(t, res, match.HTTPResponse{
133+
JSON: []match.JSON{
134+
match.JSONKeyEqual("content", PLContent),
135+
},
136+
})
137+
})
138+
139+
// sytest: PUT power_levels should not explode if the old power levels were empty
140+
t.Run("PUT power_levels should not explode if the old power levels were empty", func(t *testing.T) {
141+
// Absence of an "events" key
142+
alice.SendEventSynced(t, roomID, b.Event{
143+
Type: "m.room.power_levels",
144+
StateKey: b.Ptr(""),
145+
Content: map[string]interface{}{
146+
"users": map[string]interface{}{
147+
alice.UserID: 100,
148+
},
149+
},
150+
})
151+
152+
// Absence of a "users" key
153+
alice.SendEventSynced(t, roomID, b.Event{
154+
Type: "m.room.power_levels",
155+
StateKey: b.Ptr(""),
156+
Content: map[string]interface{}{},
157+
})
158+
159+
// This should give a 403 (not a 500)
160+
res := alice.DoFunc(
161+
t,
162+
"PUT",
163+
[]string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"},
164+
client.WithJSONBody(t, map[string]interface{}{
165+
"users": map[string]string{},
166+
}),
167+
)
168+
must.MatchResponse(t, res, match.HTTPResponse{
169+
StatusCode: 403,
170+
})
171+
172+
// Test if the old state still exists
173+
res = alice.MustDoFunc(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "state", "m.room.power_levels"})
174+
175+
must.MatchResponse(t, res, match.HTTPResponse{
176+
StatusCode: 200,
177+
JSON: []match.JSON{
178+
match.JSONKeyMissing("users"),
179+
},
180+
})
181+
})
182+
}

0 commit comments

Comments
 (0)