Files
linuxcncWebWASM/web/worker/test_configuration_startup_runtime.mjs

89 lines
5.5 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
import { WorkspaceRuntime } from "../workspace/runtime.mjs";
import { ConfigurationStartupStateMachine, startConfiguration } from "../workspace/configuration.mjs";
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
const files = {
"config/main.ini": "[HAL]\nHALFILE = machine.hal\n[RS274NGC]\nPROGRAM = main.ngc\n",
"config/machine.hal": "setp sim.x 1\n",
"config/main.ngc": "G0 X1\n",
};
const manifest = [{ component: "sim" }];
const nativeCalls = [];
let nativeSeq = 0;
const nativeCore = {
_sim_create() { nativeCalls.push("create"); return 0; },
_sim_load_workspace(path) { nativeCalls.push(`load:${path}`); return 0; },
};
const native = startConfiguration({ workspace: new WorkspaceRuntime({ files }), entrypoint: "config/main.ini", core: nativeCore, halManifest: manifest });
const nativeAgain = startConfiguration({ workspace: new WorkspaceRuntime({ files }), entrypoint: "config/main.ini", core: nativeCore, halManifest: manifest });
assert.equal(native.state, "TASK_READY");
assert.equal(native.status, "ready");
assert.equal(native.state_hash, nativeAgain.state_hash);
assert.deepEqual(native.transitions.map((row) => row.to), ["NEW", "MOUNTED", "PARSED", "RESOLVED", "CORE_CREATED", "HAL_READY", "TASK_READY"]);
assert.deepEqual(nativeCalls, ["create", "load:/workspace", "create", "load:/workspace"]);
const wasm = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) });
const wasmReport = startConfiguration({ workspace: new WorkspaceRuntime({ files }), entrypoint: "config/main.ini", core: wasm, halManifest: manifest });
assert.equal(wasmReport.state, "TASK_READY");
assert.equal(wasmReport.state_hash, native.state_hash);
const missing = startConfiguration({ workspace: new WorkspaceRuntime({ files: { "config/main.ini": "[HAL]\nHALFILE = missing.hal\n" } }), entrypoint: "config/main.ini", core: nativeCore });
assert.equal(missing.status, "blocked");
assert.equal(missing.state, "BLOCKED");
assert.equal(missing.diagnostics[0].source, "config/main.ini");
assert.equal(missing.diagnostics[0].line, 2);
assert.equal(missing.resources.resources[0].code, "resource_missing");
const duplicate = startConfiguration({ workspace: new WorkspaceRuntime({ files: { ...files, "config/duplicate.ini": "[HAL]\nHALFILE = machine.hal\nHALFILE = machine.hal\n" } }), entrypoint: "config/duplicate.ini", core: nativeCore });
assert.equal(duplicate.status, "blocked");
assert.ok(duplicate.resources.resources.some((row) => row.code === "resource_duplicate"));
const hostPath = startConfiguration({ workspace: new WorkspaceRuntime({ files: { "config/main.ini": "[HAL]\nHALFILE = /tmp/machine.hal\n" } }), entrypoint: "config/main.ini", core: nativeCore });
assert.equal(hostPath.status, "blocked");
assert.equal(hostPath.resources.resources[0].code, "resource_host_path");
const ambiguous = startConfiguration({ workspace: new WorkspaceRuntime({ files: {
"config/main.ini": "[HAL]\nHALFILE = LIB:machine.hal\n",
"linuxcnc/lib/machine.hal": "setp sim.x 1\n",
"linuxcnc/lib/hallib/machine.hal": "setp sim.x 2\n",
} }), entrypoint: "config/main.ini", core: nativeCore });
assert.equal(ambiguous.status, "blocked");
assert.equal(ambiguous.resources.resources[0].code, "resource_ambiguous");
const unsupportedHal = startConfiguration({ workspace: new WorkspaceRuntime({ files: { "config/main.ini": "[HAL]\nHALFILE = machine.hal\n", "config/machine.hal": "loadrt unknown names=u\n" } }), entrypoint: "config/main.ini", core: nativeCore, halManifest: [] });
assert.equal(unsupportedHal.status, "blocked");
assert.equal(unsupportedHal.diagnostics[0].source, "config/machine.hal");
assert.equal(unsupportedHal.diagnostics[0].line, 1);
assert.equal(unsupportedHal.diagnostics[0].hal.records[0].code, "hal_component_undeclared");
let workerSeq = 0;
const workerCore = {
_sim_protocol_reset() {},
_sim_protocol_accept(...args) { if (args[1] !== workerSeq + 1) return -101; workerSeq = args[1]; return 0; },
_sim_create() { return 0; },
_sim_load_workspace() { return 0; },
};
const session = new SimSession(workerCore, { sessionId: "startup-session" });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: "startup-session" };
assert.equal(session.accept({ ...base, kind: "HELLO", seq: 1, payload: {} }).kind, "CAPABILITIES");
assert.equal(session.accept({ ...base, kind: "SESSION_ATTACH", seq: 2, operation_id: "attach", payload: {} }).kind, "SESSION_READY");
const workerResult = session.accept({ ...base, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "startup", payload: {
root_path: "/workspace",
configuration: { entrypoint: "config/main.ini", files, halManifest: manifest },
} });
assert.equal(workerResult.kind, "COMMAND_RESULT");
assert.equal(workerResult.payload.configuration.state, "TASK_READY");
assert.equal(workerResult.payload.configuration.state_hash, native.state_hash);
const workerBlocked = session.accept({ ...base, kind: "LOAD_WORKSPACE", seq: 4, operation_id: "blocked", payload: {
root_path: "/workspace",
configuration: { entrypoint: "config/main.ini", files: { "config/main.ini": "[HAL]\nHALFILE = missing.hal\n" } },
} });
assert.equal(workerBlocked.kind, "ERROR");
assert.equal(workerBlocked.payload.code, "configuration_startup");
assert.equal(workerBlocked.payload.startup.state, "BLOCKED");
console.log(`configuration_startup_runtime=passed state_hash=${native.state_hash} resource_hash=${native.resources.state_hash}`);