Skip to content

Conversation

@MadLittleMods
Copy link
Collaborator

@MadLittleMods MadLittleMods commented Oct 27, 2025

Spawning from #808 per my suggestion on #808 (comment),

We have other spots that have flawed membership checks that need to be fixed. For example, when our goal is to wait for the user's membership to be leave, we should keep checking until it is leave. Currently, there are some spots that wait until any membership exists for the user and then asserts leave on that which is flawed because that user may have previous membership events that may be picked up first instead of waiting for the leave.

This PR fixes those flawed checks and aligns our membership checks so we don't cargo cult this bad pattern elsewhere.

  • Generalize our client.SyncXXX helpers to use syncMembershipIn utility
    • More robust
    • Standardize extra checks on event (previously, only available with client.SyncJoinedTo)
  • Introduce client.SyncBannedFrom so we can differentiate ban/leave

Dev notes

Pull Request Checklist

Signed-off-by: Eric Eastwood [email protected]

Comment on lines -300 to -311
charlie.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(
room,
func(ev gjson.Result) bool {
if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != bob.UserID {
return false
}
must.Equal(t, ev.Get("sender").Str, bob.UserID, "Bob should have joined by himself")
must.Equal(t, ev.Get("content").Get("membership").Str, "join", "Bob failed to join the room")

return true
},
))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous flawed check.

Our goal is to wait until bob is joined. Previously, this waited for any bob membership (which could have been the invite instead of the join which we're waiting for) and then asserted that it must be a join.

Comment on lines -466 to -478
bob.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(
room,
func(ev gjson.Result) bool {
if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != charlie.UserID {
return false
}
must.MatchGJSON(t, ev,
match.JSONKeyEqual("content.membership", "join"),
match.JSONKeyEqual("content.join_authorised_via_users_server", alice.UserID),
)
return true
},
))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous flawed check.

Our goal is to wait until charlie is joined. Previously, this waited for any charlie membership (which could have been the leave instead of the join which we're waiting for) and then asserted that it must be a join.

Comment on lines +299 to +315
// We assume the passively observing client user is joined to the room
roomTypeKey := "join"
// Otherwise, if the client is the user whose membership we are checking, we need to
// pick the correct room type JSON key based on the membership being checked.
if clientUserID == userID {
if membership == "join" {
roomTypeKey = "join"
} else if membership == "leave" || membership == "ban" {
roomTypeKey = "leave"
} else if membership == "invite" {
roomTypeKey = "invite"
} else if membership == "knock" {
roomTypeKey = "knock"
} else {
return fmt.Errorf("syncMembershipIn(%s, %s): unknown membership: %s", roomID, membership, membership)
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != bob.UserID {
return false
}
must.Equal(t, ev.Get("sender").Str, bob.UserID, "Bob should have joined by himself")
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've dropped this assertion as it doesn't matter to this test. You can only join yourself to a room (there is no other way).

return true
},
))
bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've double-checked the translation is correct for all of these updates:

  • The client syncing
  • The user we're checking
  • The membership being checked

Comment on lines -82 to -91
bob.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(
roomID,
func(ev gjson.Result) bool {
if ev.Get("type").Str != "m.room.member" || ev.Get("state_key").Str != bob.UserID {
return false
}
must.Equal(t, ev.Get("content").Get("membership").Str, "join", "Bob failed to join the room")
return true
},
))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any of these client.SyncTimelineHas(...) checks where we check until we see a certain event type and then use an assert for the membership are bad form.

While, it works well in some tests like this specific one, that's only because the user doesn't have any other previous membership in the room to be confused with. If there was any other previous membership for this user, this is flawed (see #813 (comment) as an example).

Instead of leaving these around to be copy-pasted and cargo-culted around, I've updated all of them to use the more proper assertion check.

Comment on lines -125 to -132
bob.MustSyncUntil(t, client.SyncReq{}, client.SyncTimelineHas(
roomID,
func(ev gjson.Result) bool {
return ev.Get("type").Str == "m.room.member" &&
ev.Get("content.membership").Str == "leave" &&
ev.Get("state_key").Str == alice.UserID
},
))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference, this kind of check was just fine. We return false until we find a leave membership for the user. While fine, I've updated it to use the more proper utility we have for this.

(notice the difference to the above bad form assertion)

@MadLittleMods MadLittleMods marked this pull request as ready for review October 27, 2025 20:47
@MadLittleMods MadLittleMods requested review from a team as code owners October 27, 2025 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants