Tests / Go and GTK tests (push) Failing after 1m57s
- Introduce a new section in README detailing the manual desktop smoke test process for the application. - Include commands for setting up and running the smoke test, along with expected outcomes and logging details. - Update the CI test script to include the new smoke test script in the shellcheck validation process.
153 lines
4.6 KiB
Bash
Executable File
153 lines
4.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Shared helpers for the manual desktop smoke test. Sourced by
|
|
# scripts/smoke/desktop-smoke.sh inside the captioneer-dev Distrobox.
|
|
set -Eeuo pipefail
|
|
|
|
SMOKE_SINK_NAME="captioneer-smoke"
|
|
SMOKE_SINK_MODULE=""
|
|
SMOKE_PREVIOUS_SINK=""
|
|
SMOKE_COMPOSITOR_PID=""
|
|
SMOKE_APP_PID=""
|
|
SMOKE_PLAYER_PID=""
|
|
SMOKE_FAILURES=()
|
|
|
|
smoke_log() {
|
|
printf 'smoke: %s\n' "$*" >&2
|
|
}
|
|
|
|
smoke_die() {
|
|
printf 'smoke: FATAL: %s\n' "$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
smoke_fail() {
|
|
SMOKE_FAILURES+=("$1")
|
|
smoke_log "FAIL: $1"
|
|
}
|
|
|
|
smoke_pass() {
|
|
smoke_log "ok: $1"
|
|
}
|
|
|
|
# smoke_wait_for_line FILE PATTERN TIMEOUT_SECONDS
|
|
smoke_wait_for_line() {
|
|
local file=$1 pattern=$2 timeout=$3 waited=0
|
|
until grep -q -- "$pattern" "$file" 2>/dev/null; do
|
|
if (( waited >= timeout )); then
|
|
return 1
|
|
fi
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
return 0
|
|
}
|
|
|
|
# smoke_wait_for_exit PID TIMEOUT_SECONDS; returns 1 on timeout
|
|
smoke_wait_for_exit() {
|
|
local pid=$1 timeout=$2 waited=0
|
|
while kill -0 "$pid" 2>/dev/null; do
|
|
if (( waited >= timeout )); then
|
|
return 1
|
|
fi
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
return 0
|
|
}
|
|
|
|
smoke_setup_audio() {
|
|
local workdir=$1
|
|
command -v pactl >/dev/null 2>&1 || smoke_die "pactl is required"
|
|
command -v paplay >/dev/null 2>&1 || smoke_die "paplay is required"
|
|
SMOKE_PREVIOUS_SINK="$(pactl get-default-sink 2>/dev/null || true)"
|
|
SMOKE_SINK_MODULE="$(pactl load-module module-null-sink \
|
|
"sink_name=$SMOKE_SINK_NAME" \
|
|
"sink_properties=device.description=Captioneer-Smoke")"
|
|
pactl set-default-sink "$SMOKE_SINK_NAME"
|
|
smoke_log "null sink $SMOKE_SINK_NAME loaded (module $SMOKE_SINK_MODULE, previous default: ${SMOKE_PREVIOUS_SINK:-none})"
|
|
|
|
command -v espeak-ng >/dev/null 2>&1 || smoke_die "espeak-ng is required"
|
|
espeak-ng -v en-us -s 140 -w "$workdir/speech.wav" \
|
|
"The quick brown fox jumps over the lazy dog. Live captions should appear for this sentence."
|
|
[[ -s "$workdir/speech.wav" ]] || smoke_die "espeak-ng produced no audio fixture"
|
|
}
|
|
|
|
smoke_teardown_audio() {
|
|
if [[ -n "$SMOKE_PLAYER_PID" ]] && kill -0 "$SMOKE_PLAYER_PID" 2>/dev/null; then
|
|
kill "$SMOKE_PLAYER_PID" 2>/dev/null || true
|
|
fi
|
|
if [[ -n "$SMOKE_PREVIOUS_SINK" ]]; then
|
|
pactl set-default-sink "$SMOKE_PREVIOUS_SINK" 2>/dev/null || true
|
|
fi
|
|
if [[ -n "$SMOKE_SINK_MODULE" ]]; then
|
|
pactl unload-module "$SMOKE_SINK_MODULE" 2>/dev/null || true
|
|
SMOKE_SINK_MODULE=""
|
|
fi
|
|
}
|
|
|
|
# smoke_play_speech WORKDIR SECONDS: loop the fixture into the null sink.
|
|
smoke_play_speech() {
|
|
local workdir=$1 seconds=$2
|
|
(
|
|
end=$((SECONDS + seconds))
|
|
while (( SECONDS < end )); do
|
|
paplay --device="$SMOKE_SINK_NAME" "$workdir/speech.wav" 2>/dev/null || sleep 1
|
|
done
|
|
) &
|
|
SMOKE_PLAYER_PID=$!
|
|
}
|
|
|
|
# smoke_start_compositor WORKDIR: starts headless sway; prints new socket name.
|
|
# sway is wlroots-based (Layer Shell capable) and, unlike labwc, can disable
|
|
# Xwayland, whose sockets are not creatable inside a rootless Distrobox.
|
|
smoke_start_compositor() {
|
|
local workdir=$1 candidate socket="" waited=0
|
|
command -v sway >/dev/null 2>&1 || smoke_die "sway is required"
|
|
local before="$workdir/sockets-before.txt"
|
|
find "$XDG_RUNTIME_DIR" -maxdepth 1 -name 'wayland-[0-9]*' ! -name '*.lock' \
|
|
-printf '%f\n' 2>/dev/null | sort > "$before"
|
|
|
|
printf 'xwayland disable\n' > "$workdir/sway-config"
|
|
WLR_BACKENDS=headless \
|
|
WLR_LIBINPUT_NO_DEVICES=1 \
|
|
WLR_RENDERER=pixman \
|
|
sway -c "$workdir/sway-config" > "$workdir/compositor.log" 2>&1 &
|
|
SMOKE_COMPOSITOR_PID=$!
|
|
|
|
while (( waited < 15 )); do
|
|
while IFS= read -r candidate; do
|
|
socket="$candidate"
|
|
done < <(find "$XDG_RUNTIME_DIR" -maxdepth 1 -name 'wayland-[0-9]*' ! -name '*.lock' \
|
|
-printf '%f\n' 2>/dev/null | sort | comm -13 "$before" -)
|
|
if [[ -n "$socket" ]]; then
|
|
printf '%s\n' "$socket"
|
|
return 0
|
|
fi
|
|
kill -0 "$SMOKE_COMPOSITOR_PID" 2>/dev/null || smoke_die "sway exited early; see $workdir/compositor.log"
|
|
sleep 1
|
|
waited=$((waited + 1))
|
|
done
|
|
smoke_die "sway did not create a Wayland socket; see $workdir/compositor.log"
|
|
}
|
|
|
|
smoke_teardown_compositor() {
|
|
if [[ -n "$SMOKE_COMPOSITOR_PID" ]] && kill -0 "$SMOKE_COMPOSITOR_PID" 2>/dev/null; then
|
|
kill "$SMOKE_COMPOSITOR_PID" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
smoke_stop_app() {
|
|
if [[ -n "$SMOKE_APP_PID" ]] && kill -0 "$SMOKE_APP_PID" 2>/dev/null; then
|
|
kill -INT "$SMOKE_APP_PID" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
smoke_cleanup() {
|
|
smoke_stop_app
|
|
if [[ -n "$SMOKE_APP_PID" ]]; then
|
|
smoke_wait_for_exit "$SMOKE_APP_PID" 10 || kill -KILL "$SMOKE_APP_PID" 2>/dev/null || true
|
|
fi
|
|
smoke_teardown_audio
|
|
smoke_teardown_compositor
|
|
}
|