Skip to content

Commit

Permalink
Update knock test utilities to be more generic/useful (#758)
Browse files Browse the repository at this point in the history
They now match the style of the other utilities under `client`: `mustKnockOnRoomSynced`/`syncKnockedOn`

This is spawning from trying to write some knock tests that also stressed element-hq/synapse#18075 but they didn't pan out. I thought this refactor and update was still useful to upstream in any case.
  • Loading branch information
MadLittleMods authored Jan 27, 2025
1 parent e21a6fb commit 6dbf2bd
Showing 1 changed file with 30 additions and 16 deletions.
46 changes: 30 additions & 16 deletions tests/knocking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,11 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki
})

t.Run("Knocking on a room with join rule 'knock' should succeed", func(t *testing.T) {
knockOnRoomSynced(t, knockingUser, roomID, testKnockReason, []string{"hs1"})
mustKnockOnRoomSynced(t, knockingUser, roomID, testKnockReason, []string{"hs1"})
})

t.Run("A user that has already knocked is allowed to knock again on the same room", func(t *testing.T) {
knockOnRoomSynced(t, knockingUser, roomID, "I really like knock knock jokes", []string{"hs1"})
mustKnockOnRoomSynced(t, knockingUser, roomID, "I really like knock knock jokes", []string{"hs1"})
})

t.Run("Users in the room see a user's membership update when they knock", func(t *testing.T) {
Expand Down Expand Up @@ -183,7 +183,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki
})

// Knock again to return us to the knocked state
knockOnRoomSynced(t, knockingUser, roomID, "Let me in... again?", []string{"hs1"})
mustKnockOnRoomSynced(t, knockingUser, roomID, "Let me in... again?", []string{"hs1"})
})
}

Expand Down Expand Up @@ -211,7 +211,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki
}))

// Knock again
knockOnRoomSynced(t, knockingUser, roomID, "Pleeease let me in?", []string{"hs1"})
mustKnockOnRoomSynced(t, knockingUser, roomID, "Pleeease let me in?", []string{"hs1"})
})

t.Run("A user can knock on a room without a reason", func(t *testing.T) {
Expand All @@ -227,7 +227,7 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki
)

// Knock again, this time without a reason
knockOnRoomSynced(t, knockingUser, roomID, "", []string{"hs1"})
mustKnockOnRoomSynced(t, knockingUser, roomID, "", []string{"hs1"})
})

t.Run("A user in the room can accept a knock", func(t *testing.T) {
Expand Down Expand Up @@ -279,22 +279,36 @@ func knockingBetweenTwoUsersTest(t *testing.T, roomID string, inRoomUser, knocki
})
}

// knockOnRoomSynced will knock on a given room on the behalf of a user, and block until the knock has persisted.
func syncKnockedOn(userID, roomID string) client.SyncCheckOpt {
return func(clientUserID string, topLevelSyncJSON gjson.Result) error {
// two forms which depend on what the client user is:
// - passively viewing a membership for a room you're joined in
// - actively leaving the room
if clientUserID == userID {
events := topLevelSyncJSON.Get("rooms.knock." + client.GjsonEscape(roomID) + ".knock_state.events")
if events.Exists() && events.IsArray() {
// We don't currently define any required state event types to be sent.
// If we've reached this point, then an entry for this room was found
return nil
}
return fmt.Errorf("no knock section for room %s", roomID)
}

// passive
return client.SyncTimelineHas(roomID, func(ev gjson.Result) bool {
return ev.Get("type").Str == "m.room.member" && ev.Get("state_key").Str == userID && ev.Get("content.membership").Str == "knock"
})(clientUserID, topLevelSyncJSON)
}
}

// mustKnockOnRoomSynced will knock on a given room on the behalf of a user, and block until the knock has persisted.
// serverNames should be populated if knocking on a room that the user's homeserver isn't currently a part of.
// Fails the test if the knock response does not return a 200 status code.
func knockOnRoomSynced(t *testing.T, c *client.CSAPI, roomID, reason string, serverNames []string) {
func mustKnockOnRoomSynced(t *testing.T, c *client.CSAPI, roomID, reason string, serverNames []string) {
knockOnRoomWithStatus(t, c, roomID, reason, serverNames, 200)

// The knock should have succeeded. Block until we see the knock appear down sync
c.MustSyncUntil(t, client.SyncReq{}, func(clientUserID string, topLevelSyncJSON gjson.Result) error {
events := topLevelSyncJSON.Get("rooms.knock." + client.GjsonEscape(roomID) + ".knock_state.events")
if events.Exists() && events.IsArray() {
// We don't currently define any required state event types to be sent.
// If we've reached this point, then an entry for this room was found
return nil
}
return fmt.Errorf("no knock section for room %s", roomID)
})
c.MustSyncUntil(t, client.SyncReq{}, syncKnockedOn(c.UserID, roomID))
}

// knockOnRoomWithStatus will knock on a given room on the behalf of a user.
Expand Down

0 comments on commit 6dbf2bd

Please sign in to comment.