Files
linuxcncWebWASM/web/worker/test_source_parity_s5.mjs

88 lines
4.4 KiB
JavaScript

import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
import { compareEndpoints, createEndpoint, endpointHash } from "./endpoint-replay.mjs";
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
const ROOT = new URL("../../", import.meta.url);
const SOURCE_REPORTS = [
"coverage/linuxcnc-source-test-s5.report.json",
"coverage/linuxcnc-source-test-execution-s5.report.json",
"coverage/linuxcnc-source-unit-execution-s5.report.json",
"coverage/linuxcnc-source-interp-s5.report.json",
"coverage/linuxcnc-source-hal-s5.report.json",
"coverage/linuxcnc-source-io-s5.report.json",
"coverage/linuxcnc-source-config-s5.report.json",
];
async function loadReports() {
const reports = [];
for (const path of SOURCE_REPORTS) {
const bytes = await readFile(new URL(path, ROOT));
const report = JSON.parse(bytes);
assert.equal(report.status, "verified", path);
reports.push({ path, task_id: report.task_id, schema: report.schema, sha256: createHash("sha256").update(bytes).digest("hex") });
}
return reports;
}
async function sessionWithPlan(id, fast = false) {
const wasmBinary = await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url));
const core = await createModule({ wasmBinary });
const session = new SimSession(core, { sessionId: id });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: id };
let sequence = 0;
const send = (kind, operationId, payload = {}) => {
sequence += 1;
const response = session.accept({ ...base, kind, seq: sequence, operation_id: operationId, payload });
assert.notEqual(response.kind, "ERROR", `${id}:${kind}:${response.payload?.code ?? "error"}`);
return response;
};
send("HELLO", "hello");
send("SESSION_ATTACH", "attach");
send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace" });
send("PROGRAM_LOAD", "program", { source: "G0 X1\nG1 X2\n", path: "parity.ngc" });
send("PROGRAM_RUN", "run");
if (fast) send("SIM_STEP", "fast-step", { cycles: 4 });
else for (let index = 0; index < 4; index += 1) send("SIM_STEP", `step-${index}`, { cycles: 1 });
return { session, send };
}
const sourceReports = await loadReports();
const oneX = await sessionWithPlan("source-parity-1x", false);
const fast = await sessionWithPlan("source-parity-fast", true);
const oneEndpoint = createEndpoint({ session: oneX.session });
const fastEndpoint = createEndpoint({ session: fast.session });
const modeParity = compareEndpoints(oneEndpoint, fastEndpoint);
assert.equal(modeParity.equal, true);
const recovering = await sessionWithPlan("source-parity-recover", false);
const checkpoint = recovering.send("CHECKPOINT", "checkpoint").payload.checkpoint;
recovering.send("SIM_STEP", "post-checkpoint", { cycles: 2 });
const continuousEndpoint = createEndpoint({ session: recovering.session });
const recovery = recovering.session.restoreCheckpoint(checkpoint, recovering.session.timeline.export(), (operation) => operation);
assert.equal(recovery.status, "recovered");
const recoveredEndpoint = createEndpoint({ session: recovering.session });
const recoveryParity = compareEndpoints(continuousEndpoint, recoveredEndpoint);
assert.equal(recoveryParity.equal, true);
const trace = recovering.session.exportTrace();
const traceCore = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) });
const traceSession = new SimSession(traceCore, { sessionId: "source-parity-recover" });
const imported = traceSession.importTrace(trace);
assert.equal(imported.trace_hash, trace.trace_hash);
const traceParity = compareEndpoints(recoveredEndpoint, createEndpoint({ session: traceSession }));
assert.equal(traceParity.equal, true);
const output = {
schema: "linuxcnc-source-parity-s5.v1",
context_id: CONTEXT_ID,
source_reports: sourceReports,
modes: { one_x: endpointHash(oneEndpoint), fast: endpointHash(fastEndpoint) },
differences: { first_divergence: null, mode: modeParity, recovery: recoveryParity, trace_import: traceParity },
recovery: { checkpoint_hash: checkpoint.checkpoint_hash, continuous_hash: endpointHash(continuousEndpoint), recovered_hash: endpointHash(recoveredEndpoint), trace_hash: trace.trace_hash, status: recovery.status },
status: "verified",
};
console.log(JSON.stringify(output));