Fix some tests

This commit is contained in:
Robin
2026-10-09 01:43:25 +02:00
parent 033f79975a
commit c6807fd9a2
11 changed files with 90 additions and 137 deletions
+4 -99
View File
@@ -49,11 +49,12 @@ describe("getSFUConfig", () => {
serviceUrl: "https://sfu.example.org",
roomId: "!example_room_id",
slotId: "m.call#room",
role: "subscriber",
role: "publisher",
logger,
};
});
afterEach(() => {
afterEach(async () => {
void (await fetchMock.flush());
vitest.clearAllMocks();
fetchMock.reset();
});
@@ -72,7 +73,6 @@ describe("getSFUConfig", () => {
livekitIdentity: "@me:example.org:ABCDEF",
livekitAlias: "!example_room_id",
});
void (await fetchMock.flush());
});
it("should fail if the SFU errors", async () => {
@@ -95,7 +95,6 @@ describe("getSFUConfig", () => {
"MatrixError: [500] Failed to look up user info from homeserver",
);
void (await fetchMock.flush());
return;
}
expect.fail("Expected test to throw;");
@@ -137,7 +136,6 @@ describe("getSFUConfig", () => {
expect(config.jwt).toBe(testJWTToken);
expect(callCount).toBe(2);
void (await fetchMock.flush());
});
it("should successfully send delay parameters to the JWT service legacy endpoint", async () => {
@@ -150,7 +148,7 @@ describe("getSFUConfig", () => {
if (
body.delay_id === "mock_delay_id" &&
body.delay_timeout === 3600000 &&
body.delay_cs_api_url === "https://homeserverserver.org/cs_api"
body.delay_cs_api_url === "https://matrix.homeserverserver.org"
) {
return {
status: 200,
@@ -172,98 +170,6 @@ describe("getSFUConfig", () => {
jwt: testJWTToken,
url: serviceUrl,
});
void (await fetchMock.flush());
});
it("should try legacy and then new endpoint with delay delegation", async () => {
fetchMock.post("https://sfu.example.org/get_token", () => {
return {
status: 500,
body: {
errcode: "M_LOOKUP_FAILED",
error: "Failed to look up user info from homeserver",
},
};
});
fetchMock.post("https://sfu.example.org/sfu/get", () => {
return {
status: 500,
body: {
errcode: "M_LOOKUP_FAILED",
error: "Failed to look up user info from homeserver",
},
};
});
try {
await getSFUConfig({ ...params, ...delayParams });
} catch (ex) {
expect(ex).toBeInstanceOf(FailToGetOpenIdToken);
expect((ex as FailToGetOpenIdToken).cause).toBeInstanceOf(MatrixError);
const mxError = (ex as Error).cause as MatrixError;
expect(mxError.message).toEqual(
"MatrixError: [500] Failed to look up user info from homeserver",
);
void (await fetchMock.flush());
}
const calls = fetchMock.calls();
expect(calls.length).toBe(2);
expect(calls[0][0]).toStrictEqual("https://sfu.example.org/get_token");
expect(calls[0][1]).toStrictEqual({
// check if it uses correct delayID!
body: '{"room_id":"!example_room_id","slot_id":"m.call#ROOM","member":{"id":"@alice:example.org:DEVICE","claimed_user_id":"@alice:example.org","claimed_device_id":"DEVICE"},"delay_id":"mock_delay_id","delay_timeout":3600000,"delay_cs_api_url":"https://matrix.homeserverserver.org"}',
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
expect(calls[1][0]).toStrictEqual("https://sfu.example.org/sfu/get");
expect(calls[1][1]).toStrictEqual({
body: '{"room":"!example_room_id","device_id":"DEVICE","delay_id":"mock_delay_id","delay_timeout":3600000,"delay_cs_api_url":"https://matrix.homeserverserver.org"}',
headers: {
"Content-Type": "application/json",
},
method: "POST",
});
});
it("dont try legacy if endpoint with delay delegation is sucessful", async () => {
fetchMock.post("https://sfu.example.org/get_token", () => {
return {
status: 200,
body: { url: serviceUrl, jwt: testJWTToken },
};
});
fetchMock.post("https://sfu.example.org/sfu/get", () => {
return {
status: 500,
body: { error: "Test failure" },
};
});
try {
await getSFUConfig({ ...params, ...delayParams });
} catch (ex) {
expect(ex).toBeInstanceOf(FailToGetOpenIdToken);
expect((ex as FailToGetOpenIdToken).cause).toEqual(
new Error("SFU Config fetch failed with status code 500"),
);
void (await fetchMock.flush());
}
const calls = fetchMock.calls();
expect(calls.length).toBe(1);
expect(calls[0][0]).toStrictEqual("https://sfu.example.org/get_token");
expect(calls[0][1]).toStrictEqual({
// check if it uses correct delayID!
body: '{"room_id":"!example_room_id","slot_id":"m.call#ROOM","member":{"id":"@alice:example.org:DEVICE","claimed_user_id":"@alice:example.org","claimed_device_id":"DEVICE"},"delay_id":"mock_delay_id","delay_timeout":3600000,"delay_cs_api_url":"https://matrix.homeserverserver.org"}',
method: "POST",
headers: {
"Content-Type": "application/json",
},
});
});
it("should retry fetching the openid token", async () => {
@@ -293,6 +199,5 @@ describe("getSFUConfig", () => {
livekitIdentity: "@me:example.org:ABCDEF",
livekitAlias: "!example_room_id",
});
void (await fetchMock.flush());
});
});
@@ -148,6 +148,7 @@ describe("DeveloperSettingsTab", () => {
getCrypto: () => ({ getVersion: (): string => "x" }),
getUserId: () => "@u:hs",
getDeviceId: () => "DEVICE",
getDomain: () => "hs",
} as unknown as MatrixClient;
it("will not update custom transport without roomId", async () => {
const user = userEvent.setup();
+6 -3
View File
@@ -742,9 +742,12 @@ export function createCallViewModel$(
return combineLatest(
connections.map((connection) =>
remoteMatrixLivekitMembers$.pipe(
switchMap((members) =>
combineLatest(members.value.map((m) => m.participant.value$)),
),
switchMap((members) => {
if (members.value.length === 0) return of([]);
return combineLatest(
members.value.map((m) => m.participant.value$),
);
}),
map((participants) => ({
url: JSON.stringify(connection.transport), // TODO
livekitRoom: connection.livekitRoom,
@@ -122,6 +122,8 @@ export function withCallViewModel(mode: MatrixRTCMode) {
};
const room = mockMatrixRoom({
client: new (class extends EventEmitter {
public readonly baseUrl = "https://matrix.example.com";
public getUserId(): string | undefined {
return localRtcMember.userId;
}
@@ -337,6 +337,7 @@ describe("LocalMembership", () => {
}),
state$: constant(ConnectionState.LivekitConnected),
transport: mockTransport,
serverName: "example.org",
} as Connection;
const connectionTransportAConnecting = {
...connectionTransportAConnected,
@@ -858,6 +859,7 @@ describe("LocalMembership", () => {
const connection = {
state$: constant(ConnectionState.LivekitConnected),
transport: mockTransport,
serverName: "example.org",
livekitRoom: mockLivekitRoom({
localParticipant: mockLocalParticipant({
isScreenShareEnabled: false,
@@ -46,8 +46,11 @@ describe("LocalTransport", () => {
getDomain: () => "example.org",
}),
).toStrictEqual({
livekit_service_url: "https://lk.example.org",
type: "livekit",
transport: {
livekit_service_url: "https://lk.example.org",
type: "livekit",
},
serverName: "example.org",
});
});
@@ -74,8 +77,11 @@ describe("LocalTransport", () => {
});
expect(await getLocalTransport(client)).toStrictEqual({
livekit_service_url: "https://lk.example.org",
type: "livekit",
transport: {
livekit_service_url: "https://lk.example.org",
type: "livekit",
},
serverName: "example.org",
});
});
@@ -86,8 +92,11 @@ describe("LocalTransport", () => {
});
expect(await getLocalTransport(client)).toStrictEqual({
livekit_service_url: "https://lk.example.org",
type: "livekit",
transport: {
livekit_service_url: "https://lk.example.org",
type: "livekit",
},
serverName: "example.org",
});
});
@@ -97,8 +106,11 @@ describe("LocalTransport", () => {
]);
expect(await getLocalTransport(client)).toStrictEqual({
livekit_service_url: "https://lk.example.org",
type: "livekit",
transport: {
livekit_service_url: "https://lk.example.org",
type: "livekit",
},
serverName: "example.org",
});
});
@@ -28,9 +28,12 @@ import {
} from "livekit-client";
import fetchMock from "fetch-mock";
import EventEmitter from "events";
import { MatrixError, type IOpenIDToken } from "matrix-js-sdk";
import { MatrixError } from "matrix-js-sdk";
import { logger, type Logger } from "matrix-js-sdk/lib/logger";
import { type UnstableLivekitTransport } from "matrix-js-sdk/lib/matrixrtc";
import {
type LivekitGetTokenResponse,
type UnstableLivekitTransport,
} from "matrix-js-sdk/lib/matrixrtc";
import {
Connection,
@@ -185,7 +188,7 @@ describe("Start connection states", () => {
expect(connection.state$.getValue()).toEqual("Initialized");
});
it("fail to getOpenId token then error state", async () => {
it("fail to get SFU token then error state", async () => {
setupTest();
vi.useFakeTimers();
@@ -209,10 +212,10 @@ describe("Start connection states", () => {
});
onTestFinished(() => s.unsubscribe());
const deferred = Promise.withResolvers<IOpenIDToken>();
const deferred = Promise.withResolvers<LivekitGetTokenResponse>();
client.getOpenIdToken.mockImplementation(
async (): Promise<IOpenIDToken> => {
client._unstable_getLivekitToken.mockImplementation(
async (): Promise<LivekitGetTokenResponse> => {
return await deferred.promise;
},
);
@@ -54,9 +54,15 @@ beforeEach(() => {
vi.mocked(fakeConnectionFactory).createConnection = vi
.fn()
.mockImplementation(
(scope: ObservableScope, transport: UnstableLivekitTransport) => {
(
scope: ObservableScope,
_role: unknown,
transport: UnstableLivekitTransport,
serverName: string,
) => {
const mockConnection = {
transport,
serverName,
remoteParticipants$: new BehaviorSubject([]),
} as unknown as Connection;
vi.mocked(mockConnection).start = vi.fn();
@@ -229,14 +235,14 @@ describe("ConnectionManagerData", () => {
test("warns when a second connection to the same URL is merged", () => {
const warn = vi.spyOn(logger, "warn").mockImplementation(() => {});
const data = new ConnectionManagerData(logger);
const connection = { transport: TRANSPORT_1 } as unknown as Connection;
const connection = TRANSPORT_1 as unknown as Connection;
const p = (identity: string): RemoteParticipant =>
({ identity }) as unknown as RemoteParticipant;
data.add(connection, [p("a")]);
data.add({ ...connection } as Connection, [p("b")]);
expect(warn).toHaveBeenCalledWith(
expect.stringContaining(
"second connection to https://lk.example.org: existing [a], adding [b]",
'second connection to [null,"https://lk.example.org","example.org"]: existing [a], adding [b]',
),
);
expect(data.getParticipantsForTransport(TRANSPORT_1)).toHaveLength(2);
@@ -247,12 +253,14 @@ describe("connectionManagerData$ stream", () => {
// Used in test to control fake connections' remoteParticipants$ streams
let fakeRemoteParticipantsStreams: Map<string, Behavior<RemoteParticipant[]>>;
function keyForTransport(transport: UnstableLivekitTransport): string {
function keyForTransport({
transport,
serverName,
}: TransportLocator): string {
return JSON.stringify([
"url" in transport ? transport.url : undefined,
"livekit_service_url" in transport
? transport.livekit_service_url
: undefined,
"url" in transport ? transport.url : null,
"livekit_service_url" in transport ? transport.livekit_service_url : null,
serverName,
]);
}
@@ -260,7 +268,7 @@ describe("connectionManagerData$ stream", () => {
fakeRemoteParticipantsStreams = new Map();
function getRemoteParticipantsFor(
transport: UnstableLivekitTransport,
transport: TransportLocator,
): Behavior<RemoteParticipant[]> {
return (
fakeRemoteParticipantsStreams.get(keyForTransport(transport)) ??
@@ -272,13 +280,22 @@ describe("connectionManagerData$ stream", () => {
vi.mocked(fakeConnectionFactory).createConnection = vi
.fn()
.mockImplementation(
(scope: ObservableScope, transport: UnstableLivekitTransport) => {
(
scope: ObservableScope,
_role: unknown,
transport: UnstableLivekitTransport,
serverName: string,
) => {
const fakeRemoteParticipants$ = new BehaviorSubject<
RemoteParticipant[]
>([]);
const mockConnection = {
transport,
remoteParticipants$: getRemoteParticipantsFor(transport),
serverName,
remoteParticipants$: getRemoteParticipantsFor({
transport,
serverName,
}),
} as unknown as Connection;
vi.mocked(mockConnection).start = vi.fn();
vi.mocked(mockConnection).stop = vi.fn();
@@ -288,7 +305,7 @@ describe("connectionManagerData$ stream", () => {
});
fakeRemoteParticipantsStreams.set(
keyForTransport(transport),
keyForTransport({ transport, serverName }),
fakeRemoteParticipants$,
);
return mockConnection;
@@ -301,7 +318,7 @@ describe("connectionManagerData$ stream", () => {
// Setup the fake participants streams behavior
// ==============================
fakeRemoteParticipantsStreams.set(
keyForTransport(TRANSPORT_1.transport),
keyForTransport(TRANSPORT_1),
behavior("oa-b", {
o: [],
a: [{ identity: "user1A" } as RemoteParticipant],
@@ -313,7 +330,7 @@ describe("connectionManagerData$ stream", () => {
);
fakeRemoteParticipantsStreams.set(
keyForTransport(TRANSPORT_2.transport),
keyForTransport(TRANSPORT_2),
behavior("o-a", {
o: [],
a: [{ identity: "user2A" } as RemoteParticipant],
@@ -50,10 +50,8 @@ export class ConnectionManagerData {
// This is enough as a key because the ConnectionManager is already scoped by room.
// We also do not need to consider the slotId at this point since each `MatrixRTCSession` is already scoped by `slotDescription: {id, application}`.
return JSON.stringify([
"url" in transport ? transport.url : undefined,
"livekit_service_url" in transport
? transport.livekit_service_url
: undefined,
"url" in transport ? transport.url : null,
"livekit_service_url" in transport ? transport.livekit_service_url : null,
serverName,
]);
}
@@ -142,6 +142,7 @@ test("should signal participant on a connection that is publishing", async () =>
const connection = {
transport: bobMembership.getTransport(),
serverName: "example.org",
} as unknown as Connection;
const dataWithPublisher = new ConnectionManagerData();
dataWithPublisher.add(connection, [
@@ -185,6 +186,7 @@ test("should signal participant on a connection that is not publishing", async (
const connection = {
transport: bobMembership.getTransport(),
serverName: "example.org",
} as unknown as Connection;
const dataWithPublisher = new ConnectionManagerData();
dataWithPublisher.add(connection, []);
@@ -226,9 +228,11 @@ describe("Publication edge case", () => {
);
const connectionA = {
transport: transportA,
serverName: "example.org",
} as unknown as Connection;
const connectionB = {
transport: transportB,
serverName: "sample.com",
} as unknown as Connection;
connectionWithPublisher.add(connectionA, [
@@ -284,8 +288,14 @@ test("bob is publishing in the wrong connection", async () => {
bobMembership.userId,
bobMembership.deviceId,
);
const connectionA = { transport: transportA } as unknown as Connection;
const connectionB = { transport: transportB } as unknown as Connection;
const connectionA = {
transport: transportA,
serverName: "example.org",
} as unknown as Connection;
const connectionB = {
transport: transportB,
serverName: "sample.com",
} as unknown as Connection;
// Bob is not publishing on A
connectionWithPublisher.add(connectionA, []);
+1 -1
View File
@@ -69,7 +69,7 @@ export function getBasicRTCSession(
getUserId: () => localRtcMember.userId,
getDeviceId: () => localRtcMember.deviceId,
getSyncState: () => SyncState.Syncing,
getDomain: () => null,
getDomain: () => "example.com",
getAccessToken: () => "fake-token",
sendEvent: vitest.fn().mockResolvedValue({ event_id: "$fake:event" }),
redactEvent: vitest.fn().mockResolvedValue({ event_id: "$fake:event" }),