Files
linuxcncWebWASM/web/worker/test_sim_scheduler.mjs

50 lines
2.9 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
import { SimScheduler, SCHEDULER_PHASES } from "./sim-scheduler.mjs";
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
const core = await createModule({ wasmBinary });
const fast = new SimScheduler(core, { budget: 100 });
const stepped = new SimScheduler(core, { budget: 100 });
const seen = [];
fast.step(10, { reconcile: () => seen.push("reconcile"), task: () => seen.push("task"), tp: () => seen.push("tp"), kinematics: () => seen.push("kinematics"), motion: () => seen.push("motion"), hal_io: () => seen.push("hal_io"), callbacks: () => seen.push("callbacks"), publish: () => seen.push("publish") });
for (let index = 0; index < 10; index += 1) stepped.step(1);
assert.equal(fast.tick, 10);
assert.equal(fast.hash(), stepped.hash());
assert.deepEqual(seen.slice(0, 8), SCHEDULER_PHASES);
assert.throws(() => fast.step(101), /scheduler_budget_exceeded/);
assert.equal(fast.tick, 10);
const restored = new SimScheduler(core, { budget: 100 });
assert.equal(restored.restore(fast.export()).state_hash, fast.hash());
const interrupted = new SimScheduler(core, { budget: 100 });
assert.throws(() => interrupted.step(10, { motion: (tick) => { if (tick === 3) throw new Error("injected_motion_fault"); } }), /injected_motion_fault/);
assert.equal(interrupted.tick, 3);
assert.equal(interrupted.last_cycles, 3);
const afterFault = [];
interrupted.step(2, { motion: (tick) => afterFault.push(tick) });
assert.deepEqual(afterFault, [4, 5]);
assert.equal(interrupted.tick, 5);
let lastSeq = 0;
const session = new SimSession({
_sim_protocol_reset() {},
_sim_protocol_accept(...args) { if (args[1] !== lastSeq + 1) return -101; lastSeq = args[1]; return 0; },
_sim_create() { return 0; },
_sim_load_workspace() { return 0; },
_sim_step() { return 0; },
_sim_protocol_set_tick() { return 0; },
}, { sessionId: "scheduler-session" });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: "scheduler-session" };
session.accept({ ...base, kind: "HELLO", seq: 1, payload: {} });
session.accept({ ...base, kind: "SESSION_ATTACH", seq: 2, operation_id: "attach", payload: {} });
session.accept({ ...base, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "load", payload: { root_path: "/workspace" } });
const steppedResponse = session.accept({ ...base, kind: "SIM_STEP", seq: 4, operation_id: "step", payload: { cycles: 4 } });
assert.equal(steppedResponse.payload.scheduler.tick, 4);
assert.deepEqual(steppedResponse.payload.scheduler.phase_trace, [...SCHEDULER_PHASES]);
assert.equal(steppedResponse.payload.task.simulation_tick, 4);
console.log(`sim_scheduler=passed tick=${fast.tick} state_hash=${fast.hash()} worker_hash=${steppedResponse.payload.scheduler.state_hash}`);