#!/usr/bin/env bats # Bats END-TO-END integration suite for the praxis v0.2 Proxmox deploy # stack (SLICE-09 capstone). # # Run (live): PRAXIS_E2E_LIVE=1 bats scripts/proxmox/test/e2e-deploy.bats # Run (default, skipped): bats scripts/proxmox/test/e2e-deploy.bats # # Unlike the per-script orchestrator tests (lxc-deploy.bats) which stub # every sibling, this suite runs the REAL lxc-deploy.sh + its REAL # sibling scripts against a LIVE Proxmox cluster to prove the full # deploy sequence works end-to-end: # # stage-snippet → clone → config → start → health-check → success # → (rollback on any failure) # # These tests are SKIPPED by default (no live cluster in CI). Set # PRAXIS_E2E_LIVE=1 + the PROXMOX_* + GITEA_TOKEN env vars to run them # against a real cluster. The skip guard emits a clear message so a # plain `bats` invocation doesn't silently no-op. # # Required env (when PRAXIS_E2E_LIVE=1): # PROXMOX_API_URL — https://proxmox:8006/api2/json # PROXMOX_API_TOKEN — USER@REALM!TOKENID=SECRET # PROXMOX_NODE — target node name # PROXMOX_STORAGE — storage holding the template # PROXMOX_TEMPLATE_VOLID — local:vztmpl/debian-12-template.tar.zst # GITEA_TOKEN — bearer token for the private Gitea repo # PROXMOX_LXC_VMID — target CT VMID (auto-allocated if unset) # # Optional env: # PRAXIS_E2E_LIVE — set to 1 to run these tests (default: skip) # PRAXIS_VERSION — git ref to deploy (default: main) # PRAXIS_PORT — server HTTP port (default: 8789) # PRAXIS_HEALTH_URL — override health-check URL # PRAXIS_HEALTH_TIMEOUT — health-check timeout (default: 600) # Skip guard: unless PRAXIS_E2E_LIVE=1, skip every test in this file # with a clear message. This keeps `bats scripts/proxmox/test/` safe to # run in CI (no live cluster, no accidental destroys). setup() { if [ "${PRAXIS_E2E_LIVE:-0}" != "1" ]; then skip "PRAXIS_E2E_LIVE!=1 — set PRAXIS_E2E_LIVE=1 + PROXMOX_* env to run live e2e tests" fi SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" # Resolve the deploy script from the real source tree. DEPLOY="${SCRIPT_DIR}/lxc-deploy.sh" [ -x "$DEPLOY" ] || skip "lxc-deploy.sh not found at ${DEPLOY}" # Validate required live env vars are present. for var in PROXMOX_API_URL PROXMOX_API_TOKEN PROXMOX_NODE \ PROXMOX_STORAGE PROXMOX_TEMPLATE_VOLID GITEA_TOKEN; do eval "val=\"\${${var}:-}\"" [ -n "$val" ] || skip "${var} is required for live e2e (PRAXIS_E2E_LIVE=1)" done # Use a dedicated VMID for e2e to avoid clobbering a production CT. # If PROXMOX_LXC_VMID is unset, default to a high number + warn. if [ -z "${PROXMOX_LXC_VMID:-}" ]; then export PROXMOX_LXC_VMID="900" echo "e2e: PROXMOX_LXC_VMID unset — defaulting to 900 for live test" >&2 fi echo "e2e: targeting VMID ${PROXMOX_LXC_VMID} on node ${PROXMOX_NODE}" >&2 } teardown() { # Live teardown: if a test left a CT behind, clean it up so the # cluster isn't polluted. Only runs when PRAXIS_E2E_LIVE=1. if [ "${PRAXIS_E2E_LIVE:-0}" = "1" ] && [ -n "${PROXMOX_LXC_VMID:-}" ]; then SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" if [ -x "${SCRIPT_DIR}/rollback.sh" ]; then "${SCRIPT_DIR}/rollback.sh" "$PROXMOX_LXC_VMID" >/dev/null 2>&1 || true fi fi } # ── Live e2e tests (only run when PRAXIS_E2E_LIVE=1) ───────────── @test "live e2e: full deploy — stage → clone → config → start → health → VMID=" { run "${DEPLOY}" [ "$status" -eq 0 ] grep -q "^VMID=${PROXMOX_LXC_VMID}$" <<< "$output" grep -q 'deploy: praxis deployed successfully' <<< "$output" # No rollback on success. ! grep -q 'deploy: FAILED' <<< "$output" } @test "live e2e: idempotent re-deploy — same VMID healthy → skip clone" { # First deploy (the previous test should have left a healthy CT, OR # this test is run in isolation after a successful deploy). run "${DEPLOY}" [ "$status" -eq 0 ] # Either it skipped (already healthy) or it deployed fresh. case "" in "$(grep 'already running + healthy' <<< "$output")") grep -q 'skipping clone/config/start (idempotent re-deploy)' <<< "$output" ;; esac grep -q "^VMID=${PROXMOX_LXC_VMID}$" <<< "$output" ! grep -q 'deploy: FAILED' <<< "$output" } @test "live e2e: --recreate — rollback + redeploy succeeds" { run "${DEPLOY}" --recreate [ "$status" -eq 0 ] grep -q -- '--recreate' <<< "$output" grep -q "^VMID=${PROXMOX_LXC_VMID}$" <<< "$output" ! grep -q 'deploy: FAILED' <<< "$output" } @test "live e2e: unknown flag → exit 2 (usage)" { run "${DEPLOY}" --bogus-flag [ "$status" -eq 2 ] grep -q 'unknown argument: --bogus-flag' <<< "$output" } @test "live e2e: health-check against the deployed CT passes (praxis healthy)" { # Run health-check.sh directly against the deployed CT. If the CT # was destroyed by a prior teardown, this skips. SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" [ -x "${SCRIPT_DIR}/health-check.sh" ] || skip "health-check.sh not found" run "${SCRIPT_DIR}/health-check.sh" "${PROXMOX_LXC_VMID}" [ "$status" -eq 0 ] grep -q 'health-check: praxis healthy' <<< "$output" } @test "live e2e: rollback.sh cleans up the CT (idempotent, 404-tolerant)" { SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" [ -x "${SCRIPT_DIR}/rollback.sh" ] || skip "rollback.sh not found" run "${SCRIPT_DIR}/rollback.sh" "${PROXMOX_LXC_VMID}" [ "$status" -eq 0 ] grep -q 'rollback: VMID .* cleaned up' <<< "$output" # A second rollback must be 404-tolerant (idempotent). run "${SCRIPT_DIR}/rollback.sh" "${PROXMOX_LXC_VMID}" [ "$status" -eq 0 ] grep -q 'rollback: VMID .* cleaned up' <<< "$output" } @test "live e2e: rollback.sh on a never-existed VMID → exit 0 (404-tolerant)" { SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" [ -x "${SCRIPT_DIR}/rollback.sh" ] || skip "rollback.sh not found" # Pick a VMID that definitely doesn't exist (high random range). nonexistent="99999" run "${SCRIPT_DIR}/rollback.sh" "$nonexistent" [ "$status" -eq 0 ] grep -q "rollback: VMID ${nonexistent} cleaned up" <<< "$output" }