Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Engineered tests to always reproduce tricky remote invite -> join/reject scenarios #760

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions federation/server.go
Original file line number Diff line number Diff line change
@@ -357,6 +357,57 @@ func (s *Server) MustCreateEvent(t ct.TestLike, room *ServerRoom, ev Event) goma
return signedEvent
}

// Invite someone a room.
func (s *Server) MustInviteRoom(
t ct.TestLike,
deployment FederationDeployment,
remoteServer spec.ServerName,
roomID string,
inviterUserID string,
inviteeUserID string,
) {
t.Helper()
fedClient := s.FederationClient(deployment)

room := s.rooms[roomID]
if room == nil {
ct.Fatalf(t, "MustInviteRoom: room %s not found", roomID)
}
roomVersionImplementation, err := gomatrixserverlib.GetRoomVersion(room.Version)

rawInviteEvent := s.MustCreateEvent(t, room, Event{
Type: "m.room.member",
StateKey: &inviterUserID,
Sender: inviteeUserID,
Content: map[string]interface{}{
"membership": "invite",
},
})
inviteReq, err := fclient.NewInviteV2Request(rawInviteEvent, []gomatrixserverlib.InviteStrippedState{})
if err != nil {
t.Fatalf("failed to make invite request: %s", err)
}
sendInviteResp, err := fedClient.SendInviteV2(
context.Background(),
spec.ServerName(s.ServerName()),
remoteServer,
inviteReq,
)
if err != nil {
t.Fatalf("MustInviteRoom: failed to send invite v2: %s", err)
}

inviteEvent, err := roomVersionImplementation.NewEventFromUntrustedJSON(sendInviteResp.Event)
if err != nil {
t.Fatalf("MustInviteRoom: failed to decode event response: %w", err)
}

room.AddEvent(inviteEvent)
s.rooms[roomID] = room

t.Logf("Server.MustInviteRoom %s invited %s to room ID %s", inviterUserID, inviteeUserID, roomID)
}

// MustJoinRoom will make the server send a make_join and a send_join to join a room
// It returns the resultant room.
func (s *Server) MustJoinRoom(t ct.TestLike, deployment FederationDeployment, remoteServer spec.ServerName, roomID string, userID string, partialState ...bool) *ServerRoom {
43 changes: 41 additions & 2 deletions tests/federation_rooms_invite_test.go
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ import (
"github.com/tidwall/gjson"

"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/federation"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
"github.com/matrix-org/complement/must"
@@ -99,7 +100,7 @@ func TestFederationRoomsInvite(t *testing.T) {
verifyState(t, res, wantFields, wantValues, roomID, alice)
})

t.Run("Remote invited user can join the room when homeserver is already participating in the room", func(t *testing.T) {
t.Run("Remote invited user can join the room when homeserver is already participating in the room (e2e)", func(t *testing.T) {
t.Parallel()
roomID := alice.MustCreateRoom(t, map[string]interface{}{
"preset": "private_chat",
@@ -121,7 +122,7 @@ func TestFederationRoomsInvite(t *testing.T) {
alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob2.UserID, roomID))
})

t.Run("Remote invited user can reject invite when homeserver is already participating in the room", func(t *testing.T) {
t.Run("Remote invited user can reject invite when homeserver is already participating in the room (e2e)", func(t *testing.T) {
t.Parallel()
roomID := alice.MustCreateRoom(t, map[string]interface{}{
"preset": "private_chat",
@@ -143,6 +144,44 @@ func TestFederationRoomsInvite(t *testing.T) {
alice.MustSyncUntil(t, client.SyncReq{Filter: includeLeaveSyncFilter}, client.SyncLeftFrom(bob2.UserID, roomID))
})

// Engineered condition where we only send `/invite` requests over federation and do
// not send the event in a `/send` transaction. Regression tests for
// https://github.com/element-hq/synapse/pull/18075
t.Run("Remote invited user can join the room when homeserver is already participating in the room (engineered)", func(t *testing.T) {
t.Parallel()

srv := federation.NewServer(t, deployment,
federation.HandleKeyRequests(),
// bob1 will use this to join the remote room
federation.HandleMakeSendJoinRequests(),
)
cancel := srv.Listen()
defer cancel()

engineeredAliceUserId := srv.UserID("alice")

roomVersion := alice.GetDefaultRoomVersion(t)
initalEvents := federation.InitialRoomEvents(roomVersion, engineeredAliceUserId)
serverRoom := srv.MustMakeRoom(t, roomVersion, initalEvents)
roomID := serverRoom.RoomID

// bob1 is invited and can join the room (hs2 is now participating of the room)
//
// alice.MustInviteRoom(t, roomID, bob.UserID)
srv.MustInviteRoom(t, deployment, "hs1", roomID, engineeredAliceUserId, bob.UserID)
bob.MustSyncUntil(t, client.SyncReq{}, client.SyncInvitedTo(bob.UserID, roomID))
bob.MustJoinRoom(t, roomID, []string{srv.ServerName()})
// Make sure alice can see bob in the room
// alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID))

// bob2 is invited and can also join the room
// alice.MustInviteRoom(t, roomID, bob2.UserID)
// bob2.MustSyncUntil(t, client.SyncReq{}, client.SyncInvitedTo(bob2.UserID, roomID))
// bob2.MustJoinRoom(t, roomID, []string{srv.ServerName()})
// // Make sure alice can see bob2 in the room
// alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob2.UserID, roomID))
})

t.Run("Invited user has 'is_direct' flag in prev_content after joining", func(t *testing.T) {
roomID := alice.MustCreateRoom(t, map[string]interface{}{
"preset": "private_chat",