79 lines
2.6 KiB
TypeScript
79 lines
2.6 KiB
TypeScript
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?: { actor_ref: string } };
|
|
}
|
|
|
|
export function response(request: TestRequest, reply: unknown): string {
|
|
return json({ version: 3, request_id: request.request_id, result: { Ok: reply } });
|
|
}
|
|
|
|
export async function fakeImage(
|
|
t: TestContext,
|
|
handle: (request: TestRequest, socket: WebSocket) => void,
|
|
protocol = WEBSOCKET_SUBPROTOCOL,
|
|
): Promise<string> {
|
|
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<void>((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: 3, event: { event: "image_changed", data: { revision } } });
|
|
}
|