qemu: wake verb, idle stat, and no fbcon cursor in the framebuffer
- tests/qmp.py: `wake` is a judged verb (the reply must be the channel's own ack) and `assert_stat` knows `idle` (0 awake, 1 dimmed, 2 asleep). warden-ui's sleep.c swallows the touch that wakes a dimmed or blanked panel, so every compiled flow script now opens with wake (flare-edge #148); tests cover both. - run.sh: vt.global_cursor_default=0. fbcon shares the virtio-gpu framebuffer with warden-ui and its cursor blinked an 8x2 block onto the top-left corner in some boots and not others, which made a structural pixel reference fail by one cell (#18). The panel has no fbcon on its display, so this only makes the rig match it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013aHKWzT5EF86RFKRMtAv9n
This commit is contained in:
+19
-6
@@ -26,6 +26,10 @@ warden_debug.c. The same channel is what tools/warden-ctl reaches over SSH on
|
||||
a real panel, so these verbs mean the same thing on the rig and on hardware:
|
||||
|
||||
nav MENU[/TAB] jump to a page; fails if the page is unknown
|
||||
wake wake the UI as if touched, minus the swallow
|
||||
(sleep.c dims and then blanks an idle panel and
|
||||
eats the touch that ends either); every compiled
|
||||
flow script opens with it
|
||||
page | stats | hit X Y print the reply, judge nothing
|
||||
ctl WORDS... raw passthrough for anything the channel grows
|
||||
assert_page MENU/TAB the active page is exactly this
|
||||
@@ -55,9 +59,10 @@ math, this file only drives it.
|
||||
document is a live snapshot and the key might
|
||||
simply not be built yet.
|
||||
assert_stat FIELD OP VALUE
|
||||
FIELD is cpu, fps or render, read off a fresh
|
||||
`stats` reply (warden_debug.c). Same OP vocabulary
|
||||
as assert_json.
|
||||
FIELD is cpu, fps, render or idle (0 awake,
|
||||
1 dimmed, 2 asleep), read off a fresh `stats`
|
||||
reply (warden_debug.c). Same OP vocabulary as
|
||||
assert_json.
|
||||
capture_region NAME X Y W H TOLERANCE
|
||||
screendump now, crop to X,Y,WxH, and (over)write
|
||||
NAME in the refs file with both a phash and a
|
||||
@@ -382,12 +387,13 @@ STATS_FIELD_RE = {
|
||||
"cpu": re.compile(r'^cpu:\s*(-?\d+(?:\.\d+)?)%?\s*$'),
|
||||
"fps": re.compile(r'^fps:\s*(-?\d+(?:\.\d+)?)\s*$'),
|
||||
"render": re.compile(r'^render:\s*(-?\d+(?:\.\d+)?)\s*ms/frame\s*$'),
|
||||
"idle": re.compile(r'^idle:\s*(\d+)\s*$'),
|
||||
}
|
||||
|
||||
|
||||
def parse_stats(reply):
|
||||
"""The `stats` reply (warden_debug.c: 'page: X\\ncpu: N%\\nfps: N\\n
|
||||
render: A.BB ms/frame\\nrga: N%') -> {'cpu'|'fps'|'render': float} for
|
||||
render: A.BB ms/frame\\nrga: N%\\nidle: N') -> {'cpu'|'fps'|'render'|'idle': float} for
|
||||
whichever lines are present. A field the reply lacks is simply absent
|
||||
from the result -- the caller reports that as 'no such field', the same
|
||||
shape as resolve_path's 'no such path' for the json channel."""
|
||||
@@ -515,6 +521,13 @@ def drive(s, f, script_path, outdir, size, ctl_path=None, console_path=None, ref
|
||||
need_ctl(lineno, cmd)
|
||||
reply = ctl.send("nav " + " ".join(args))
|
||||
record(lineno, line, "ok" if reply.endswith(": ok") else "fail", reply)
|
||||
elif cmd == "wake":
|
||||
# Judged, unlike the query verbs: a UI that does not answer the
|
||||
# wake is one whose next tap may be swallowed, and that must not
|
||||
# read as a passing step.
|
||||
need_ctl(lineno, cmd)
|
||||
reply = ctl.send("wake")
|
||||
record(lineno, line, "ok" if reply == "wake: ok" else "fail", reply)
|
||||
elif cmd in ("page", "hit", "stats", "ctl"):
|
||||
# Query verbs: print the reply, never judge it. `ctl` is a raw
|
||||
# passthrough for anything the channel grows later.
|
||||
@@ -587,9 +600,9 @@ def drive(s, f, script_path, outdir, size, ctl_path=None, console_path=None, ref
|
||||
# assert_stat FIELD OP VALUE: FIELD off a fresh `stats` reply.
|
||||
need_ctl(lineno, cmd)
|
||||
field, op, value = args[0], args[1], args[2]
|
||||
if field not in ("cpu", "fps", "render"):
|
||||
if field not in ("cpu", "fps", "render", "idle"):
|
||||
record(lineno, line, "fail", f"unknown stat field {field!r} "
|
||||
f"(known: cpu, fps, render)")
|
||||
f"(known: cpu, fps, render, idle)")
|
||||
else:
|
||||
stats = parse_stats(ctl.send("stats"))
|
||||
if field not in stats:
|
||||
|
||||
Reference in New Issue
Block a user