import { once } from "node:events"; import WebSocket, { WebSocketServer } from "ws"; import { TestContext } from "node:test"; import { stringify } from "lossless-json"; import { ActorSnapshot, WEBSOCKET_SUBPROTOCOL } from "../src/protocol"; export const REF = "abcdefghijklmnopqrstu"; export function actor(): ActorSnapshot { return { actor_ref: REF, mailbox_id: 18446744073709551615n, implementation_id: "implementation:test", incarnation: 1n, state: { type: "record", data: { minimum: { type: "integer", data: -9223372036854775808n }, maximum: { type: "integer", data: 9223372036854775807n }, reference: { type: "actor_ref", data: REF }, text: { type: "string", data: `@${REF} "雪"` }, list: { type: "list", data: [{ type: "null" }, { type: "bool", data: true }] }, }, }, status: { status: "paused" }, execution: { vm_steps: 20n, instruction_pointer: 12n, call_depth: 1n }, queued: [{ type: "bool", data: false }], reserved: { type: "null" }, }; } export function json(value: unknown): string { const result = stringify(value); if (result === undefined) throw new Error("Cannot encode test fixture"); return result; } export interface TestRequest { version: number; request_id: string; command: { operation: string; parameters?: Record }; } export function response(request: TestRequest, reply: unknown): string { return json({ version: 4, request_id: request.request_id, result: { Ok: reply } }); } export async function fakeImage( t: TestContext, handle: (request: TestRequest, socket: WebSocket) => void, protocol = WEBSOCKET_SUBPROTOCOL, ): Promise { const server = new WebSocketServer({ host: "127.0.0.1", port: 0, handleProtocols: (offered) => (offered.has(protocol) ? protocol : false), }); server.on("connection", (socket) => { socket.on("error", () => { // Transport-failure tests intentionally close a socket while the fixture is writing. }); socket.on("message", (data) => handle(JSON.parse(data.toString()), socket)); }); await once(server, "listening"); t.after(async () => { for (const socket of server.clients) socket.terminate(); await new Promise((resolve, reject) => server.close((error) => (error ? reject(error) : resolve())), ); }); const address = server.address(); if (!address || typeof address === "string") throw new Error("Missing test listener"); return `127.0.0.1:${address.port}`; } export function notification(revision: bigint): string { return json({ version: 4, event: { event: "image_changed", data: { revision } } }); }