#!/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 vr1-dc0 or vr1-dc1'  "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 vr1-dc0
run 1 'never assume .glance.'      "T7 failover missing --pool FAILS, cites no-assume-glance" failover --dc vr1-dc0 --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 vr1-dc0
run 1 'must differ'                     "T11 failback recovering-dc == primary-dc FAILS" failback --pool glance --recovering-dc vr1-dc0 --primary-dc vr1-dc0 --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 vr1-dc0 --primary-dc vr1-dc1
run 1 '\-\-primary-unit is required'    "T13 failback missing --primary-unit FAILS" failback --pool glance --recovering-dc vr1-dc0 --primary-dc vr1-dc1 --recovering-unit u/0

# --- failover: --confirmed-down gates --apply, but not the dry-run plan print ---
FO_DRY="$(bash "$SCRIPT" failover --dc vr1-dc0 --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 vr1-dc0 --unit ceph-mon/0 --pool glance --apply

FO_REREG="$(bash "$SCRIPT" failover --dc vr1-dc0 --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 vr1-dc0 --recovering-unit rec/0 --primary-dc vr1-dc1 --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 vr1-dc0 --recovering-unit rec/0 --primary-dc vr1-dc1 --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: both DCs now pass (vr1-dc1 literals RATIFIED, D-124 amendment
# 2026-07-21). The gate's refusal path (exit 3) is retained in the script as
# defense-in-depth for future unassigned DC tokens, but is no longer reachable
# through the CLI (arg validation admits only the two ratified tokens).
grep -q 'gate: OK (vr1-dc1)' <<<"$FB_OUT" && grep -q 'gate: OK (vr1-dc0)' <<<"$FB_OUT" \
  && { echo "  PASS  T21 failback dry-run reports BOTH DC gates OK (dc1 ratified), still prints full plan"; PASS=$((PASS+1)); } || { echo "  FAIL  T21"; echo "$FB_OUT" | sed 's/^/        /'; FAIL=$((FAIL+1)); }

if command -v juju >/dev/null 2>&1; then
  echo "  SKIP  T22 juju-missing case (juju IS present in this environment -- can't exercise the missing-tool guard here)"
else
  run 2 'juju required on PATH' "T22 failback --apply passes both DC gates, FAILS on missing juju (rc 2)" failback --pool glance --recovering-dc vr1-dc0 --recovering-unit rec/0 --primary-dc vr1-dc1 --primary-unit pri/0 --apply --no-prompt
fi

# --- --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 vr1-dc0 --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
