Skip to content

Commit

Permalink
test work
Browse files Browse the repository at this point in the history
  • Loading branch information
toger5 committed May 27, 2024
1 parent 272d1a1 commit f5bca40
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 89 deletions.
237 changes: 153 additions & 84 deletions spec/unit/matrixrtc/CallMembership.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,7 @@ limitations under the License.
*/

import { MatrixEvent } from "../../../src";
import { CallMembership, CallMembershipData } from "../../../src/matrixrtc/CallMembership";

const membershipTemplate: CallMembershipData = {
call_id: "",
scope: "m.room",
application: "m.call",
device_id: "AAAAAAA",
expires: 5000,
membershipID: "bloop",
foci_active: [{ type: "livekit" }],
};
import { CallMembership, CallMembershipDataLegacy, SessionMembershipData } from "../../../src/matrixrtc/CallMembership";

function makeMockEvent(originTs = 0): MatrixEvent {
return {
Expand All @@ -35,96 +25,175 @@ function makeMockEvent(originTs = 0): MatrixEvent {
}

describe("CallMembership", () => {
it("rejects membership with no expiry and no expires_ts", () => {
expect(() => {
new CallMembership(
makeMockEvent(),
Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: undefined }),
describe("CallMembershipDataLegacy", () => {
const membershipTemplate: CallMembershipDataLegacy = {
call_id: "",
scope: "m.room",
application: "m.call",
device_id: "AAAAAAA",
expires: 5000,
membershipID: "bloop",
foci_active: [{ type: "livekit" }],
};
it("rejects membership with no expiry and no expires_ts", () => {
expect(() => {
new CallMembership(
makeMockEvent(),
Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: undefined }),
);
}).toThrow();
});

it("rejects membership with no device_id", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { device_id: undefined }));
}).toThrow();
});

it("rejects membership with no call_id", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { call_id: undefined }));
}).toThrow();
});

it("allow membership with no scope", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined }));
}).not.toThrow();
});
it("rejects with malformatted expires_ts", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires_ts: "string" }));
}).toThrow();
});
it("rejects with malformatted expires", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires: "string" }));
}).toThrow();
});

it("uses event timestamp if no created_ts", () => {
const membership = new CallMembership(makeMockEvent(12345), membershipTemplate);
expect(membership.createdTs()).toEqual(12345);
});

it("uses created_ts if present", () => {
const membership = new CallMembership(
makeMockEvent(12345),
Object.assign({}, membershipTemplate, { created_ts: 67890 }),
);
}).toThrow();
});
expect(membership.createdTs()).toEqual(67890);
});

it("rejects membership with no device_id", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { device_id: undefined }));
}).toThrow();
});
it("computes absolute expiry time based on expires", () => {
const membership = new CallMembership(makeMockEvent(1000), membershipTemplate);
expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000);
});

it("rejects membership with no call_id", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { call_id: undefined }));
}).toThrow();
});
it("computes absolute expiry time based on expires_ts", () => {
const membership = new CallMembership(
makeMockEvent(1000),
Object.assign({}, membershipTemplate, { expires_ts: 6000 }),
);
expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000);
});

it("allow membership with no scope", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined }));
}).not.toThrow();
});
it("rejects with malformatted expires_ts", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires_ts: "string" }));
}).toThrow();
});
it("rejects with malformatted expires", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires: "string" }));
}).toThrow();
});
it("considers memberships unexpired if local age low enough", () => {
const fakeEvent = makeMockEvent(1000);
fakeEvent.getLocalAge = jest.fn().mockReturnValue(3000);
const membership = new CallMembership(fakeEvent, membershipTemplate);
expect(membership.isExpired()).toEqual(false);
});

it("uses event timestamp if no created_ts", () => {
const membership = new CallMembership(makeMockEvent(12345), membershipTemplate);
expect(membership.createdTs()).toEqual(12345);
});
it("considers memberships expired when local age large", () => {
const fakeEvent = makeMockEvent(1000);
fakeEvent.localTimestamp = Date.now() - 6000;
const membership = new CallMembership(fakeEvent, membershipTemplate);
expect(membership.isExpired()).toEqual(true);
});

it("uses created_ts if present", () => {
const membership = new CallMembership(
makeMockEvent(12345),
Object.assign({}, membershipTemplate, { created_ts: 67890 }),
);
expect(membership.createdTs()).toEqual(67890);
it("returns preferred foci", () => {
const fakeEvent = makeMockEvent();
const mockFocus = { type: "this_is_a_mock_focus" };
const membership = new CallMembership(
fakeEvent,
Object.assign({}, membershipTemplate, { foci_active: [mockFocus] }),
);
expect(membership.getPreferredFoci()).toEqual([mockFocus]);
});
});

it("computes absolute expiry time based on expires", () => {
const membership = new CallMembership(makeMockEvent(1000), membershipTemplate);
expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000);
});
describe("SessionMembershipData", () => {
const membershipTemplate: SessionMembershipData = {
call_id: "",
scope: "m.room",
application: "m.call",
device_id: "AAAAAAA",
foci_active: { type: "livekit" },
foci_preferred: [{ type: "livekit" }],
};

it("rejects membership with no device_id", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { device_id: undefined }));
}).toThrow();
});

it("computes absolute expiry time based on expires_ts", () => {
const membership = new CallMembership(
makeMockEvent(1000),
Object.assign({}, membershipTemplate, { expires_ts: 6000 }),
);
expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000);
});
it("rejects membership with no call_id", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { call_id: undefined }));
}).toThrow();
});

it("considers memberships unexpired if local age low enough", () => {
const fakeEvent = makeMockEvent(1000);
fakeEvent.getLocalAge = jest.fn().mockReturnValue(3000);
const membership = new CallMembership(fakeEvent, membershipTemplate);
expect(membership.isExpired()).toEqual(false);
});
it("allow membership with no scope", () => {
expect(() => {
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined }));
}).not.toThrow();
});

it("considers memberships expired when local age large", () => {
const fakeEvent = makeMockEvent(1000);
fakeEvent.localTimestamp = Date.now() - 6000;
const membership = new CallMembership(fakeEvent, membershipTemplate);
expect(membership.isExpired()).toEqual(true);
});
it("uses event timestamp if no created_ts", () => {
const membership = new CallMembership(makeMockEvent(12345), membershipTemplate);
expect(membership.createdTs()).toEqual(12345);
});

it("uses created_ts if present", () => {
const membership = new CallMembership(
makeMockEvent(12345),
Object.assign({}, membershipTemplate, { created_ts: 67890 }),
);
expect(membership.createdTs()).toEqual(67890);
});

it("considers memberships unexpired if local age low enough", () => {
const fakeEvent = makeMockEvent(1000);
fakeEvent.getLocalAge = jest.fn().mockReturnValue(3000);
const membership = new CallMembership(fakeEvent, membershipTemplate);
expect(membership.isExpired()).toEqual(false);
});

it("returns preferred foci", () => {
const fakeEvent = makeMockEvent();
const mockFocus = { type: "this_is_a_mock_focus" };
const membership = new CallMembership(
fakeEvent,
Object.assign({}, membershipTemplate, { foci_active: [mockFocus] }),
);
expect(membership.getPreferredFoci()).toEqual([mockFocus]);
it("returns preferred foci", () => {
const fakeEvent = makeMockEvent();
const mockFocus = { type: "this_is_a_mock_focus" };
const membership = new CallMembership(
fakeEvent,
Object.assign({}, membershipTemplate, { foci_preferred: [mockFocus] }),
);
expect(membership.getPreferredFoci()).toEqual([mockFocus]);
});
});

describe("expiry calculation", () => {
let fakeEvent: MatrixEvent;
let membership: CallMembership;
const membershipTemplate: CallMembershipDataLegacy = {
call_id: "",
scope: "m.room",
application: "m.call",
device_id: "AAAAAAA",
expires: 5000,
membershipID: "bloop",
foci_active: [{ type: "livekit" }],
};

beforeEach(() => {
// server origin timestamp for this event is 1000
Expand Down
60 changes: 60 additions & 0 deletions spec/unit/matrixrtc/LivekitFocus.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
Copyright 2023 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 { isLivekitFocus, isLivekitFocusActive, isLivekitFocusConfig } from "../../../src/matrixrtc/LivekitFocus";

describe("LivekitFocus", () => {
it("isLivekitFocus", () => {
expect(
isLivekitFocus({
type: "livekit",
livekit_service_url: "http://test.com",
livekit_alias: "test",
}),
).toBeTruthy();
expect(isLivekitFocus({ type: "livekit" })).toBeFalsy();
expect(
isLivekitFocus({ type: "not-livekit", livekit_service_url: "http://test.com", livekit_alias: "test" }),
).toBeFalsy();
expect(
isLivekitFocus({ type: "livekit", other_service_url: "http://test.com", livekit_alias: "test" }),
).toBeFalsy();
expect(
isLivekitFocus({ type: "livekit", livekit_service_url: "http://test.com", other_alias: "test" }),
).toBeFalsy();
});
it("isLivekitFocusActive", () => {
expect(
isLivekitFocusActive({
type: "livekit",
focus_selection: "oldest_membership",
}),
).toBeTruthy();
expect(isLivekitFocusActive({ type: "livekit" })).toBeFalsy();
expect(isLivekitFocusActive({ type: "not-livekit", focus_selection: "oldest_membership" })).toBeFalsy();
});
it("isLivekitFocusConfig", () => {
expect(
isLivekitFocusConfig({
type: "livekit",
livekit_service_url: "http://test.com",
}),
).toBeTruthy();
expect(isLivekitFocusConfig({ type: "livekit" })).toBeFalsy();
expect(isLivekitFocusConfig({ type: "not-livekit", livekit_service_url: "http://test.com" })).toBeFalsy();
expect(isLivekitFocusConfig({ type: "livekit", other_service_url: "oldest_membership" })).toBeFalsy();
});
});
3 changes: 1 addition & 2 deletions src/matrixrtc/CallMembership.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ export interface SessionMembershipData {
export const isSessionMembershipData = (data: any): data is SessionMembershipData =>
"foci_active" in data &&
"foci_preferred" in data &&
"membership_id" in data &&
!Array.isArray(data.foci_active) &&
Array.isArray(data.foci_preferred);

Expand All @@ -53,7 +52,7 @@ const checkSessionsMembershipData = (data: SessionMembershipData): void => {
if (typeof data.call_id !== "string") throw new Error(prefix + "call_id must be string");
if (typeof data.application !== "string") throw new Error(prefix + "application must be a string");
if (typeof data.foci_active?.type !== "string") throw new Error(prefix + "foci_active.type must be a string");
if (Array.isArray(data.foci_preferred)) throw new Error(prefix + "foci_preferred must be an array");
if (!Array.isArray(data.foci_preferred)) throw new Error(prefix + "foci_preferred must be an array");
// optional elements
if (data.created_ts && typeof data.created_ts !== "number") throw new Error(prefix + "created_ts must be number");

Expand Down
6 changes: 3 additions & 3 deletions src/matrixrtc/LivekitFocus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ export interface LivekitFocusConfig extends Focus {
livekit_service_url: string;
}

export const isLivekitFocusConfig = (object: Focus): object is LivekitFocusConfig =>
export const isLivekitFocusConfig = (object: any): object is LivekitFocusConfig =>
object.type === "livekit" && "livekit_service_url" in object;

export interface LivekitFocus extends LivekitFocusConfig {
livekit_alias: string;
}

export const isLivekitFocus = (object: Focus): object is LivekitFocus =>
export const isLivekitFocus = (object: any): object is LivekitFocus =>
isLivekitFocusConfig(object) && "livekit_alias" in object;

export interface LivekitFocusActive extends Focus {
type: "livekit";
focus_selection: "oldest_membership";
}
export const isLivekitFocusActive = (object: Focus): object is LivekitFocusActive =>
export const isLivekitFocusActive = (object: any): object is LivekitFocusActive =>
object.type === "livekit" && "focus_selection" in object;

0 comments on commit f5bca40

Please sign in to comment.