Fix flawed membership checks and align membership checking patterns#813
Conversation
Same fix as applied in #808
| 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 | ||
| }, | ||
| )) |
There was a problem hiding this comment.
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.
| 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 | ||
| }, | ||
| )) |
There was a problem hiding this comment.
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.
| // 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) | ||
| } | ||
| } |
There was a problem hiding this comment.
| return true | ||
| }, | ||
| )) | ||
| bob.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) |
There was a problem hiding this comment.
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
| 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 | ||
| }, | ||
| )) |
There was a problem hiding this comment.
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.
| 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 | ||
| }, | ||
| )) |
There was a problem hiding this comment.
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)
anoadragon453
left a comment
There was a problem hiding this comment.
Thanks for taking this on! I wonder if it fixes any flaky tests in Synapse.
| // FIXME: Ideally, we'd use something like `state_after` to get the actual current | ||
| // state in the room instead of us assuming that no state resets/conflicts happen | ||
| // when we apply state from the `timeline` on top of the `state`. But `state_after` | ||
| // is gated behind a sync request parameter which we can't control here. |
There was a problem hiding this comment.
Any reason not to enable state_after for all /sync calls in Complement?
There was a problem hiding this comment.
Could work although it's only available in new Matrix versions (added in v1.16) and I don't think we can assume all homeservers support that version yet.
Something to revisit in the future ⏩
| if clientUserID != userID || | ||
| // Otherwise, if the client is the user whose membership we are checking, |
There was a problem hiding this comment.
This comment and if statement don't align.
There was a problem hiding this comment.
I think it does align although more subtle than the other similar comments as it's using negative logic.
There was a problem hiding this comment.
In any case, I've updated the logic layout and comments to make this more clear:
Lines 347 to 357 in e1ac188
|
Thanks for the review @anoadragon453 🦘 |
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 isleave. Currently, there are some spots that wait until any membership exists for the user and then assertsleaveon that which is flawed because that user may have previous membership events that may be picked up first instead of waiting for theleave.This PR fixes those flawed checks and aligns our membership checks so we don't cargo cult this bad pattern elsewhere.
client.SyncXXXhelpers to usesyncMembershipInutilitycheckson event (previously, only available withclient.SyncJoinedTo)client.SyncBannedFromso we can differentiate ban/leaveDev notes
30rooms/22profiletest #511Pull Request Checklist
Signed-off-by: Eric Eastwood erice@element.io