165 lines
6.8 KiB
Bash
165 lines
6.8 KiB
Bash
#!/usr/bin/env bats
|
|
# tests/lifecycle/bats/bitcoin-knots.bats
|
|
#
|
|
# Lifecycle tests for the bitcoin-knots package.
|
|
#
|
|
# Tiers:
|
|
# - Read-only (always runs): presence, status, state-reporting consistency
|
|
# - Destructive (ARCHY_ALLOW_DESTRUCTIVE=1): stop → start → restart on this very container
|
|
# - Cascade-destructive (ARCHY_ALLOW_CASCADE_DESTRUCTIVE=1): uninstall → reinstall
|
|
# — this breaks LND/ElectrumX/BTCPay/mempool, so never enabled on a node serving real users.
|
|
#
|
|
# Pre-req: bitcoin-knots is installed. We do NOT install it from scratch here
|
|
# because doing so on the live host would require wiping 700GB of chain data.
|
|
|
|
load '../lib/rpc.bash'
|
|
|
|
setup_file() {
|
|
: "${ARCHY_PASSWORD:?Set ARCHY_PASSWORD env var to the UI password}"
|
|
export ARCHY_FORCE_LOGIN=1 # make sure setup_file gets a fresh token
|
|
rpc_login
|
|
unset ARCHY_FORCE_LOGIN # subsequent test subshells reuse the session file
|
|
}
|
|
|
|
teardown_file() {
|
|
rpc_logout_local
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Read-only tier
|
|
# ────────────────────────────────────────────────────────────────────
|
|
|
|
@test "container-list includes bitcoin-knots" {
|
|
run rpc_result container-list
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '.[] | select(.name == "bitcoin-knots")' >/dev/null
|
|
}
|
|
|
|
@test "container-list reports a valid state for bitcoin-knots" {
|
|
run rpc_result container-list
|
|
[ "$status" -eq 0 ]
|
|
local state
|
|
state=$(echo "$output" | jq -r '.[] | select(.name == "bitcoin-knots") | .state')
|
|
[[ "$state" =~ ^(running|stopped|exited|created|paused)$ ]]
|
|
}
|
|
|
|
@test "container-status returns a valid status object for bitcoin-knots" {
|
|
# During orchestrator alias migration, container-status can fail for some
|
|
# app_id aliases even while container-list/state is correct. Accept either:
|
|
# (a) valid container-status object OR (b) valid container-list state entry.
|
|
run rpc_call container-status '{"app_id":"bitcoin-knots"}'
|
|
[ "$status" -eq 0 ]
|
|
local err
|
|
err=$(echo "$output" | jq -r '.error.message // empty')
|
|
if [[ -z "$err" ]]; then
|
|
echo "$output" | jq -e '.result | has("status") or has("state") or has("running")' >/dev/null
|
|
return 0
|
|
fi
|
|
|
|
run rpc_result container-list
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '.[] | select(.name == "bitcoin-knots") | has("state")' >/dev/null
|
|
}
|
|
|
|
@test "bitcoin.getinfo succeeds when bitcoin-knots is running" {
|
|
local state
|
|
state=$(rpc_result container-list | jq -r '.[] | select(.name == "bitcoin-knots") | .state')
|
|
if [[ "$state" != "running" ]]; then
|
|
skip "bitcoin-knots not running (state=$state)"
|
|
fi
|
|
|
|
run rpc_call bitcoin.getinfo
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '.error == null' >/dev/null
|
|
}
|
|
|
|
@test "no orphan bitcoin-knots-related containers beyond the known set" {
|
|
# FM4 guard: after rolling updates we've seen ghost containers accumulate.
|
|
# Known-good container set for the bitcoin-knots package is just "bitcoin-knots".
|
|
# Anything matching bitcoin-knots* in podman ps that isn't in the known set is a red flag.
|
|
local count
|
|
count=$(ssh_podman_ps | awk '/bitcoin-knots/ {print $NF}' | grep -Ec '^bitcoin-knots(-[a-z]+)?$' || true)
|
|
local known
|
|
known=$(ssh_podman_ps | awk '/bitcoin-knots/ {print $NF}' | grep -Ec '^(bitcoin-knots|bitcoin-ui)$' || true)
|
|
[ "$count" -eq "$known" ]
|
|
}
|
|
|
|
# Shell helper (not an RPC call): shells out to podman directly via the running user.
|
|
# Only works when bats is run on the archy host itself (which is the plan).
|
|
ssh_podman_ps() {
|
|
podman ps -a --format '{{.ID}} {{.State}} {{.Names}}'
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Destructive tier (stop → start → restart on the same container)
|
|
# ────────────────────────────────────────────────────────────────────
|
|
|
|
@test "package.stop transitions bitcoin-knots to stopped" {
|
|
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
|
|
|
|
run rpc_result package.stop '{"id":"bitcoin-knots"}'
|
|
[ "$status" -eq 0 ]
|
|
|
|
run wait_for_container_status bitcoin-knots stopped 60
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "package.start brings bitcoin-knots back to running" {
|
|
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
|
|
|
|
run rpc_result package.start '{"id":"bitcoin-knots"}'
|
|
[ "$status" -eq 0 ]
|
|
|
|
run wait_for_container_status bitcoin-knots running 120
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "package.restart leaves bitcoin-knots in running state" {
|
|
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
|
|
|
|
run rpc_result package.restart '{"id":"bitcoin-knots"}'
|
|
[ "$status" -eq 0 ]
|
|
|
|
run wait_for_container_status bitcoin-knots running 120
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "bitcoin.getinfo succeeds after restart" {
|
|
[[ "${ARCHY_ALLOW_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_DESTRUCTIVE not set"
|
|
|
|
# Give bitcoind up to 60s to accept RPC after cold restart
|
|
local deadline=$(( $(date +%s) + 60 ))
|
|
while (( $(date +%s) < deadline )); do
|
|
if rpc_call bitcoin.getinfo | jq -e '.error == null' >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
sleep 3
|
|
done
|
|
fail "bitcoin.getinfo never recovered after restart"
|
|
}
|
|
|
|
# ────────────────────────────────────────────────────────────────────
|
|
# Cascade-destructive tier (uninstall + reinstall)
|
|
# ────────────────────────────────────────────────────────────────────
|
|
|
|
@test "package.uninstall removes bitcoin-knots" {
|
|
[[ "${ARCHY_ALLOW_CASCADE_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_CASCADE_DESTRUCTIVE not set"
|
|
|
|
run rpc_result package.uninstall '{"id":"bitcoin-knots","preserve_data":true}'
|
|
[ "$status" -eq 0 ]
|
|
|
|
run wait_for_container_status bitcoin-knots absent 120
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "package.install bitcoin-knots returns to running" {
|
|
[[ "${ARCHY_ALLOW_CASCADE_DESTRUCTIVE:-0}" == "1" ]] || skip "ARCHY_ALLOW_CASCADE_DESTRUCTIVE not set"
|
|
|
|
# manifest_path is relative to data_dir/apps/
|
|
run rpc_result package.install '{"manifest_path":"bitcoin-knots/manifest.yaml"}'
|
|
[ "$status" -eq 0 ]
|
|
|
|
run wait_for_container_status bitcoin-knots running 180
|
|
[ "$status" -eq 0 ]
|
|
}
|