All checks were successful
Queue Release Build / prepare (push) Successful in 18s
Deploy Web Apps / deploy (push) Successful in 6m32s
Queue Release Build / build-windows (push) Successful in 26m8s
Queue Release Build / build-linux (push) Successful in 40m18s
Queue Release Build / finalize (push) Successful in 42s
162 lines
4.8 KiB
TypeScript
162 lines
4.8 KiB
TypeScript
import { of } from 'rxjs';
|
|
import {
|
|
beforeEach,
|
|
describe,
|
|
expect,
|
|
it,
|
|
vi
|
|
} from 'vitest';
|
|
import type { Store } from '@ngrx/store';
|
|
import type { RealtimeSessionFacade } from '../../core/realtime';
|
|
import type { ServerDirectoryFacade } from '../../domains/server-directory';
|
|
import type { Room, User } from '../../shared-kernel';
|
|
import { RoomSignalingConnection } from './room-signaling-connection';
|
|
|
|
interface EndpointFixture {
|
|
id: string;
|
|
isActive: boolean;
|
|
name: string;
|
|
status: 'offline' | 'online';
|
|
url: string;
|
|
}
|
|
|
|
interface SignalSourceFixture {
|
|
sourceId: string;
|
|
sourceName?: string;
|
|
sourceUrl: string;
|
|
}
|
|
|
|
interface SignalSelectorFixture {
|
|
sourceId: string;
|
|
sourceUrl: string;
|
|
}
|
|
|
|
interface FakeRealtimeSessionFacade {
|
|
connectToSignalingServer: ReturnType<typeof vi.fn>;
|
|
hasJoinedServer: ReturnType<typeof vi.fn>;
|
|
identify: ReturnType<typeof vi.fn>;
|
|
isSignalingConnectedTo: ReturnType<typeof vi.fn>;
|
|
joinRoom: ReturnType<typeof vi.fn>;
|
|
peerId: ReturnType<typeof vi.fn>;
|
|
setCurrentServer: ReturnType<typeof vi.fn>;
|
|
switchServer: ReturnType<typeof vi.fn>;
|
|
}
|
|
|
|
interface FakeServerDirectoryFacade {
|
|
awaitInitialServerHealthCheck: ReturnType<typeof vi.fn>;
|
|
buildRoomSignalSelector: ReturnType<typeof vi.fn>;
|
|
ensureEndpointVersionCompatibility: ReturnType<typeof vi.fn>;
|
|
findServerAcrossActiveEndpoints: ReturnType<typeof vi.fn>;
|
|
getFallbackRoomEndpoints: ReturnType<typeof vi.fn>;
|
|
getServer: ReturnType<typeof vi.fn>;
|
|
getWebSocketUrl: ReturnType<typeof vi.fn>;
|
|
normaliseRoomSignalSource: ReturnType<typeof vi.fn>;
|
|
resolveRoomEndpoint: ReturnType<typeof vi.fn>;
|
|
}
|
|
|
|
interface FakeStore {
|
|
dispatch: ReturnType<typeof vi.fn>;
|
|
}
|
|
|
|
describe('RoomSignalingConnection', () => {
|
|
const room: Room = {
|
|
id: 'room-1',
|
|
name: 'Room One',
|
|
description: '',
|
|
hostId: 'user-1',
|
|
createdAt: 1,
|
|
userCount: 1,
|
|
sourceId: 'primary',
|
|
sourceName: 'Primary',
|
|
sourceUrl: 'https://signal.toju.app'
|
|
};
|
|
const user: User = {
|
|
id: 'user-1',
|
|
oderId: 'peer-a',
|
|
username: 'maomao',
|
|
displayName: 'maomao',
|
|
status: 'online',
|
|
createdAt: 1
|
|
};
|
|
|
|
let webrtc: FakeRealtimeSessionFacade;
|
|
let serverDirectory: FakeServerDirectoryFacade;
|
|
let store: FakeStore;
|
|
|
|
beforeEach(() => {
|
|
const endpoints = new Map<string, EndpointFixture>([
|
|
[
|
|
'primary',
|
|
{
|
|
id: 'primary',
|
|
name: 'Primary',
|
|
url: 'https://signal.toju.app',
|
|
isActive: true,
|
|
status: 'offline'
|
|
}
|
|
],
|
|
[
|
|
'fallback',
|
|
{
|
|
id: 'fallback',
|
|
name: 'Sweden',
|
|
url: 'https://signal-sweden.toju.app',
|
|
isActive: true,
|
|
status: 'online'
|
|
}
|
|
]
|
|
]);
|
|
|
|
webrtc = {
|
|
connectToSignalingServer: vi.fn((url: string) => of(url === 'wss://signal-sweden.toju.app')),
|
|
hasJoinedServer: vi.fn(() => false),
|
|
identify: vi.fn(),
|
|
isSignalingConnectedTo: vi.fn(() => false),
|
|
joinRoom: vi.fn(),
|
|
peerId: vi.fn(() => 'peer-a'),
|
|
setCurrentServer: vi.fn(),
|
|
switchServer: vi.fn()
|
|
};
|
|
|
|
serverDirectory = {
|
|
awaitInitialServerHealthCheck: vi.fn(() => Promise.resolve()),
|
|
buildRoomSignalSelector: vi.fn((source: SignalSourceFixture) => ({
|
|
sourceId: source.sourceId,
|
|
sourceUrl: source.sourceUrl
|
|
})),
|
|
ensureEndpointVersionCompatibility: vi.fn((selector: SignalSelectorFixture) =>
|
|
Promise.resolve(selector.sourceId === 'fallback')
|
|
),
|
|
findServerAcrossActiveEndpoints: vi.fn(() => of(null)),
|
|
getFallbackRoomEndpoints: vi.fn(() => [endpoints.get('fallback')]),
|
|
getServer: vi.fn(() => of(null)),
|
|
getWebSocketUrl: vi.fn((selector: SignalSelectorFixture) => selector.sourceUrl.replace(/^http/, 'ws')),
|
|
normaliseRoomSignalSource: vi.fn((source: SignalSourceFixture) => ({
|
|
sourceId: source.sourceId,
|
|
sourceName: source.sourceName,
|
|
sourceUrl: source.sourceUrl
|
|
})),
|
|
resolveRoomEndpoint: vi.fn((source: SignalSourceFixture) => endpoints.get(source.sourceId) ?? null)
|
|
};
|
|
|
|
store = {
|
|
dispatch: vi.fn()
|
|
};
|
|
});
|
|
|
|
it('tries fallback endpoints when the primary endpoint is offline', async () => {
|
|
const connection = new RoomSignalingConnection(
|
|
webrtc as unknown as RealtimeSessionFacade,
|
|
serverDirectory as unknown as ServerDirectoryFacade,
|
|
store as unknown as Store
|
|
);
|
|
|
|
connection.beginRoomNavigation(room.id);
|
|
await connection.connectToRoomSignaling(room, user, user.oderId, [room]);
|
|
|
|
expect(serverDirectory.ensureEndpointVersionCompatibility).toHaveBeenCalledTimes(2);
|
|
expect(webrtc.connectToSignalingServer).toHaveBeenCalledWith('wss://signal-sweden.toju.app');
|
|
expect(webrtc.joinRoom).toHaveBeenCalledWith(room.id, user.oderId, 'wss://signal-sweden.toju.app');
|
|
});
|
|
});
|