import type { RelayOptions } from "./relay"; import { type RelayPool, initRelayPool } from "./relayPool"; import { assert, afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { WS } from "vitest-websocket-mock"; import WebSocket from "ws"; import { setTimeout as delay } from "node:timers/promises"; vi.mock("ws"); class MockRelayServer { #ws: WS; connected = false; url: string; #setupMockWS(rurl: string): WS { const ws = new WS(rurl); ws.on("connection", () => { this.connected = true; }); ws.on("close", () => { this.connected = false; }); return ws; } constructor(relayUrl: string) { this.url = relayUrl; this.#ws = this.#setupMockWS(relayUrl); } async closeFromServer() { this.#ws.close(); await this.#ws.closed; // refresh mock server so that client can connect again this.#ws = this.#setupMockWS(this.url); } } describe("RelayPool", () => { const opts: RelayOptions = { connectTimeoutMs: 1000, webSocketConstructor: WebSocket }; let pool: RelayPool; beforeEach(() => { pool = initRelayPool({ minLogLevel: "none", webSocketConstructor: WebSocket }); }); afterEach(() => { WS.clean(); }); test("normal case", async () => { const url1 = "ws://localhost:8001/"; const url2 = "ws://localhost:8002/"; // setup mock relay server const srv1 = new MockRelayServer(url1); const srv2 = new MockRelayServer(url2); // ensure connections to the relays const ensuredRelays1 = await pool.ensureRelays([url1, url2], opts); expect(ensuredRelays1).toEqual(expect.arrayContaining([url1, url2])); assert(srv1.connected && srv2.connected); await expect(pool.ensureSingleRelay(url1, opts)).resolves.toBeDefined(); await expect(pool.ensureSingleRelay(url2, opts)).resolves.toBeDefined(); // close connections from relays await srv1.closeFromServer(); await srv2.closeFromServer(); // ensuring a connection to single relay await expect(pool.ensureSingleRelay(url1, opts)).resolves.toBeDefined(); assert(srv1.connected && !srv2.connected); // close the connection again await srv1.closeFromServer(); // ensuring connections again const ensuredRelays2 = await pool.ensureRelays([url1, url2], opts); expect(ensuredRelays2).toEqual(expect.arrayContaining([url1, url2])); assert(srv1.connected && srv2.connected); // shutdown closes connections to the all relays pool.shutdown(); await delay(1000); assert(!srv1.connected && !srv2.connected); }); test("connection error", async () => { const url = "ws://localhost:8000/"; const ensuredRelays1 = await pool.ensureRelays([url], { connectTimeoutMs: 1000, webSocketConstructor: WebSocket, }); expect(ensuredRelays1).toEqual([]); // TODO: test behavior around reconnection cool time }); });