Files
cnc_wams/wasm-port/tests/native/probe_tool_db_runtime.sh

233 lines
7.5 KiB
Bash

#!/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