验证ToolDb浏览器证据
结论:已新增Tool DB browser smoke,验证protocol transcript、OPFS flat-file/transcript persistence和diagnostics guard,baseline保持28/28/131/0且promotion继续锁定。
This commit is contained in:
115
wasm-port/tests/browser/tool_db_process_browser_smoke.html
Normal file
115
wasm-port/tests/browser/tool_db_process_browser_smoke.html
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>LinuxCNC Tool DB Process Browser Smoke</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<pre id="status">running</pre>
|
||||||
|
<script type="module">
|
||||||
|
import {
|
||||||
|
createLinuxCncToolDbProcessPort,
|
||||||
|
createToolDbProcessDiagnostics,
|
||||||
|
createToolDbStorePaths,
|
||||||
|
loadToolDbFile,
|
||||||
|
loadToolDbTranscript,
|
||||||
|
saveToolDbFile,
|
||||||
|
saveToolDbTranscript,
|
||||||
|
validateToolDbTranscript,
|
||||||
|
} from "../../runtime/sdk/src/index.js";
|
||||||
|
|
||||||
|
const status = document.getElementById("status");
|
||||||
|
|
||||||
|
function assertEqual(actual, expected, label) {
|
||||||
|
if (actual !== expected) {
|
||||||
|
throw new Error(`${label}: expected ${expected}, got ${actual}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function assertMatch(value, pattern, label) {
|
||||||
|
if (!pattern.test(value)) {
|
||||||
|
throw new Error(`${label}: ${value}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const machineId = "browser-tool-db-gate";
|
||||||
|
const runId = "browser-tool-db-run";
|
||||||
|
const paths = createToolDbStorePaths(machineId, { runId });
|
||||||
|
assertEqual(paths.dbFile, "linuxcnc/machines/browser-tool-db-gate/tool-db/db_nonran_file", "DB file path");
|
||||||
|
assertEqual(
|
||||||
|
paths.transcript,
|
||||||
|
"linuxcnc/machines/browser-tool-db-gate/tool-db/transcripts/browser-tool-db-run/transcript.json",
|
||||||
|
"transcript path",
|
||||||
|
);
|
||||||
|
|
||||||
|
const port = createLinuxCncToolDbProcessPort({
|
||||||
|
dbProgramPath: "./db_nonran.py",
|
||||||
|
sourceFiles: [
|
||||||
|
"configs/sim/axis/db_demo/db_nonran.py",
|
||||||
|
"configs/sim/axis/db_demo/db.py",
|
||||||
|
"lib/python/tooldb.py",
|
||||||
|
],
|
||||||
|
runtimeMode: "contract-only",
|
||||||
|
});
|
||||||
|
const startResult = await port.start();
|
||||||
|
assertEqual(startResult.runtimeExecutionReady, false, "contract-only runtime execution");
|
||||||
|
const planResult = await port.runTransactionPlan();
|
||||||
|
assertEqual(planResult.status, "blocked_runtime_adapter_required", "contract-only plan status");
|
||||||
|
assertEqual(planResult.tblFallbackSufficient, false, "tbl fallback guard");
|
||||||
|
|
||||||
|
const transcript = [
|
||||||
|
{ direction: "read", line: "v2.1" },
|
||||||
|
{ direction: "write", line: "g" },
|
||||||
|
{ direction: "read", line: "T10 P110 D0.10 Z0.10" },
|
||||||
|
{ direction: "read", line: "FINI (get_cmd)" },
|
||||||
|
{ direction: "write", line: "p t11 p111 d0.33 z0.11" },
|
||||||
|
{ direction: "write", line: "l t14 p0" },
|
||||||
|
{ direction: "write", line: "u t0 p0" },
|
||||||
|
];
|
||||||
|
assertEqual(validateToolDbTranscript(transcript).ready, true, "transcript readiness");
|
||||||
|
|
||||||
|
const dbFileText = "T11 P111 D0.33 Z0.11\nT14 P114 D0.14 Z0.14\n";
|
||||||
|
const savedDb = await saveToolDbFile(machineId, dbFileText);
|
||||||
|
const savedTranscript = await saveToolDbTranscript(machineId, runId, transcript);
|
||||||
|
assertEqual(savedDb.displayPath, "/machines/browser-tool-db-gate/tool-db/db_nonran_file", "display DB path");
|
||||||
|
assertEqual(
|
||||||
|
savedTranscript.displayPath,
|
||||||
|
"/machines/browser-tool-db-gate/tool-db/transcripts/browser-tool-db-run/transcript.json",
|
||||||
|
"display transcript path",
|
||||||
|
);
|
||||||
|
assertMatch(savedDb.dbFileHash, /^[0-9a-f]{8}$/, "DB hash");
|
||||||
|
assertMatch(savedTranscript.transcriptHash, /^[0-9a-f]{8}$/, "transcript hash");
|
||||||
|
|
||||||
|
const loadedDb = await loadToolDbFile(machineId);
|
||||||
|
const loadedTranscript = await loadToolDbTranscript(machineId, runId);
|
||||||
|
assertEqual(loadedDb.text, dbFileText, "loaded DB file");
|
||||||
|
assertEqual(loadedTranscript.payload.schema, "linuxcnc.toolDbProcessTranscript.v1", "transcript schema");
|
||||||
|
assertEqual(loadedTranscript.payload.transcript.length, transcript.length, "loaded transcript length");
|
||||||
|
|
||||||
|
const diagnostics = createToolDbProcessDiagnostics({
|
||||||
|
dbProgramPath: "./db_nonran.py",
|
||||||
|
opfsDbPath: savedDb.displayPath,
|
||||||
|
transcript,
|
||||||
|
dbFileText,
|
||||||
|
startupToolCount: 10,
|
||||||
|
mutationCount: 3,
|
||||||
|
runtimeMode: "wasm-tool-db-protocol-worker",
|
||||||
|
});
|
||||||
|
assertEqual(diagnostics.runtimeMode, "wasm-tool-db-protocol-worker", "diagnostics runtime mode");
|
||||||
|
assertEqual(diagnostics.dbProgramPath, "./db_nonran.py", "diagnostics DB_PROGRAM");
|
||||||
|
assertEqual(diagnostics.protocolTranscriptReady, true, "diagnostics transcript");
|
||||||
|
assertEqual(diagnostics.opfsPersistenceReady, true, "diagnostics OPFS");
|
||||||
|
assertEqual(diagnostics.tblFallbackSufficient, false, "diagnostics tbl fallback guard");
|
||||||
|
assertEqual(diagnostics.runtimeExecutionReady, false, "diagnostics runtime execution");
|
||||||
|
assertEqual(diagnostics.executionEnabled, false, "diagnostics execution");
|
||||||
|
assertEqual(diagnostics.promotionAllowed, false, "diagnostics promotion");
|
||||||
|
|
||||||
|
status.textContent = "browser_tool_db_process_smoke=ok";
|
||||||
|
} catch (error) {
|
||||||
|
status.textContent = `browser_tool_db_process_smoke=fail\n${error.stack || error}`;
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
74
wasm-port/tests/browser/verify_tool_db_process_browser.sh
Normal file
74
wasm-port/tests/browser/verify_tool_db_process_browser.sh
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||||
|
CHROMIUM="${CHROMIUM:-$(command -v chromium || command -v chromium-browser || command -v google-chrome || command -v google-chrome-stable || true)}"
|
||||||
|
|
||||||
|
if [[ -z "$CHROMIUM" ]]; then
|
||||||
|
echo "missing Chromium-compatible browser; set CHROMIUM=/path/to/browser" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TMP_DIR="$(mktemp -d)"
|
||||||
|
PORT_FILE="$TMP_DIR/port"
|
||||||
|
SERVER_LOG="$TMP_DIR/server.log"
|
||||||
|
CHROME_PROFILE="$TMP_DIR/chrome-profile"
|
||||||
|
mkdir -p "$CHROME_PROFILE"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
if [[ -n "${SERVER_PID:-}" ]]; then
|
||||||
|
kill "$SERVER_PID" 2>/dev/null || true
|
||||||
|
wait "$SERVER_PID" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
rm -rf "$TMP_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
python3 - <<'PY' "$ROOT_DIR" "$PORT_FILE" >"$SERVER_LOG" 2>&1 &
|
||||||
|
import functools
|
||||||
|
import http.server
|
||||||
|
import pathlib
|
||||||
|
import socketserver
|
||||||
|
import sys
|
||||||
|
|
||||||
|
root = pathlib.Path(sys.argv[1])
|
||||||
|
port_file = pathlib.Path(sys.argv[2])
|
||||||
|
|
||||||
|
handler = functools.partial(http.server.SimpleHTTPRequestHandler, directory=str(root))
|
||||||
|
with socketserver.TCPServer(("127.0.0.1", 0), handler) as httpd:
|
||||||
|
port_file.write_text(str(httpd.server_address[1]), encoding="ascii")
|
||||||
|
httpd.serve_forever()
|
||||||
|
PY
|
||||||
|
SERVER_PID=$!
|
||||||
|
|
||||||
|
for _ in $(seq 1 100); do
|
||||||
|
[[ -s "$PORT_FILE" ]] && break
|
||||||
|
sleep 0.05
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ! -s "$PORT_FILE" ]]; then
|
||||||
|
echo "Tool DB process browser smoke HTTP server did not start" >&2
|
||||||
|
cat "$SERVER_LOG" >&2 || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PORT="$(cat "$PORT_FILE")"
|
||||||
|
URL="http://127.0.0.1:$PORT/tests/browser/tool_db_process_browser_smoke.html"
|
||||||
|
OUT="$TMP_DIR/chromium.out"
|
||||||
|
|
||||||
|
"$CHROMIUM" \
|
||||||
|
--headless=new \
|
||||||
|
--disable-gpu \
|
||||||
|
--no-sandbox \
|
||||||
|
--user-data-dir="$CHROME_PROFILE" \
|
||||||
|
--virtual-time-budget=10000 \
|
||||||
|
--dump-dom \
|
||||||
|
"$URL" >"$OUT" 2>&1
|
||||||
|
|
||||||
|
if ! grep -Fq "browser_tool_db_process_smoke=ok" "$OUT"; then
|
||||||
|
echo "Tool DB process browser smoke failed" >&2
|
||||||
|
sed -n '1,220p' "$OUT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "browser_tool_db_process_smoke=ok"
|
||||||
Reference in New Issue
Block a user