From 5ea0ed14e940fa978af7a308267b30f5929734c8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 16 May 2022 21:34:25 -0600 Subject: [PATCH 1/3] Write the failing test --- spec/integ/matrix-client-syncing.spec.js | 109 ++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/spec/integ/matrix-client-syncing.spec.js b/spec/integ/matrix-client-syncing.spec.js index 6adb35a50c0..2efb5c74f71 100644 --- a/spec/integ/matrix-client-syncing.spec.js +++ b/spec/integ/matrix-client-syncing.spec.js @@ -1,5 +1,4 @@ -import { MatrixEvent } from "../../src/models/event"; -import { EventTimeline } from "../../src/models/event-timeline"; +import { EventTimeline, MatrixEvent, RoomEvent } from "../../src"; import * as utils from "../test-utils/test-utils"; import { TestClient } from "../TestClient"; @@ -60,6 +59,112 @@ describe("MatrixClient syncing", function() { done(); }); }); + + it("should emit Room.myMembership for invite->leave->invite cycles", async () => { + const roomId = "!cycles:example.org"; + + // First sync: an invite + const inviteSyncRoomSection = { + invite: { + [roomId]: { + invite_state: { + events: [{ + type: "m.room.member", + state_key: selfUserId, + content: { + membership: "invite", + }, + }], + }, + }, + }, + }; + httpBackend.when("GET", "/sync").respond(200, { + ...syncData, + rooms: inviteSyncRoomSection, + }); + + // Second sync: a leave (reject of some kind) + httpBackend.when("POST", "/leave").respond(200, {}); + httpBackend.when("GET", "/sync").respond(200, { + ...syncData, + rooms: { + leave: { + [roomId]: { + account_data: { events: [] }, + ephemeral: { events: [] }, + state: { + events: [{ + type: "m.room.member", + state_key: selfUserId, + content: { + membership: "leave", + }, + prev_content: { + membership: "invite", + }, + // XXX: And other fields required on an event + }], + }, + timeline: { + limited: false, + events: [{ + type: "m.room.member", + state_key: selfUserId, + content: { + membership: "leave", + }, + prev_content: { + membership: "invite", + }, + // XXX: And other fields required on an event + }], + }, + }, + }, + }, + }); + + // Third sync: another invite + httpBackend.when("GET", "/sync").respond(200, { + ...syncData, + rooms: inviteSyncRoomSection, + }); + + // First fire: an initial invite + let fires = 0; + client.once(RoomEvent.MyMembership, (room, membership, oldMembership) => { // Room, string, string + fires++; + expect(room.roomId).toBe(roomId); + expect(membership).toBe("invite"); + expect(oldMembership).toBeFalsy(); + + // Second fire: a leave + client.once(RoomEvent.MyMembership, (room, membership, oldMembership) => { + fires++; + expect(room.roomId).toBe(roomId); + expect(membership).toBe("leave"); + expect(oldMembership).toBe("invite"); + + // Third/final fire: a second invite + client.once(RoomEvent.MyMembership, (room, membership, oldMembership) => { + fires++; + expect(room.roomId).toBe(roomId); + expect(membership).toBe("invite"); + expect(oldMembership).toBe("leave"); + }); + }); + + // For maximum safety, "leave" the room after we register the handler + client.leave(roomId); + }); + + // noinspection ES6MissingAwait + client.startClient(); + await httpBackend.flushAllExpected(); + + expect(fires).toBe(3); + }); }); describe("resolving invites to profile info", function() { From c94e833a3599f074324ac6eee8374a22c74072ff Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 16 May 2022 21:42:05 -0600 Subject: [PATCH 2/3] Fix the bug --- src/sync.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/sync.ts b/src/sync.ts index eee27af170f..b7f03400bfa 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -1166,6 +1166,9 @@ export class SyncApi { room.recalculate(); client.store.storeRoom(room); client.emit(ClientEvent.Room, room); + } else { + // Update room state for invite->reject->invite cycles + room.recalculate(); } stateEvents.forEach(function(e) { client.emit(ClientEvent.Event, e); From f90ee9d516445f7011d0177630650f9f735f138e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 17 May 2022 22:30:58 -0600 Subject: [PATCH 3/3] Add known copyright --- spec/integ/matrix-client-syncing.spec.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spec/integ/matrix-client-syncing.spec.js b/spec/integ/matrix-client-syncing.spec.js index 2efb5c74f71..7c33f0948ea 100644 --- a/spec/integ/matrix-client-syncing.spec.js +++ b/spec/integ/matrix-client-syncing.spec.js @@ -1,3 +1,19 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + import { EventTimeline, MatrixEvent, RoomEvent } from "../../src"; import * as utils from "../test-utils/test-utils"; import { TestClient } from "../TestClient";