Skip to content

Commit 91b0879

Browse files
Merge pull request #68 from matrix-org/eric/msc2716-backfilling-history
Add tests for MSC2716 and backfilling history
2 parents b383ce0 + 0b0355b commit 91b0879

File tree

8 files changed

+957
-26
lines changed

8 files changed

+957
-26
lines changed

dockerfiles/synapse/homeserver.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,5 @@ experimental_features:
107107
msc2403_enabled: true
108108
# Enable spaces support
109109
spaces_enabled: true
110+
# Enable history backfilling support
111+
msc2716_enabled: true

dockerfiles/synapse/workers-shared.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,7 @@ federation_rr_transactions_per_room_per_second: 9999
6464
experimental_features:
6565
# Enable knocking support
6666
msc2403_enabled: true
67+
# Enable history backfilling support
68+
msc2716_enabled: true
6769
# Enable spaces support
6870
spaces_enabled: true

internal/b/hs_with_application_service.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package b
22

33
// BlueprintHSWithApplicationService who has an application service to interact with
44
var BlueprintHSWithApplicationService = MustValidate(Blueprint{
5-
Name: "alice",
5+
Name: "hs_with_application_service",
66
Homeservers: []Homeserver{
77
{
88
Name: "hs1",
@@ -21,5 +21,14 @@ var BlueprintHSWithApplicationService = MustValidate(Blueprint{
2121
},
2222
},
2323
},
24+
{
25+
Name: "hs2",
26+
Users: []User{
27+
{
28+
Localpart: "@charlie",
29+
DisplayName: "Charlie",
30+
},
31+
},
32+
},
2433
},
2534
})

internal/client/client.go

+28-2
Original file line numberDiff line numberDiff line change
@@ -132,13 +132,13 @@ func (c *CSAPI) SendEventSynced(t *testing.T, roomID string, e b.Event) string {
132132
// Will time out after CSAPI.SyncUntilTimeout.
133133
func (c *CSAPI) SyncUntilTimelineHas(t *testing.T, roomID string, check func(gjson.Result) bool) {
134134
t.Helper()
135-
c.SyncUntil(t, "", "rooms.join."+GjsonEscape(roomID)+".timeline.events", check)
135+
c.SyncUntil(t, "", "", "rooms.join."+GjsonEscape(roomID)+".timeline.events", check)
136136
}
137137

138138
// SyncUntil blocks and continually calls /sync until the `check` function returns true.
139139
// If the `check` function fails the test, the failing event will be automatically logged.
140140
// Will time out after CSAPI.SyncUntilTimeout.
141-
func (c *CSAPI) SyncUntil(t *testing.T, since, key string, check func(gjson.Result) bool) {
141+
func (c *CSAPI) SyncUntil(t *testing.T, since, filter, key string, check func(gjson.Result) bool) {
142142
t.Helper()
143143
start := time.Now()
144144
checkCounter := 0
@@ -152,6 +152,9 @@ func (c *CSAPI) SyncUntil(t *testing.T, since, key string, check func(gjson.Resu
152152
if since != "" {
153153
query["since"] = []string{since}
154154
}
155+
if filter != "" {
156+
query["filter"] = []string{filter}
157+
}
155158
res := c.MustDoFunc(t, "GET", []string{"_matrix", "client", "r0", "sync"}, WithQueries(query))
156159
body := ParseJSON(t, res)
157160
since = GetJSONFieldStr(t, body, "next_batch")
@@ -369,6 +372,29 @@ func GetJSONFieldStr(t *testing.T, body []byte, wantKey string) string {
369372
return res.Str
370373
}
371374

375+
func GetJSONFieldStringArray(t *testing.T, body []byte, wantKey string) []string {
376+
t.Helper()
377+
378+
res := gjson.GetBytes(body, wantKey)
379+
380+
if !res.Exists() {
381+
t.Fatalf("JSONFieldStr: key '%s' missing from %s", wantKey, string(body))
382+
}
383+
384+
arrLength := len(res.Array())
385+
arr := make([]string, arrLength)
386+
i := 0
387+
res.ForEach(func(key, value gjson.Result) bool {
388+
arr[i] = value.Str
389+
390+
// Keep iterating
391+
i++
392+
return true
393+
})
394+
395+
return arr
396+
}
397+
372398
// ParseJSON parses a JSON-encoded HTTP Response body into a byte slice
373399
func ParseJSON(t *testing.T, res *http.Response) []byte {
374400
t.Helper()

internal/docker/builder.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,9 @@ func generateASRegistrationYaml(as b.ApplicationService) string {
476476
fmt.Sprintf("sender_localpart: %s\n", as.SenderLocalpart) +
477477
fmt.Sprintf("rate_limited: %v\n", as.RateLimited) +
478478
"namespaces:\n" +
479-
" users: []\n" +
479+
" users:\n" +
480+
" - exclusive: false\n" +
481+
" regex: .*\n" +
480482
" rooms: []\n" +
481483
" aliases: []\n"
482484
}

internal/match/json.go

+51-22
Original file line numberDiff line numberDiff line change
@@ -55,25 +55,7 @@ func JSONKeyTypeEqual(wantKey string, wantType gjson.Type) JSON {
5555
}
5656
}
5757

58-
// JSONCheckOff returns a matcher which will loop over `wantKey` and ensure that the items
59-
// (which can be array elements or object keys)
60-
// are present exactly once in any order in `wantItems`. If there are unexpected items or items
61-
// appear more than once then the match fails. This matcher can be used to check off items in
62-
// an array/object. The `mapper` function should map the item to an interface which will be
63-
// comparable via `reflect.DeepEqual` with items in `wantItems`. The optional `fn` callback
64-
// allows more checks to be performed other than checking off the item from the list. It is
65-
// called with 2 args: the result of the `mapper` function and the element itself (or value if
66-
// it's an object).
67-
//
68-
// Usage: (ensures `events` has these events in any order, with the right event type)
69-
// JSONCheckOff("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} {
70-
// return r.Get("event_id").Str
71-
// }, func(eventID interface{}, eventBody gjson.Result) error {
72-
// if eventBody.Get("type").Str != "m.room.message" {
73-
// return fmt.Errorf("expected event to be 'm.room.message'")
74-
// }
75-
// })
76-
func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON {
58+
func jsonCheckOffInternal(wantKey string, wantItems []interface{}, allowUnwantedItems bool, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON {
7759
return func(body []byte) error {
7860
res := gjson.GetBytes(body, wantKey)
7961
if !res.Exists() {
@@ -103,12 +85,15 @@ func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Res
10385
break
10486
}
10587
}
106-
if want == -1 {
88+
if !allowUnwantedItems && want == -1 {
10789
err = fmt.Errorf("JSONCheckOff: unexpected item %s", item)
10890
return false
10991
}
110-
// delete the wanted item
111-
wantItems = append(wantItems[:want], wantItems[want+1:]...)
92+
93+
if want != -1 {
94+
// delete the wanted item
95+
wantItems = append(wantItems[:want], wantItems[want+1:]...)
96+
}
11297

11398
// do further checks
11499
if fn != nil {
@@ -130,6 +115,50 @@ func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Res
130115
}
131116
}
132117

118+
// JSONCheckOffAllowUnwanted returns a matcher which will loop over `wantKey` and ensure that the items
119+
// (which can be array elements or object keys)
120+
// are present exactly once in any order in `wantItems`. Allows unexpected items or items
121+
// appear that more than once. This matcher can be used to check off items in
122+
// an array/object. The `mapper` function should map the item to an interface which will be
123+
// comparable via `reflect.DeepEqual` with items in `wantItems`. The optional `fn` callback
124+
// allows more checks to be performed other than checking off the item from the list. It is
125+
// called with 2 args: the result of the `mapper` function and the element itself (or value if
126+
// it's an object).
127+
//
128+
// Usage: (ensures `events` has these events in any order, with the right event type)
129+
// JSONCheckOffAllowUnwanted("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} {
130+
// return r.Get("event_id").Str
131+
// }, func(eventID interface{}, eventBody gjson.Result) error {
132+
// if eventBody.Get("type").Str != "m.room.message" {
133+
// return fmt.Errorf("expected event to be 'm.room.message'")
134+
// }
135+
// })
136+
func JSONCheckOffAllowUnwanted(wantKey string, wantItems []interface{}, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON {
137+
return jsonCheckOffInternal(wantKey, wantItems, true, mapper, fn)
138+
}
139+
140+
// JSONCheckOff returns a matcher which will loop over `wantKey` and ensure that the items
141+
// (which can be array elements or object keys)
142+
// are present exactly once in any order in `wantItems`. If there are unexpected items or items
143+
// appear more than once then the match fails. This matcher can be used to check off items in
144+
// an array/object. The `mapper` function should map the item to an interface which will be
145+
// comparable via `reflect.DeepEqual` with items in `wantItems`. The optional `fn` callback
146+
// allows more checks to be performed other than checking off the item from the list. It is
147+
// called with 2 args: the result of the `mapper` function and the element itself (or value if
148+
// it's an object).
149+
//
150+
// Usage: (ensures `events` has these events in any order, with the right event type)
151+
// JSONCheckOff("events", []interface{}{"$foo:bar", "$baz:quuz"}, func(r gjson.Result) interface{} {
152+
// return r.Get("event_id").Str
153+
// }, func(eventID interface{}, eventBody gjson.Result) error {
154+
// if eventBody.Get("type").Str != "m.room.message" {
155+
// return fmt.Errorf("expected event to be 'm.room.message'")
156+
// }
157+
// })
158+
func JSONCheckOff(wantKey string, wantItems []interface{}, mapper func(gjson.Result) interface{}, fn func(interface{}, gjson.Result) error) JSON {
159+
return jsonCheckOffInternal(wantKey, wantItems, false, mapper, fn)
160+
}
161+
133162
// JSONArrayEach returns a matcher which will check that `wantKey` is an array then loops over each
134163
// item calling `fn`. If `fn` returns an error, iterating stops and an error is returned.
135164
func JSONArrayEach(wantKey string, fn func(gjson.Result) error) JSON {

tests/msc2403_test.go

+2
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki
182182
knockingUser.SyncUntil(
183183
t,
184184
since,
185+
"",
185186
"rooms.leave."+client.GjsonEscape(roomID)+".timeline.events",
186187
func(ev gjson.Result) bool {
187188
if ev.Get("type").Str != "m.room.member" || ev.Get("sender").Str != knockingUser.UserID {
@@ -313,6 +314,7 @@ func knockOnRoomSynced(t *testing.T, c *client.CSAPI, roomID, reason string, ser
313314
c.SyncUntil(
314315
t,
315316
"",
317+
"",
316318
"rooms.knock."+client.GjsonEscape(roomID)+".knock_state.events",
317319
func(ev gjson.Result) bool {
318320
// We don't currently define any required state event types to be sent.

0 commit comments

Comments
 (0)