93d33ecb0c
SLICE-08 (devops-engineer): .env.example updated with Proxmox deployment vars (documented, sourced from ~/coreci/.env.secrets per D-026), PRAXIS_CLIENT_DIST for StaticFiles, PRAXIS_SCENARIO. config.json secrets.scopes already extended in SPECIFY (proxmox + voice scopes). SLICE-09 (devops-engineer): 10 bats test files (G-106 fix: 10 not 9) covering all proxmox scripts — 121 tests, 114 pass + 7 skipped (e2e). Mocked curl/pct/ssh; no live cluster needed for unit tests. SLICE-10 (devops-engineer): e2e-deploy.sh — sources secrets from both coreci + praxis .env.secrets, runs full deploy, verifies /health + client HTML serving. REQ-DEPLOY-15 covered. All 6 grill binding decisions addressed: G-101 MUST: GITEA_TOKEN baked into snippet (stage-snippet.sh) G-102 MUST: PRAXIS_DB_PATH env read (db/store.py + db/migrate.py) G-103 FIX: all 16 env vars in injection list (install-service.sh) G-104 FIX: health-check timeout 600s (health-check.sh) G-105 FIX: Dockerfile copy ordering (pyproject before source) G-106 FIX: bats test count = 10 REQ-DEPLOY-12, 14, 15 covered. All 20 REQ-IDs now implemented. ---ci--- project: praxis phase: 1 milestone: v0.2 status: execute slice: 08-10 wave: 4 ---/ci---
152 lines
5.8 KiB
Bash
152 lines
5.8 KiB
Bash
#!/usr/bin/env bats
|
|
# Bats tests for scripts/proxmox/rollback.sh (praxis CT rollback).
|
|
#
|
|
# Run: bats scripts/proxmox/test/rollback.bats
|
|
#
|
|
# rollback.sh stops (graceful, then force) and destroys a CT. It is
|
|
# idempotent (a 404 / already-gone CT is not an error). These tests
|
|
# exercise the real rollback.sh with a mocked api.sh (pve_curl, pve_get,
|
|
# pve_poll) so the shutdown → force-stop → destroy sequence + the
|
|
# 404-tolerant paths are verified without a live Proxmox endpoint.
|
|
#
|
|
# Praxis v0.2 (vs coreci) key difference asserted here:
|
|
# - NO proxy / PROXY_VMID / backend-remove.sh references (the proxy
|
|
# tier was removed in v0.2). rollback.sh is stop + destroy only.
|
|
|
|
setup() {
|
|
SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
ROLLBACK="${SCRIPT_DIR}/rollback.sh"
|
|
|
|
STUB_DIR="$(mktemp -d)"
|
|
export STUB_DIR
|
|
LOG="${STUB_DIR}/calls.log"
|
|
export CALL_LOG="$LOG"
|
|
: > "$LOG" 2>/dev/null || true
|
|
|
|
# Sandbox layout:
|
|
# <ROOT>/rollback.sh (SCRIPT_DIR)
|
|
# <ROOT>/api.sh (sourced)
|
|
ROOT="${STUB_DIR}/root"
|
|
mkdir -p "$ROOT"
|
|
cp "$ROLLBACK" "${ROOT}/rollback.sh"
|
|
|
|
# Mocked api.sh — pve_curl records method+path and returns STUB_UPID
|
|
# (or null); pve_get returns STUB_PVE_GET (so the "still running?"
|
|
# check fires when status=running); pve_poll no-op.
|
|
cat > "${ROOT}/api.sh" <<'ASTUB'
|
|
pve_env() { :; }
|
|
pve_curl() {
|
|
method="$1"; path="$2"
|
|
printf 'pve_curl:%s %s\n' "$method" "$path" >> "$CALL_LOG"
|
|
printf '%s\n' "${STUB_UPID:-null}"
|
|
}
|
|
pve_get() {
|
|
printf 'pve_get:%s\n' "$1" >> "$CALL_LOG"
|
|
printf '%s\n' "${STUB_PVE_GET:-}"
|
|
}
|
|
pve_poll() {
|
|
printf 'pve_poll:%s\n' "$1" >> "$CALL_LOG"
|
|
}
|
|
pve_tls_insecure() { :; }
|
|
pve_auth_header() { :; }
|
|
ASTUB
|
|
|
|
chmod +x "${ROOT}"/*.sh
|
|
|
|
export PROXMOX_API_URL="https://proxmox.test:8006/api2/json"
|
|
export PROXMOX_API_TOKEN="root@pam!test=secret"
|
|
export PROXMOX_NODE="testnode"
|
|
}
|
|
|
|
teardown() {
|
|
[ -n "${STUB_DIR:-}" ] && rm -rf "$STUB_DIR"
|
|
}
|
|
|
|
@test "rollback: shutdown → force-stop → destroy sequence (CT running)" {
|
|
# CT is running → graceful shutdown, then status=running → force stop, then destroy.
|
|
STUB_UPID="UPID:task:123"
|
|
STUB_PVE_GET='{"status":"running"}'
|
|
export STUB_UPID STUB_PVE_GET
|
|
run "${ROOT}/rollback.sh" 200
|
|
[ "$status" -eq 0 ]
|
|
grep -q 'rollback: cleaning up VMID 200' <<< "$output"
|
|
# shutdown POST recorded.
|
|
grep -q '^pve_curl:POST /nodes/testnode/lxc/200/status/shutdown$' "$LOG"
|
|
# status check via pve_get.
|
|
grep -q '^pve_get:/nodes/testnode/lxc/200/status/current$' "$LOG"
|
|
grep -q 'rollback: force-stopping VMID 200' <<< "$output"
|
|
grep -q '^pve_curl:POST /nodes/testnode/lxc/200/status/stop$' "$LOG"
|
|
grep -q 'rollback: destroying VMID 200' <<< "$output"
|
|
grep -q '^pve_curl:DELETE /nodes/testnode/lxc/200$' "$LOG"
|
|
grep -q 'rollback: VMID 200 cleaned up' <<< "$output"
|
|
}
|
|
|
|
@test "rollback: CT not running (stopped) → shutdown, no force-stop, destroy" {
|
|
# CT exists but status=stopped → no force-stop needed; destroy still runs.
|
|
STUB_UPID="UPID:task:456"
|
|
STUB_PVE_GET='{"status":"stopped"}'
|
|
export STUB_UPID STUB_PVE_GET
|
|
run "${ROOT}/rollback.sh" 200
|
|
[ "$status" -eq 0 ]
|
|
grep -q '^pve_curl:POST /nodes/testnode/lxc/200/status/shutdown$' "$LOG"
|
|
! grep -q 'force-stopping' <<< "$output"
|
|
! grep -q '^pve_curl:POST /nodes/testnode/lxc/200/status/stop$' "$LOG"
|
|
grep -q '^pve_curl:DELETE /nodes/testnode/lxc/200$' "$LOG"
|
|
grep -q 'rollback: VMID 200 cleaned up' <<< "$output"
|
|
}
|
|
|
|
@test "rollback: 404 (CT already gone) → idempotent, exit 0 (no force-stop, no error)" {
|
|
# pve_get returns empty (404) → no force-stop; shutdown + destroy both
|
|
# return null UPID (no poll). Exit 0.
|
|
STUB_UPID="null"
|
|
STUB_PVE_GET=""
|
|
export STUB_UPID STUB_PVE_GET
|
|
run "${ROOT}/rollback.sh" 200
|
|
[ "$status" -eq 0 ]
|
|
! grep -q 'force-stopping' <<< "$output"
|
|
grep -q 'rollback: destroying VMID 200' <<< "$output"
|
|
grep -q 'rollback: VMID 200 cleaned up' <<< "$output"
|
|
}
|
|
|
|
@test "rollback: shutdown returns null UPID → no poll, but destroy still runs (404-tolerant)" {
|
|
# shutdown returns null (CT already stopped) → skip poll; destroy still runs.
|
|
STUB_UPID="null"
|
|
STUB_PVE_GET='{"status":"stopped"}'
|
|
export STUB_UPID STUB_PVE_GET
|
|
run "${ROOT}/rollback.sh" 200
|
|
[ "$status" -eq 0 ]
|
|
! grep -q '^pve_poll:' "$LOG"
|
|
grep -q '^pve_curl:DELETE /nodes/testnode/lxc/200$' "$LOG"
|
|
}
|
|
|
|
@test "rollback: missing VMID arg → exit non-zero (usage)" {
|
|
run "${ROOT}/rollback.sh"
|
|
[ "$status" -ne 0 ]
|
|
grep -q 'usage: rollback.sh' <<< "$output"
|
|
}
|
|
|
|
@test "rollback: NO proxy/PROXY_VMID/backend-remove references in CODE (v0.2 proxy tier removed)" {
|
|
# G-106 / v0.2: the proxy tier was removed. rollback.sh must NOT
|
|
# reference PROXY_VMID or invoke proxy/backend-remove.sh in its CODE
|
|
# (the header comment may mention the removal for future readers, but
|
|
# no executable path references the proxy tier). Assert by grepping the
|
|
# call log (no backend-remove invocation at runtime) + stripping
|
|
# comments before grepping the source for PROXY_VMID / backend-remove.sh.
|
|
STUB_UPID="null"
|
|
STUB_PVE_GET=""
|
|
export STUB_UPID STUB_PVE_GET
|
|
PROXY_VMID=100 run "${ROOT}/rollback.sh" 200
|
|
[ "$status" -eq 0 ]
|
|
! grep -q 'backend-remove' "$LOG"
|
|
! grep -q 'proxy' "$LOG"
|
|
# Static source guard: strip comment-only lines, then assert no code
|
|
# references to the proxy tier.
|
|
code_only=$(grep -v '^[[:space:]]*#' "${ROOT}/rollback.sh")
|
|
! printf '%s\n' "$code_only" | grep -q 'PROXY_VMID'
|
|
! printf '%s\n' "$code_only" | grep -q 'backend-remove\.sh'
|
|
}
|
|
|
|
@test "rollback: pve_env fails on missing PROXMOX_NODE → exit non-zero (set -u)" {
|
|
run env -u PROXMOX_NODE "${ROOT}/rollback.sh" 200
|
|
[ "$status" -ne 0 ]
|
|
} |