#!/bin/bash
|
# Round01 overlay lifecycle QA. It verifies one visible overlay while the PoC is
|
# open, then verifies that no Round01 overlay remains after auto-close.
|
|
set -euo pipefail
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
OUTPUT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
# shellcheck source=build-output-paths.sh
|
source "$SCRIPT_DIR/build-output-paths.sh"
|
APP="$BUILD_CURRENT_APP"
|
REPORT="$BUILD_REPORT_ROOT/round01-overlay-qa-report.json"
|
OPEN_WAIT="${ALIGNER_ROUND1_OVERLAY_QA_OPEN_WAIT:-2.0}"
|
HIDE_AFTER="${ALIGNER_ROUND1_OVERLAY_QA_HIDE_AFTER:-8.0}"
|
QUIT_AFTER="${ALIGNER_ROUND1_OVERLAY_QA_QUIT_AFTER:-10.0}"
|
AFTER_HIDE_WAIT="${ALIGNER_ROUND1_OVERLAY_QA_AFTER_HIDE_WAIT:-0.8}"
|
QUIT_TIMEOUT="${ALIGNER_ROUND1_OVERLAY_QA_QUIT_TIMEOUT:-5.0}"
|
|
fail() {
|
echo "Round01 overlay QA failed: $*" >&2
|
exit 1
|
}
|
|
python_float_check() {
|
/usr/bin/python3 - "$@" <<'PY'
|
import sys
|
|
hide_after, quit_after, after_hide_wait = map(float, sys.argv[1:4])
|
if quit_after <= hide_after + after_hide_wait:
|
print(
|
f"QUIT_AFTER must be greater than HIDE_AFTER + AFTER_HIDE_WAIT: "
|
f"{quit_after} <= {hide_after} + {after_hide_wait}",
|
file=sys.stderr,
|
)
|
sys.exit(1)
|
PY
|
}
|
|
seconds_after_open_until_hidden() {
|
/usr/bin/python3 - "$OPEN_WAIT" "$HIDE_AFTER" "$AFTER_HIDE_WAIT" <<'PY'
|
import sys
|
|
open_wait, hide_after, after_hide_wait = map(float, sys.argv[1:4])
|
print(max(0.0, hide_after + after_hide_wait - open_wait))
|
PY
|
}
|
|
aligner_pids_for_current_app() {
|
ps -axo pid=,args= | while read -r pid command; do
|
case "$command" in
|
"$APP/Contents/MacOS/Aligner"*) echo "$pid" ;;
|
esac
|
done
|
}
|
|
stop_current_aligner() {
|
for pid in $(aligner_pids_for_current_app); do
|
kill "$pid" 2>/dev/null || true
|
done
|
|
for _ in {1..30}; do
|
[ -z "$(aligner_pids_for_current_app)" ] && return
|
sleep 0.1
|
done
|
|
fail "current Aligner app did not exit before QA"
|
}
|
|
wait_for_app_exit() {
|
local timeout="$1"
|
/usr/bin/python3 - "$APP_PID" "$timeout" <<'PY'
|
import os
|
import signal
|
import sys
|
import time
|
|
pid = int(sys.argv[1])
|
timeout = float(sys.argv[2])
|
deadline = time.monotonic() + timeout
|
|
while time.monotonic() < deadline:
|
stat = os.popen(f"ps -p {pid} -o stat=").read().strip()
|
if not stat or "Z" in stat:
|
sys.exit(0)
|
try:
|
os.kill(pid, 0)
|
except ProcessLookupError:
|
sys.exit(0)
|
time.sleep(0.1)
|
|
print(f"Aligner app did not quit within {timeout:.1f}s", file=sys.stderr)
|
sys.exit(1)
|
PY
|
}
|
|
python_float_check "$HIDE_AFTER" "$QUIT_AFTER" "$AFTER_HIDE_WAIT"
|
POST_OPEN_HIDE_WAIT="$(seconds_after_open_until_hidden)"
|
stop_current_aligner
|
"$SCRIPT_DIR/package-app.sh" >&2
|
|
rm -f "$REPORT"
|
|
"$APP/Contents/MacOS/Aligner" \
|
--round0-skip-permissions \
|
--round01-performance-poc \
|
--round01-poc-auto-cycle \
|
--round01-poc-auto-hide-after="$HIDE_AFTER" \
|
--round01-poc-quit-after="$QUIT_AFTER" \
|
--round01-poc-report="$REPORT" &
|
|
APP_PID=$!
|
|
cleanup() {
|
if kill -0 "$APP_PID" 2>/dev/null; then
|
kill "$APP_PID" 2>/dev/null || true
|
wait "$APP_PID" 2>/dev/null || true
|
fi
|
}
|
trap cleanup EXIT
|
|
sleep "$OPEN_WAIT"
|
|
swift "$SCRIPT_DIR/window-logic-qa.swift" \
|
--expect-round01-performance-poc \
|
--expect-single-aligner-overlay \
|
--expect-overlay-on-mouse-screen \
|
--expect-overlay-uses-screen-frame
|
|
sleep "$POST_OPEN_HIDE_WAIT"
|
swift "$SCRIPT_DIR/window-logic-qa.swift" --expect-no-round01-performance-poc
|
|
wait_for_app_exit "$QUIT_TIMEOUT" || fail "app did not quit after overlay hide"
|
wait "$APP_PID"
|
trap - EXIT
|
|
swift "$SCRIPT_DIR/window-logic-qa.swift" --expect-no-round01-performance-poc
|
|
if [[ ! -f "$REPORT" ]]; then
|
echo "Round01 overlay QA report was not created: $REPORT" >&2
|
exit 1
|
fi
|
|
cat "$REPORT"
|