Files
linuxcncAllWasm/tests/ui-smoke/_lib/quit-launch.sh
2026-08-20 06:17:39 +08:00

130 lines
4.7 KiB
Bash
Executable File

#!/bin/bash
# Quit-path launcher for UI smoke tests.
# Usage: quit-launch.sh <sim-config-ini> <gui-process-match>
#
# Boots linuxcnc + GUI under xvfb-run exactly like launch.sh, waits for
# the NML task to come up (via drive.py), then sends SIGTERM to the GUI
# process *alone* and asserts the GUI exits on its own within a short
# grace. This is the regression guard for the SIGTERM clean-shutdown
# handlers: a GUI that absorbs SIGTERM and has to be SIGKILLed fails.
#
# <gui-process-match> is a pgrep -f pattern identifying the GUI process
# (e.g. "bin/touchy", "bin/gmoccapy"). It must not match the linuxcnc
# launcher or task/motion helpers.
#
# Markers (consumed by checkresult-quit.sh):
# UI_SMOKE_QUIT_OK GUI exited on SIGTERM within QUIT_GRACE
# UI_SMOKE_QUIT_FAIL GUI never started, was not found, or ignored TERM
set -u
CONFIG_INI="$1"
GUI_MATCH="$2"
TEST_DIR="${TEST_DIR:-$(cd "$(dirname "$0")" && pwd)}"
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$TEST_DIR" || exit 1
rm -f ui-smoke.out ui-smoke.err linuxcnc.pid
bash "$LIB_DIR/cleanup-runtime.sh"
LINUXCNC_TIMEOUT=240
DRIVER_TIMEOUT=90
# Seconds to wait for the GUI to exit after SIGTERM before declaring it
# stuck. A GUI honouring SIGTERM exits in well under a second; the
# margin covers Cleanup of task/motion on slow CI.
QUIT_GRACE=15
# Shared headless environment (software GL + audio silencing), kept in
# launch-env.sh so launch.sh and quit-launch.sh cannot drift apart.
. "$LIB_DIR/launch-env.sh"
# Arm a core dump so a GUI segfault can be backtraced after the run.
. "$LIB_DIR/crashdump.sh"
crashdump_arm
export CONFIG_INI LIB_DIR DRIVER_TIMEOUT GUI_MATCH QUIT_GRACE
# shellcheck disable=SC2016
xvfb-run -a --server-args="-screen 0 1024x768x24" \
timeout "$LINUXCNC_TIMEOUT" \
bash -c '
setsid linuxcnc -r "$CONFIG_INI" >linuxcnc.out 2>linuxcnc.err &
LINUXCNC_PID=$!
echo "$LINUXCNC_PID" >linuxcnc.pid
# Wait until the task is reachable (GUI has constructed and the
# NML round-trip works). Reuse the phase-1 driver for readiness.
timeout "$DRIVER_TIMEOUT" python3 "$LIB_DIR/drive.py" >ui-smoke.out 2>ui-smoke.err
if ! grep -q "^UI_SMOKE_OK$" ui-smoke.out; then
echo "UI_SMOKE_QUIT_FAIL: GUI did not come up; cannot test quit"
kill -KILL -- -"$LINUXCNC_PID" 2>/dev/null || true
bash "$LIB_DIR/cleanup-runtime.sh"
exit 1
fi
# Identify the GUI process. pgrep -f matches against the whole
# command line, so wrapper processes (the linuxcnc launcher, the
# xvfb-run shell, this bash -c) also match because the GUI name
# appears in the config path or the embedded script text. Every
# such wrapper has a shell or xvfb-run as argv[0]; the real GUI
# is a python interpreter. Pick the first match whose argv[0]
# basename is a python binary.
GUI_PID=""
for p in $(pgrep -f "$GUI_MATCH"); do
arg0=$(tr "\0" "\n" <"/proc/$p/cmdline" 2>/dev/null | head -1)
case "$(basename "$arg0" 2>/dev/null)" in
python*) GUI_PID="$p"; break ;;
esac
done
if [ -z "$GUI_PID" ]; then
echo "UI_SMOKE_QUIT_FAIL: GUI process matching \"$GUI_MATCH\" not found"
kill -KILL -- -"$LINUXCNC_PID" 2>/dev/null || true
bash "$LIB_DIR/cleanup-runtime.sh"
exit 1
fi
# Send SIGTERM to the GUI alone and time how long it takes to go.
kill -TERM "$GUI_PID" 2>/dev/null || true
waited=0
while [ "$waited" -lt "$QUIT_GRACE" ]; do
kill -0 "$GUI_PID" 2>/dev/null || break
sleep 1
waited=$((waited + 1))
done
if kill -0 "$GUI_PID" 2>/dev/null; then
echo "UI_SMOKE_QUIT_FAIL: GUI (pid $GUI_PID) still alive ${QUIT_GRACE}s after SIGTERM"
RC=1
else
echo "UI_SMOKE_QUIT_OK: GUI exited ${waited}s after SIGTERM"
RC=0
fi
# Tear down whatever is left (task/motion, or the GUI on failure).
kill -TERM -- -"$LINUXCNC_PID" 2>/dev/null || true
for _ in $(seq 30); do
kill -0 "$LINUXCNC_PID" 2>/dev/null || break
sleep 1
done
if kill -0 "$LINUXCNC_PID" 2>/dev/null; then
kill -KILL -- -"$LINUXCNC_PID" 2>/dev/null || true
sleep 2
bash "$LIB_DIR/cleanup-runtime.sh"
fi
exit "$RC"
'
RC=$?
echo "=== linuxcnc.err ==="
[ -f linuxcnc.err ] && cat linuxcnc.err
echo "=== ui-smoke.out ==="
[ -f ui-smoke.out ] && cat ui-smoke.out
echo "=== ui-smoke.err ==="
[ -f ui-smoke.err ] && cat ui-smoke.err
# If the GUI dumped a core, print its native backtrace.
crashdump_report
exit "$RC"