#!/usr/bin/env bash
# tests/cloud-assert/run-tests.sh -- offline fakebin harness for cloud-assert.sh
# (DOCFIX-075). Fake juju/openstack/jq-free: real jq stays real; fake juju and
# openstack replay fixture outputs keyed by argument patterns, selected per test
# via FIXDIR. Asserts the behavioral checks fire on the exact incident
# signatures they were written for (D-045/D-046/D-051/D-062/vault-sealed).
# Mutates nothing outside $TMP. Exit: 0 all pass | 1 any failed.  ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
PASS=0; FAIL=0
BIN="$TMP/bin"; mkdir -p "$BIN"

cat > "$BIN/juju" <<'FB'
#!/usr/bin/env bash
# fake juju: replay fixtures from $FIXDIR keyed by argv patterns
A="$*"
case "$A" in
  *"status -m"*"keystone --format=json"*) cat "$FIXDIR/ks-status.json" ;;
  *"status -m"*"--format=json"*)          cat "$FIXDIR/status.json" ;;
  *"vault/0"*"vault status"*)             cat "$FIXDIR/vault.txt" ;;
  *"cluster/status OVN_Northbound"*)      cat "$FIXDIR/ovn-nb.txt" ;;
  *"cluster/status OVN_Southbound"*)      cat "$FIXDIR/ovn-sb.txt" ;;
  *"connection-status"*)                  cat "$FIXDIR/chassis.txt" ;;
  *"ps -ww -C magnum-conductor"*)         cat "$FIXDIR/conductor.txt" ;;
  *) echo "fake-juju: unmatched: $A" >&2; exit 1 ;;
esac
FB
cat > "$BIN/openstack" <<'FB'
#!/usr/bin/env bash
A="$*"
# truthful-mock knobs (DOCFIX-094): FIXDIR/noise -> realistic deprecation notice on
# STDERR for the three list calls; FIXDIR/svc-err -> compute service list ERRORS
# (stderr + rc1, no stdout), the shape that was silently fail-open pre-fix.
case "$A" in
  *"hypervisor list"*|*"compute service list"*|*"loadbalancer list"*)
    [ -f "$FIXDIR/noise" ] && echo "WARNING: this CLI call is deprecated and will be removed" >&2 ;;
esac
case "$A" in
  *"hypervisor list"*)        cat "$FIXDIR/hypervisors.json" ;;
  *"compute service list"*)
    if [ -f "$FIXDIR/svc-err" ]; then echo "Unauthorized (HTTP 401)" >&2; exit 1; fi
    cat "$FIXDIR/services.json" ;;
  *"loadbalancer list"*)      cat "$FIXDIR/lbs.json" ;;
  *"domain show magnum"*)     cat "$FIXDIR/domain.txt" ;;
  *"user show magnum_domain_admin"*) cat "$FIXDIR/user.txt" ;;
  *"coe service list"*)       cat "$FIXDIR/coe.txt" ;;
  *) echo "fake-openstack: unmatched: $A" >&2; exit 1 ;;
esac
FB
chmod +x "$BIN/juju" "$BIN/openstack"

mkgood() { # healthy-cloud fixture set
  local d="$1"; mkdir -p "$d"
  cat > "$d/status.json" <<'J'
{"applications":{
 "mysql-innodb-cluster":{"units":{
   "mysql-innodb-cluster/0":{"workload-status":{"current":"active","message":"Unit is ready: Mode: R/W, Cluster is ONLINE"}},
   "mysql-innodb-cluster/1":{"workload-status":{"current":"active","message":"Unit is ready: Mode: R/O, Cluster is ONLINE"}},
   "mysql-innodb-cluster/2":{"workload-status":{"current":"active","message":"Unit is ready: Mode: R/O, Cluster is ONLINE"}}}},
 "ovn-central":{"units":{"ovn-central/0":{"workload-status":{"current":"active"}},
   "ovn-central/1":{"workload-status":{"current":"active"}},"ovn-central/2":{"workload-status":{"current":"active"}}}},
 "nova-compute":{"units":{"nova-compute/0":{"workload-status":{"current":"active"}}}},
 "octavia":{"units":{"octavia/0":{"workload-status":{"current":"active"}}}},
 "glance-simplestreams-sync":{"units":{"glance-simplestreams-sync/0":{"workload-status":{"current":"unknown"}}}}
}}
J
  printf 'Initialized  true\nSealed       false\n' > "$d/vault.txt"
  printf 'Cluster ID: abcd (uuid)\nServers: 3\n' > "$d/ovn-nb.txt"
  cp "$d/ovn-nb.txt" "$d/ovn-sb.txt"
  printf 'connected\n' > "$d/chassis.txt"
  printf '/usr/bin/python3 /usr/bin/magnum-conductor --config-file /etc/magnum/magnum.conf --config-dir /etc/magnum/magnum.conf.d\n' > "$d/conductor.txt"
  printf '[{"Hypervisor Hostname":"openstack0","State":"up"}]\n' > "$d/hypervisors.json"
  printf '[{"Binary":"nova-compute","Host":"openstack0","Status":"enabled","State":"up"}]\n' > "$d/services.json"
  printf '[]\n' > "$d/lbs.json"
  printf 'True\n' > "$d/domain.txt"
  printf 'magnum_domain_admin\n' > "$d/user.txt"
  printf 'magnum-conductor\n' > "$d/coe.txt"
  # truthful mock: real juju 3.6 status JSON shape (line-format omits messages,
  # which is exactly the DOCFIX-087 false-negative this fixture used to hide)
  cat > "$d/ks-status.json" <<'J'
{"applications":{"keystone":{
  "application-status":{"current":"active","message":"Application Ready"},
  "units":{"keystone/0":{"workload-status":{"current":"active","message":"PO: Unit is ready"}}}}}}
J
}
run() { # run <want_rc> <regex> <label> <fixdir> [env...]
  local want="$1" rx="$2" label="$3" fd="$4"; shift 4
  local out rc
  out="$(cd "$TMP" && env "$@" FIXDIR="$fd" PATH="$BIN:$PATH" OS_AUTH_URL="https://fake:5000/v3" \
        bash "$REPO/scripts/cloud-assert.sh" 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)"; grep -E '\[(FAIL|WARN)\]|CLOUD-ASSERT' <<<"$out" | head -6 | sed 's/^/        /'; FAIL=$((FAIL+1))
  fi
}

F="$TMP/good"; mkgood "$F";  run 0 'CLOUD-ASSERT: PASS' "T1 healthy cloud -> PASS" "$F"
F="$TMP/sealed"; mkgood "$F"; printf 'Initialized  true\nSealed       true\n' > "$F/vault.txt"
                              run 1 'vault SEALED' "T2 sealed vault FAILS (with unseal pointer)" "$F"
F="$TMP/rw2"; mkgood "$F"; python3 - "$F/status.json" <<'PY'
import json,sys; p=sys.argv[1]; d=json.load(open(p))
u=d["applications"]["mysql-innodb-cluster"]["units"]
u["mysql-innodb-cluster/1"]["workload-status"]["message"]="Unit is ready: Mode: R/W, Cluster is ONLINE"
json.dump(d,open(p,"w"))
PY
                              run 1 'R/W count=2' "T3 mysql split-brain (2x R/W) FAILS" "$F"
F="$TMP/chassis"; mkgood "$F"; printf 'not connected\n' > "$F/chassis.txt"
                              run 1 'chassis NOT connected' "T4 dead chassis FAILS (D-045 class)" "$F"
F="$TMP/pobroken"; mkgood "$F"; cat > "$F/ks-status.json" <<'J'
{"applications":{"keystone":{
  "application-status":{"current":"active","message":"Application Ready"},
  "units":{"keystone/0":{"workload-status":{"current":"active","message":"PO (broken): policy zip attached but unparsed"}}}}}}
J
                              run 1 'PO \(broken\)' "T5 PO(broken) FAILS (DOCFIX-071)" "$F"
F="$TMP/nodomain"; mkgood "$F"; printf 'No domain with a name or ID\n' > "$F/domain.txt"
                              run 1 "domain-setup" "T6 missing trustee domain FAILS (D-046)" "$F"
F="$TMP/graft"; mkgood "$F"; printf '/usr/bin/python3 /usr/bin/magnum-conductor --config-file /etc/magnum/magnum.conf\n' > "$F/conductor.txt"
                              run 1 'lack --config-dir' "T7 dead conductor graft FAILS (D-037)" "$F"
F="$TMP/lberr"; mkgood "$F"; printf '[{"name":"lb1","provisioning_status":"ERROR","operating_status":"OFFLINE"}]\n' > "$F/lbs.json"
                              run 1 'LBs unhealthy' "T8 LB in ERROR FAILS (with failover pointer)" "$F"
# T10 (DOCFIX-087 regression): healthy keystone but NO PO: in any message -> FAIL
F="$TMP/nopo"; mkgood "$F"; cat > "$F/ks-status.json" <<'J'
{"applications":{"keystone":{
  "application-status":{"current":"active","message":"Application Ready"},
  "units":{"keystone/0":{"workload-status":{"current":"active","message":"Unit is ready"}}}}}}
J
                              run 1 'NO policy override' "T10 missing PO: marker FAILS (DOCFIX-087)" "$F"
# T11 (DOCFIX-094): stderr deprecation noise on healthy cloud must NOT break the
# structured captures (pre-fix: merged noise killed the A5 parse -> false FAIL)
F="$TMP/noise"; mkgood "$F"; : > "$F/noise"
                              run 0 'CLOUD-ASSERT: PASS' "T11 stderr noise does not break A5/A6 parsing" "$F"
# T12 (DOCFIX-094): compute service list ERRORING must FAIL (pre-fix: silently OK)
F="$TMP/svcerr"; mkgood "$F"; : > "$F/svc-err"
                              run 1 'compute service list unreadable' "T12 erroring service-list FAILS (was fail-open)" "$F"

# T9: no admin scope -> A5-A7 HELD, exit 2 (never a silent pass)
F="$TMP/held"; mkgood "$F"
out="$(cd "$TMP" && env -u OS_AUTH_URL FIXDIR="$F" PATH="$BIN:$PATH" bash "$REPO/scripts/cloud-assert.sh" 2>&1)"; rc=$?
if [[ "$rc" == "2" ]] && grep -q 'HELD: no admin scope' <<<"$out"; then echo "  PASS  T9 missing admin scope -> HELD (rc 2)"; PASS=$((PASS+1))
else echo "  FAIL  T9 (rc=$rc)"; FAIL=$((FAIL+1)); fi

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