runa/vscode/test/fixtures.ts

73 lines
2.5 KiB
TypeScript

import { createServer, Socket } from "node:net";
import { createInterface } from "node:readline";
import { TestContext } from "node:test";
import { stringify } from "lossless-json";
import { ActorSnapshot } 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 } }) + "\n";
}
export async function fakeImage(
t: TestContext,
handle: (request: TestRequest, socket: Socket) => void,
): Promise<string> {
const sockets = new Set<Socket>();
const server = createServer((socket) => {
sockets.add(socket);
socket.on("close", () => sockets.delete(socket));
socket.on("error", () => {
// Transport-failure tests intentionally close a socket while the fixture is writing.
});
const lines = createInterface({ input: socket });
lines.on("line", (line) => handle(JSON.parse(line), socket));
});
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
t.after(async () => {
for (const socket of sockets) socket.destroy();
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}`;
}