176 lines
5.2 KiB
TypeScript
176 lines
5.2 KiB
TypeScript
import { test, expect, describe, beforeEach } from "bun:test";
|
|
import { SignalingService } from "../src/services/SignalingService.ts";
|
|
import { ClientManager } from "../src/services/ClientManager.ts";
|
|
import type { ISignalingMessage } from "../src/interfaces/ISignalingMessage.ts";
|
|
|
|
class MockWebSocket {
|
|
sentMessages: string[] = [];
|
|
closed = false;
|
|
|
|
send(data: string) {
|
|
this.sentMessages.push(data);
|
|
}
|
|
|
|
close() {
|
|
this.closed = true;
|
|
}
|
|
}
|
|
|
|
describe("SignalingService", () => {
|
|
let signalingService: SignalingService;
|
|
let clientManager: ClientManager;
|
|
let mockWs: MockWebSocket;
|
|
|
|
beforeEach(() => {
|
|
clientManager = new ClientManager();
|
|
signalingService = new SignalingService(clientManager);
|
|
mockWs = new MockWebSocket();
|
|
});
|
|
|
|
test("should handle publisher connection", () => {
|
|
const clientId = signalingService.handleConnection(mockWs, "publisher");
|
|
|
|
expect(typeof clientId).toBe("string");
|
|
expect(clientId.length).toBeGreaterThan(0);
|
|
expect(mockWs.sentMessages[0]).toBe(
|
|
JSON.stringify({
|
|
type: 'join',
|
|
data: { clientId, role: 'publisher' }
|
|
})
|
|
);
|
|
expect(clientManager.getPublisher()?.id).toBe(clientId);
|
|
});
|
|
|
|
test("should handle subscriber connection", () => {
|
|
const clientId = signalingService.handleConnection(mockWs, "subscriber");
|
|
|
|
expect(typeof clientId).toBe("string");
|
|
expect(clientId.length).toBeGreaterThan(0);
|
|
expect(mockWs.sentMessages[0]).toBe(
|
|
JSON.stringify({
|
|
type: 'join',
|
|
data: { clientId, role: 'subscriber' }
|
|
})
|
|
);
|
|
|
|
const subscribers = clientManager.getSubscribers();
|
|
expect(subscribers).toHaveLength(1);
|
|
expect(subscribers[0].id).toBe(clientId);
|
|
});
|
|
|
|
test("should handle disconnection", () => {
|
|
const clientId = signalingService.handleConnection(mockWs, "publisher");
|
|
expect(clientManager.getPublisher()).not.toBeNull();
|
|
|
|
signalingService.handleDisconnection(clientId);
|
|
expect(clientManager.getPublisher()).toBeNull();
|
|
});
|
|
|
|
test("should handle offer from publisher to subscribers", () => {
|
|
// Add publisher
|
|
const publisherId = signalingService.handleConnection(mockWs, "publisher");
|
|
|
|
// Add subscribers
|
|
const subscriber1Ws = new MockWebSocket();
|
|
const subscriber2Ws = new MockWebSocket();
|
|
signalingService.handleConnection(subscriber1Ws, "subscriber");
|
|
signalingService.handleConnection(subscriber2Ws, "subscriber");
|
|
|
|
const offerMessage: ISignalingMessage = {
|
|
type: "offer",
|
|
data: { sdp: "fake-offer-sdp", type: "offer" }
|
|
};
|
|
|
|
signalingService.handleMessage(publisherId, offerMessage);
|
|
|
|
expect(subscriber1Ws.sentMessages).toContain(
|
|
JSON.stringify({
|
|
...offerMessage,
|
|
senderId: publisherId
|
|
})
|
|
);
|
|
expect(subscriber2Ws.sentMessages).toContain(
|
|
JSON.stringify({
|
|
...offerMessage,
|
|
senderId: publisherId
|
|
})
|
|
);
|
|
});
|
|
|
|
test("should handle answer from subscriber to publisher", () => {
|
|
// Add publisher
|
|
const publisherWs = new MockWebSocket();
|
|
const publisherId = signalingService.handleConnection(publisherWs, "publisher");
|
|
|
|
// Add subscriber
|
|
const subscriberWs = new MockWebSocket();
|
|
const subscriberId = signalingService.handleConnection(subscriberWs, "subscriber");
|
|
|
|
const answerMessage: ISignalingMessage = {
|
|
type: "answer",
|
|
data: { sdp: "fake-answer-sdp", type: "answer" }
|
|
};
|
|
|
|
signalingService.handleMessage(subscriberId, answerMessage);
|
|
|
|
expect(publisherWs.sentMessages).toContain(
|
|
JSON.stringify({
|
|
...answerMessage,
|
|
senderId: subscriberId
|
|
})
|
|
);
|
|
});
|
|
|
|
test("should handle ice candidates from publisher to subscribers", () => {
|
|
const publisherId = signalingService.handleConnection(mockWs, "publisher");
|
|
|
|
const subscriberWs = new MockWebSocket();
|
|
signalingService.handleConnection(subscriberWs, "subscriber");
|
|
|
|
const iceCandidateMessage: ISignalingMessage = {
|
|
type: "ice-candidate",
|
|
data: { candidate: "fake-ice-candidate" }
|
|
};
|
|
|
|
signalingService.handleMessage(publisherId, iceCandidateMessage);
|
|
|
|
expect(subscriberWs.sentMessages).toContain(
|
|
JSON.stringify({
|
|
...iceCandidateMessage,
|
|
senderId: publisherId
|
|
})
|
|
);
|
|
});
|
|
|
|
test("should handle ice candidates from subscriber to publisher", () => {
|
|
const publisherWs = new MockWebSocket();
|
|
const publisherId = signalingService.handleConnection(publisherWs, "publisher");
|
|
|
|
const subscriberId = signalingService.handleConnection(mockWs, "subscriber");
|
|
|
|
const iceCandidateMessage: ISignalingMessage = {
|
|
type: "ice-candidate",
|
|
data: { candidate: "fake-ice-candidate" }
|
|
};
|
|
|
|
signalingService.handleMessage(subscriberId, iceCandidateMessage);
|
|
|
|
expect(publisherWs.sentMessages).toContain(
|
|
JSON.stringify({
|
|
...iceCandidateMessage,
|
|
senderId: subscriberId
|
|
})
|
|
);
|
|
});
|
|
|
|
test("should ignore messages from non-existent clients", () => {
|
|
const message: ISignalingMessage = {
|
|
type: "offer",
|
|
data: { sdp: "fake-sdp" }
|
|
};
|
|
|
|
expect(() => {
|
|
signalingService.handleMessage("non-existent-id", message);
|
|
}).not.toThrow();
|
|
});
|
|
}); |