#!/usr/bin/env bats # Bats tests for scripts/proxmox/lxc-clone.sh (praxis CT clone). # # Run: bats scripts/proxmox/test/lxc-clone.bats # # lxc-clone.sh creates a CT from a template via POST /nodes/{node}/lxc # (create-from-template), then polls the returned UPID. These tests # exercise the real lxc-clone.sh with a mocked api.sh (pve_curl records # its argv to $CALL_LOG then returns STUB_UPID; pve_poll records the # UPID) so the POST body shape + UPID-poll + empty-UPID error path are # verified without a live Proxmox endpoint. # # Praxis v0.2 (vs coreci) key differences asserted here: # - hostname defaults to "praxis" (NOT "coreci") # - memory defaults to 4096 (NOT 2048) # - rootfs is :16 (NOT :8) # - features=nesting=1, net0=name=eth0,bridge=vmbr0,ip=dhcp setup() { SCRIPT_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" CLONE="${SCRIPT_DIR}/lxc-clone.sh" STUB_DIR="$(mktemp -d)" export STUB_DIR LOG="${STUB_DIR}/calls.log" export CALL_LOG="$LOG" : > "$LOG" 2>/dev/null || true # Sandbox: /lxc-clone.sh (SCRIPT_DIR) + /api.sh (sourced). ROOT="${STUB_DIR}/root" mkdir -p "$ROOT" cp "$CLONE" "${ROOT}/lxc-clone.sh" # Mocked api.sh — pve_env no-op; pve_curl records method + path + # every form-data pair to $CALL_LOG then returns STUB_UPID; pve_poll # records the UPID it was asked to wait on. cat > "${ROOT}/api.sh" <<'ASTUB' pve_env() { :; } pve_curl() { method="$1"; path="$2"; shift 2 printf '%s\n' "${method} ${path} $*" >> "$CALL_LOG" printf '%s\n' "${STUB_UPID:-null}" } pve_poll() { printf '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" export PROXMOX_STORAGE="local" export PROXMOX_TEMPLATE_VOLID="local:vztmpl/debian-12-template.tar.zst" } teardown() { [ -n "${STUB_DIR:-}" ] && rm -rf "$STUB_DIR" } @test "clone: create-from-template POST shape (vmid, ostemplate, hostname=praxis, storage, rootfs=16, memory=4096, net0, arch, features)" { STUB_UPID="UPID:testnode:00012345:ABCDEF" export STUB_UPID run "${ROOT}/lxc-clone.sh" 200 [ "$status" -eq 0 ] # The new VMID is echoed on stdout. grep -q '^200$' <<< "$output" # pve_curl POST to /nodes/testnode/lxc recorded with the full body. grep -q '^POST /nodes/testnode/lxc vmid=200 ostemplate=local:vztmpl/debian-12-template.tar.zst hostname=praxis storage=local rootfs=local:16 memory=4096 net0=name=eth0,bridge=vmbr0,ip=dhcp arch=amd64 features=nesting=1$' "$LOG" # UPID was polled. grep -q '^poll:UPID:testnode:00012345:ABCDEF$' "$LOG" grep -q 'lxc-clone: CT 200 created' <<< "$output" } @test "clone: hostname is 'praxis' (NOT 'coreci') — G-106 praxis rebrand" { STUB_UPID="UPID:h:1" export STUB_UPID run "${ROOT}/lxc-clone.sh" 201 [ "$status" -eq 0 ] grep -q ' hostname=praxis ' "$LOG" ! grep -q 'hostname=coreci' "$LOG" } @test "clone: memory defaults to 4096 (NOT 2048) — praxis v0.2 sizing" { STUB_UPID="UPID:m:1" export STUB_UPID run "${ROOT}/lxc-clone.sh" 202 [ "$status" -eq 0 ] grep -q ' memory=4096 ' "$LOG" ! grep -q 'memory=2048' "$LOG" } @test "clone: rootfs is :16 (NOT :8) — praxis v0.2 disk sizing" { STUB_UPID="UPID:r:1" export STUB_UPID run "${ROOT}/lxc-clone.sh" 203 [ "$status" -eq 0 ] grep -q ' rootfs=local:16 ' "$LOG" ! grep -q 'rootfs=local:8' "$LOG" } @test "clone: features=nesting=1 (Docker-in-LXC requires nesting)" { STUB_UPID="UPID:f:1" export STUB_UPID run "${ROOT}/lxc-clone.sh" 204 [ "$status" -eq 0 ] grep -q 'features=nesting=1' "$LOG" } @test "clone: net0 uses bridge=vmbr0,ip=dhcp" { STUB_UPID="UPID:n:1" export STUB_UPID run "${ROOT}/lxc-clone.sh" 205 [ "$status" -eq 0 ] grep -q 'net0=name=eth0,bridge=vmbr0,ip=dhcp' "$LOG" } @test "clone: PRAXIS_HOSTNAME override flows into hostname field" { STUB_UPID="UPID:h:2" export STUB_UPID PRAXIS_HOSTNAME="praxis-staging" run "${ROOT}/lxc-clone.sh" 206 [ "$status" -eq 0 ] grep -q 'hostname=praxis-staging' "$LOG" } @test "clone: PROXMOX_MEMORY_MB override flows into memory field" { STUB_UPID="UPID:m:2" export STUB_UPID PROXMOX_MEMORY_MB=8192 run "${ROOT}/lxc-clone.sh" 207 [ "$status" -eq 0 ] grep -q 'memory=8192' "$LOG" } @test "clone: empty UPID (null) → exit 1, no poll, error logged" { STUB_UPID="null" export STUB_UPID run "${ROOT}/lxc-clone.sh" 208 [ "$status" -ne 0 ] grep -q 'failed to start create (empty UPID)' <<< "$output" ! grep -q '^poll:' "$LOG" } @test "clone: empty-string UPID → exit 1, no poll" { STUB_UPID="" export STUB_UPID run "${ROOT}/lxc-clone.sh" 209 [ "$status" -ne 0 ] grep -q 'failed to start create (empty UPID)' <<< "$output" ! grep -q '^poll:' "$LOG" } @test "clone: missing VMID arg → exit non-zero (usage)" { run "${ROOT}/lxc-clone.sh" [ "$status" -ne 0 ] grep -q 'usage: lxc-clone.sh' <<< "$output" } @test "clone: pve_env fails on missing PROXMOX_STORAGE → exit non-zero" { STUB_UPID="UPID:e:1" export STUB_UPID run env -u PROXMOX_STORAGE "${ROOT}/lxc-clone.sh" 210 [ "$status" -ne 0 ] } @test "clone: pve_env fails on missing PROXMOX_TEMPLATE_VOLID → exit non-zero" { STUB_UPID="UPID:e:2" export STUB_UPID run env -u PROXMOX_TEMPLATE_VOLID "${ROOT}/lxc-clone.sh" 211 [ "$status" -ne 0 ] }