Complete sim config boundary coverage
This commit is contained in:
8648
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs
Normal file
8648
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs
Normal file
File diff suppressed because it is too large
Load Diff
45
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
Executable file
45
wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh
Executable file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../../.." && pwd)"
|
||||
NATIVE_SUMMARY="$ROOT_DIR/build/native/sim-configs/summary.tsv"
|
||||
NATIVE_CLASS_SUMMARY="$ROOT_DIR/build/native/sim-configs/class-summary.tsv"
|
||||
NATIVE_PATH_MATRIX="$ROOT_DIR/build/native/sim-configs/path-matrix.tsv"
|
||||
NATIVE_SOURCE_PROOF_SUMMARY="$ROOT_DIR/build/native/native-source-proof-summary.tsv"
|
||||
NATIVE_BUILD_DIR="$ROOT_DIR/build/native/sim-configs"
|
||||
NATIVE_SOURCE_PROOF_INPUTS=(
|
||||
"$ROOT_DIR/tools/build_native_probes.sh"
|
||||
"$ROOT_DIR/tools/source-manifest.txt"
|
||||
"$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_millturn_user_m_boundary_probe.cpp"
|
||||
"$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_tool_db_boundary_probe.cpp"
|
||||
"$ROOT_DIR/runtime/core/linuxcnc_wrap/linuxcnc_python_remap_boundary_probe.cpp"
|
||||
)
|
||||
|
||||
native_source_proof_refresh_required() {
|
||||
if [[ ! -f "$NATIVE_SOURCE_PROOF_SUMMARY" ]]; then
|
||||
return 0
|
||||
fi
|
||||
for input in "${NATIVE_SOURCE_PROOF_INPUTS[@]}"; do
|
||||
if [[ "$input" -nt "$NATIVE_SOURCE_PROOF_SUMMARY" ]]; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
if [[ ! -f "$NATIVE_SUMMARY" || ! -f "$NATIVE_CLASS_SUMMARY" || ! -f "$NATIVE_PATH_MATRIX" ]]; then
|
||||
"$ROOT_DIR/tests/native/verify_sim_configs.sh"
|
||||
fi
|
||||
if native_source_proof_refresh_required; then
|
||||
"$ROOT_DIR/tools/build_native_probes.sh"
|
||||
fi
|
||||
|
||||
mkdir -p "$NATIVE_BUILD_DIR"
|
||||
exec 9>"$NATIVE_BUILD_DIR/inventory.lock"
|
||||
flock 9
|
||||
|
||||
if [[ "${SKIP_INTERP_BUILD:-0}" != "1" ]]; then
|
||||
"$ROOT_DIR/tools/build_wasm_core.sh"
|
||||
fi
|
||||
|
||||
node "$ROOT_DIR/tests/wasm/node/verify_sim_configs_inventory_wasm.mjs"
|
||||
@@ -4,6 +4,7 @@ import { dirname, resolve } from "node:path";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import {
|
||||
analyzeIniRuntimeBoundaries,
|
||||
createLinuxCncInterpSdk,
|
||||
planIniFileContextStaging,
|
||||
planSimConfigStaging,
|
||||
@@ -46,6 +47,10 @@ const interp = await createLinuxCncInterpSdk({
|
||||
},
|
||||
});
|
||||
|
||||
function readSimIni(machineRel, iniFile) {
|
||||
return readFileSync(resolve(vendorRoot, `configs/sim/${machineRel}/${iniFile}`), "utf8");
|
||||
}
|
||||
|
||||
const syntheticPlan = planSimConfigStaging({
|
||||
manifestText: [
|
||||
"configs/sim/example/test.ini",
|
||||
@@ -80,6 +85,80 @@ assert.deepEqual(
|
||||
],
|
||||
"synthetic sim-config staging plan",
|
||||
);
|
||||
|
||||
const syntheticBoundary = analyzeIniRuntimeBoundaries({
|
||||
manifestText: [
|
||||
"configs/sim/example/test.ini",
|
||||
"configs/sim/example/test.ngc",
|
||||
"configs/sim/example/tool.tbl",
|
||||
"configs/sim/example/M123",
|
||||
].join("\n"),
|
||||
sourceRootRel: "configs/sim/example",
|
||||
sourceSearchRootRel: "configs/sim",
|
||||
iniFile: "test.ini",
|
||||
iniText: [
|
||||
"[DISPLAY]",
|
||||
"DISPLAY = axis",
|
||||
"OPEN_FILE = test.ngc",
|
||||
"[RS274NGC]",
|
||||
"USER_M_PATH = .",
|
||||
"[EMCIO]",
|
||||
"TOOL_TABLE = tool.tbl",
|
||||
].join("\n"),
|
||||
});
|
||||
assert.deepEqual(
|
||||
syntheticBoundary,
|
||||
{
|
||||
dependencies: [],
|
||||
recommendedBlockedKind: "-",
|
||||
toolDatabaseProgram: "",
|
||||
halRuntime: { values: [], requiresProcess: false },
|
||||
uiRuntime: { values: ["axis"], requiresProcess: false },
|
||||
haluiRuntime: { mdiCommands: [], requiresProcess: false },
|
||||
userMRuntime: {
|
||||
paths: ["."],
|
||||
vendoredExecutableCount: 1,
|
||||
executionCodes: [],
|
||||
unstagedExecutionCodes: [],
|
||||
requiresExternalProcess: false,
|
||||
},
|
||||
pythonRuntime: { references: [], remapReferences: [], uiReferences: [], requiresProcess: false },
|
||||
},
|
||||
"synthetic runtime-boundary analysis",
|
||||
);
|
||||
|
||||
const mixedUserMBoundary = analyzeIniRuntimeBoundaries({
|
||||
manifestText: [
|
||||
"configs/sim/example/test.ini",
|
||||
"configs/sim/example/test.ngc",
|
||||
"configs/sim/example/M123",
|
||||
].join("\n"),
|
||||
sourceRootRel: "configs/sim/example",
|
||||
sourceSearchRootRel: "configs/sim",
|
||||
iniFile: "test.ini",
|
||||
iniText: [
|
||||
"[DISPLAY]",
|
||||
"DISPLAY = axis",
|
||||
"[RS274NGC]",
|
||||
"USER_M_PATH = .",
|
||||
].join("\n"),
|
||||
executionTexts: ["M123\nM124\n"],
|
||||
});
|
||||
assert.equal(
|
||||
mixedUserMBoundary.recommendedBlockedKind,
|
||||
"L4-USER-M-PROCESS",
|
||||
"mixed vendored and unstaged user-M calls must block",
|
||||
);
|
||||
assert.deepEqual(
|
||||
mixedUserMBoundary.userMRuntime.executionCodes,
|
||||
["M123", "M124"],
|
||||
"mixed user-M execution codes",
|
||||
);
|
||||
assert.deepEqual(
|
||||
mixedUserMBoundary.userMRuntime.unstagedExecutionCodes,
|
||||
["M124"],
|
||||
"only unstaged user-M execution codes require the external process boundary",
|
||||
);
|
||||
assert.deepEqual(
|
||||
syntheticPlan.files.map((file) => [file.sourceRel, file.wasmPath]).sort(),
|
||||
[
|
||||
@@ -134,6 +213,111 @@ assert.deepEqual(
|
||||
"generic INI file-context staging plan",
|
||||
);
|
||||
|
||||
function simBoundary(machineRel, iniFile, executionRelFiles = []) {
|
||||
return analyzeIniRuntimeBoundaries({
|
||||
manifestText,
|
||||
sourceRootRel: `configs/sim/${machineRel}`,
|
||||
sourceSearchRootRel: "configs/sim",
|
||||
iniFile,
|
||||
iniText: readSimIni(machineRel, iniFile),
|
||||
executionTexts: executionRelFiles.map((relFile) =>
|
||||
readFileSync(resolve(vendorRoot, `configs/sim/${machineRel}/${relFile}`), "utf8"),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
const dbDemoBoundary = simBoundary("axis/db_demo", "db_nonran.ini");
|
||||
assert.deepEqual(
|
||||
dbDemoBoundary.dependencies,
|
||||
["python_runtime", "tool_database_process"],
|
||||
"db_demo tool database boundary dependencies",
|
||||
);
|
||||
assert.equal(dbDemoBoundary.recommendedBlockedKind, "L4-TOOL-DB", "db_demo blocked kind");
|
||||
assert.equal(dbDemoBoundary.toolDatabaseProgram, "./db_nonran.py", "db_demo DB_PROGRAM");
|
||||
assert.deepEqual(
|
||||
dbDemoBoundary.pythonRuntime.uiReferences,
|
||||
["./db_nonran.py"],
|
||||
"db_demo Python dependency is the DB program process",
|
||||
);
|
||||
assert.deepEqual(
|
||||
dbDemoBoundary.pythonRuntime.remapReferences,
|
||||
[],
|
||||
"db_demo does not declare Python remap runtime",
|
||||
);
|
||||
|
||||
const millturnBoundary = simBoundary("axis/vismach/millturn", "millturn.ini", [
|
||||
"example.ngc",
|
||||
"remap_subs/428remap.ngc",
|
||||
"remap_subs/429remap.ngc",
|
||||
]);
|
||||
assert.equal(
|
||||
millturnBoundary.recommendedBlockedKind,
|
||||
"L4-USER-M-PROCESS",
|
||||
"millturn blocked kind",
|
||||
);
|
||||
assert.deepEqual(
|
||||
millturnBoundary.dependencies,
|
||||
["external_user_m_process", "hal_process", "halui_mdi_process", "ui_process"],
|
||||
"millturn full-process boundary dependencies",
|
||||
);
|
||||
assert.equal(
|
||||
millturnBoundary.userMRuntime.vendoredExecutableCount,
|
||||
0,
|
||||
"millturn external user-M files are not staged",
|
||||
);
|
||||
assert.deepEqual(
|
||||
millturnBoundary.userMRuntime.executionCodes,
|
||||
["M128", "M129"],
|
||||
"millturn execution chain calls external user-M processes",
|
||||
);
|
||||
assert.deepEqual(
|
||||
millturnBoundary.userMRuntime.unstagedExecutionCodes,
|
||||
["M128", "M129"],
|
||||
"millturn execution chain calls unstaged user-M processes",
|
||||
);
|
||||
|
||||
const pumaBoundary = simBoundary("axis/vismach/puma", "puma_cube.ini");
|
||||
assert.equal(pumaBoundary.recommendedBlockedKind, "-", "puma_cube representative is not blocked");
|
||||
assert.equal(pumaBoundary.userMRuntime.vendoredExecutableCount, 0, "puma_cube has no vendored user-M processes");
|
||||
assert.equal(pumaBoundary.halRuntime.requiresProcess, true, "puma_cube declares HAL process files");
|
||||
assert.equal(pumaBoundary.haluiRuntime.requiresProcess, true, "puma_cube declares HALUI MDI commands");
|
||||
|
||||
const melfaBoundary = simBoundary("axis/vismach/melfa-sim", "melfa.ini");
|
||||
assert.equal(melfaBoundary.recommendedBlockedKind, "-", "melfa representative is not blocked");
|
||||
assert.deepEqual(
|
||||
melfaBoundary.dependencies,
|
||||
["hal_process", "halui_mdi_process", "ui_process"],
|
||||
"melfa declares HAL/UI/HALUI process dependencies",
|
||||
);
|
||||
assert.equal(melfaBoundary.pythonRuntime.requiresProcess, false, "melfa representative has no Python runtime");
|
||||
|
||||
const woodpeckerBoundary = simBoundary("woodpecker", "woodpecker.ini");
|
||||
assert.equal(woodpeckerBoundary.recommendedBlockedKind, "-", "woodpecker representative is not blocked");
|
||||
assert.deepEqual(
|
||||
woodpeckerBoundary.dependencies,
|
||||
["hal_process", "ui_process"],
|
||||
"woodpecker declares HAL/UI process dependencies",
|
||||
);
|
||||
assert.equal(woodpeckerBoundary.haluiRuntime.requiresProcess, false, "woodpecker representative has no HALUI MDI");
|
||||
|
||||
const gladevcpBoundary = simBoundary("axis/gladevcp", "gladevcp_panel.ini");
|
||||
assert.equal(gladevcpBoundary.recommendedBlockedKind, "-", "gladevcp probe representative is not blocked");
|
||||
assert.ok(
|
||||
gladevcpBoundary.dependencies.includes("ui_process"),
|
||||
"gladevcp declares UI process dependency",
|
||||
);
|
||||
assert.equal(gladevcpBoundary.pythonRuntime.requiresProcess, true, "gladevcp declares Python UI handler");
|
||||
assert.deepEqual(
|
||||
gladevcpBoundary.pythonRuntime.uiReferences,
|
||||
["-u hitcounter.py manual-example.ui"],
|
||||
"gladevcp Python dependency is a UI handler",
|
||||
);
|
||||
assert.deepEqual(
|
||||
gladevcpBoundary.pythonRuntime.remapReferences,
|
||||
[],
|
||||
"gladevcp representative must not be treated as Python remap runtime",
|
||||
);
|
||||
|
||||
function simMachine(machineRel, iniFile, programFile = null) {
|
||||
const iniText = readFileSync(
|
||||
resolve(vendorRoot, `configs/sim/${machineRel}/${iniFile}`),
|
||||
@@ -158,6 +342,23 @@ function simMachine(machineRel, iniFile, programFile = null) {
|
||||
};
|
||||
}
|
||||
|
||||
function wrapSimProgram(machine, wrappedName) {
|
||||
const sourceFile = machine.files.find((file) => file.path === machine.programPath);
|
||||
assert.ok(sourceFile, `${machine.programPath}: wrapped source file`);
|
||||
return {
|
||||
...machine,
|
||||
programPath: `${machine.wasmDir}/${wrappedName}`,
|
||||
files: [
|
||||
...machine.files,
|
||||
{
|
||||
path: `${machine.wasmDir}/${wrappedName}`,
|
||||
text: `${sourceFile.text}\nM2\n`,
|
||||
executable: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const foam = simMachine("axis/foam", "axis_foam.ini", "foam.ngc");
|
||||
verifyExpectedOutput(
|
||||
"sim_axis_foam_uv_wasm",
|
||||
@@ -225,6 +426,49 @@ verifyExpectedOutput(
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const gladevcpProbe = simMachine("axis/gladevcp", "gladevcp_panel.ini", "probe.ngc");
|
||||
verifyExpectedOutput(
|
||||
"sim_axis_gladevcp_probe_wasm",
|
||||
interp.runSimConfigProgram({
|
||||
files: gladevcpProbe.files,
|
||||
programPath: gladevcpProbe.programPath,
|
||||
iniPath: gladevcpProbe.iniPath,
|
||||
}),
|
||||
[
|
||||
"file_open=0",
|
||||
"file_saw_error=0",
|
||||
"canon_event=PROGRAM_END",
|
||||
"absent=file_error_text=",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const externalOffsetsMacro = wrapSimProgram(
|
||||
simMachine("axis/external_offsets", "dynamic_offsets.ini", "circles.ngc"),
|
||||
"__wrapped_circles.ngc",
|
||||
);
|
||||
verifyExpectedOutput(
|
||||
"sim_axis_external_offsets_circles_macro_wasm",
|
||||
interp.runSimConfigProgram({
|
||||
files: externalOffsetsMacro.files,
|
||||
programPath: externalOffsetsMacro.programPath,
|
||||
iniPath: externalOffsetsMacro.iniPath,
|
||||
}),
|
||||
[
|
||||
"file_open=0",
|
||||
"file_execute_45=1",
|
||||
"statement_uri=M2",
|
||||
"file_read_count=45",
|
||||
"file_execute_count=45",
|
||||
"file_saw_error=0",
|
||||
"canon_event=COMMENT: info: Multiple circles at radius R, use 0 for current val",
|
||||
"canon_event=PROGRAM_END",
|
||||
"post_execute.origin_index=1",
|
||||
"post_execute.mist=0",
|
||||
"post_execute.flood=0",
|
||||
"absent=file_error_text=",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
for (const externalOffsetCase of [
|
||||
{
|
||||
name: "dyn_demo",
|
||||
@@ -287,4 +531,62 @@ for (const externalOffsetCase of [
|
||||
);
|
||||
}
|
||||
|
||||
const melfaSim = simMachine("axis/vismach/melfa-sim", "melfa.ini", "example.ngc");
|
||||
verifyExpectedOutput(
|
||||
"sim_axis_vismach_melfa_wasm",
|
||||
interp.runSimConfigProgram({
|
||||
files: melfaSim.files,
|
||||
programPath: melfaSim.programPath,
|
||||
iniPath: melfaSim.iniPath,
|
||||
executionMode: "fiveAxisRemap",
|
||||
}),
|
||||
[
|
||||
"fiveaxis_ini_open=1",
|
||||
"fiveaxis_tool_table_load=0",
|
||||
"fiveaxis_file_open=0",
|
||||
"fiveaxis_file_reached_exit=1",
|
||||
"fiveaxis_linuxcnc_remap_file_execute=1",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const pumaCube = simMachine("axis/vismach/puma", "puma_cube.ini", "puma_cube.ngc");
|
||||
verifyExpectedOutput(
|
||||
"sim_axis_vismach_puma_cube_wasm",
|
||||
interp.runSimConfigProgram({
|
||||
files: pumaCube.files,
|
||||
programPath: pumaCube.programPath,
|
||||
iniPath: pumaCube.iniPath,
|
||||
}),
|
||||
[
|
||||
"file_open=0",
|
||||
"file_saw_error=0",
|
||||
"canon_event=PROGRAM_END",
|
||||
"absent=file_error_text=",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const woodpeckerOnAbort = simMachine("woodpecker", "woodpecker.ini", "on_abort.ngc");
|
||||
verifyExpectedOutput(
|
||||
"sim_woodpecker_on_abort_wasm",
|
||||
interp.runSimConfigProgram({
|
||||
files: woodpeckerOnAbort.files,
|
||||
programPath: woodpeckerOnAbort.programPath,
|
||||
iniPath: woodpeckerOnAbort.iniPath,
|
||||
}),
|
||||
[
|
||||
"file_open=0",
|
||||
"run_step phase=execute step=17 rc=1 line=17",
|
||||
"statement_uri=m2",
|
||||
"file_read_count=17",
|
||||
"file_execute_count=17",
|
||||
"file_saw_error=0",
|
||||
"canon_event=ON_RESET",
|
||||
"canon_event=PROGRAM_END",
|
||||
"post_execute.origin_index=1",
|
||||
"post_execute.mist=0",
|
||||
"post_execute.flood=0",
|
||||
"absent=file_error_text=",
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
console.log("sim_configs_wasm_node_smoke=ok");
|
||||
|
||||
Reference in New Issue
Block a user