Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure we do not add relations to the wrong timeline #3427

Merged
merged 19 commits into from
Jun 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions spec/integ/matrix-client-event-timeline.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ describe("MatrixClient event timelines", function () {

const prom = emitPromise(room, ThreadEvent.Update);
// Assume we're seeing the reply while loading backlog
room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2]);
httpBackend
.when(
"GET",
Expand All @@ -1156,7 +1156,7 @@ describe("MatrixClient event timelines", function () {
});
await flushHttp(prom);
// but while loading the metadata, a new reply has arrived
room.addLiveEvents([THREAD_REPLY3]);
await room.addLiveEvents([THREAD_REPLY3]);
const thread = room.getThread(THREAD_ROOT_UPDATED.event_id!)!;
// then the events should still be all in the right order
expect(thread.events.map((it) => it.getId())).toEqual([
Expand Down Expand Up @@ -1248,7 +1248,7 @@ describe("MatrixClient event timelines", function () {

const prom = emitPromise(room, ThreadEvent.Update);
// Assume we're seeing the reply while loading backlog
room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2]);
httpBackend
.when(
"GET",
Expand All @@ -1267,7 +1267,7 @@ describe("MatrixClient event timelines", function () {
});
await flushHttp(prom);
// but while loading the metadata, a new reply has arrived
room.addLiveEvents([THREAD_REPLY3]);
await room.addLiveEvents([THREAD_REPLY3]);
const thread = room.getThread(THREAD_ROOT_UPDATED.event_id!)!;
// then the events should still be all in the right order
expect(thread.events.map((it) => it.getId())).toEqual([
Expand Down Expand Up @@ -1572,7 +1572,7 @@ describe("MatrixClient event timelines", function () {
respondToEvent(THREAD_ROOT_UPDATED);
respondToEvent(THREAD_ROOT_UPDATED);
respondToEvent(THREAD2_ROOT);
room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2]);
await httpBackend.flushAllExpected();
await prom;
expect(thread.length).toBe(2);
Expand Down Expand Up @@ -1937,11 +1937,6 @@ describe("MatrixClient event timelines", function () {
.respond(200, function () {
return THREAD_ROOT;
});
httpBackend
.when("GET", "/rooms/!foo%3Abar/event/" + encodeURIComponent(THREAD_ROOT.event_id!))
.respond(200, function () {
return THREAD_ROOT;
});
httpBackend
.when("GET", "/rooms/!foo%3Abar/context/" + encodeURIComponent(THREAD_ROOT.event_id!))
.respond(200, function () {
Expand Down
124 changes: 124 additions & 0 deletions spec/integ/matrix-client-syncing.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,15 @@ import {
NotificationCountType,
IEphemeral,
Room,
IndexedDBStore,
RelationType,
} from "../../src";
import { ReceiptType } from "../../src/@types/read_receipts";
import { UNREAD_THREAD_NOTIFICATIONS } from "../../src/@types/sync";
import * as utils from "../test-utils/test-utils";
import { TestClient } from "../TestClient";
import { emitPromise, mkEvent, mkMessage } from "../test-utils/test-utils";
import { THREAD_RELATION_TYPE } from "../../src/models/thread";

describe("MatrixClient syncing", () => {
const selfUserId = "@alice:localhost";
Expand Down Expand Up @@ -1867,4 +1871,124 @@ describe("MatrixClient syncing (IndexedDB version)", () => {
idbClient.stopClient();
idbHttpBackend.stop();
});

it("should query server for which thread a 2nd order relation belongs to and stash in sync accumulator", async () => {
const roomId = "!room:example.org";

async function startClient(client: MatrixClient): Promise<void> {
await Promise.all([
idbClient.startClient({
// Without this all events just go into the main timeline
threadSupport: true,
}),
idbHttpBackend.flushAllExpected(),
emitPromise(idbClient, ClientEvent.Room),
]);
}

function assertEventsExpected(client: MatrixClient): void {
const room = client.getRoom(roomId);
const mainTimelineEvents = room!.getLiveTimeline().getEvents();
expect(mainTimelineEvents).toHaveLength(1);
expect(mainTimelineEvents[0].getContent().body).toEqual("Test");

const thread = room!.getThread("$someThreadId")!;
expect(thread.replayEvents).toHaveLength(1);
expect(thread.replayEvents![0].getRelation()!.key).toEqual("🪿");
}

let idbTestClient = new TestClient(selfUserId, "DEVICE", selfAccessToken, undefined, {
store: new IndexedDBStore({
indexedDB: global.indexedDB,
dbName: "test",
}),
});
let idbHttpBackend = idbTestClient.httpBackend;
let idbClient = idbTestClient.client;
await idbClient.store.startup();

idbHttpBackend.when("GET", "/versions").respond(200, { versions: ["v1.4"] });
idbHttpBackend.when("GET", "/pushrules/").respond(200, {});
idbHttpBackend.when("POST", "/filter").respond(200, { filter_id: "a filter id" });

const syncRoomSection = {
join: {
[roomId]: {
timeline: {
prev_batch: "foo",
events: [
mkMessage({
room: roomId,
user: selfUserId,
msg: "Test",
}),
mkEvent({
room: roomId,
user: selfUserId,
content: {
"m.relates_to": {
rel_type: RelationType.Annotation,
event_id: "$someUnknownEvent",
key: "🪿",
},
},
type: "m.reaction",
}),
],
},
},
},
};
idbHttpBackend.when("GET", "/sync").respond(200, {
...syncData,
rooms: syncRoomSection,
});
idbHttpBackend.when("GET", `/rooms/${encodeURIComponent(roomId)}/event/%24someUnknownEvent`).respond(
200,
mkEvent({
room: roomId,
user: selfUserId,
content: {
"body": "Thread response",
"m.relates_to": {
rel_type: THREAD_RELATION_TYPE.name,
event_id: "$someThreadId",
},
},
type: "m.room.message",
}),
);

await startClient(idbClient);
assertEventsExpected(idbClient);

idbHttpBackend.verifyNoOutstandingExpectation();
// Force sync accumulator to persist, reset client, assert it doesn't re-fetch event on next start-up
await idbClient.store.save(true);
await idbClient.stopClient();
await idbClient.store.destroy();
await idbHttpBackend.stop();

idbTestClient = new TestClient(selfUserId, "DEVICE", selfAccessToken, undefined, {
store: new IndexedDBStore({
indexedDB: global.indexedDB,
dbName: "test",
}),
});
idbHttpBackend = idbTestClient.httpBackend;
idbClient = idbTestClient.client;
await idbClient.store.startup();

idbHttpBackend.when("GET", "/versions").respond(200, { versions: ["v1.4"] });
idbHttpBackend.when("GET", "/pushrules/").respond(200, {});
idbHttpBackend.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
idbHttpBackend.when("GET", "/sync").respond(200, syncData);

await startClient(idbClient);
assertEventsExpected(idbClient);

idbHttpBackend.verifyNoOutstandingExpectation();
await idbClient.stopClient();
await idbHttpBackend.stop();
});
});
2 changes: 1 addition & 1 deletion spec/integ/matrix-client-unread-notifications.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe("MatrixClient syncing", () => {

const thread = mkThread({ room, client: client!, authorId: selfUserId, participantUserIds: [selfUserId] });
const threadReply = thread.events.at(-1)!;
room.addLiveEvents([thread.rootEvent]);
await room.addLiveEvents([thread.rootEvent]);

// Initialize read receipt datastructure before testing the reaction
room.addReceiptToStructure(thread.rootEvent.getId()!, ReceiptType.Read, selfUserId, { ts: 1 }, false);
Expand Down
Loading