Skip to content

Commit 18aa82f

Browse files
authored
Test for partial-state responses from /send_join (#320)
MSC3706 adds extensions to /send_join for partial state. Here we add a test which checks the response is correct. (The test is skipped if the server does not support it). Tests the implementation which was introduced in matrix-org/synapse#11967
1 parent face844 commit 18aa82f

File tree

5 files changed

+115
-7
lines changed

5 files changed

+115
-7
lines changed

dockerfiles/synapse/homeserver.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,5 @@ experimental_features:
110110
spaces_enabled: true
111111
# Enable history backfilling support
112112
msc2716_enabled: true
113+
# server-side support for partial state in /send_join
114+
msc3706_enabled: true

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ require (
1010
github.com/docker/go-connections v0.4.0
1111
github.com/gorilla/mux v1.8.0
1212
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16
13-
github.com/matrix-org/gomatrixserverlib v0.0.0-20220214133635-20632dd262ed
13+
github.com/matrix-org/gomatrixserverlib v0.0.0-20220217085017-e92d47416973
1414
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4
1515
github.com/morikuni/aec v1.0.0 // indirect
1616
github.com/sirupsen/logrus v1.8.1

go.sum

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
340340
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
341341
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
342342
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
343+
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
343344
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
344345
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
345346
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -436,10 +437,12 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
436437
github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0=
437438
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4=
438439
github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s=
439-
github.com/matrix-org/gomatrixserverlib v0.0.0-20220106115324-39c7d37db009 h1:RV3hT9eHpBSjg0m8W44bgonVUrJI866FkfrW6lf03a0=
440-
github.com/matrix-org/gomatrixserverlib v0.0.0-20220106115324-39c7d37db009/go.mod h1:qFvhfbQ5orQxlH9vCiFnP4dW27xxnWHdNUBKyj/fbiY=
441440
github.com/matrix-org/gomatrixserverlib v0.0.0-20220214133635-20632dd262ed h1:R8EiLWArq7KT96DrUq1xq9scPh8vLwKKeCTnORPyjhU=
442441
github.com/matrix-org/gomatrixserverlib v0.0.0-20220214133635-20632dd262ed/go.mod h1:qFvhfbQ5orQxlH9vCiFnP4dW27xxnWHdNUBKyj/fbiY=
442+
github.com/matrix-org/gomatrixserverlib v0.0.0-20220214182556-d5581e0dccf6 h1:AHrGktqua3V0GUqAN3sQZAxuRXFTV3dQikYkoAzsAbU=
443+
github.com/matrix-org/gomatrixserverlib v0.0.0-20220214182556-d5581e0dccf6/go.mod h1:+WF5InseAMgi1fTnU46JH39IDpEvLep0fDzx9LDf2Bo=
444+
github.com/matrix-org/gomatrixserverlib v0.0.0-20220217085017-e92d47416973 h1:LbyGlBQwzt2jByuKNBllgCPUtqBQqCaAywP57yQOYhw=
445+
github.com/matrix-org/gomatrixserverlib v0.0.0-20220217085017-e92d47416973/go.mod h1:+WF5InseAMgi1fTnU46JH39IDpEvLep0fDzx9LDf2Bo=
443446
github.com/matrix-org/util v0.0.0-20190711121626-527ce5ddefc7/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
444447
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 h1:eCEHXWDv9Rm335MSuB49mFUK44bwZPFSDde3ORE3syk=
445448
github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4/go.mod h1:vVQlW/emklohkZnOPwD3LrZUBqdfsbiyO3p1lNV8F6U=
@@ -685,8 +688,6 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh
685688
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
686689
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
687690
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
688-
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
689-
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
690691
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
691692
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
692693
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=

internal/must/must.go

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@ import (
1010
"strings"
1111
"testing"
1212

13-
"github.com/matrix-org/gomatrixserverlib"
1413
"github.com/tidwall/gjson"
1514

15+
"github.com/matrix-org/gomatrixserverlib"
16+
1617
"github.com/matrix-org/complement/internal/match"
1718
)
1819

@@ -182,10 +183,37 @@ func HaveInOrder(t *testing.T, gots []string, wants []string) {
182183
}
183184
}
184185

186+
// CheckOffAll checks that a list contains exactly the given items, in any order.
187+
//
188+
// if an item is not present, the test is failed.
189+
// if an item not present in the want list is present, the test is failed.
190+
// Items are compared using reflect.DeepEqual
191+
func CheckOffAll(t *testing.T, items []interface{}, wantItems []interface{}) {
192+
t.Helper()
193+
remaining := CheckOffAllAllowUnwanted(t, items, wantItems)
194+
if len(remaining) > 0 {
195+
t.Errorf("CheckOffAll: unexpected items %v", remaining)
196+
}
197+
}
198+
199+
// CheckOffAllAllowUnwanted checks that a list contains all of the given items, in any order.
200+
// The updated list with the matched items removed from it is returned.
201+
//
202+
// if an item is not present, the test is failed.
203+
// Items are compared using reflect.DeepEqual
204+
func CheckOffAllAllowUnwanted(t *testing.T, items []interface{}, wantItems []interface{}) []interface{} {
205+
t.Helper()
206+
for _, wantItem := range wantItems {
207+
items = CheckOff(t, items, wantItem)
208+
}
209+
return items
210+
}
211+
185212
// CheckOff an item from the list. If the item is not present the test is failed.
186213
// The updated list with the matched item removed from it is returned. Items are
187214
// compared using reflect.DeepEqual
188215
func CheckOff(t *testing.T, items []interface{}, wantItem interface{}) []interface{} {
216+
t.Helper()
189217
// check off the item
190218
want := -1
191219
for i, w := range items {
@@ -195,7 +223,7 @@ func CheckOff(t *testing.T, items []interface{}, wantItem interface{}) []interfa
195223
}
196224
}
197225
if want == -1 {
198-
t.Errorf("CheckOff: unexpected item %s", wantItem)
226+
t.Errorf("CheckOff: item %s not present", wantItem)
199227
return items
200228
}
201229
// delete the wanted item

tests/federation_room_join_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import (
66
"fmt"
77
"net/http"
88
"net/url"
9+
"strings"
910
"testing"
1011
"time"
1112

1213
"github.com/matrix-org/gomatrix"
14+
1315
"github.com/matrix-org/gomatrixserverlib"
1416

17+
"github.com/tidwall/gjson"
1518
"github.com/tidwall/sjson"
1619

1720
"github.com/matrix-org/complement/internal/b"
@@ -445,3 +448,77 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected
445448
assertRequestFails(t, event)
446449
})
447450
}
451+
452+
// Tests an implementation's support for MSC3706-style partial-state responses to send_join.
453+
//
454+
// Will be skipped if the server returns a full-state response.
455+
func TestSendJoinPartialStateResponse(t *testing.T) {
456+
// start with a homeserver with two users
457+
deployment := Deploy(t, b.BlueprintOneToOneRoom)
458+
defer deployment.Destroy(t)
459+
460+
srv := federation.NewServer(t, deployment,
461+
federation.HandleKeyRequests(),
462+
)
463+
cancel := srv.Listen()
464+
defer cancel()
465+
466+
// annoyingly we can't get to the room that alice and bob already share (see https://github.com/matrix-org/complement/issues/254)
467+
// so we have to create a new one.
468+
// alice creates a room, which bob joins
469+
alice := deployment.Client(t, "hs1", "@alice:hs1")
470+
bob := deployment.Client(t, "hs1", "@bob:hs1")
471+
roomID := alice.CreateRoom(t, map[string]interface{}{"preset": "public_chat"})
472+
bob.JoinRoom(t, roomID, nil)
473+
474+
// now we send a make_join...
475+
charlie := srv.UserID("charlie")
476+
fedClient := srv.FederationClient(deployment)
477+
makeJoinResp, err := fedClient.MakeJoin(context.Background(), "hs1", roomID, charlie, federation.SupportedRoomVersions())
478+
if err != nil {
479+
t.Fatalf("make_join failed: %v", err)
480+
}
481+
482+
// ... construct a signed join event ...
483+
roomVer := makeJoinResp.RoomVersion
484+
joinEvent, err := makeJoinResp.JoinEvent.Build(time.Now(), gomatrixserverlib.ServerName(srv.ServerName()), srv.KeyID, srv.Priv, roomVer)
485+
if err != nil {
486+
t.Fatalf("failed to sign join event: %v", err)
487+
}
488+
489+
// and send_join it, with the magic param
490+
sendJoinResp, err := fedClient.SendJoinPartialState(context.Background(), "hs1", joinEvent)
491+
if err != nil {
492+
t.Fatalf("send_join failed: %v", err)
493+
}
494+
495+
if !sendJoinResp.PartialState {
496+
t.Skip("Server does not support partial_state")
497+
}
498+
499+
// check the returned state events match those expected
500+
var returnedStateEventKeys []interface{}
501+
for _, ev := range sendJoinResp.StateEvents {
502+
returnedStateEventKeys = append(returnedStateEventKeys, typeAndStateKeyForEvent(gjson.ParseBytes(ev)))
503+
}
504+
must.CheckOffAll(t, returnedStateEventKeys, []interface{}{
505+
"m.room.create|", "m.room.power_levels|", "m.room.join_rules|", "m.room.history_visibility|",
506+
})
507+
508+
// check the returned auth events match those expected
509+
var returnedAuthEventKeys []interface{}
510+
for _, ev := range sendJoinResp.AuthEvents {
511+
returnedAuthEventKeys = append(returnedAuthEventKeys, typeAndStateKeyForEvent(gjson.ParseBytes(ev)))
512+
}
513+
must.CheckOffAll(t, returnedAuthEventKeys, []interface{}{
514+
"m.room.member|" + alice.UserID,
515+
})
516+
517+
// check the server list. Only one, so we can use HaveInOrder even though the list is unordered
518+
must.HaveInOrder(t, sendJoinResp.ServersInRoom, []string{"hs1"})
519+
}
520+
521+
// given an event JSON, return the type and state_key, joined with a "|"
522+
func typeAndStateKeyForEvent(result gjson.Result) string {
523+
return strings.Join([]string{result.Map()["type"].Str, result.Map()["state_key"].Str}, "|")
524+
}

0 commit comments

Comments
 (0)