Support MSC3946 in RoomListStore (#10054)

pull/28217/head
Andy Balaam 2023-02-03 09:14:44 +00:00 committed by GitHub
parent 2bde31dcff
commit b7cd28bd29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 8 deletions

View File

@ -286,9 +286,9 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
// If we're joining an upgraded room, we'll want to make sure we don't proliferate // If we're joining an upgraded room, we'll want to make sure we don't proliferate
// the dead room in the list. // the dead room in the list.
const roomState: RoomState = membershipPayload.room.currentState; const roomState: RoomState = membershipPayload.room.currentState;
const createEvent = roomState.getStateEvents(EventType.RoomCreate, ""); const predecessor = roomState.findPredecessor(SettingsStore.getValue("feature_dynamic_room_predecessors"));
if (createEvent && createEvent.getContent()["predecessor"]) { if (predecessor) {
const prevRoom = this.matrixClient.getRoom(createEvent.getContent()["predecessor"]["room_id"]); const prevRoom = this.matrixClient.getRoom(predecessor.roomId);
if (prevRoom) { if (prevRoom) {
const isSticky = this.algorithm.stickyRoom === prevRoom; const isSticky = this.algorithm.stickyRoom === prevRoom;
if (isSticky) { if (isSticky) {
@ -298,6 +298,8 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> implements
// Note: we hit the algorithm instead of our handleRoomUpdate() function to // Note: we hit the algorithm instead of our handleRoomUpdate() function to
// avoid redundant updates. // avoid redundant updates.
this.algorithm.handleRoomUpdate(prevRoom, RoomUpdateCause.RoomRemoved); this.algorithm.handleRoomUpdate(prevRoom, RoomUpdateCause.RoomRemoved);
} else {
logger.warn(`Unable to find predecessor room with id ${predecessor.roomId}`);
} }
} }

View File

@ -17,6 +17,7 @@ limitations under the License.
import { EventType, MatrixEvent, Room } from "matrix-js-sdk/src/matrix"; import { EventType, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
import { MatrixDispatcher } from "../../../src/dispatcher/dispatcher"; import { MatrixDispatcher } from "../../../src/dispatcher/dispatcher";
import SettingsStore from "../../../src/settings/SettingsStore";
import { ListAlgorithm, SortAlgorithm } from "../../../src/stores/room-list/algorithms/models"; import { ListAlgorithm, SortAlgorithm } from "../../../src/stores/room-list/algorithms/models";
import { OrderedDefaultTagIDs, RoomUpdateCause } from "../../../src/stores/room-list/models"; import { OrderedDefaultTagIDs, RoomUpdateCause } from "../../../src/stores/room-list/models";
import RoomListStore, { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore"; import RoomListStore, { RoomListStoreClass } from "../../../src/stores/room-list/RoomListStore";
@ -24,14 +25,14 @@ import { stubClient, upsertRoomStateEvents } from "../../test-utils";
describe("RoomListStore", () => { describe("RoomListStore", () => {
const client = stubClient(); const client = stubClient();
const roomWithCreatePredecessorId = "!roomid:example.com"; const newRoomId = "!roomid:example.com";
const roomNoPredecessorId = "!roomnopreid:example.com"; const roomNoPredecessorId = "!roomnopreid:example.com";
const oldRoomId = "!oldroomid:example.com"; const oldRoomId = "!oldroomid:example.com";
const userId = "@user:example.com"; const userId = "@user:example.com";
const createWithPredecessor = new MatrixEvent({ const createWithPredecessor = new MatrixEvent({
type: EventType.RoomCreate, type: EventType.RoomCreate,
sender: userId, sender: userId,
room_id: roomWithCreatePredecessorId, room_id: newRoomId,
content: { content: {
predecessor: { room_id: oldRoomId, event_id: "tombstone_event_id" }, predecessor: { room_id: oldRoomId, event_id: "tombstone_event_id" },
}, },
@ -41,19 +42,32 @@ describe("RoomListStore", () => {
const createNoPredecessor = new MatrixEvent({ const createNoPredecessor = new MatrixEvent({
type: EventType.RoomCreate, type: EventType.RoomCreate,
sender: userId, sender: userId,
room_id: roomWithCreatePredecessorId, room_id: newRoomId,
content: {}, content: {},
event_id: "$create", event_id: "$create",
state_key: "", state_key: "",
}); });
const roomWithCreatePredecessor = new Room(roomWithCreatePredecessorId, client, userId, {}); const predecessor = new MatrixEvent({
type: EventType.RoomPredecessor,
sender: userId,
room_id: newRoomId,
content: {
predecessor_room_id: oldRoomId,
last_known_event_id: "tombstone_event_id",
},
event_id: "$pred",
state_key: "",
});
const roomWithPredecessorEvent = new Room(newRoomId, client, userId, {});
upsertRoomStateEvents(roomWithPredecessorEvent, [predecessor]);
const roomWithCreatePredecessor = new Room(newRoomId, client, userId, {});
upsertRoomStateEvents(roomWithCreatePredecessor, [createWithPredecessor]); upsertRoomStateEvents(roomWithCreatePredecessor, [createWithPredecessor]);
const roomNoPredecessor = new Room(roomNoPredecessorId, client, userId, {}); const roomNoPredecessor = new Room(roomNoPredecessorId, client, userId, {});
upsertRoomStateEvents(roomNoPredecessor, [createNoPredecessor]); upsertRoomStateEvents(roomNoPredecessor, [createNoPredecessor]);
const oldRoom = new Room(oldRoomId, client, userId, {}); const oldRoom = new Room(oldRoomId, client, userId, {});
client.getRoom = jest.fn().mockImplementation((roomId) => { client.getRoom = jest.fn().mockImplementation((roomId) => {
switch (roomId) { switch (roomId) {
case roomWithCreatePredecessorId: case newRoomId:
return roomWithCreatePredecessor; return roomWithCreatePredecessor;
case oldRoomId: case oldRoomId:
return oldRoom; return oldRoom;
@ -123,4 +137,36 @@ describe("RoomListStore", () => {
// And no other updates happen // And no other updates happen
expect(handleRoomUpdate).toHaveBeenCalledTimes(1); expect(handleRoomUpdate).toHaveBeenCalledTimes(1);
}); });
describe("When feature_dynamic_room_predecessors = true", () => {
beforeEach(() => {
jest.spyOn(SettingsStore, "getValue").mockImplementation(
(settingName) => settingName === "feature_dynamic_room_predecessors",
);
});
afterEach(() => {
jest.spyOn(SettingsStore, "getValue").mockReset();
});
it("Removes old room if it finds a predecessor in the m.predecessor event", () => {
// Given a store we can spy on
const { store, handleRoomUpdate } = createStore();
// When we tell it we joined a new room that has an old room as
// predecessor in the create event
const payload = {
oldMembership: "invite",
membership: "join",
room: roomWithPredecessorEvent,
};
store.onDispatchMyMembership(payload);
// Then the old room is removed
expect(handleRoomUpdate).toHaveBeenCalledWith(oldRoom, RoomUpdateCause.RoomRemoved);
// And the new room is added
expect(handleRoomUpdate).toHaveBeenCalledWith(roomWithPredecessorEvent, RoomUpdateCause.NewRoom);
});
});
}); });