Complete sim config boundary coverage
This commit is contained in:
202
wasm-port/tests/native/probe_millturn_user_m_runtime.sh
Normal file
202
wasm-port/tests/native/probe_millturn_user_m_runtime.sh
Normal file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
LINUXCNC_ROOT="${LINUXCNC_ROOT:-$ROOT_DIR/../linuxcnc}"
|
||||
MACHINE_DIR="$LINUXCNC_ROOT/configs/sim/axis/vismach/millturn"
|
||||
INI_FILE="$MACHINE_DIR/millturn.ini"
|
||||
RUN_DIR="$ROOT_DIR/build/native/millturn-user-m-runtime"
|
||||
LINUXCNC_STDOUT="$RUN_DIR/linuxcnc.stdout.log"
|
||||
LINUXCNC_STDERR="$RUN_DIR/linuxcnc.stderr.log"
|
||||
|
||||
required_commands=(tclsh halrun halcmd linuxcnc)
|
||||
missing_commands=()
|
||||
LINUXCNC_PID=""
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$LINUXCNC_PID" ]]; then
|
||||
kill "$LINUXCNC_PID" 2>/dev/null || true
|
||||
wait "$LINUXCNC_PID" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
command_path() {
|
||||
command -v "$1" 2>/dev/null || true
|
||||
}
|
||||
|
||||
csv_join() {
|
||||
local IFS=,
|
||||
printf '%s' "$*"
|
||||
}
|
||||
|
||||
print_kv() {
|
||||
printf '%s=%s\n' "$1" "$2"
|
||||
}
|
||||
|
||||
runtime_requirements=()
|
||||
for command_name in "${required_commands[@]}"; do
|
||||
path="$(command_path "$command_name")"
|
||||
if [[ -n "$path" ]]; then
|
||||
runtime_requirements+=("$command_name:1")
|
||||
print_kv "millturn_user_m_runtime_${command_name}_path" "$path"
|
||||
else
|
||||
runtime_requirements+=("$command_name:0")
|
||||
missing_commands+=("$command_name")
|
||||
fi
|
||||
done
|
||||
|
||||
source_ready=1
|
||||
for rel in \
|
||||
millturn.ini \
|
||||
mcodes/M128 \
|
||||
mcodes/M129 \
|
||||
remap_subs/428remap.ngc \
|
||||
remap_subs/429remap.ngc; do
|
||||
if [[ ! -f "$MACHINE_DIR/$rel" ]]; then
|
||||
source_ready=0
|
||||
print_kv "millturn_user_m_missing_source_${rel//[^A-Za-z0-9]/_}" "$MACHINE_DIR/$rel"
|
||||
fi
|
||||
done
|
||||
|
||||
runtime_ready=0
|
||||
if [[ "${#missing_commands[@]}" -eq 0 ]]; then
|
||||
runtime_ready=1
|
||||
fi
|
||||
|
||||
print_kv millturn_user_m_runtime_requirements "$(csv_join "${runtime_requirements[@]}")"
|
||||
if [[ "${#missing_commands[@]}" -eq 0 ]]; then
|
||||
print_kv millturn_user_m_missing_requirements "-"
|
||||
else
|
||||
print_kv millturn_user_m_missing_requirements "$(csv_join "${missing_commands[@]}")"
|
||||
fi
|
||||
print_kv millturn_user_m_source_proof_ready "$source_ready"
|
||||
print_kv millturn_user_m_runtime_ready "$runtime_ready"
|
||||
print_kv millturn_user_m_execution_enabled 0
|
||||
print_kv millturn_user_m_promotion_allowed 0
|
||||
|
||||
if [[ "$source_ready" != "1" ]]; then
|
||||
print_kv millturn_user_m_runtime_probe_status "blocked_missing_source"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$runtime_ready" != "1" ]]; then
|
||||
print_kv millturn_user_m_runtime_probe_status "skipped_missing_host_runtime"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_MILLTURN_USER_M_RUNTIME_PROBE:-0}" != "1" ]]; then
|
||||
print_kv millturn_user_m_runtime_probe_status "ready_disabled_by_default"
|
||||
print_kv millturn_user_m_runtime_probe_note "set_ENABLE_MILLTURN_USER_M_RUNTIME_PROBE_1_to_run_full_process_probe"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
|
||||
wait_for_hal_pin() {
|
||||
local pin="$1"
|
||||
local limit="${MILLTURN_USER_M_RUNTIME_WAIT_SECONDS:-30}"
|
||||
local end=$((SECONDS + limit))
|
||||
while (( SECONDS < end )); do
|
||||
if halcmd getp "$pin" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.25
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
read_hal_pin() {
|
||||
halcmd getp "$1" 2>/dev/null | tr -d '[:space:]'
|
||||
}
|
||||
|
||||
expect_hal_pin() {
|
||||
local label="$1"
|
||||
local pin="$2"
|
||||
local expected="$3"
|
||||
local actual
|
||||
actual="$(read_hal_pin "$pin")"
|
||||
print_kv "millturn_user_m_${label}_${pin//[^A-Za-z0-9]/_}" "$actual"
|
||||
[[ "$actual" == "$expected" ]]
|
||||
}
|
||||
|
||||
set_switchkins_target() {
|
||||
local target="$1"
|
||||
local guard_pin="kinstype.is-$target"
|
||||
if ! halcmd setp motion.switchkins-type "$target" >/dev/null 2>&1; then
|
||||
halcmd unlinkp motion.switchkins-type >/dev/null 2>&1 || true
|
||||
halcmd setp motion.switchkins-type "$target"
|
||||
fi
|
||||
for _ in $(seq 1 40); do
|
||||
if [[ "$(read_hal_pin "$guard_pin")" =~ ^(TRUE|1)$ ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.05
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
run_user_m_case() {
|
||||
local code="$1"
|
||||
local mode="$2"
|
||||
local switchkins_target="$3"
|
||||
local expected_x_min="$4"
|
||||
local expected_x_max="$5"
|
||||
local expected_y_min="$6"
|
||||
local expected_y_max="$7"
|
||||
local expected_z_min="$8"
|
||||
local expected_z_max="$9"
|
||||
|
||||
print_kv "millturn_user_m_${code}_runtime_mode" "$mode"
|
||||
if ! set_switchkins_target "$switchkins_target"; then
|
||||
print_kv "millturn_user_m_${code}_switchkins_target_ready" 0
|
||||
return 1
|
||||
fi
|
||||
print_kv "millturn_user_m_${code}_switchkins_target_ready" 1
|
||||
|
||||
INI_FILE_NAME="$INI_FILE" "$MACHINE_DIR/mcodes/$code"
|
||||
|
||||
local ok=1
|
||||
expect_hal_pin "${code}" ini.x.min_limit "$expected_x_min" || ok=0
|
||||
expect_hal_pin "${code}" ini.x.max_limit "$expected_x_max" || ok=0
|
||||
expect_hal_pin "${code}" ini.y.min_limit "$expected_y_min" || ok=0
|
||||
expect_hal_pin "${code}" ini.y.max_limit "$expected_y_max" || ok=0
|
||||
expect_hal_pin "${code}" ini.z.min_limit "$expected_z_min" || ok=0
|
||||
expect_hal_pin "${code}" ini.z.max_limit "$expected_z_max" || ok=0
|
||||
expect_hal_pin "${code}" ini.x.max_velocity "60" || ok=0
|
||||
expect_hal_pin "${code}" ini.y.max_velocity "60" || ok=0
|
||||
expect_hal_pin "${code}" ini.z.max_velocity "60" || ok=0
|
||||
expect_hal_pin "${code}" ini.x.max_acceleration "400" || ok=0
|
||||
expect_hal_pin "${code}" ini.y.max_acceleration "400" || ok=0
|
||||
expect_hal_pin "${code}" ini.z.max_acceleration "400" || ok=0
|
||||
|
||||
print_kv "millturn_user_m_${code}_runtime_state_ok" "$ok"
|
||||
[[ "$ok" == "1" ]]
|
||||
}
|
||||
|
||||
print_kv millturn_user_m_runtime_probe_ini "$INI_FILE"
|
||||
print_kv millturn_user_m_runtime_probe_linuxcnc_stdout "$LINUXCNC_STDOUT"
|
||||
print_kv millturn_user_m_runtime_probe_linuxcnc_stderr "$LINUXCNC_STDERR"
|
||||
|
||||
linuxcnc -r "$INI_FILE" >"$LINUXCNC_STDOUT" 2>"$LINUXCNC_STDERR" &
|
||||
LINUXCNC_PID="$!"
|
||||
|
||||
if ! wait_for_hal_pin ini.x.min_limit || ! wait_for_hal_pin motion.switchkins-type; then
|
||||
print_kv millturn_user_m_runtime_probe_status "runtime_state_probe_failed"
|
||||
print_kv millturn_user_m_runtime_probe_note "linuxcnc_started_but_required_hal_pins_did_not_appear"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
probe_ok=1
|
||||
run_user_m_case M128 mill 0 -300 300 -100 100 -240 0 || probe_ok=0
|
||||
run_user_m_case M129 turn 1 -240 0 -100 100 -300 300 || probe_ok=0
|
||||
|
||||
if [[ "$probe_ok" == "1" ]]; then
|
||||
print_kv millturn_user_m_runtime_probe_status "runtime_state_probe_passed"
|
||||
print_kv millturn_user_m_runtime_probe_note "linuxcnc_owned_M128_M129_tcl_hal_state_probe_passed_without_promotion"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
print_kv millturn_user_m_runtime_probe_status "runtime_state_probe_failed"
|
||||
print_kv millturn_user_m_runtime_probe_note "linuxcnc_owned_M128_M129_tcl_hal_state_probe_failed"
|
||||
exit 1
|
||||
189
wasm-port/tests/native/probe_python_remap_runtime.sh
Executable file
189
wasm-port/tests/native/probe_python_remap_runtime.sh
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
LINUXCNC_ROOT="${LINUXCNC_ROOT:-$ROOT_DIR/../linuxcnc}"
|
||||
FIXTURE_FAMILY="axis/remap/stop-lookahead/nc_files"
|
||||
FIXTURE_DIR="$LINUXCNC_ROOT/configs/sim/axis/remap/stop-lookahead"
|
||||
FIXTURE_INI="$FIXTURE_DIR/demo.ini"
|
||||
RUN_DIR="$ROOT_DIR/build/native/python-remap-runtime"
|
||||
PYTHON_RUNTIME_STDOUT="$RUN_DIR/python_lifecycle.stdout.log"
|
||||
PYTHON_RUNTIME_STDERR="$RUN_DIR/python_lifecycle.stderr.log"
|
||||
|
||||
required_commands=(python3 linuxcnc)
|
||||
missing_requirements=()
|
||||
|
||||
command_path() {
|
||||
command -v "$1" 2>/dev/null || true
|
||||
}
|
||||
|
||||
csv_join() {
|
||||
local IFS=,
|
||||
printf '%s' "$*"
|
||||
}
|
||||
|
||||
print_kv() {
|
||||
printf '%s=%s\n' "$1" "$2"
|
||||
}
|
||||
|
||||
runtime_requirements=()
|
||||
for command_name in "${required_commands[@]}"; do
|
||||
path="$(command_path "$command_name")"
|
||||
if [[ -n "$path" ]]; then
|
||||
runtime_requirements+=("$command_name:1")
|
||||
print_kv "python_remap_runtime_${command_name}_path" "$path"
|
||||
else
|
||||
runtime_requirements+=("$command_name:0")
|
||||
missing_requirements+=("$command_name")
|
||||
fi
|
||||
done
|
||||
|
||||
source_ready=1
|
||||
for rel in \
|
||||
src/emc/rs274ngc/interp_python.cc \
|
||||
src/emc/pythonplugin/python_plugin.cc \
|
||||
configs/sim/axis/remap/stop-lookahead/demo.ini \
|
||||
configs/sim/axis/remap/stop-lookahead/python/remap.py \
|
||||
configs/sim/axis/remap/stop-lookahead/python/toplevel.py; do
|
||||
if [[ ! -f "$LINUXCNC_ROOT/$rel" ]]; then
|
||||
source_ready=0
|
||||
missing_requirements+=("$rel")
|
||||
print_kv "python_remap_missing_source_${rel//[^A-Za-z0-9]/_}" "$LINUXCNC_ROOT/$rel"
|
||||
fi
|
||||
done
|
||||
|
||||
runtime_ready=0
|
||||
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
|
||||
runtime_ready=1
|
||||
fi
|
||||
|
||||
print_kv python_remap_runtime_fixture_family "$FIXTURE_FAMILY"
|
||||
print_kv python_remap_runtime_fixture_id "stop_lookahead_python_runtime_lifecycle"
|
||||
print_kv python_remap_runtime_fixture_scope "no_python_callables_no_ngc_only_subpaths"
|
||||
print_kv python_remap_runtime_phases "initialize_python,apply_ini_python_path,execute_toplevel,callable_lookup,pycall_dispatch,callable_invoke,remap_phase_dispatch,generator_finish,execute_python_runtime,reload_on_change"
|
||||
print_kv python_remap_runtime_modules "axis/remap/stop-lookahead/python/remap.py,axis/remap/stop-lookahead/python/toplevel.py"
|
||||
print_kv python_remap_runtime_requirements "$(csv_join "${runtime_requirements[@]}")"
|
||||
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
|
||||
print_kv python_remap_missing_requirements "-"
|
||||
else
|
||||
print_kv python_remap_missing_requirements "$(csv_join "${missing_requirements[@]}")"
|
||||
fi
|
||||
print_kv python_remap_source_proof_ready "$source_ready"
|
||||
print_kv python_remap_runtime_ready "$runtime_ready"
|
||||
print_kv python_remap_execution_enabled 0
|
||||
print_kv python_remap_promotion_allowed 0
|
||||
|
||||
if [[ "$source_ready" != "1" ]]; then
|
||||
print_kv python_remap_runtime_probe_status "blocked_missing_source"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$runtime_ready" != "1" ]]; then
|
||||
print_kv python_remap_runtime_probe_status "skipped_missing_host_runtime"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_PYTHON_REMAP_RUNTIME_PROBE:-0}" != "1" ]]; then
|
||||
print_kv python_remap_runtime_probe_status "ready_disabled_by_default"
|
||||
print_kv python_remap_runtime_probe_note "set_ENABLE_PYTHON_REMAP_RUNTIME_PROBE_1_to_run_python_lifecycle_probe"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
rm -f "$PYTHON_RUNTIME_STDOUT" "$PYTHON_RUNTIME_STDERR"
|
||||
|
||||
print_kv python_remap_runtime_probe_fixture "$FIXTURE_DIR"
|
||||
print_kv python_remap_runtime_probe_ini "$FIXTURE_INI"
|
||||
print_kv python_remap_runtime_probe_stdout "$PYTHON_RUNTIME_STDOUT"
|
||||
print_kv python_remap_runtime_probe_stderr "$PYTHON_RUNTIME_STDERR"
|
||||
|
||||
if python3 - "$LINUXCNC_ROOT" "$FIXTURE_DIR" "$FIXTURE_INI" "$RUN_DIR" \
|
||||
>"$PYTHON_RUNTIME_STDOUT" 2>"$PYTHON_RUNTIME_STDERR" <<'PY'
|
||||
import configparser
|
||||
import importlib
|
||||
import inspect
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
linuxcnc_root = Path(sys.argv[1])
|
||||
fixture_dir = Path(sys.argv[2])
|
||||
fixture_ini = Path(sys.argv[3])
|
||||
run_dir = Path(sys.argv[4])
|
||||
|
||||
def emit(name, value):
|
||||
print(f"{name}={value}")
|
||||
|
||||
def require(condition, message):
|
||||
if not condition:
|
||||
raise RuntimeError(message)
|
||||
|
||||
interp_return = linuxcnc_root / "src/emc/nml_intf/interp_return.hh"
|
||||
match = re.search(
|
||||
r"INTERP_EXECUTE_FINISH\s*=\s*([0-9]+)",
|
||||
interp_return.read_text(encoding="utf-8"),
|
||||
)
|
||||
require(match, "missing_INTERP_EXECUTE_FINISH_source_value")
|
||||
execute_finish = int(match.group(1))
|
||||
emit("python_remap_lifecycle_execute_finish_source_value", execute_finish)
|
||||
|
||||
stub_dir = Path(tempfile.mkdtemp(prefix="python-remap-interpreter-", dir=run_dir))
|
||||
(stub_dir / "interpreter.py").write_text(
|
||||
f"INTERP_EXECUTE_FINISH = {execute_finish}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
parser = configparser.ConfigParser(strict=False)
|
||||
parser.optionxform = str
|
||||
parser.read(fixture_ini)
|
||||
require(parser.has_section("PYTHON"), "missing_PYTHON_section")
|
||||
path_prepend = parser.get("PYTHON", "PATH_PREPEND", fallback="")
|
||||
toplevel = parser.get("PYTHON", "TOPLEVEL", fallback="")
|
||||
require(path_prepend == "python", f"PATH_PREPEND_drift:{path_prepend}")
|
||||
require(toplevel == "python/toplevel.py", f"TOPLEVEL_drift:{toplevel}")
|
||||
emit("python_remap_lifecycle_ini_path_prepend", path_prepend)
|
||||
emit("python_remap_lifecycle_ini_toplevel", toplevel)
|
||||
|
||||
sys.path.insert(0, str(stub_dir))
|
||||
sys.path.insert(0, str(fixture_dir / path_prepend))
|
||||
sys.path.insert(0, str(linuxcnc_root / "lib/python"))
|
||||
|
||||
import interpreter # noqa: E402
|
||||
require(interpreter.INTERP_EXECUTE_FINISH == execute_finish, "interpreter_sentinel_drift")
|
||||
emit("python_remap_lifecycle_interpreter_sentinel_ok", 1)
|
||||
|
||||
toplevel_module = importlib.import_module(Path(toplevel).stem)
|
||||
emit("python_remap_lifecycle_toplevel_imported", int(toplevel_module.__name__ == "toplevel"))
|
||||
remap_module = importlib.import_module("remap")
|
||||
emit("python_remap_lifecycle_remap_imported", int(remap_module.__name__ == "remap"))
|
||||
require(hasattr(remap_module, "queuebuster"), "missing_queuebuster_callable")
|
||||
require(callable(remap_module.queuebuster), "queuebuster_not_callable")
|
||||
emit("python_remap_lifecycle_callable_lookup_ok", 1)
|
||||
|
||||
result = remap_module.queuebuster(object())
|
||||
require(inspect.isgenerator(result), "queuebuster_not_generator")
|
||||
emit("python_remap_lifecycle_generator_returned", 1)
|
||||
first_yield = next(result)
|
||||
require(first_yield == execute_finish, f"queuebuster_yield_drift:{first_yield}")
|
||||
emit("python_remap_lifecycle_generator_first_yield", first_yield)
|
||||
try:
|
||||
next(result)
|
||||
raise RuntimeError("queuebuster_generator_did_not_finish")
|
||||
except StopIteration:
|
||||
emit("python_remap_lifecycle_generator_finish_ok", 1)
|
||||
|
||||
emit("python_remap_runtime_lifecycle_probe_ok", 1)
|
||||
PY
|
||||
then
|
||||
cat "$PYTHON_RUNTIME_STDOUT"
|
||||
print_kv python_remap_runtime_probe_status "runtime_lifecycle_probe_passed"
|
||||
print_kv python_remap_runtime_probe_note "linuxcnc_stop_lookahead_python_lifecycle_probe_passed_without_promotion"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cat "$PYTHON_RUNTIME_STDOUT" || true
|
||||
print_kv python_remap_runtime_probe_status "runtime_lifecycle_probe_failed"
|
||||
print_kv python_remap_runtime_probe_note "linuxcnc_stop_lookahead_python_lifecycle_probe_failed"
|
||||
exit 1
|
||||
232
wasm-port/tests/native/probe_tool_db_runtime.sh
Normal file
232
wasm-port/tests/native/probe_tool_db_runtime.sh
Normal file
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
LINUXCNC_ROOT="${LINUXCNC_ROOT:-$ROOT_DIR/../linuxcnc}"
|
||||
DB_DEMO_DIR="$LINUXCNC_ROOT/configs/sim/axis/db_demo"
|
||||
DB_PROGRAM="$DB_DEMO_DIR/db_nonran.py"
|
||||
RUN_DIR="$ROOT_DIR/build/native/tool-db-runtime"
|
||||
DB_SAVEFILE="$RUN_DIR/db_nonran_probe"
|
||||
DB_STDOUT="$RUN_DIR/db_program.stdout.log"
|
||||
DB_STDERR="$RUN_DIR/db_program.stderr.log"
|
||||
|
||||
required_commands=(python3 linuxcnc milltask halcmd)
|
||||
missing_requirements=()
|
||||
|
||||
command_path() {
|
||||
command -v "$1" 2>/dev/null || true
|
||||
}
|
||||
|
||||
csv_join() {
|
||||
local IFS=,
|
||||
printf '%s' "$*"
|
||||
}
|
||||
|
||||
print_kv() {
|
||||
printf '%s=%s\n' "$1" "$2"
|
||||
}
|
||||
|
||||
runtime_requirements=()
|
||||
for command_name in "${required_commands[@]}"; do
|
||||
path="$(command_path "$command_name")"
|
||||
if [[ -n "$path" ]]; then
|
||||
runtime_requirements+=("$command_name:1")
|
||||
print_kv "tool_db_runtime_${command_name}_path" "$path"
|
||||
else
|
||||
runtime_requirements+=("$command_name:0")
|
||||
missing_requirements+=("$command_name")
|
||||
fi
|
||||
done
|
||||
|
||||
source_ready=1
|
||||
for rel in \
|
||||
configs/sim/axis/db_demo/db_nonran.ini \
|
||||
configs/sim/axis/db_demo/db.py \
|
||||
lib/python/tooldb.py \
|
||||
lib/python/linuxcnc.so; do
|
||||
if [[ ! -e "$LINUXCNC_ROOT/$rel" ]]; then
|
||||
source_ready=0
|
||||
missing_requirements+=("$rel")
|
||||
print_kv "tool_db_missing_source_${rel//[^A-Za-z0-9]/_}" "$LINUXCNC_ROOT/$rel"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ ! -x "$DB_PROGRAM" ]]; then
|
||||
source_ready=0
|
||||
missing_requirements+=("configs/sim/axis/db_demo/db_nonran.py:executable")
|
||||
fi
|
||||
|
||||
runtime_ready=0
|
||||
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
|
||||
runtime_ready=1
|
||||
fi
|
||||
|
||||
print_kv tool_db_runtime_requirements "$(csv_join "${runtime_requirements[@]}")"
|
||||
if [[ "${#missing_requirements[@]}" -eq 0 ]]; then
|
||||
print_kv tool_db_missing_requirements "-"
|
||||
else
|
||||
print_kv tool_db_missing_requirements "$(csv_join "${missing_requirements[@]}")"
|
||||
fi
|
||||
print_kv tool_db_source_proof_ready "$source_ready"
|
||||
print_kv tool_db_runtime_ready "$runtime_ready"
|
||||
print_kv tool_db_execution_enabled 0
|
||||
print_kv tool_db_promotion_allowed 0
|
||||
|
||||
if [[ "$source_ready" != "1" ]]; then
|
||||
print_kv tool_db_runtime_probe_status "blocked_missing_source"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$runtime_ready" != "1" ]]; then
|
||||
print_kv tool_db_runtime_probe_status "skipped_missing_host_runtime"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "${ENABLE_TOOL_DB_RUNTIME_PROBE:-0}" != "1" ]]; then
|
||||
print_kv tool_db_runtime_probe_status "ready_disabled_by_default"
|
||||
print_kv tool_db_runtime_probe_note "set_ENABLE_TOOL_DB_RUNTIME_PROBE_1_to_run_db_protocol_probe"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
rm -f "$DB_SAVEFILE" "$DB_STDOUT" "$DB_STDERR"
|
||||
|
||||
print_kv tool_db_runtime_probe_program "$DB_PROGRAM"
|
||||
print_kv tool_db_runtime_probe_db_savefile "$DB_SAVEFILE"
|
||||
print_kv tool_db_runtime_probe_stdout "$DB_STDOUT"
|
||||
print_kv tool_db_runtime_probe_stderr "$DB_STDERR"
|
||||
|
||||
if python3 - "$DB_PROGRAM" "$DB_DEMO_DIR" "$LINUXCNC_ROOT/lib/python" "$DB_SAVEFILE" "$DB_STDOUT" "$DB_STDERR" <<'PY'
|
||||
import os
|
||||
import select
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
db_program, db_demo_dir, python_path, db_savefile, stdout_log, stderr_log = sys.argv[1:]
|
||||
|
||||
env = os.environ.copy()
|
||||
env["PYTHONPATH"] = python_path + (os.pathsep + env["PYTHONPATH"] if env.get("PYTHONPATH") else "")
|
||||
|
||||
stdout_file = open(stdout_log, "w", encoding="utf-8")
|
||||
stderr_file = open(stderr_log, "w", encoding="utf-8")
|
||||
proc = subprocess.Popen(
|
||||
[db_program, "--period_minutes=999", db_savefile],
|
||||
cwd=db_demo_dir,
|
||||
env=env,
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=stderr_file,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
)
|
||||
|
||||
def emit(name, value):
|
||||
print(f"{name}={value}")
|
||||
|
||||
def read_line(timeout=5.0):
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
ready, _, _ = select.select([proc.stdout], [], [], 0.1)
|
||||
if ready:
|
||||
line = proc.stdout.readline()
|
||||
if line == "":
|
||||
raise RuntimeError("db_program_stdout_closed")
|
||||
line = line.rstrip("\n")
|
||||
stdout_file.write(line + "\n")
|
||||
stdout_file.flush()
|
||||
return line
|
||||
if proc.poll() is not None:
|
||||
raise RuntimeError(f"db_program_exited_{proc.returncode}")
|
||||
raise RuntimeError("timeout_waiting_for_db_program_reply")
|
||||
|
||||
def send(command):
|
||||
proc.stdin.write(command + "\n")
|
||||
proc.stdin.flush()
|
||||
|
||||
def read_until_fini(command, timeout=5.0):
|
||||
send(command)
|
||||
lines = []
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
line = read_line(max(0.1, deadline - time.monotonic()))
|
||||
lines.append(line)
|
||||
if line.startswith("FINI"):
|
||||
return lines
|
||||
raise RuntimeError(f"timeout_waiting_for_fini_{command.split()[0]}")
|
||||
|
||||
def require(condition, message):
|
||||
if not condition:
|
||||
raise RuntimeError(message)
|
||||
|
||||
ok = False
|
||||
try:
|
||||
version = read_line()
|
||||
emit("tool_db_protocol_version", version)
|
||||
require(version == "v2.1", f"version_drift:{version}")
|
||||
|
||||
get_all = read_until_fini("g")
|
||||
tool_lines = [line for line in get_all if line.startswith("T")]
|
||||
emit("tool_db_get_all_count", len(tool_lines))
|
||||
require(len(tool_lines) == 10, "get_all_tool_count_drift")
|
||||
for toolno in range(10, 20):
|
||||
expected = f"T{toolno} "
|
||||
require(any(line.startswith(expected) for line in tool_lines), f"missing_tool_{toolno}")
|
||||
require(any(line.startswith(expected) and f"P{toolno + 100}" in line for line in tool_lines), f"pocket_drift_{toolno}")
|
||||
emit("tool_db_get_all_fini", int(get_all[-1].startswith("FINI")))
|
||||
|
||||
put_reply = read_until_fini("p t11 p111 d0.33 z0.11")
|
||||
emit("tool_db_put_tool_update_fini", int(put_reply[-1].startswith("FINI")))
|
||||
|
||||
get_after_put = read_until_fini("g")
|
||||
t11_rows = [line for line in get_after_put if line.startswith("T11 ")]
|
||||
require(t11_rows and "D0.33" in t11_rows[0] and "Z0.11" in t11_rows[0], "put_update_state_drift")
|
||||
emit("tool_db_put_tool_update_state_ok", 1)
|
||||
|
||||
load_reply = read_until_fini("l t14 p0")
|
||||
emit("tool_db_load_spindle_fini", int(load_reply[-1].startswith("FINI")))
|
||||
t14_loaded = read_until_fini("t 14")
|
||||
require(any(line.startswith("T14 ") and "P0" in line for line in t14_loaded), "load_spindle_state_drift")
|
||||
emit("tool_db_load_spindle_state_ok", 1)
|
||||
|
||||
unload_reply = read_until_fini("u t0 p0")
|
||||
emit("tool_db_unload_spindle_fini", int(unload_reply[-1].startswith("FINI")))
|
||||
t14_unloaded = read_until_fini("t 14")
|
||||
require(any(line.startswith("T14 ") and "P114" in line for line in t14_unloaded), "unload_spindle_state_drift")
|
||||
emit("tool_db_unload_spindle_state_ok", 1)
|
||||
|
||||
require(os.path.exists(db_savefile), "db_savefile_missing")
|
||||
with open(db_savefile, "r", encoding="utf-8") as handle:
|
||||
saved = handle.read()
|
||||
require("T11 P111 D0.33 Z0.11" in saved, "db_savefile_put_update_missing")
|
||||
require("T14 P114" in saved, "db_savefile_unload_state_missing")
|
||||
emit("tool_db_persistence_state_ok", 1)
|
||||
ok = True
|
||||
finally:
|
||||
try:
|
||||
if proc.stdin:
|
||||
proc.stdin.close()
|
||||
except Exception:
|
||||
pass
|
||||
if proc.poll() is None:
|
||||
proc.terminate()
|
||||
try:
|
||||
proc.wait(timeout=2)
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
proc.wait(timeout=2)
|
||||
stderr_file.close()
|
||||
stdout_file.close()
|
||||
|
||||
emit("tool_db_runtime_protocol_probe_ok", int(ok))
|
||||
sys.exit(0 if ok else 1)
|
||||
PY
|
||||
then
|
||||
print_kv tool_db_runtime_probe_status "runtime_protocol_probe_passed"
|
||||
print_kv tool_db_runtime_probe_note "linuxcnc_owned_DB_PROGRAM_protocol_probe_passed_without_promotion"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
print_kv tool_db_runtime_probe_status "runtime_protocol_probe_failed"
|
||||
print_kv tool_db_runtime_probe_note "linuxcnc_owned_DB_PROGRAM_protocol_probe_failed"
|
||||
exit 1
|
||||
@@ -32,6 +32,8 @@ hash_build_validation_inputs() {
|
||||
-o -name '*.run.stdout.log' \
|
||||
-o -name '*.run.stderr.log' \
|
||||
-o -name 'source-probes.tsv' \
|
||||
-o -name 'native-source-proof-summary.tsv' \
|
||||
-o -name 'native-runtime-probe-summary.tsv' \
|
||||
-o -name 'native-probes.ok' \
|
||||
-o -name 'linuxcnc_interp_minimal_harness' \
|
||||
\) \
|
||||
@@ -122,13 +124,195 @@ check_exitcode() {
|
||||
fi
|
||||
}
|
||||
|
||||
check_native_source_proof_summary_row() {
|
||||
local boundary_class="$1"
|
||||
local proof_key="$2"
|
||||
local summary_file="$BUILD_DIR/native-source-proof-summary.tsv"
|
||||
|
||||
local row
|
||||
row="$(awk -F'\t' -v boundary_class="$boundary_class" -v proof_key="$proof_key" '
|
||||
NR > 1 && $1 == boundary_class && $2 == proof_key { print; count++ }
|
||||
END {
|
||||
if (count != 1) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$summary_file")" || {
|
||||
echo "missing native source proof summary row: $boundary_class $proof_key" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
local proof_value
|
||||
local execution_enabled
|
||||
local promotion_allowed
|
||||
local stdout_log
|
||||
IFS=$'\t' read -r _ _ proof_value execution_enabled promotion_allowed stdout_log <<< "$row"
|
||||
|
||||
if [[ "$proof_value" != "1" ]]; then
|
||||
echo "$boundary_class native source proof is not complete: $proof_value" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$execution_enabled" != "0" || "$promotion_allowed" != "0" ]]; then
|
||||
echo "$boundary_class unexpectedly enables execution or promotion" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$BUILD_DIR/$stdout_log" ]]; then
|
||||
echo "$boundary_class summary references missing stdout log: $stdout_log" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_native_source_proof_summary() {
|
||||
local summary_file="$BUILD_DIR/native-source-proof-summary.tsv"
|
||||
|
||||
if [[ ! -f "$summary_file" ]]; then
|
||||
echo "missing native source proof summary: $summary_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local expected_header
|
||||
expected_header=$'boundary_class\tproof_key\tproof_value\texecution_enabled\tpromotion_allowed\tstdout_log'
|
||||
if [[ "$(sed -n '1p' "$summary_file")" != "$expected_header" ]]; then
|
||||
echo "native source proof summary header drift: $summary_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local row_count
|
||||
row_count="$(awk 'END { print NR - 1 }' "$summary_file")"
|
||||
if [[ "$row_count" != "3" ]]; then
|
||||
echo "native source proof summary must contain exactly 3 proof rows, got $row_count" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_native_source_proof_summary_row \
|
||||
L4-USER-M-PROCESS \
|
||||
millturn_user_m_native_source_state_proof
|
||||
check_native_source_proof_summary_row \
|
||||
L4-TOOL-DB \
|
||||
tool_db_native_source_protocol_proof
|
||||
check_native_source_proof_summary_row \
|
||||
L4-PYTHON-REMAP \
|
||||
python_remap_native_source_inventory_proof
|
||||
}
|
||||
|
||||
check_native_runtime_probe_summary_row() {
|
||||
local boundary_class="$1"
|
||||
local boundary_kind="$2"
|
||||
local target="$3"
|
||||
local runtime_probe="$4"
|
||||
local summary_file="$BUILD_DIR/native-runtime-probe-summary.tsv"
|
||||
|
||||
local row
|
||||
row="$(awk -F'\t' \
|
||||
-v boundary_class="$boundary_class" \
|
||||
-v boundary_kind="$boundary_kind" \
|
||||
-v target="$target" \
|
||||
-v runtime_probe="$runtime_probe" '
|
||||
NR > 1 && $1 == boundary_class && $2 == boundary_kind && $3 == target && $4 == runtime_probe {
|
||||
print
|
||||
count++
|
||||
}
|
||||
END {
|
||||
if (count != 1) {
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
' "$summary_file")" || {
|
||||
echo "missing native runtime probe summary row: $boundary_class $boundary_kind $target" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
local runtime_ready
|
||||
local source_proof_ready
|
||||
local probe_status
|
||||
local execution_enabled
|
||||
local promotion_allowed
|
||||
local missing_requirements
|
||||
local stdout_log
|
||||
IFS=$'\t' read -r _ _ _ _ runtime_ready source_proof_ready probe_status execution_enabled promotion_allowed missing_requirements stdout_log <<< "$row"
|
||||
|
||||
if [[ "$source_proof_ready" != "1" ]]; then
|
||||
echo "$target runtime probe lacks source proof readiness: $source_proof_ready" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$execution_enabled" != "0" || "$promotion_allowed" != "0" ]]; then
|
||||
echo "$target runtime probe unexpectedly enables execution or promotion" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! "$probe_status" =~ ^(skipped_missing_host_runtime|ready_disabled_by_default|not_implemented_full_process_guard|runtime_state_probe_passed|runtime_protocol_probe_passed|runtime_lifecycle_probe_passed)$ ]]; then
|
||||
echo "$target runtime probe has invalid status: $probe_status" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$runtime_ready" == "0" && "$probe_status" != "skipped_missing_host_runtime" ]]; then
|
||||
echo "$target runtime probe is not ready but did not skip: $probe_status" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$runtime_ready" == "1" && "$missing_requirements" != "-" ]]; then
|
||||
echo "$target runtime probe is ready but lists missing requirements: $missing_requirements" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -f "$BUILD_DIR/$stdout_log" ]]; then
|
||||
echo "$target runtime summary references missing stdout log: $stdout_log" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
check_native_runtime_probe_summary() {
|
||||
local summary_file="$BUILD_DIR/native-runtime-probe-summary.tsv"
|
||||
|
||||
if [[ ! -f "$summary_file" ]]; then
|
||||
echo "missing native runtime probe summary: $summary_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local expected_header
|
||||
expected_header=$'boundary_class\tboundary_kind\ttarget\truntime_probe\truntime_ready\tsource_proof_ready\tprobe_status\texecution_enabled\tpromotion_allowed\tmissing_requirements\tstdout_log'
|
||||
if [[ "$(sed -n '1p' "$summary_file")" != "$expected_header" ]]; then
|
||||
echo "native runtime probe summary header drift: $summary_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local row_count
|
||||
row_count="$(awk 'END { print NR - 1 }' "$summary_file")"
|
||||
if [[ "$row_count" != "3" ]]; then
|
||||
echo "native runtime probe summary must contain exactly 3 probe rows, got $row_count" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
check_native_runtime_probe_summary_row \
|
||||
L4-USER-M-PROCESS \
|
||||
external_user_m_process \
|
||||
axis/vismach/millturn/example.ngc \
|
||||
linuxcnc_millturn_user_m_runtime_probe
|
||||
check_native_runtime_probe_summary_row \
|
||||
L4-TOOL-DB \
|
||||
tool_database_process \
|
||||
axis/db_demo/base.ngc \
|
||||
linuxcnc_tool_db_runtime_probe
|
||||
check_native_runtime_probe_summary_row \
|
||||
L4-PYTHON-REMAP \
|
||||
python_runtime \
|
||||
axis/remap/stop-lookahead/nc_files \
|
||||
linuxcnc_python_remap_runtime_probe
|
||||
}
|
||||
|
||||
check_source_probe_coverage
|
||||
check_native_source_proof_summary
|
||||
check_native_runtime_probe_summary
|
||||
check_exitcode linuxcnc_interp_state_probe
|
||||
check_exitcode linuxcnc_emc_status_probe
|
||||
check_exitcode linuxcnc_emc_status_probe.run
|
||||
check_exitcode linuxcnc_inifile_source_probe
|
||||
check_exitcode linuxcnc_5axis_remap_asset_probe
|
||||
check_exitcode linuxcnc_5axis_remap_asset_probe.run
|
||||
check_exitcode linuxcnc_millturn_user_m_boundary_probe
|
||||
check_exitcode linuxcnc_millturn_user_m_boundary_probe.run
|
||||
check_exitcode linuxcnc_millturn_user_m_runtime_probe.run
|
||||
check_exitcode linuxcnc_tool_db_boundary_probe
|
||||
check_exitcode linuxcnc_tool_db_boundary_probe.run
|
||||
check_exitcode linuxcnc_python_remap_boundary_probe
|
||||
check_exitcode linuxcnc_python_remap_boundary_probe.run
|
||||
check_exitcode linuxcnc_python_remap_runtime_probe.run
|
||||
check_exitcode linuxcnc_tp_api_probe
|
||||
check_exitcode linuxcnc_tp_api_probe.run
|
||||
check_exitcode linuxcnc_kinematics_probe
|
||||
@@ -381,6 +565,157 @@ grep -Fq "xyzac_trt_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT
|
||||
grep -Fq "xyzbc_trt_switch_mcodes_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
|
||||
grep -Fq "fiveaxis_remap_assets_from_linuxcnc=1" "$FIVEAXIS_REMAP_ASSET_STDOUT"
|
||||
|
||||
MILLTURN_USER_M_BOUNDARY_STDOUT="$BUILD_DIR/linuxcnc_millturn_user_m_boundary_probe.run.stdout.log"
|
||||
grep -Fq "millturn_ini_open=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_RS274NGC.USER_M_PATH_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_RS274NGC.SUBROUTINE_PATH_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_DISPLAY.PYVCP_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_HAL.HALUI_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_state_mode=mill" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_guard_pin=kinstype.is-0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_script_tcl_hal_runtime=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_remap_calls_user_m_process=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_switchkins_output_pin=motion.analog-out-03" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_switchkins_target=0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_work_offset_pocket=P7" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_work_offset_words=X-290 Y0 Z-160 A0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_active_g5x=G59.1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_calls_M128=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M428_source_transition_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_X_AXIS_X.MIN_LIMIT_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_X_AXIS_X.MAX_LIMIT_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_Z_AXIS_Z.MAX_LIMIT_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M128_source_state_targets_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_state_mode=turn" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_guard_pin=kinstype.is-1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_script_tcl_hal_runtime=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_remap_calls_user_m_process=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_switchkins_output_pin=motion.analog-out-03" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_switchkins_target=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_work_offset_pocket=P8" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_work_offset_words=X-160 Y0 Z-290 A0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_active_g5x=G59.2" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_calls_M129=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M429_source_transition_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_X_AXIS_X.MIN_LIMIT_TURN_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_Z_AXIS_Z.MAX_LIMIT_TURN_ok=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "M129_source_state_targets_from_linuxcnc=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_user_m_native_source_state_proof=1" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_user_m_execution_enabled=0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
grep -Fq "millturn_user_m_promotion_allowed=0" "$MILLTURN_USER_M_BOUNDARY_STDOUT"
|
||||
|
||||
MILLTURN_USER_M_RUNTIME_STDOUT="$BUILD_DIR/linuxcnc_millturn_user_m_runtime_probe.run.stdout.log"
|
||||
grep -Fq "millturn_user_m_runtime_requirements=" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
grep -Fq "millturn_user_m_source_proof_ready=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
grep -Fq "millturn_user_m_execution_enabled=0" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
grep -Fq "millturn_user_m_promotion_allowed=0" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
if grep -Fq "millturn_user_m_runtime_ready=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"; then
|
||||
grep -Eq "millturn_user_m_runtime_probe_status=(ready_disabled_by_default|runtime_state_probe_passed)" \
|
||||
"$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
if grep -Fq "millturn_user_m_runtime_probe_status=runtime_state_probe_passed" "$MILLTURN_USER_M_RUNTIME_STDOUT"; then
|
||||
grep -Fq "millturn_user_m_M128_runtime_state_ok=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
grep -Fq "millturn_user_m_M129_runtime_state_ok=1" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
fi
|
||||
else
|
||||
grep -Fq "millturn_user_m_runtime_ready=0" "$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
grep -Fq "millturn_user_m_runtime_probe_status=skipped_missing_host_runtime" \
|
||||
"$MILLTURN_USER_M_RUNTIME_STDOUT"
|
||||
fi
|
||||
|
||||
TOOL_DB_BOUNDARY_STDOUT="$BUILD_DIR/linuxcnc_tool_db_boundary_probe.run.stdout.log"
|
||||
grep -Fq "db_nonran_ini_open=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "db_nonran_EMCIO.RANDOM_TOOLCHANGER_ok=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "db_nonran_EMCIO.DB_PROGRAM_ok=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "db_nonran_tool_table_ignored_with_db_program=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_task_db_mode_init=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_task_ignores_tool_table_with_db_program=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_task_load_unload_notify=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_child_process_boundary=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_program_executable_check=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_v2_1_handshake=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_getall_g_until_fini=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_notify_l_u_p_protocol=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_program_tooldb_module=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_program_nonran_callbacks=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_program_nonran_state_targets=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_program_reload_rules=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_native_source_protocol_proof=1" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_execution_enabled=0" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
grep -Fq "tool_db_promotion_allowed=0" "$TOOL_DB_BOUNDARY_STDOUT"
|
||||
|
||||
TOOL_DB_RUNTIME_STDOUT="$BUILD_DIR/linuxcnc_tool_db_runtime_probe.run.stdout.log"
|
||||
grep -Fq "tool_db_runtime_requirements=" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_source_proof_ready=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_execution_enabled=0" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_promotion_allowed=0" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
if grep -Fq "tool_db_runtime_ready=1" "$TOOL_DB_RUNTIME_STDOUT"; then
|
||||
grep -Eq "tool_db_runtime_probe_status=(ready_disabled_by_default|runtime_protocol_probe_passed)" \
|
||||
"$TOOL_DB_RUNTIME_STDOUT"
|
||||
if grep -Fq "tool_db_runtime_probe_status=runtime_protocol_probe_passed" "$TOOL_DB_RUNTIME_STDOUT"; then
|
||||
grep -Fq "tool_db_runtime_protocol_probe_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_get_all_fini=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_put_tool_update_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_load_spindle_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_unload_spindle_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_persistence_state_ok=1" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
fi
|
||||
else
|
||||
grep -Fq "tool_db_runtime_ready=0" "$TOOL_DB_RUNTIME_STDOUT"
|
||||
grep -Fq "tool_db_runtime_probe_status=skipped_missing_host_runtime" \
|
||||
"$TOOL_DB_RUNTIME_STDOUT"
|
||||
fi
|
||||
|
||||
PYTHON_REMAP_BOUNDARY_STDOUT="$BUILD_DIR/linuxcnc_python_remap_boundary_probe.run.stdout.log"
|
||||
grep -Fq "python_runtime_pycall_dispatch=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_runtime_remap_phases=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_runtime_generator_finish=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_runtime_callable_lookup=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_runtime_execute_runtime=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_plugin_initializes_python=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_plugin_toplevel_exec_file=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_plugin_ini_python_path=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_plugin_callable_invoke=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_plugin_reload_on_change=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_family_axis_laser_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_family_twp_nutating_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_family_axis_remap_cycle_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_family_gmoccapy_stdglue_inventory=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_remap_native_source_inventory_proof=1" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_remap_execution_enabled=0" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
grep -Fq "python_remap_promotion_allowed=0" "$PYTHON_REMAP_BOUNDARY_STDOUT"
|
||||
|
||||
PYTHON_REMAP_RUNTIME_STDOUT="$BUILD_DIR/linuxcnc_python_remap_runtime_probe.run.stdout.log"
|
||||
grep -Fq "python_remap_runtime_fixture_family=axis/remap/stop-lookahead/nc_files" \
|
||||
"$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_runtime_fixture_id=stop_lookahead_python_runtime_lifecycle" \
|
||||
"$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_runtime_fixture_scope=no_python_callables_no_ngc_only_subpaths" \
|
||||
"$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_runtime_requirements=" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_runtime_modules=axis/remap/stop-lookahead/python/remap.py,axis/remap/stop-lookahead/python/toplevel.py" \
|
||||
"$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_source_proof_ready=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_execution_enabled=0" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_promotion_allowed=0" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
if grep -Fq "python_remap_runtime_ready=1" "$PYTHON_REMAP_RUNTIME_STDOUT"; then
|
||||
grep -Eq "python_remap_runtime_probe_status=(ready_disabled_by_default|runtime_lifecycle_probe_passed)" \
|
||||
"$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
if grep -Fq "python_remap_runtime_probe_status=runtime_lifecycle_probe_passed" "$PYTHON_REMAP_RUNTIME_STDOUT"; then
|
||||
grep -Fq "python_remap_runtime_lifecycle_probe_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_interpreter_sentinel_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_toplevel_imported=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_remap_imported=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_callable_lookup_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_generator_returned=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_generator_first_yield=2" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_lifecycle_generator_finish_ok=1" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
fi
|
||||
else
|
||||
grep -Fq "python_remap_runtime_ready=0" "$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
grep -Fq "python_remap_runtime_probe_status=skipped_missing_host_runtime" \
|
||||
"$PYTHON_REMAP_RUNTIME_STDOUT"
|
||||
fi
|
||||
|
||||
REMAP_PARSE_STDOUT="$BUILD_DIR/linuxcnc_remap_parse_harness.run.stdout.log"
|
||||
|
||||
check_remap_descriptor() {
|
||||
|
||||
@@ -22,7 +22,8 @@ while [[ $# -gt 0 ]]; do
|
||||
Usage: $0 [--only PATH_SUBSTRING]
|
||||
|
||||
Runs LinuxCNC configs/sim .ngc programs through LinuxCNC's rs274 standalone
|
||||
entry point and writes logs plus summary.tsv under:
|
||||
entry point and writes logs plus summary.tsv, class-summary.tsv, and
|
||||
path-matrix.tsv under:
|
||||
$BUILD_DIR
|
||||
EOF
|
||||
exit 0
|
||||
@@ -44,6 +45,10 @@ if [[ ! -d "$SIM_DIR" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$BUILD_DIR"
|
||||
exec 9>"$BUILD_DIR/inventory.lock"
|
||||
flock 9
|
||||
|
||||
"$ROOT_DIR/tools/build_native_probes.sh"
|
||||
|
||||
export LD_LIBRARY_PATH="$LINUXCNC_DIR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
@@ -52,6 +57,8 @@ export PYTHONPATH="$LINUXCNC_DIR/lib/python${PYTHONPATH:+:$PYTHONPATH}"
|
||||
mkdir -p "$BUILD_DIR"/{logs,out,wrapped,params}
|
||||
: > "$BUILD_DIR/skipped.tsv"
|
||||
SUMMARY_FILE="$BUILD_DIR/summary.tsv"
|
||||
CLASS_SUMMARY_FILE="$BUILD_DIR/class-summary.tsv"
|
||||
PATH_MATRIX_FILE="$BUILD_DIR/path-matrix.tsv"
|
||||
printf 'path\tclass\tstatus\texpected_failure\texit_code\tseconds\tini\ttbl\toutput_lines\tstderr_summary\n' > "$SUMMARY_FILE"
|
||||
|
||||
relpath() {
|
||||
@@ -392,9 +399,69 @@ while IFS= read -r ngc; do
|
||||
"$stderr_summary" >> "$SUMMARY_FILE"
|
||||
done < <(find "$SIM_DIR" -type f -name '*.ngc' | sort)
|
||||
|
||||
{
|
||||
printf 'class\tstatus\texpected_failure\tcount\n'
|
||||
awk -F '\t' '
|
||||
NR > 1 {
|
||||
class[$2] += 1
|
||||
status[$2 "\t" $3] += 1
|
||||
if ($4 != "") {
|
||||
expected[$2 "\t" $4] += 1
|
||||
}
|
||||
}
|
||||
END {
|
||||
for (key in class) {
|
||||
print key "\tALL\t-\t" class[key]
|
||||
}
|
||||
for (key in status) {
|
||||
split(key, parts, "\t")
|
||||
print parts[1] "\t" parts[2] "\t-\t" status[key]
|
||||
}
|
||||
for (key in expected) {
|
||||
split(key, parts, "\t")
|
||||
print parts[1] "\tEXPECTED_FAIL\t" parts[2] "\t" expected[key]
|
||||
}
|
||||
}
|
||||
' "$SUMMARY_FILE" | sort
|
||||
} > "$CLASS_SUMMARY_FILE"
|
||||
|
||||
awk -F '\t' '
|
||||
BEGIN {
|
||||
OFS = "\t"
|
||||
print "path", "class", "status", "expected_failure", "ini", "tbl", "runtime_family", "blocked"
|
||||
}
|
||||
NR > 1 {
|
||||
runtime_family = $1
|
||||
sub("/[^/]+$", "", runtime_family)
|
||||
blocked = ""
|
||||
if ($1 ~ /^axis\/db_demo\//) {
|
||||
blocked = "L4-TOOL-DB"
|
||||
} else if ($1 ~ /^axis\/vismach\/millturn\// && $2 == "main") {
|
||||
blocked = "L4-USER-M-PROCESS"
|
||||
} else if ($4 == "upstream-demo-missing-motion-gcode") {
|
||||
blocked = "UPSTREAM-DEMO"
|
||||
} else if ($1 ~ /^axis\/remap\// && $2 == "main") {
|
||||
blocked = "L4-PYTHON-REMAP"
|
||||
} else if ($1 ~ /^axis\/vismach\/VMC_toolchange\// && $2 == "main") {
|
||||
blocked = "L4-PYTHON-REMAP"
|
||||
} else if ($1 ~ /^gmoccapy\//) {
|
||||
blocked = "L4-PYTHON-REMAP"
|
||||
} else if ($1 ~ /^axis\/laser\//) {
|
||||
blocked = "L4-PYTHON-REMAP"
|
||||
} else if ($1 ~ /^axis\/vismach\/5axis\/table-rotary_spindle-rotary-nutating\/demos\//) {
|
||||
blocked = "L4-PYTHON-REMAP"
|
||||
} else if ($2 == "remap_subroutine") {
|
||||
blocked = "ASSET-ONLY"
|
||||
}
|
||||
print $1, $2, $3, ($4 == "" ? "-" : $4), $7, $8, runtime_family, (blocked == "" ? "-" : blocked)
|
||||
}
|
||||
' "$SUMMARY_FILE" > "$PATH_MATRIX_FILE"
|
||||
|
||||
{
|
||||
printf 'sim config harness summary\n'
|
||||
printf 'summary: %s\n' "$SUMMARY_FILE"
|
||||
printf 'class_summary: %s\n' "$CLASS_SUMMARY_FILE"
|
||||
printf 'path_matrix: %s\n' "$PATH_MATRIX_FILE"
|
||||
printf 'total: %s\n' "$total"
|
||||
printf 'pass: %s\n' "$pass"
|
||||
printf 'fail: %s\n' "$fail"
|
||||
|
||||
Reference in New Issue
Block a user