69 lines
4.3 KiB
JavaScript
69 lines
4.3 KiB
JavaScript
import assert from "node:assert/strict";
|
|
import { SimSession, CONTEXT_ID } from "./sim-session.mjs";
|
|
import { MemoryStorage, WorkspaceJournal } from "../workspace/journal.mjs";
|
|
import { createWorkspacePackage, migrateWorkspacePackage, verifyWorkspacePackage } from "../workspace/migration.mjs";
|
|
import { fnv1a64 } from "./replay.mjs";
|
|
|
|
let lastSeq = 0;
|
|
const core = {
|
|
_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; },
|
|
};
|
|
const session = new SimSession(core);
|
|
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: "workspace-session-1" };
|
|
const config = { entrypoint: "linuxcnc/configs/sim/demo/main.ini", availablePaths: ["linuxcnc/configs/sim/demo/main.ini"], rows: [] };
|
|
const hal = { manifest: [{ component: "demo" }], lines: ["loadrt demo names=d0", "addf d0 servo-thread"] };
|
|
assert.equal(session.accept({ ...base, kind: "HELLO", seq: 1, payload: {} }).kind, "CAPABILITIES");
|
|
assert.equal(session.accept({ ...base, kind: "SESSION_ATTACH", seq: 2, payload: {} }).kind, "SESSION_READY");
|
|
assert.equal(session.accept({ ...base, kind: "LOAD_WORKSPACE", seq: 3, operation_id: "load", payload: { root_path: "/workspace", configuration: config, hal } }).payload.status, "verified");
|
|
session.accept({ ...base, kind: "SPINDLE_COMMAND", seq: 4, operation_id: "spindle", payload: { spindle: 0, rpm: 600, enabled: true } });
|
|
session.accept({ ...base, kind: "IO_STEP", seq: 5, operation_id: "step-1", payload: { ticks: 5 } });
|
|
const checkpointResponse = session.accept({ ...base, kind: "CHECKPOINT", seq: 6, operation_id: "checkpoint", payload: {} });
|
|
assert.equal(checkpointResponse.kind, "CHECKPOINT_READY");
|
|
const checkpoint = checkpointResponse.payload.checkpoint;
|
|
assert.equal(checkpoint.state.configuration.status, "ready");
|
|
assert.equal(checkpoint.state.hal.status, "ready");
|
|
assert.ok(checkpoint.state.devices);
|
|
session.accept({ ...base, kind: "TOOL_PREPARE", seq: 7, operation_id: "tool", payload: { tool: 7, pocket: 3 } });
|
|
session.accept({ ...base, kind: "TOOL_PREPARED", seq: 8, operation_id: "tool-prepared", payload: { prepared: true } });
|
|
session.accept({ ...base, kind: "SPINDLE_COMMAND", seq: 9, operation_id: "spindle-stop", payload: { spindle: 0, rpm: 0, enabled: false } });
|
|
session.accept({ ...base, kind: "IO_STEP", seq: 10, operation_id: "step-2", payload: { ticks: 10 } });
|
|
session.accept({ ...base, kind: "TOOL_CHANGE", seq: 11, operation_id: "change", payload: {} });
|
|
session.accept({ ...base, kind: "TOOL_CHANGED", seq: 12, operation_id: "changed", payload: { changed: true } });
|
|
const expectedState = session.workspacePackageState();
|
|
const recovery = session.restoreCheckpoint(checkpoint, session.timeline.export(), (operation) => operation);
|
|
assert.equal(recovery.status, "recovered");
|
|
assert.equal(session.workspacePackageState().state_hash, expectedState.state_hash);
|
|
|
|
const storage = new MemoryStorage();
|
|
const journal = new WorkspaceJournal(storage, { projectId: "workspace-session" });
|
|
journal.prepare("op-config", [{ path: "config/main.ini", data: "[EMC]\n" }]);
|
|
journal.commit("op-config");
|
|
const timeline = session.timeline;
|
|
const packageV1 = createWorkspacePackage({ contextId: CONTEXT_ID, timeline, checkpoint, journal: journal.records(), committedSeq: journal.records().at(-1).commit_seq });
|
|
const packageV2 = migrateWorkspacePackage(packageV1, 2);
|
|
const roundTrip = migrateWorkspacePackage(packageV2, 1);
|
|
assert.equal(verifyWorkspacePackage(packageV2, { contextId: CONTEXT_ID, expectedVersion: 2 }).format_version, 2);
|
|
assert.deepEqual(roundTrip, packageV1);
|
|
|
|
const report = {
|
|
schema: "workspace-session-integration-sample.v1",
|
|
context_id: CONTEXT_ID,
|
|
session_state_hash: expectedState.state_hash,
|
|
recovery_state_hash: session.workspacePackageState().state_hash,
|
|
checkpoint_hash: checkpoint.checkpoint_hash,
|
|
package_v1_hash: packageV1.package_hash,
|
|
package_v2_hash: packageV2.package_hash,
|
|
round_trip_equal: roundTrip.package_hash === packageV1.package_hash,
|
|
event_cursor: session.timeline.events.cursor,
|
|
journal_hash: fnv1a64(journal.records()),
|
|
operation_count: session.operations.size,
|
|
};
|
|
assert.equal(report.session_state_hash, report.recovery_state_hash);
|
|
assert.equal(report.round_trip_equal, true);
|
|
console.log(JSON.stringify(report));
|