#!/usr/bin/env bash # tenantsync-usage-harness.sh (v0.65.0, R-5) — Group-A test for the felhom-tenantsync `usage` op. # Stubs proxmox-backup-manager + df on PATH (real jq), runs the op, and asserts: # 1. usage → {"status":"ok","total","used","avail"} + exit 0 + ZERO mutation calls. # 2. provision (regression) → reaches the mutation path (admin-token generate) — the usage op did # not disturb the case dispatch — and NEVER emits the usage JSON. # Non-hollow: the stub LOGS every proxmox-backup-manager invocation; the zero-mutation assertion reads it. set -uo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" SCRIPT="$HERE/felhom-tenantsync.sh" WORK="$(mktemp -d)" trap 'rm -rf "$WORK"' EXIT STUB="$WORK/bin"; mkdir -p "$STUB" export MUTLOG="$WORK/mutations.log"; : > "$MUTLOG" export CALLLOG="$WORK/calls.log"; : > "$CALLLOG" DS_PATH="$WORK/ds"; mkdir -p "$DS_PATH" # Stub proxmox-backup-manager: read-only ops answered; MUTATING subcommands logged to MUTLOG. cat > "$STUB/proxmox-backup-manager" <<'PBM' #!/usr/bin/env bash echo "pbm $*" >> "$CALLLOG" case "$1 $2" in "cert info") echo "Fingerprint (sha256): aa:bb:cc:dd" ;; "datastore list") printf '[{"name":"scratch","path":"/srv/pbs-scratch"},{"name":"felhom-offsite","path":"%s"}]\n' "$DS_PATH" ;; "user generate-token") echo "MUTATION: $*" >> "$MUTLOG"; echo '{"value":"FAKE-ADMIN-TOKEN"}' ;; "user delete-token") echo "MUTATION: $*" >> "$MUTLOG" ;; "acl update") echo "MUTATION: $*" >> "$MUTLOG" ;; "namespace "*) echo "MUTATION: $*" >> "$MUTLOG" ;; *) echo "MUTATION: $*" >> "$MUTLOG" ;; # any other subcommand is mutating here esac PBM chmod +x "$STUB/proxmox-backup-manager" # Stub proxmox-backup-client (used only by the mutating ops; log if invoked). cat > "$STUB/proxmox-backup-client" <<'PBC' #!/usr/bin/env bash echo "MUTATION: pbc $*" >> "$MUTLOG" PBC chmod +x "$STUB/proxmox-backup-client" # Stub df: fixed bytes (total 41943040, used 8388608, avail 33554432 ⇒ 20% full). cat > "$STUB/df" <<'DF' #!/usr/bin/env bash echo "1B-blocks Used Avail" echo "41943040 8388608 33554432" DF chmod +x "$STUB/df" export DS_PATH CALLLOG MUTLOG RC=0 fail() { echo "FAIL: $*"; RC=1; } # --- Test 1: usage op --- OUT=$(echo '{"op":"usage"}' | PATH="$STUB:$PATH" bash "$SCRIPT" 2>/dev/null); EC=$? [ "$EC" -eq 0 ] || fail "usage exit $EC (want 0)" EXP='{"status":"ok","total":41943040,"used":8388608,"avail":33554432}' [ "$OUT" = "$EXP" ] || fail "usage stdout = $OUT (want $EXP)" if [ -s "$MUTLOG" ]; then fail "usage ran mutations: $(cat "$MUTLOG")"; else echo "PASS: usage emits totals, exit 0, ZERO mutations"; fi # --- Test 2: provision regression (dispatch intact; usage op did not break the case) --- : > "$MUTLOG" POUT=$(echo '{"op":"provision","customer_id":"harness"}' | PATH="$STUB:$PATH" bash "$SCRIPT" 2>/dev/null || true) grep -q "generate-token" "$MUTLOG" || fail "provision did not reach the mutation path (case dispatch broken by the usage op?)" case "$POUT" in *'"total"'*) fail "provision leaked the usage shape: $POUT" ;; esac [ "$RC" -eq 0 ] && echo "PASS: provision still dispatches to the mutation path (regression)" exit $RC