import { describe, expect, it } from "vitest"; import type { RegexExecutionRequest, RegexExecutionResult, } from "../model/match"; import type { RegexFlavourId } from "../model/flavour"; import { EngineSupervisor } from "./EngineSupervisor"; import { ENGINE_WORKER_REGISTRY, EngineWorkerRegistry, } from "./engine-registry"; import type { WorkerLike } from "./WorkerSupervisor"; import { WORKER_PROTOCOL_VERSION, type EngineWorkerOperation, type EngineWorkerResult, type WorkerRequest, type WorkerResponse, } from "./worker-protocol"; function request(flavour: RegexFlavourId): RegexExecutionRequest { return { flavour, flavourVersion: "fixture", pattern: "a", flags: [], options: {}, subject: "a", captureMetadata: [], scanAll: false, maximumMatches: 10, maximumCaptureRows: 10, }; } function result(flavour: RegexFlavourId): RegexExecutionResult { return { accepted: true, engine: { flavour, adapterVersion: "fixture", engineName: `${flavour} fixture`, engineVersion: "fixture", offsetUnit: "utf16", capabilities: { compilation: true, matching: true, replacement: false, namedCaptures: false, captureHistory: false, actualTrace: false, benchmark: false, }, }, flags: { userFlags: "", effectiveFlags: "", internallyAddedIndicesFlag: false, internallyAddedGlobalFlag: false, }, matches: [], diagnostics: [], elapsedMs: 0, truncated: false, }; } class ResponsiveWorker implements WorkerLike { onmessage: ((event: MessageEvent) => void) | null = null; onerror: ((event: ErrorEvent) => void) | null = null; onmessageerror: ((event: MessageEvent) => void) | null = null; readonly operations: EngineWorkerOperation[] = []; terminateCalls = 0; private readonly flavour: RegexFlavourId; constructor(flavour: RegexFlavourId) { this.flavour = flavour; } postMessage(message: unknown): void { const request = message as WorkerRequest; this.operations.push(request.payload); const payload: EngineWorkerResult = request.payload.kind === "load" ? { kind: "load", info: result(this.flavour).engine, } : request.payload.kind === "execute" ? { kind: "execute", result: result(request.payload.request.flavour), } : { kind: "replace", result: { execution: result(request.payload.request.flavour), output: "", outputBytes: 0, outputTruncated: false, truncated: false, }, }; const response: WorkerResponse = { protocolVersion: WORKER_PROTOCOL_VERSION, requestId: request.requestId, generation: request.generation, ok: true, payload, }; this.onmessage?.({ data: response } as MessageEvent); } terminate(): void { this.terminateCalls += 1; } } class StallingWorker implements WorkerLike { onmessage: ((event: MessageEvent) => void) | null = null; onerror: ((event: ErrorEvent) => void) | null = null; onmessageerror: ((event: MessageEvent) => void) | null = null; readonly operations: EngineWorkerOperation[] = []; terminateCalls = 0; postMessage(message: unknown): void { const request = message as WorkerRequest; this.operations.push(request.payload); } terminate(): void { this.terminateCalls += 1; } } describe("engine worker selection", () => { it("registers every shipped execution worker with a startup budget", () => { expect( ENGINE_WORKER_REGISTRY.registrations.map( (registration) => registration.flavour, ), ).toEqual(["ecmascript", "pcre2", "python", "java"]); expect(ENGINE_WORKER_REGISTRY.require("pcre2").label).toBe("PCRE2 engine"); expect(ENGINE_WORKER_REGISTRY.require("python").startupTimeoutMs).toBe( 30_000, ); }); it("selects and reuses a dedicated supervisor per registered flavour", async () => { const workers = new Map(); const registration = (flavour: RegexFlavourId) => ({ flavour, label: `${flavour} fixture`, startupTimeoutMs: 100, createWorker: () => { const worker = new ResponsiveWorker(flavour); workers.set(flavour, [...(workers.get(flavour) ?? []), worker]); return worker; }, }); const supervisor = new EngineSupervisor( new EngineWorkerRegistry([ registration("ecmascript"), registration("pcre2"), ]), ); await expect( supervisor.execute(request("ecmascript"), 100), ).resolves.toEqual( expect.objectContaining({ engine: expect.objectContaining({ flavour: "ecmascript" }), }), ); await expect(supervisor.execute(request("pcre2"), 100)).resolves.toEqual( expect.objectContaining({ engine: expect.objectContaining({ flavour: "pcre2" }), }), ); await supervisor.execute(request("ecmascript"), 100); expect(workers.get("ecmascript")).toHaveLength(1); expect(workers.get("pcre2")).toHaveLength(1); expect( workers .get("ecmascript")?.[0] ?.operations.map((operation) => operation.kind), ).toEqual(["load", "execute", "execute"]); expect( workers.get("pcre2")?.[0]?.operations.map((operation) => operation.kind), ).toEqual(["load", "execute"]); supervisor.dispose(); expect(workers.get("ecmascript")?.[0]?.terminateCalls).toBe(1); expect(workers.get("pcre2")?.[0]?.terminateCalls).toBe(1); }); it("fails closed before constructing a worker for an unavailable flavour", async () => { const supervisor = new EngineSupervisor(new EngineWorkerRegistry([])); await expect(supervisor.execute(request("pcre2"), 100)).rejects.toThrow( /No execution worker is registered/u, ); supervisor.dispose(); }); it("lets the newest request supersede a shared ready-engine continuation", async () => { const worker = new ResponsiveWorker("python"); const supervisor = new EngineSupervisor( new EngineWorkerRegistry([ { flavour: "python", label: "Python fixture", startupTimeoutMs: 100, createWorker: () => worker, }, ]), ); await supervisor.load("python"); const older = supervisor.execute(request("python"), 100); const newer = supervisor.execute(request("python"), 100); await expect(older).rejects.toMatchObject({ kind: "cancelled" }); await expect(newer).resolves.toEqual( expect.objectContaining({ engine: expect.objectContaining({ flavour: "python" }), }), ); expect(worker.operations.map((operation) => operation.kind)).toEqual([ "load", "execute", ]); supervisor.dispose(); }); it("restarts a superseded cold runtime under the startup budget before execution", async () => { const coldWorker = new StallingWorker(); const readyWorker = new ResponsiveWorker("python"); let factoryCalls = 0; const supervisor = new EngineSupervisor( new EngineWorkerRegistry([ { flavour: "python", label: "Python fixture", startupTimeoutMs: 100, createWorker: () => { factoryCalls += 1; return factoryCalls === 1 ? coldWorker : readyWorker; }, }, ]), ); const older = supervisor.execute(request("python"), 1); const newer = supervisor.execute(request("python"), 1); await expect(older).rejects.toMatchObject({ kind: "cancelled" }); await expect(newer).resolves.toEqual( expect.objectContaining({ engine: expect.objectContaining({ flavour: "python" }), }), ); expect(coldWorker.operations.map((operation) => operation.kind)).toEqual([ "load", ]); expect(coldWorker.terminateCalls).toBe(1); expect(readyWorker.operations.map((operation) => operation.kind)).toEqual([ "load", "execute", ]); supervisor.dispose(); }); });