chore: import upstream snapshot with attribution
This commit is contained in:
Executable
+152
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env bash
|
||||
# Linux canvas smoke under Xvfb — run on a machine with NO WebKitGTK dev
|
||||
# package, which makes the build itself the native-only link test.
|
||||
#
|
||||
# Exercises the Linux gpu_surface software path without a display server:
|
||||
# builds examples/ui-inbox (a native-only app, so its GTK host compiles
|
||||
# with the WebKitGTK stub seam and never links webkitgtk-6.0) with
|
||||
# -Dplatform=linux -Dweb-engine=system -Dautomation=true, runs it under
|
||||
# Xvfb, and asserts against the automation snapshot:
|
||||
#
|
||||
# 1. the built ELF carries no WebKitGTK reference (no libwebkitgtk
|
||||
# DT_NEEDED entry, no webkit_/jsc_ dynamic symbol), audited on the
|
||||
# real binary by tools/audit_web_layer.zig
|
||||
# 2. snapshot ready=true (app booted, automation server live)
|
||||
# 3. gpu_backend=software (the software present path is active)
|
||||
# 4. gpu_nonblank=true (real pixels were presented)
|
||||
# 5. widget-click "Add task" -> '4 open' (automation input mutates state)
|
||||
# 6. automate screenshot renders a non-empty PNG
|
||||
# 7. ZERO WebKit helper processes for the whole run (a native-only app
|
||||
# has no web layer to boot WebKit with)
|
||||
#
|
||||
# Deliberately NOT `set -e` (same as windows-canvas-smoke.sh): grep exits 1
|
||||
# on zero matches, and under `set -e` an assignment like `x=$(grep ...)` or
|
||||
# a swallowed `$(cli 2>&1)` capture dies with NO output — this job failed
|
||||
# three times with nothing in the log but the exit code. Every assertion
|
||||
# goes through fail(), which dumps the snapshot and the app log.
|
||||
set -u
|
||||
|
||||
# No WebKit sandbox workaround: a native-only app's host is compiled
|
||||
# without the web layer entirely (and even in web builds the main
|
||||
# WebView is lazy), so no WebKit helper processes start and the runner's
|
||||
# user-namespace restrictions never come into play. The zero-WebKit
|
||||
# assertion below keeps it that way.
|
||||
|
||||
# GTK_A11Y=none: under Xvfb there is no session bus providing org.a11y.Bus,
|
||||
# and GTK4's a11y init blocks ~25 s on the GDBus name lookup before warning
|
||||
# and continuing — the app's first runtime event landed after the readiness
|
||||
# window had already expired (reproduced in a local container: without this
|
||||
# the wait times out at startup; with it the full smoke passes).
|
||||
# Accessibility is not what this smoke tests.
|
||||
export GTK_A11Y="${GTK_A11Y:-none}"
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
app_dir="$repo_root/examples/ui-inbox"
|
||||
snap="$app_dir/.zig-cache/native-sdk-automation/snapshot.txt"
|
||||
cli="$repo_root/zig-out/bin/native"
|
||||
app_log="${TMPDIR:-/tmp}/linux-canvas-smoke-app.log"
|
||||
|
||||
# Readiness budget. Even with GTK_A11Y=none, shared ubuntu-24.04 runners
|
||||
# show a consistent ~27 s stall between EGL init and the app's first
|
||||
# runtime event (measured in runs 28690855597 pass / 28691951139 fail —
|
||||
# the SAME stall in both; the old hard 30 s `automate wait` window flipped
|
||||
# green/red on one or two seconds of runner noise). Local containers show
|
||||
# no stall at all. Widen the budget here instead of weakening the CLI
|
||||
# default; every correctness assertion stays strict.
|
||||
ready_timeout_ms=90000
|
||||
|
||||
app_pid=""
|
||||
cleanup() {
|
||||
[ -n "$app_pid" ] && kill "$app_pid" >/dev/null 2>&1
|
||||
# xvfb-run does not forward signals to an already-detached app; reap the
|
||||
# app and its Xvfb directly so local runs exit clean (CI would otherwise
|
||||
# rely on the runner's orphan sweep).
|
||||
pkill -f "$app_dir/zig-out/bin/ui-inbox" >/dev/null 2>&1
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
diagnostics() {
|
||||
echo "---- diagnostics ----"
|
||||
echo "-- snapshot ($snap):"
|
||||
if [ -f "$snap" ]; then tr '|' '\n' < "$snap" | sed 's/^/ /'; else echo " (missing)"; fi
|
||||
echo "-- app log head ($app_log):"
|
||||
head -20 "$app_log" 2>/dev/null | sed 's/^/ /'
|
||||
echo "-- app log tail ($app_log):"
|
||||
tail -40 "$app_log" 2>/dev/null | sed 's/^/ /'
|
||||
echo "---------------------"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $1"
|
||||
diagnostics
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Canvas apps must never spawn WebKit: the window's main WebView is
|
||||
# created lazily and nothing in this app materializes it, so any
|
||||
# WebKitWebProcess/WebKitNetworkProcess during the run means an eager
|
||||
# creation regressed (and with it launch latency, resident helper
|
||||
# processes, and the sandbox trouble this smoke used to work around).
|
||||
assert_no_webkit() {
|
||||
local helpers
|
||||
helpers=$(pgrep -af 'WebKit(Web|Network)Process' 2>/dev/null)
|
||||
if [ -n "$helpers" ]; then
|
||||
echo "-- WebKit helper processes found ($1):"
|
||||
echo "$helpers" | sed 's/^/ /'
|
||||
fail "canvas app spawned WebKit processes ($1)"
|
||||
fi
|
||||
}
|
||||
|
||||
# ---- build ----------------------------------------------------------------
|
||||
(cd "$repo_root" && zig build) || fail "root zig build (CLI) failed"
|
||||
(cd "$app_dir" && zig build -Dplatform=linux -Dweb-engine=system -Dautomation=true) \
|
||||
|| fail "ui-inbox Linux build failed (a native-only app must build without the WebKitGTK dev package)"
|
||||
|
||||
# ---- 1: the native-only ELF carries no WebKitGTK reference -----------------
|
||||
(cd "$repo_root" && zig run tools/audit_web_layer.zig -- "$app_dir/zig-out/bin/ui-inbox" absent) \
|
||||
|| fail "native-only ELF audit failed (the binary references WebKitGTK)"
|
||||
echo "== native-only ELF audit ok"
|
||||
|
||||
# ---- launch ---------------------------------------------------------------
|
||||
cd "$app_dir" || fail "missing $app_dir"
|
||||
rm -rf .zig-cache/native-sdk-automation
|
||||
xvfb-run -a "$app_dir/zig-out/bin/ui-inbox" > "$app_log" 2>&1 &
|
||||
app_pid=$!
|
||||
|
||||
# ---- 2: automation snapshot becomes ready ---------------------------------
|
||||
# `automate assert` self-reports on timeout (missing patterns + snapshot
|
||||
# tail) and prints the measured latency on success, so green logs carry
|
||||
# the readiness margin.
|
||||
"$cli" automate assert --timeout-ms "$ready_timeout_ms" 'ready=true' \
|
||||
|| fail "snapshot never became ready"
|
||||
|
||||
# ---- 3 + 4: software backend presented non-blank pixels --------------------
|
||||
"$cli" automate assert --timeout-ms 30000 'gpu_nonblank=true' \
|
||||
|| fail "gpu_nonblank never became true"
|
||||
grep -q 'gpu_backend=software' "$snap" || fail "gpu_backend is not software"
|
||||
echo "== canvas: $(grep -o 'gpu_backend=[a-z]*' "$snap" | head -1)" \
|
||||
"$(grep -o 'gpu_nonblank=[a-z]*' "$snap" | head -1)"
|
||||
assert_no_webkit "after first presented frame"
|
||||
echo "== zero WebKit processes after first presented frame"
|
||||
|
||||
# ---- 5: automation widget-click mutates the model --------------------------
|
||||
echo "== open before click: $(grep -oE '[0-9]+ open' "$snap" | head -1)"
|
||||
add_id=$(grep -o 'widget @w1/inbox-canvas#[0-9]* role=button name="Add task"' "$snap" \
|
||||
| grep -o '#[0-9]*' | tr -d '#')
|
||||
[ -n "$add_id" ] || fail "Add task button not found in snapshot"
|
||||
"$cli" automate widget-click inbox-canvas "$add_id" || fail "CLI widget-click failed"
|
||||
"$cli" automate assert --timeout-ms 30000 '4 open' \
|
||||
|| fail "widget-click did not reach '4 open'"
|
||||
echo "== open after click: $(grep -oE '[0-9]+ open' "$snap" | head -1)"
|
||||
|
||||
# ---- 6: screenshot renders a non-empty PNG ---------------------------------
|
||||
"$cli" automate screenshot inbox-canvas || fail "CLI screenshot failed"
|
||||
test -s .zig-cache/native-sdk-automation/screenshot-inbox-canvas.png \
|
||||
|| fail "screenshot PNG missing or empty"
|
||||
|
||||
# ---- 7: still zero WebKit processes at the end of the run -------------------
|
||||
assert_no_webkit "at end of run"
|
||||
echo "== zero WebKit processes at end of run"
|
||||
|
||||
echo "PASS: linux canvas smoke"
|
||||
exit 0
|
||||
Executable
+172
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env bash
|
||||
# Windows canvas smoke under Wine.
|
||||
#
|
||||
# Exercises the Windows gpu_surface software path (src/platform/windows/
|
||||
# webview2_host.cpp: child HWND, WM_TIMER frame events, SetDIBitsToDevice
|
||||
# blits) without Windows hardware: cross-compiles examples/ui-inbox for
|
||||
# x86_64-windows-gnu, runs the .exe under Xvfb + Wine, and asserts against
|
||||
# the automation snapshot:
|
||||
#
|
||||
# 1. snapshot ready=true (app booted, automation server live)
|
||||
# 2. gpu_backend=software (the SetDIBitsToDevice path is active)
|
||||
# 3. gpu_nonblank=true (real pixels were presented)
|
||||
# 4. widget-click "Add task" -> '4 open' (automation input mutates state)
|
||||
# 5. real X11 click + typing lands in the draft textbox (XTEST -> Wine ->
|
||||
# WM_LBUTTONDOWN/WM_CHAR -> runtime)
|
||||
#
|
||||
# Step 5 (xdotool) is deliberately included: it is the only coverage of the
|
||||
# Win32 pointer/keyboard input mapping in webview2_host.cpp. It is also the
|
||||
# flakiest step (window lookup, focus without a window manager), so every
|
||||
# failure path dumps the X window list, the snapshot, and the app log.
|
||||
#
|
||||
# Deliberately NOT `set -e`: grep exits 1 on zero matches inside the poll
|
||||
# loops, and we want explicit, diagnosable failures instead of silent early
|
||||
# exits. Every assertion goes through fail(), which dumps diagnostics.
|
||||
set -u
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
app_dir="$repo_root/examples/ui-inbox"
|
||||
snap="$app_dir/.zig-cache/native-sdk-automation/snapshot.txt"
|
||||
cli="$repo_root/zig-out/bin/native"
|
||||
app_log="${TMPDIR:-/tmp}/windows-canvas-smoke-app.log"
|
||||
|
||||
# Wine needs an X display; when none is present (CI), re-exec the whole
|
||||
# script under a private Xvfb server so the app and xdotool share it. The
|
||||
# explicit screen size beats xvfb-run's 640x480x8 default: the app window is
|
||||
# 720x520 and Wine wants a 24-bit visual.
|
||||
if [ -z "${DISPLAY:-}" ]; then
|
||||
exec xvfb-run -a --server-args="-screen 0 1280x800x24" "$0" "$@"
|
||||
fi
|
||||
|
||||
export WINEPREFIX="${WINEPREFIX:-$repo_root/.zig-cache/wineprefix}"
|
||||
export WINEDEBUG="${WINEDEBUG:--all}"
|
||||
|
||||
app_pid=""
|
||||
cleanup() {
|
||||
[ -n "$app_pid" ] && kill "$app_pid" >/dev/null 2>&1
|
||||
wineserver -k >/dev/null 2>&1
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
diagnostics() {
|
||||
echo "---- diagnostics ----"
|
||||
echo "-- X windows:"
|
||||
xdotool search --name "." 2>/dev/null | while read -r w; do
|
||||
echo " $w: $(xdotool getwindowname "$w" 2>/dev/null)"
|
||||
done
|
||||
echo "-- snapshot ($snap):"
|
||||
if [ -f "$snap" ]; then tr '|' '\n' < "$snap" | sed 's/^/ /'; else echo " (missing)"; fi
|
||||
echo "-- app log tail ($app_log):"
|
||||
tail -40 "$app_log" 2>/dev/null | sed 's/^/ /'
|
||||
echo "---------------------"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $1"
|
||||
diagnostics
|
||||
exit 1
|
||||
}
|
||||
|
||||
# poll <seconds> <pattern>: wait until $snap contains <pattern>.
|
||||
poll() {
|
||||
local deadline=$((SECONDS + $1))
|
||||
while [ "$SECONDS" -lt "$deadline" ]; do
|
||||
[ -f "$snap" ] && grep -q "$2" "$snap" && return 0
|
||||
sleep 0.5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ---- build ----------------------------------------------------------------
|
||||
(cd "$repo_root" && zig build) || fail "root zig build (CLI) failed"
|
||||
(cd "$app_dir" && zig build -Dtarget=x86_64-windows-gnu -Dplatform=windows -Dweb-engine=system -Dautomation=true) \
|
||||
|| fail "ui-inbox Windows cross-compile failed"
|
||||
|
||||
# ---- wineprefix -----------------------------------------------------------
|
||||
# First run initializes the prefix (measured ~10-30s on CI-class machines);
|
||||
# subsequent runs are instant, so no cache step is needed.
|
||||
start=$SECONDS
|
||||
wineboot --init >/dev/null 2>&1
|
||||
wineserver --wait >/dev/null 2>&1
|
||||
echo "== wineprefix ready in $((SECONDS - start))s ($WINEPREFIX)"
|
||||
|
||||
# ---- launch ---------------------------------------------------------------
|
||||
cd "$app_dir" || fail "missing $app_dir"
|
||||
rm -rf .zig-cache/native-sdk-automation
|
||||
mkdir -p .zig-cache/native-sdk-automation
|
||||
wine zig-out/bin/ui-inbox.exe > "$app_log" 2>&1 &
|
||||
app_pid=$!
|
||||
|
||||
# ---- 1: automation snapshot becomes ready ---------------------------------
|
||||
poll 180 'ready=true' || fail "snapshot never became ready"
|
||||
echo "== ready: $(head -1 "$snap" | cut -d'|' -f1)"
|
||||
|
||||
# ---- 2 + 3: software backend presented non-blank pixels --------------------
|
||||
poll 60 'gpu_nonblank=true' || fail "gpu_nonblank never became true"
|
||||
grep -q 'gpu_backend=software' "$snap" || fail "gpu_backend is not software"
|
||||
echo "== canvas: $(grep -o 'gpu_backend=[a-z]*' "$snap" | head -1)" \
|
||||
"$(grep -o 'gpu_nonblank=[a-z]*' "$snap" | head -1)" \
|
||||
"$(grep -o 'gpu_sample=0x[0-9a-f]*' "$snap" | head -1)" \
|
||||
"$(grep -o 'gpu_present_mode=[a-z]*' "$snap" | head -1)"
|
||||
|
||||
# ---- 4: automation widget-click mutates the model --------------------------
|
||||
echo "== open before click: $(grep -oE '[0-9]+ open' "$snap" | head -1)"
|
||||
add_id=$(grep -o 'widget @w1/inbox-canvas#[0-9]* role=button name="Add task"' "$snap" \
|
||||
| grep -o '#[0-9]*' | tr -d '#')
|
||||
[ -n "$add_id" ] || fail "Add task button not found in snapshot"
|
||||
"$cli" automate widget-click inbox-canvas "$add_id" || fail "CLI widget-click failed"
|
||||
poll 30 '4 open' || fail "widget-click did not reach '4 open'"
|
||||
echo "== open after click: $(grep -oE '[0-9]+ open' "$snap" | head -1)"
|
||||
|
||||
# ---- 5: real X11 input through the Win32 path ------------------------------
|
||||
# Root-coordinate math. Hidden-titlebar windows keep the full overlapped
|
||||
# frame and reclaim the caption band through WM_NCCALCSIZE, so the Win32
|
||||
# client area starts at the very top of the window. Under a WM-less Wine
|
||||
# the X11 driver still places (and reports) the client X window at the
|
||||
# DEFAULT frame offset - one caption band lower - so the X origin sits a
|
||||
# band BELOW where Win32 client coordinates actually map, and the reported
|
||||
# X height is short by exactly that band (measured: X window 718x489 at
|
||||
# y=30 for a 718x519 client whose clicks land at y=0). The snapshot knows
|
||||
# the true client height, so the height shortfall IS the y correction; a
|
||||
# standard-frame window reports matching heights and corrects by zero.
|
||||
win=""
|
||||
for w in $(xdotool search --name "." 2>/dev/null); do
|
||||
case "$(xdotool getwindowname "$w" 2>/dev/null)" in
|
||||
*[Ii]nbox*) win="$w" ;;
|
||||
esac
|
||||
done
|
||||
[ -n "$win" ] || fail "app X window not found"
|
||||
eval "$(xdotool getwindowgeometry --shell "$win")"
|
||||
client_h=$(grep -o 'window @w1 "[^"]*" bounds=([^)]*)' "$snap" | head -1 \
|
||||
| sed -n 's/.*x\([0-9]*\)[^x]*$/\1/p')
|
||||
[ -n "$client_h" ] || client_h=$HEIGHT
|
||||
y_off=$((client_h - HEIGHT))
|
||||
[ "$y_off" -ge 0 ] 2>/dev/null || y_off=0
|
||||
echo "== x window $win: pos=($X,$Y) size=${WIDTH}x${HEIGHT} client_h=$client_h y_off=$y_off"
|
||||
xdotool windowactivate "$win" >/dev/null 2>&1 || xdotool windowfocus "$win" >/dev/null 2>&1
|
||||
|
||||
draft_line=$(grep -o 'widget @w1/inbox-canvas#[0-9]* role=textbox[^|]*' "$snap" | head -1)
|
||||
[ -n "$draft_line" ] || fail "draft textbox not found in snapshot"
|
||||
bounds=$(echo "$draft_line" | grep -o 'bounds=([^)]*)')
|
||||
bx=$(echo "$bounds" | sed -n 's/bounds=(\([0-9.]*\),.*/\1/p')
|
||||
by=$(echo "$bounds" | sed -n 's/bounds=([0-9.]*,\([0-9.]*\) .*/\1/p')
|
||||
bw=$(echo "$bounds" | sed -n 's/.* \([0-9.]*\)x[0-9.]*).*/\1/p')
|
||||
bh=$(echo "$bounds" | sed -n 's/.* [0-9.]*x\([0-9.]*\)).*/\1/p')
|
||||
[ -n "$bx" ] && [ -n "$by" ] && [ -n "$bw" ] && [ -n "$bh" ] || fail "could not parse draft bounds: $draft_line"
|
||||
cx=$(awk "BEGIN{printf \"%d\", $X + $bx + $bw / 2}")
|
||||
cy=$(awk "BEGIN{printf \"%d\", $Y - $y_off + $by + $bh / 2}")
|
||||
echo "== clicking draft field $bounds at ($cx,$cy)"
|
||||
xdotool mousemove "$cx" "$cy" click 1
|
||||
# The click must move widget focus into the textbox before any keys are
|
||||
# sent: spaces in the typed string would otherwise activate whatever
|
||||
# widget held focus (a button press adds a task and the real failure -
|
||||
# input landing in the wrong widget - would read as missing text).
|
||||
poll 10 'role=textbox[^|]*focused=true' || fail "draft textbox did not take focus from the click"
|
||||
sleep 1
|
||||
xdotool type --delay 120 "hi from wine"
|
||||
poll 30 'hi from wine' || fail "typed text never appeared in the snapshot"
|
||||
echo "== draft after typing: $(grep -o 'widget @w1/inbox-canvas#[0-9]* role=textbox[^|]*' "$snap" | head -1 | cut -c1-160)"
|
||||
echo "== input latency: $(grep -o 'gpu_input_latency_ns=[0-9]*' "$snap" | head -1)"
|
||||
|
||||
echo "PASS: windows canvas smoke"
|
||||
exit 0
|
||||
Executable
+165
@@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env bash
|
||||
# Windows effects smoke under Wine.
|
||||
#
|
||||
# Exercises the effect system's live Windows path (src/runtime/effects.zig
|
||||
# worker threads -> PostMessageW wake in src/platform/windows/
|
||||
# webview2_host.cpp -> loop-thread drain) without Windows hardware:
|
||||
# cross-compiles examples/effects-probe for x86_64-windows-gnu, runs the
|
||||
# .exe under Xvfb + Wine, and asserts against the automation snapshot and
|
||||
# the app's trace log:
|
||||
#
|
||||
# 1. snapshot ready=true (app booted, automation server live)
|
||||
# 2. gpu_backend=software + nonblank (the canvas presented real pixels)
|
||||
# 3. widget-click "Start stream" (fx.spawn launches cmd.exe under
|
||||
# Wine; streamed lines land in the
|
||||
# model and grow the snapshot)
|
||||
# 4. app log shows event=effects_wake (the worker's PostMessageW wake was
|
||||
# marshalled through the message
|
||||
# loop -- the wake path itself, not
|
||||
# just the frame-tick drain)
|
||||
# 5. widget-click "Cancel" (fx.cancel terminates the child;
|
||||
# status shows "cancelled")
|
||||
# 6. the line count freezes (no lines arrive after cancel,
|
||||
# sampled across ~5 more would-be
|
||||
# line intervals)
|
||||
#
|
||||
# Known caveat: the timer present mode also drains effect completions on
|
||||
# every frame tick (ui_app.zig handleFrame), so line delivery alone cannot
|
||||
# isolate the wake; that is why step 4 checks the trace log for the wake
|
||||
# events directly instead of inferring the wake from model updates.
|
||||
#
|
||||
# Deliberately NOT `set -e`: grep exits 1 on zero matches inside the poll
|
||||
# loops, and we want explicit, diagnosable failures instead of silent early
|
||||
# exits. Every assertion goes through fail(), which dumps diagnostics.
|
||||
set -u
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
app_dir="$repo_root/examples/effects-probe"
|
||||
snap="$app_dir/.zig-cache/native-sdk-automation/snapshot.txt"
|
||||
cli="$repo_root/zig-out/bin/native"
|
||||
app_log="${TMPDIR:-/tmp}/windows-effects-smoke-app.log"
|
||||
|
||||
# Wine needs an X display; when none is present (CI), re-exec the whole
|
||||
# script under a private Xvfb server. The explicit screen size beats
|
||||
# xvfb-run's 640x480x8 default: the app window is 560x480 and Wine wants a
|
||||
# 24-bit visual.
|
||||
if [ -z "${DISPLAY:-}" ]; then
|
||||
exec xvfb-run -a --server-args="-screen 0 1280x800x24" "$0" "$@"
|
||||
fi
|
||||
|
||||
export WINEPREFIX="${WINEPREFIX:-$repo_root/.zig-cache/wineprefix}"
|
||||
export WINEDEBUG="${WINEDEBUG:--all}"
|
||||
|
||||
app_pid=""
|
||||
cleanup() {
|
||||
[ -n "$app_pid" ] && kill "$app_pid" >/dev/null 2>&1
|
||||
wineserver -k >/dev/null 2>&1
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
diagnostics() {
|
||||
echo "---- diagnostics ----"
|
||||
echo "-- snapshot ($snap):"
|
||||
if [ -f "$snap" ]; then tr '|' '\n' < "$snap" | sed 's/^/ /'; else echo " (missing)"; fi
|
||||
echo "-- app log tail ($app_log):"
|
||||
tail -40 "$app_log" 2>/dev/null | sed 's/^/ /'
|
||||
echo "---------------------"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "FAIL: $1"
|
||||
diagnostics
|
||||
exit 1
|
||||
}
|
||||
|
||||
# poll <seconds> <pattern>: wait until $snap contains <pattern>.
|
||||
poll() {
|
||||
local deadline=$((SECONDS + $1))
|
||||
while [ "$SECONDS" -lt "$deadline" ]; do
|
||||
[ -f "$snap" ] && grep -q "$2" "$snap" && return 0
|
||||
sleep 0.5
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# The status bar renders "{N} lines total · {M} dropped"; extract N.
|
||||
total_lines() {
|
||||
grep -o '[0-9]* lines total' "$snap" 2>/dev/null | head -1 | grep -o '^[0-9]*'
|
||||
}
|
||||
|
||||
# widget_id <name>: find a widget id in the snapshot by accessible name.
|
||||
widget_id() {
|
||||
grep -o "widget @w1/probe-canvas#[0-9]* role=button name=\"$1\"" "$snap" \
|
||||
| grep -o '#[0-9]*' | tr -d '#'
|
||||
}
|
||||
|
||||
# ---- build ----------------------------------------------------------------
|
||||
(cd "$repo_root" && zig build) || fail "root zig build (CLI) failed"
|
||||
# effects-probe is a zero-config app (app.zon + src, no build.zig): the CLI
|
||||
# synthesizes its build graph. -Doptimize=Debug keeps the smoke binary at
|
||||
# the debug shape (`native build` alone would inject ReleaseFast).
|
||||
"$cli" build "$app_dir" -Dtarget=x86_64-windows-gnu -Dplatform=windows -Dweb-engine=system -Dautomation=true -Doptimize=Debug \
|
||||
|| fail "effects-probe Windows cross-compile failed"
|
||||
|
||||
# ---- wineprefix -----------------------------------------------------------
|
||||
start=$SECONDS
|
||||
wineboot --init >/dev/null 2>&1
|
||||
wineserver --wait >/dev/null 2>&1
|
||||
echo "== wineprefix ready in $((SECONDS - start))s ($WINEPREFIX)"
|
||||
|
||||
# ---- launch ---------------------------------------------------------------
|
||||
cd "$app_dir" || fail "missing $app_dir"
|
||||
rm -rf .zig-cache/native-sdk-automation
|
||||
mkdir -p .zig-cache/native-sdk-automation
|
||||
wine zig-out/bin/effects-probe.exe > "$app_log" 2>&1 &
|
||||
app_pid=$!
|
||||
|
||||
# ---- 1: automation snapshot becomes ready ---------------------------------
|
||||
poll 180 'ready=true' || fail "snapshot never became ready"
|
||||
echo "== ready: $(head -1 "$snap" | cut -d'|' -f1)"
|
||||
|
||||
# ---- 2: software backend presented non-blank pixels ------------------------
|
||||
poll 60 'gpu_nonblank=true' || fail "gpu_nonblank never became true"
|
||||
grep -q 'gpu_backend=software' "$snap" || fail "gpu_backend is not software"
|
||||
echo "== canvas: $(grep -o 'gpu_backend=[a-z]*' "$snap" | head -1)" \
|
||||
"$(grep -o 'gpu_nonblank=[a-z]*' "$snap" | head -1)"
|
||||
grep -q 'idle' "$snap" || fail "probe did not start idle"
|
||||
|
||||
# ---- 3: Start spawns the stream and lines arrive ---------------------------
|
||||
start_id=$(widget_id "Start stream")
|
||||
[ -n "$start_id" ] || fail "Start stream button not found in snapshot"
|
||||
"$cli" automate widget-click probe-canvas "$start_id" || fail "CLI widget-click Start failed"
|
||||
poll 30 'streaming:' || fail "status never showed streaming (spawn failed under Wine?)"
|
||||
# The Windows stream paces ~1 line/s (cmd for /L + ping); wait for at
|
||||
# least 2 visible lines so cancel provably interrupts an active stream.
|
||||
poll 60 'stream line 2' || fail "stream lines never reached the model"
|
||||
echo "== streaming: $(grep -o 'streaming: [0-9]* lines' "$snap" | head -1), status-bar: $(total_lines) lines total"
|
||||
|
||||
# ---- 4: the PostMessage wake path fired ------------------------------------
|
||||
# handleFrame also drains completions on every frame tick, so lines in the
|
||||
# model alone cannot isolate the wake. The runner's default -Dtrace=events
|
||||
# sink prints every runtime event; effects_wake records prove the worker's
|
||||
# PostMessageW -> kWakeMessage -> kWake -> .effects_wake marshalling ran.
|
||||
grep -q 'event="effects_wake"' "$app_log" || fail "no effects_wake events in the app log (PostMessage wake never fired)"
|
||||
echo "== effects_wake events so far: $(grep -c 'event="effects_wake"' "$app_log")"
|
||||
|
||||
# ---- 5: Cancel terminates the child ----------------------------------------
|
||||
cancel_id=$(widget_id "Cancel")
|
||||
[ -n "$cancel_id" ] || fail "Cancel button not found in snapshot"
|
||||
"$cli" automate widget-click probe-canvas "$cancel_id" || fail "CLI widget-click Cancel failed"
|
||||
poll 30 'cancelled: code' || fail "status never showed cancelled"
|
||||
frozen=$(total_lines)
|
||||
[ -n "$frozen" ] || fail "could not read line count after cancel"
|
||||
echo "== cancelled at $frozen lines: $(grep -o 'cancelled: code [0-9-]* after [0-9]* lines' "$snap" | head -1)"
|
||||
|
||||
# ---- 6: the line count is frozen -------------------------------------------
|
||||
# ~5 more lines would have arrived at the ~1s cadence if the child were
|
||||
# still alive or queued lines were still draining.
|
||||
sleep 6
|
||||
after=$(total_lines)
|
||||
[ "$after" = "$frozen" ] || fail "line count moved after cancel ($frozen -> $after)"
|
||||
grep -q 'streaming:' "$snap" && fail "status went back to streaming after cancel"
|
||||
echo "== count frozen at $after lines across 6s"
|
||||
|
||||
echo "PASS: windows effects smoke"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user