@@ -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