fix(tests): exempt user-stopped apps from quadlet unit active-state asserts

backend_quadlet_units() enumerates every *.container file on disk and the
active-state tests asserted each unit active + container running. A
user-stopped app keeps its unit file (e.g. the inactive half of the
bitcoin-core/bitcoin-knots multi-version pair after tonight's crash-loop
wave left core's unit on disk), so its inactive service / absent container
is the CORRECT state — gate run E false-failed on it (tests 123/124,
.228 2026-07-09). Honour the orchestrator's user-stopped.json intent
marker and skip those units in both tests.

Verified on .228: bitcoin-core's lingering unit now exempted; suite parses
(bats --count = 6) and the two fixed tests pass user-stopped filtering.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago 2026-07-09 03:02:22 -04:00
parent dd3afbbac2
commit 2683ad4f0e

View File

@ -50,6 +50,22 @@ backend_quadlet_units() {
done done
} }
# A unit file on disk does NOT imply the app should be running: an
# explicitly user-stopped app keeps its .container file (e.g. the inactive
# half of the bitcoin-core/bitcoin-knots multi-version pair), and its
# .service being inactive / container absent is the CORRECT state. The
# orchestrator persists that intent in user-stopped.json; honour it here so
# the active-state assertions below don't false-fail on stopped-on-purpose
# apps (gate tests 123/124, .228 2026-07-09).
USER_STOPPED_FILE="${ARCHY_DATA_DIR:-/var/lib/archipelago}/user-stopped.json"
is_user_stopped() {
local name="$1"
[[ -r "$USER_STOPPED_FILE" ]] || return 1
jq -e --arg n "$name" --arg s "${name#archy-}" \
'index($n) != null or index($s) != null' "$USER_STOPPED_FILE" >/dev/null 2>&1
}
# Read the cgroup path of a running container's main process. For # Read the cgroup path of a running container's main process. For
# rootless podman the conmon-run target lands the container's pid1 in # rootless podman the conmon-run target lands the container's pid1 in
# the cgroup that owns its supervising .service. # the cgroup that owns its supervising .service.
@ -127,6 +143,7 @@ require_quadlet_backends() {
require_quadlet_backends require_quadlet_backends
while read -r name; do while read -r name; do
[[ -z "$name" ]] && continue [[ -z "$name" ]] && continue
is_user_stopped "$name" && continue
run systemctl --user is-active "$name.service" run systemctl --user is-active "$name.service"
[[ "$status" -eq 0 ]] || fail "$name.service is '$output' — expected 'active'" [[ "$status" -eq 0 ]] || fail "$name.service is '$output' — expected 'active'"
done < <(backend_quadlet_units) done < <(backend_quadlet_units)
@ -136,6 +153,7 @@ require_quadlet_backends() {
require_quadlet_backends require_quadlet_backends
while read -r name; do while read -r name; do
[[ -z "$name" ]] && continue [[ -z "$name" ]] && continue
is_user_stopped "$name" && continue
run sh -c "podman inspect --format '{{.State.Running}}' '$name'" run sh -c "podman inspect --format '{{.State.Running}}' '$name'"
[[ "$status" -eq 0 ]] || fail "$name not present in podman" [[ "$status" -eq 0 ]] || fail "$name not present in podman"
[[ "$output" == "true" ]] || fail "$name container exists but not running (state=$output)" [[ "$output" == "true" ]] || fail "$name container exists but not running (state=$output)"