Bridge warden-ui's debug channel out of the qemu VM
The rig could drive the UI and detect one outcome: the process died. Nothing could ask the UI what page it was on or what a tap would land on, because that channel is a FIFO inside the guest and the initramfs is busybox-only with no sshd. Scenarios therefore asserted nothing and screenshots went unread. run.sh --ctl exposes a second pci-serial port as a unix socket, the same device the RS485 bridge already rides, listed first so it is always ttyS0. It also puts warden.ctl on the kernel command line, and init bridges only when that marker is present: a VM launched with --rs485 alone has a ttyS0 too, and that one is the Modbus wire. The bridge relays one command line in and the FIFO's reply out, then a sentinel so the reader needs no timeout. qmp.py gains the channel verbs (nav, page, stats, hit, assert_page, assert_hit), records every step to results.jsonl as ok/fail/fatal, continues past an assertion mismatch so one run reports every broken expectation, and checks the console after EVERY step for the stage-2 init's EXITED line so a crash is pinned to the step that caused it. assert_hit matches the widget's bounding box: an icon has no usable caption and two list rows share a class, but the geometry the UI itself resolved is exact. The vocabulary is what tools/warden-ctl already speaks over SSH to a real panel, so a script that runs here runs there. Verified end to end on the rig (11/11 verbs round-tripped) and against the bench panel, where the same commands returned byte-identical results. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013aHKWzT5EF86RFKRMtAv9n
This commit is contained in:
+34
-5
@@ -64,6 +64,7 @@ for _attempt in 1 2 3; do
|
||||
PORT=$((21000 + RANDOM % 20000))
|
||||
: > "$WORK/console.log"
|
||||
bash "$QDIR/run.sh" --kernel "$ZIMAGE" --display headless --qmp "$WORK/qmp.sock" \
|
||||
--ctl "$WORK/ctl.sock" \
|
||||
--ssh-port "$PORT" --http-port $((PORT + 1)) --api-port $((PORT + 2)) \
|
||||
> "$WORK/console.log" 2>&1 &
|
||||
QEMU_PID=$!
|
||||
@@ -118,15 +119,43 @@ done
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "== driving $SCRIPT"
|
||||
python3 "$HERE/qmp.py" "$WORK/qmp.sock" drive "$SCRIPT" "$OUTDIR"
|
||||
# The control bridge (init -> warden-ui's debug FIFO, see run.sh --ctl) comes
|
||||
# up with the UI; a script's first `page`/`hit` must not race it. Bounded, and
|
||||
# fail-closed: a scenario that asserts on UI state needs the channel, and a
|
||||
# silently absent one would turn every assertion into an infrastructure error
|
||||
# dressed as a test result.
|
||||
echo "== waiting for the control bridge"
|
||||
deadline=$((SECONDS + 60))
|
||||
until grep -aq 'init: control bridge on' "$WORK/console.log"; do
|
||||
[ $SECONDS -lt $deadline ] || {
|
||||
echo "FATAL: the control bridge never announced itself (run.sh --ctl / init marker)" >&2
|
||||
tail -25 "$WORK/console.log" >&2
|
||||
exit 1
|
||||
}
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# The UI must still be alive: see the header. Checked AFTER the script so a
|
||||
# crash caused by the interaction is caught, which is the usual case.
|
||||
echo "== driving $SCRIPT"
|
||||
# Every step lands in results.jsonl (ok / fail / fatal); an assertion mismatch
|
||||
# is a `fail` and the run continues, so one run reports every broken
|
||||
# expectation. The driver's exit status is the verdict; capture it rather than
|
||||
# let `set -e` skip the backstop and the summary below.
|
||||
drive_rc=0
|
||||
python3 "$HERE/qmp.py" "$WORK/qmp.sock" drive "$SCRIPT" "$OUTDIR" \
|
||||
--ctl "$WORK/ctl.sock" --console "$WORK/console.log" || drive_rc=$?
|
||||
|
||||
# The UI must still be alive: see the header. The driver checks this after
|
||||
# every step and pins a crash to the step that caused it; this is the
|
||||
# backstop for a death after the last step, or a driver that itself fell over.
|
||||
if grep -aq 'warden-ui EXITED' "$WORK/console.log"; then
|
||||
echo "FATAL: warden-ui DIED during the run:" >&2
|
||||
grep -a -A22 'warden-ui EXITED' "$WORK/console.log" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$drive_rc" -ne 0 ]; then
|
||||
echo "UI-DRIVE-FAIL: see $OUTDIR/results.jsonl" >&2
|
||||
grep -E '"status": "(fail|fatal)"' "$OUTDIR/results.jsonl" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "UI-DRIVE-PASS (screenshots in $OUTDIR)"
|
||||
echo "UI-DRIVE-PASS (results in $OUTDIR/results.jsonl, screenshots in $OUTDIR)"
|
||||
|
||||
Reference in New Issue
Block a user