Files
linuxcncWebWASM/web/worker/test_sim_task.mjs

73 lines
4.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 { SimSession, CONTEXT_ID } from "./sim-session.mjs";
import { fnv1a64 } from "./replay.mjs";
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
function base(sessionId) {
return { schema_version: 1, context_id: CONTEXT_ID, session_id: sessionId };
}
async function createSession(sessionId) {
const core = await createModule({ wasmBinary });
const session = new SimSession(core, { sessionId });
const prefix = base(sessionId);
assert.equal(session.accept({ ...prefix, kind: "HELLO", seq: 1, payload: {} }).kind, "CAPABILITIES");
const ready = session.accept({ ...prefix, kind: "SESSION_ATTACH", seq: 2, operation_id: `${sessionId}-attach`, payload: {} });
assert.equal(ready.kind, "SESSION_READY");
assert.equal(ready.payload.task.schema, "sim_task.v1");
assert.equal(ready.payload.task.state, "READY");
assert.equal(ready.payload.task.seq, 2);
return { core, session, prefix };
}
const first = await createSession("task-a");
const { session, prefix } = first;
let response = session.accept({ ...prefix, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "load", payload: { root_path: "/workspace" } });
assert.equal(response.payload.task.state, "READY");
response = session.accept({ ...prefix, kind: "PROGRAM_LOAD", seq: 4, operation_id: "program-load", payload: { path: "task.ngc", source: "G21 G90\nG1 X2 F60\nM2\n" } });
assert.equal(response.payload.task.program_status, "loaded");
response = session.accept({ ...prefix, kind: "PROGRAM_RUN", seq: 5, operation_id: "program-run", payload: {} });
assert.equal(response.payload.task.state, "RUNNING");
response = session.accept({ ...prefix, kind: "SIM_STEP", seq: 6, operation_id: "tick-1", payload: { cycles: 1 } });
assert.equal(response.payload.task.simulation_tick, 1);
const firstTickHash = response.payload.task.state_hash;
response = session.accept({ ...prefix, kind: "PROGRAM_PAUSE", seq: 7, operation_id: "pause", payload: {} });
assert.equal(response.payload.task.state, "PAUSED");
response = session.accept({ ...prefix, kind: "PROGRAM_RESUME", seq: 8, operation_id: "resume", payload: {} });
assert.equal(response.payload.task.state, "RUNNING");
response = session.accept({ ...prefix, kind: "PROGRAM_ABORT", seq: 9, operation_id: "abort", payload: {} });
assert.equal(response.payload.task.state, "STOPPED");
assert.equal(response.payload.task.program_status, "aborted");
const checkpointResponse = session.accept({ ...prefix, kind: "CHECKPOINT", seq: 10, operation_id: "checkpoint", payload: {} });
assert.equal(checkpointResponse.kind, "CHECKPOINT_READY");
assert.equal(checkpointResponse.payload.checkpoint.state.task.schema, "sim_task.v1");
const checkpoint = checkpointResponse.payload.checkpoint;
const recovered = session.restoreCheckpoint(checkpoint, null, (operation) => operation);
assert.equal(recovered.status, "recovered");
assert.equal(recovered.state.task.state, "STOPPED");
assert.equal(recovered.state.task.state_hash, checkpoint.state.task.state_hash);
const faultSession = await createSession("task-fault");
const faultBase = faultSession.prefix;
faultSession.session.accept({ ...faultBase, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "fault-load", payload: { root_path: "/workspace" } });
faultSession.session.accept({ ...faultBase, kind: "PROGRAM_LOAD", seq: 4, operation_id: "fault-program", payload: { source: "G21\nG1 X1\n" } });
faultSession.session.accept({ ...faultBase, kind: "PROGRAM_RUN", seq: 5, operation_id: "fault-run", payload: {} });
const estop = faultSession.session.accept({ ...faultBase, kind: "ESTOP", seq: 6, operation_id: "estop", payload: { active: true } });
assert.equal(estop.payload.task.state, "ESTOP");
faultSession.session.accept({ ...faultBase, kind: "ESTOP", seq: 7, operation_id: "estop-clear", payload: { active: false } });
const recoveredIo = faultSession.session.accept({ ...faultBase, kind: "IO_RECOVER", seq: 8, operation_id: "io-recover", payload: {} });
assert.equal(recoveredIo.payload.task.state, "READY");
const second = await createSession("task-a");
second.session.accept({ ...second.prefix, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "load", payload: { root_path: "/workspace" } });
second.session.accept({ ...second.prefix, kind: "PROGRAM_LOAD", seq: 4, operation_id: "program-load", payload: { path: "task.ngc", source: "G21 G90\nG1 X2 F60\nM2\n" } });
second.session.accept({ ...second.prefix, kind: "PROGRAM_RUN", seq: 5, operation_id: "program-run", payload: {} });
const secondTick = second.session.accept({ ...second.prefix, kind: "SIM_STEP", seq: 6, operation_id: "tick-1", payload: { cycles: 1 } });
assert.equal(secondTick.payload.task.state_hash, firstTickHash);
console.log(`sim_task=passed state=${recovered.state.task.state} tick_hash=${firstTickHash} recovery_hash=${recovered.state.task.state_hash}`);