Skip to content

Commit 2ce019a

Browse files
committed
Add more tests for coverage
1 parent b6a782b commit 2ce019a

File tree

4 files changed

+111
-10
lines changed

4 files changed

+111
-10
lines changed

spec/unit/matrixrtc/MatrixRTCSession.spec.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import {
3636
mockRTCEvent,
3737
} from "./mocks";
3838
import { RTCEncryptionManager } from "../../../src/matrixrtc/RTCEncryptionManager.ts";
39-
import { type StickyMatrixEvent } from "../../../src/models/room-sticky-events.ts";
39+
import { RoomStickyEventsEvent, type StickyMatrixEvent } from "../../../src/models/room-sticky-events.ts";
40+
import { StickyEventMembershipManager } from "../../../src/matrixrtc/MembershipManager.ts";
4041

4142
const mockFocus = { type: "mock" };
4243

@@ -395,6 +396,31 @@ describe("MatrixRTCSession", () => {
395396

396397
expect(sess?.sessionDescription.id).toEqual("");
397398
});
399+
it("handles an incoming sticky event to an existing session", () => {
400+
const mockRoom = makeMockRoom([membershipTemplate]);
401+
const stickyUserId = "@stickyev:user.example";
402+
403+
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession, {
404+
listenForStickyEvents: true,
405+
listenForMemberStateEvents: true,
406+
});
407+
expect(sess.memberships.length).toEqual(1);
408+
const stickyEv = mockRTCEvent(
409+
{
410+
...membershipTemplate,
411+
user_id: stickyUserId,
412+
msc4354_sticky_key: `_${stickyUserId}_${membershipTemplate.device_id}`,
413+
},
414+
mockRoom.roomId,
415+
15000,
416+
Date.now() - 1000, // Sticky event comes first.
417+
) as StickyMatrixEvent;
418+
mockRoom._unstable_getStickyEvents.mockImplementation(() => {
419+
return [stickyEv];
420+
});
421+
mockRoom.emit(RoomStickyEventsEvent.Update, [stickyEv], [], []);
422+
expect(sess.memberships.length).toEqual(2);
423+
});
398424
});
399425

400426
describe("getOldestMembership", () => {
@@ -521,6 +547,12 @@ describe("MatrixRTCSession", () => {
521547
expect(sess!.isJoined()).toEqual(true);
522548
});
523549

550+
it("uses the sticky events membership manager implementation", () => {
551+
sess!.joinRoomSession([mockFocus], mockFocus, { unstableSendStickyEvents: true });
552+
expect(sess!.isJoined()).toEqual(true);
553+
expect(sess!["membershipManager"] instanceof StickyEventMembershipManager).toEqual(true);
554+
});
555+
524556
it("sends a notification when starting a call and emit DidSendCallNotification", async () => {
525557
// Simulate a join, including the update to the room state
526558
// Ensure sendEvent returns event IDs so the DidSendCallNotification payload includes them

spec/unit/matrixrtc/MembershipManager.spec.ts

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
MatrixError,
2424
UnsupportedDelayedEventsEndpointError,
2525
type Room,
26+
MAX_STICKY_DURATION_MS,
2627
} from "../../../src";
2728
import {
2829
MembershipManagerEvent,
@@ -33,7 +34,7 @@ import {
3334
} from "../../../src/matrixrtc";
3435
import { makeMockClient, makeMockRoom, membershipTemplate, mockCallMembership, type MockClient } from "./mocks";
3536
import { logger } from "../../../src/logger.ts";
36-
import { MembershipManager } from "../../../src/matrixrtc/MembershipManager.ts";
37+
import { MembershipManager, StickyEventMembershipManager } from "../../../src/matrixrtc/MembershipManager.ts";
3738

3839
/**
3940
* Create a promise that will resolve once a mocked method is called.
@@ -474,7 +475,7 @@ describe("MembershipManager", () => {
474475

475476
it("does not provide focus if the selection method is unknown", () => {
476477
const manager = new MembershipManager({}, room, client, () => undefined, callSession);
477-
manager.join([focus], Object.assign(focusActive, { type: "unknown_type" }));
478+
manager.join([focus], { ...focusActive, type: "unknown_type" });
478479
expect(manager.getActiveFocus()).toBe(undefined);
479480
});
480481
});
@@ -938,6 +939,67 @@ describe("MembershipManager", () => {
938939
expect(client.sendStateEvent).toHaveBeenCalledTimes(0);
939940
});
940941
});
942+
943+
describe("StickyEventMembershipManager", () => {
944+
beforeEach(() => {
945+
// Provide a default mock that is like the default "non error" server behaviour.
946+
(client._unstable_sendStickyDelayedEvent as Mock<any>).mockResolvedValue({ delay_id: "id" });
947+
(client._unstable_sendStickyEvent as Mock<any>).mockResolvedValue(undefined);
948+
});
949+
950+
describe("join()", () => {
951+
describe("sends a membership event", () => {
952+
it("sends a membership event and schedules delayed leave when joining a call", async () => {
953+
const updateDelayedEventHandle = createAsyncHandle<void>(
954+
client._unstable_updateDelayedEvent as Mock,
955+
);
956+
const memberManager = new StickyEventMembershipManager(
957+
undefined,
958+
room,
959+
client,
960+
() => undefined,
961+
callSession,
962+
);
963+
964+
memberManager.join([focus], focusActive);
965+
966+
await waitForMockCall(client._unstable_sendStickyEvent, Promise.resolve({ event_id: "id" }));
967+
// Test we sent the initial join
968+
expect(client._unstable_sendStickyEvent).toHaveBeenCalledWith(
969+
room.roomId,
970+
MAX_STICKY_DURATION_MS,
971+
null,
972+
"org.matrix.msc3401.call.member",
973+
{
974+
application: "m.call",
975+
call_id: "",
976+
device_id: "AAAAAAA",
977+
expires: 14400000,
978+
foci_preferred: [focus],
979+
focus_active: focusActive,
980+
scope: "m.room",
981+
msc4354_sticky_key: "_@alice:example.org_AAAAAAA_m.call",
982+
} satisfies SessionMembershipData,
983+
);
984+
updateDelayedEventHandle.resolve?.();
985+
986+
// Ensure we have sent the delayed disconnect event.
987+
expect(client._unstable_sendStickyDelayedEvent).toHaveBeenCalledWith(
988+
room.roomId,
989+
MAX_STICKY_DURATION_MS,
990+
{ delay: 8000 },
991+
null,
992+
"org.matrix.msc3401.call.member",
993+
{
994+
msc4354_sticky_key: "_@alice:example.org_AAAAAAA_m.call",
995+
},
996+
);
997+
// ..once
998+
expect(client._unstable_sendStickyDelayedEvent).toHaveBeenCalledTimes(1);
999+
});
1000+
});
1001+
});
1002+
});
9411003
});
9421004

9431005
it("Should prefix log with MembershipManager used", () => {

src/matrixrtc/MatrixRTCSession.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -811,14 +811,14 @@ export class MatrixRTCSession extends TypedEventEmitter<
811811
/**
812812
* Call this when the Matrix room members have changed.
813813
*/
814-
private onRoomMemberUpdate = (): void => {
814+
private readonly onRoomMemberUpdate = (): void => {
815815
this.recalculateSessionMembers();
816816
};
817817

818818
/**
819819
* Call this when a sticky event update has occured.
820820
*/
821-
private onStickyEventUpdate: RoomStickyEventsMap[RoomStickyEventsEvent.Update] = (
821+
private readonly onStickyEventUpdate: RoomStickyEventsMap[RoomStickyEventsEvent.Update] = (
822822
added,
823823
updated,
824824
removed,

src/matrixrtc/MembershipManager.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -679,8 +679,14 @@ export class MembershipManager
679679
}
680680

681681
protected clientSendMembership: (myMembership: SessionMembershipData | EmptyObject) => Promise<ISendEventResponse> =
682-
(myMembership) =>
683-
this.client.sendStateEvent(this.room.roomId, EventType.GroupCallMemberPrefix, myMembership, this.stateKey);
682+
(myMembership) => {
683+
return this.client.sendStateEvent(
684+
this.room.roomId,
685+
EventType.GroupCallMemberPrefix,
686+
myMembership,
687+
this.stateKey,
688+
);
689+
};
684690

685691
private async sendJoinEvent(): Promise<ActionUpdate> {
686692
return await this.clientSendMembership(this.makeMyMembership(this.membershipEventExpiryMs))
@@ -1030,7 +1036,7 @@ export class StickyEventMembershipManager extends MembershipManager {
10301036
super(joinConfig, room, clientWithSticky, getOldestMembership, sessionDescription, parentLogger);
10311037
}
10321038

1033-
protected clientSendDelayedEvent: () => Promise<SendDelayedEventResponse> = () =>
1039+
protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse> = () =>
10341040
this.clientWithSticky._unstable_sendStickyDelayedEvent(
10351041
this.room.roomId,
10361042
STICK_DURATION_MS,
@@ -1041,14 +1047,15 @@ export class StickyEventMembershipManager extends MembershipManager {
10411047
);
10421048

10431049
protected clientSendMembership: (myMembership: SessionMembershipData | EmptyObject) => Promise<ISendEventResponse> =
1044-
(myMembership) =>
1045-
this.clientWithSticky._unstable_sendStickyEvent(
1050+
(myMembership) => {
1051+
return this.clientWithSticky._unstable_sendStickyEvent(
10461052
this.room.roomId,
10471053
STICK_DURATION_MS,
10481054
null,
10491055
EventType.GroupCallMemberPrefix,
10501056
{ ...myMembership, msc4354_sticky_key: this.stateKey },
10511057
);
1058+
};
10521059

10531060
protected actionUpdateFromErrors(
10541061
error: unknown,

0 commit comments

Comments
 (0)