#!/usr/bin/env bash
# tests/dc-dc-dr-drill/run-tests.sh -- offline harness for
# scripts/dc-dc-dr-drill.sh. Only tests THIS SCRIPT's own logic: argument
# parsing / guard clauses, the --confirmed-down gate on failover --apply,
# the failback --apply typed-confirmation gate, and -- the single most
# important assertion in this suite -- that the failback PLAN's printed
# step order is demote-recovering, then demote-CURRENT-PRIMARY-before-
# promote-recovering, verified by grepping the actual LINE ORDER of the
# dry-run output (not just that all four lines are present). Does NOT and
# CANNOT validate real rbd-mirror promote/demote behavior -- no live
# cluster exists this session (2026-07-10, prep-only).
# Exit: 0 all pass | 1 any case failed.  ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="$HERE/../../scripts/dc-dc-dr-drill.sh"
PASS=0; FAIL=0

run() { # run <want_rc> <regex> <label> -- args...
  local want="$1" rx="$2" label="$3"; shift 3
  local out rc
  out="$(bash "$SCRIPT" "$@" 2>&1)"; rc=$?
  if [[ "$rc" == "$want" ]] && grep -qE "$rx" <<<"$out"; then
    echo "  PASS  $label"; PASS=$((PASS+1))
  else
    echo "  FAIL  $label (rc=$rc want=$want)"; echo "$out" | sed 's/^/        /'; FAIL=$((FAIL+1))
  fi
}

run 1 'a subcommand is required'  "T1 no subcommand FAILS (rc 1)"
run 1 'unknown subcommand'        "T2 bogus subcommand FAILS (rc 1)" bogus
run 0 'usage:'                    "T3 --help exits 0 with usage" --help

# --- failover arg parsing ---
run 1 '\-\-dc is required'         "T4 failover missing --dc FAILS" failover
run 1 '\-\-dc must be dc1 or dc2'  "T5 failover bad --dc token FAILS" failover --dc bogus --unit ceph-mon/0 --pool glance
run 1 '\-\-unit is required'       "T6 failover missing --unit FAILS" failover --dc dc1
run 1 'never assume .glance.'      "T7 failover missing --pool FAILS, cites no-assume-glance" failover --dc dc1 --unit ceph-mon/0

# --- failback arg parsing ---
run 1 '\-\-pool is required'            "T8 failback missing --pool FAILS" failback
run 1 '\-\-recovering-dc is required'   "T9 failback missing --recovering-dc FAILS" failback --pool glance
run 1 '\-\-primary-dc is required'      "T10 failback missing --primary-dc FAILS" failback --pool glance --recovering-dc dc1
run 1 'must differ'                     "T11 failback recovering-dc == primary-dc FAILS" failback --pool glance --recovering-dc dc1 --primary-dc dc1 --recovering-unit u/0 --primary-unit u/1
run 1 '\-\-recovering-unit is required' "T12 failback missing --recovering-unit FAILS" failback --pool glance --recovering-dc dc1 --primary-dc dc2
run 1 '\-\-primary-unit is required'    "T13 failback missing --primary-unit FAILS" failback --pool glance --recovering-dc dc1 --primary-dc dc2 --recovering-unit u/0

# --- failover: --confirmed-down gates --apply, but not the dry-run plan print ---
FO_DRY="$(bash "$SCRIPT" failover --dc dc1 --unit ceph-mon/0 --pool glance 2>&1)"; FO_DRY_RC=$?
[[ "$FO_DRY_RC" == 0 ]] && grep -q 'promote --force glance' <<<"$FO_DRY" && grep -q 'confirmed-down is required' <<<"$FO_DRY" \
  && { echo "  PASS  T14 failover dry-run (no --confirmed-down) still prints the plan, rc 0"; PASS=$((PASS+1)); } || { echo "  FAIL  T14"; echo "$FO_DRY" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

run 1 'confirmed-down is required'  "T15 failover --apply WITHOUT --confirmed-down is BLOCKED (rc 1)" failover --dc dc1 --unit ceph-mon/0 --pool glance --apply

FO_REREG="$(bash "$SCRIPT" failover --dc dc1 --unit ceph-mon/0 --pool glance --confirmed-down --reregister-image img1 2>&1)"
grep -q 'NEVER EXECUTED BY THIS SCRIPT' <<<"$FO_REREG" && grep -q 'img1' <<<"$FO_REREG" \
  && { echo "  PASS  T16 failover re-registration step is printed but flagged manual (never auto-executed)"; PASS=$((PASS+1)); } || { echo "  FAIL  T16"; echo "$FO_REREG" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

# --- failback: the safety-critical step ORDER, verified by LINE NUMBER ---
FB_OUT="$(bash "$SCRIPT" failback --pool glance --recovering-dc dc1 --recovering-unit rec/0 --primary-dc dc2 --primary-unit pri/0 2>&1)"; FB_RC=$?
[[ "$FB_RC" == 0 ]] && { echo "  PASS  T17 failback dry-run (dc1 recovering, dc2 primary) exits 0"; PASS=$((PASS+1)); } || { echo "  FAIL  T17"; echo "$FB_OUT" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

L_112=$(grep -n '11.2 (demote recovering' <<<"$FB_OUT" | head -1 | cut -d: -f1)
L_114A=$(grep -n '11.4a (demote CURRENT PRIMARY' <<<"$FB_OUT" | head -1 | cut -d: -f1)
L_114B=$(grep -n '11.4b (promote RECOVERING' <<<"$FB_OUT" | head -1 | cut -d: -f1)
if [[ -n "$L_112" && -n "$L_114A" && -n "$L_114B" && "$L_112" -lt "$L_114A" && "$L_114A" -lt "$L_114B" ]]; then
  echo "  PASS  T18 failback PLAN line order is 11.2 < 11.4a(demote primary) < 11.4b(promote recovering)"; PASS=$((PASS+1))
else
  echo "  FAIL  T18 failback PLAN line order wrong (11.2=$L_112 11.4a=$L_114A 11.4b=$L_114B)"; echo "$FB_OUT" | sed 's/^/        /'; FAIL=$((FAIL+1))
fi
# the demote command must appear on the primary line BEFORE the promote command on the recovering line
grep -A0 '11.4a' <<<"$FB_OUT" | grep -q 'demote glance' \
  && grep -A0 '11.4b' <<<"$FB_OUT" | grep -q 'promote glance' \
  && { echo "  PASS  T19 11.4a is a demote, 11.4b is a promote (not swapped)"; PASS=$((PASS+1)); } || { echo "  FAIL  T19"; echo "$FB_OUT" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

FB_SKIP="$(bash "$SCRIPT" failback --pool glance --recovering-dc dc1 --recovering-unit rec/0 --primary-dc dc2 --primary-unit pri/0 --skip-11-4 2>&1)"
grep -q '11.4 SKIPPED' <<<"$FB_SKIP" && ! grep -q '11.4a' <<<"$FB_SKIP" \
  && { echo "  PASS  T20 --skip-11-4 stops the plan after 11.2/11.3"; PASS=$((PASS+1)); } || { echo "  FAIL  T20"; echo "$FB_SKIP" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

# --- $DC gate: informational in dry-run (dc2 involved), blocking before --apply ---
grep -q 'gate: FAILED' <<<"$FB_OUT" && grep -q 'gate: OK (dc1)' <<<"$FB_OUT" \
  && { echo "  PASS  T21 failback dry-run reports dc1 OK / dc2 FAILED, still prints full plan"; PASS=$((PASS+1)); } || { echo "  FAIL  T21"; echo "$FB_OUT" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

run 3 '\$DC gate refused' "T22 failback --apply is BLOCKED by the dc2 gate (rc 3)" failback --pool glance --recovering-dc dc1 --recovering-unit rec/0 --primary-dc dc2 --primary-unit pri/0 --apply --no-prompt

# --- --apply never runs without --apply: no juju invocation attempted in dry-run ---
if command -v juju >/dev/null 2>&1; then
  echo "  SKIP  T23 juju-missing case (juju IS present in this environment -- can't exercise the missing-tool guard here)"
else
  run 2 'juju required on PATH' "T23 failover --apply (dc1 gate OK) but juju absent FAILS (rc 2)" failover --dc dc1 --unit ceph-mon/0 --pool glance --confirmed-down --apply
fi

echo; echo "RESULT: PASS=$PASS FAIL=$FAIL"
[[ "$FAIL" -eq 0 ]] && { echo "ALL PASS"; exit 0; } || exit 1
