nigig-org/crates/apps/nigig-site/tools/runtime-smoke.sh
2026-09-12 21:54:30 +00:00

107 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# Launch the real desktop binary in an isolated X11 session, prove its window
# renders, capture evidence, request a normal window close, and require a clean
# process exit so SiteStandaloneApp::drop runs its bounded writer drain.
set -euo pipefail
binary=${1:-target/debug/nigig-site}
evidence_dir=${2:-/tmp/nigig-site-ci}
[[ -x "$binary" ]] || {
echo "ERROR: runtime binary is not executable: $binary" >&2
exit 1
}
for command in xvfb-run xdotool import identify timeout; do
command -v "$command" >/dev/null || {
echo "ERROR: required runtime-smoke tool is missing: $command" >&2
exit 1
}
done
mkdir -p "$evidence_dir"
runtime_root=$(mktemp -d)
cleanup() {
rm -rf "$runtime_root"
}
trap cleanup EXIT
mkdir -p "$runtime_root/home" "$runtime_root/data" "$runtime_root/cache"
export HOME="$runtime_root/home"
export XDG_DATA_HOME="$runtime_root/data"
export XDG_CACHE_HOME="$runtime_root/cache"
export NIGIG_SITE_RUNTIME_BINARY="$binary"
export NIGIG_SITE_RUNTIME_ROOT="$runtime_root"
export NIGIG_SITE_RUNTIME_EVIDENCE="$evidence_dir"
timeout --signal=TERM --kill-after=5s 30s xvfb-run -a bash -c '
set -euo pipefail
"$NIGIG_SITE_RUNTIME_BINARY" >"$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-app.log" 2>&1 &
pid=$!
cleanup_child() {
if [[ -n "${pid:-}" ]] && kill -0 "$pid" 2>/dev/null; then
kill "$pid" 2>/dev/null || true
wait "$pid" 2>/dev/null || true
fi
}
trap cleanup_child EXIT
window=""
for _ in $(seq 1 200); do
window=$(xdotool search --pid "$pid" --name "^nigig-site$" 2>/dev/null | head -n 1 || true)
[[ -n "$window" ]] && break
if ! kill -0 "$pid" 2>/dev/null; then
cat "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-app.log" >&2
wait "$pid"
exit 1
fi
sleep 0.1
done
[[ -n "$window" ]] || {
echo "ERROR: nigig-site did not create its desktop window" >&2
cat "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-app.log" >&2
kill "$pid" 2>/dev/null || true
exit 1
}
[[ $(xdotool getwindowname "$window") == nigig-site ]]
# Wait for the first GL present; finding a mapped-but-unpainted black window
# is not runtime UI evidence.
sleep 2
import -window "$window" "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui.png"
identify "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui.png" \
>"$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui-image.txt"
mean=$(identify -format "%[fx:mean]" "$NIGIG_SITE_RUNTIME_EVIDENCE/runtime-ui.png")
awk -v mean="$mean" "BEGIN { exit !(mean > 0.05) }" || {
echo "ERROR: runtime window remained effectively black after first paint" >&2
exit 1
}
# WM_DELETE_WINDOW follows the normal Makepad close path. A forced signal
# would not prove the Rust Drop implementation and is therefore forbidden.
xdotool windowclose "$window"
for _ in $(seq 1 200); do
! kill -0 "$pid" 2>/dev/null && break
sleep 0.1
done
if kill -0 "$pid" 2>/dev/null; then
echo "ERROR: nigig-site ignored a normal window-close request" >&2
kill "$pid" 2>/dev/null || true
exit 1
fi
wait "$pid"
pid=""
'
# An absent repository must stay absent: startup is open-only and setup is
# security-review locked. Cache/shader output is outside XDG_DATA_HOME.
if find "$runtime_root/data" -type f -print -quit | grep -q .; then
echo "ERROR: runtime startup created repository data without setup consent" >&2
find "$runtime_root/data" -type f -print >&2
exit 1
fi
if grep -Eiq 'panicked|fatal|segmentation fault|graceful persistence drain failed' \
"$evidence_dir/runtime-app.log"; then
echo "ERROR: runtime log contains a fatal or shutdown failure" >&2
cat "$evidence_dir/runtime-app.log" >&2
exit 1
fi
[[ -s "$evidence_dir/runtime-ui.png" ]]
[[ -s "$evidence_dir/runtime-ui-image.txt" ]]
echo "runtime smoke passed: isolated startup, rendered window, normal close, no repository creation"