archy/tests/lifecycle/bats/electrumx.bats
archipelago 57a013bc66 test(gate): make 5× the canonical gate, drop 20x naming
Rename run-20x.sh → run-gate.sh, default ARCHY_ITERATIONS 20→5, and scrub
20× references across CLAUDE.md, the master plan, TESTING.md, app-registry
status, the orchestrator/config doc-comments, and the bats suites. Also add
a minimal fail() helper to mempool.bats so guard failures report cleanly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-22 18:12:41 -04:00

147 lines
5.6 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bats
# tests/lifecycle/bats/electrumx.bats
#
# Lifecycle tests for the electrumx package (containers are named
# `electrumx` + `archy-electrs-ui`). Mirrors bitcoin-knots.bats /
# lnd.bats so the 5× release-gate run exercises electrumx through
# the same state matrix.
#
# Tiers:
# - Read-only (always runs): presence, valid state, TCP reachable
# - Destructive (ARCHY_ALLOW_DESTRUCTIVE=1): stop → start → restart
# - Cascade-destructive (ARCHY_ALLOW_CASCADE_DESTRUCTIVE=1): uninstall → reinstall
#
# Pre-req: electrumx is installed and bitcoin-knots is running (electrumx
# depends on bitcoind RPC for headers).
load '../lib/rpc.bash'
setup_file() {
: "${ARCHY_PASSWORD:?Set ARCHY_PASSWORD env var to the UI password}"
export ARCHY_FORCE_LOGIN=1
rpc_login
unset ARCHY_FORCE_LOGIN
}
teardown_file() {
rpc_logout_local
}
# ────────────────────────────────────────────────────────────────────
# Read-only tier
# ────────────────────────────────────────────────────────────────────
@test "container-list includes electrumx" {
run rpc_result container-list
[ "$status" -eq 0 ]
echo "$output" | jq -e '.[] | select(.name == "electrumx")' >/dev/null
}
@test "container-list reports a valid state for electrumx" {
run rpc_result container-list
[ "$status" -eq 0 ]
local state
state=$(echo "$output" | jq -r '.[] | select(.name == "electrumx") | .state')
[[ "$state" =~ ^(running|stopped|exited|created|paused)$ ]]
}
@test "electrumx TCP port accepts connections when running" {
local state
state=$(rpc_result container-list | jq -r '.[] | select(.name == "electrumx") | .state')
if [[ "$state" != "running" ]]; then
skip "electrumx not running (state=$state)"
fi
# Same probe required-stack.bats uses — divergence flags a real regression.
run python3 - <<'PY'
import socket
s = socket.create_connection(("127.0.0.1", 50001), 3)
s.close()
print("ok")
PY
[ "$status" -eq 0 ]
}
@test "no orphan electrumx-related containers beyond the known set" {
# FM4 guard: known-good electrumx-package set is {electrumx, archy-electrs-ui}.
local total known
total=$(podman ps -a --format '{{.Names}}' \
| grep -Ec '^(electrumx|electrs|archy-electrs(-[a-z]+)?)$' || true)
known=$(podman ps -a --format '{{.Names}}' \
| grep -Ec '^(electrumx|archy-electrs-ui)$' || true)
[ "$total" -eq "$known" ]
}
# ────────────────────────────────────────────────────────────────────
# Destructive tier (stop → start → restart on the same container)
# ────────────────────────────────────────────────────────────────────
@test "package.stop transitions electrumx to stopped" {
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
run rpc_result package.stop '{"id":"electrumx"}'
[ "$status" -eq 0 ]
run wait_for_container_status electrumx stopped 60
[ "$status" -eq 0 ]
}
@test "package.start brings electrumx back to running" {
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
run rpc_result package.start '{"id":"electrumx"}'
[ "$status" -eq 0 ]
run wait_for_container_status electrumx running 120
[ "$status" -eq 0 ]
}
@test "package.restart leaves electrumx in running state" {
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
run rpc_result package.restart '{"id":"electrumx"}'
[ "$status" -eq 0 ]
run wait_for_container_status electrumx running 120
[ "$status" -eq 0 ]
}
@test "electrumx TCP port recovers after restart" {
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
# electrumx replays its index against bitcoind on cold start; allow 120s.
local deadline=$(( $(date +%s) + 120 ))
while (( $(date +%s) < deadline )); do
if python3 -c 'import socket; socket.create_connection(("127.0.0.1", 50001), 3).close()' \
>/dev/null 2>&1; then
return 0
fi
sleep 3
done
fail "electrumx TCP port never reopened after restart"
}
# ────────────────────────────────────────────────────────────────────
# Cascade-destructive tier (uninstall + reinstall)
# ────────────────────────────────────────────────────────────────────
@test "package.uninstall removes electrumx" {
[[ "${ARCHY_ALLOW_CASCADE_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_CASCADE_DESTRUCTIVE not set"
run rpc_result package.uninstall '{"id":"electrumx","preserve_data":true}'
[ "$status" -eq 0 ]
run wait_for_container_status electrumx absent 120
[ "$status" -eq 0 ]
}
@test "package.install electrumx returns to running" {
[[ "${ARCHY_ALLOW_CASCADE_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_CASCADE_DESTRUCTIVE not set"
run rpc_result package.install '{"manifest_path":"electrumx/manifest.yaml"}'
[ "$status" -eq 0 ]
run wait_for_container_status electrumx running 240
[ "$status" -eq 0 ]
}