#!/usr/bin/env bash
# tests/provider-bundle-check/run-tests.sh
#
# Offline regression harness for scripts/provider-bundle-check.py. No live infra;
# fixtures are generated from the repo bundle by targeted mutation, so every check
# is proven to FAIL when its invariant is violated (bash -n / "it parsed" proves
# nothing -- behavior is the contract). Mutates NOTHING outside $TMP.
# Exit: 0 all pass | 1 any case failed.  ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO="$(cd "$HERE/../.." && pwd)"
CHK="$REPO/scripts/provider-bundle-check.py"
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
PASS=0; FAIL=0

# fixture base: real bundle + the policies dir the DOCFIX-071 check resolves
mkdir -p "$TMP/policies"
cp "$REPO/bundle.yaml" "$TMP/good.yaml"
cp "$REPO/policies/domain-manager-policy.yaml" "$REPO/policies/overrides.zip" "$TMP/policies/"

mutate() { # mutate <out> <python-expr operating on dict b>
  python3 - "$TMP/good.yaml" "$TMP/$1" "$2" <<'PY'
import sys, yaml
src, dst, expr = sys.argv[1], sys.argv[2], sys.argv[3]
b = yaml.safe_load(open(src))
exec(expr)
yaml.safe_dump(b, open(dst, "w"))
PY
}

run() { # run <want_rc> <regex> <label> <bundle>
  local want="$1" rx="$2" label="$3" f="$4"
  local out rc
  out="$(python3 "$CHK" "$f" 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/^/        /' | head -6; FAIL=$((FAIL+1))
  fi
}

# T1 happy path: the repo bundle itself must PASS
run 0 'PASS: Pattern A' "T1 repo bundle passes clean" "$TMP/good.yaml"

# T2 relation referencing a ghost app
mutate t2.yaml 'b["relations"].append(["ghost-app:amqp","rabbitmq-server:amqp"])'
run 1 'unknown app' "T2 ghost relation app FAILS" "$TMP/t2.yaml"

# T3 endpoint-less relation side (the missing-colon class)
mutate t3.yaml 'b["relations"].append(["keystone","rabbitmq-server:amqp"])'
run 1 'lacks explicit :endpoint' "T3 endpoint-less relation FAILS" "$TMP/t3.yaml"

# T4 D-062 regression: mysql at 1 unit
mutate t4.yaml 'b["applications"]["mysql-innodb-cluster"]["num_units"]=1'
run 1 'D-062 requires 3' "T4 mysql num_units=1 FAILS" "$TMP/t4.yaml"

# T5 shared VIP octet between two apps
mutate t5.yaml 'b["applications"]["glance"]["options"]["vip"]="10.12.4.50 10.12.8.50 10.12.12.50"'
run 1 'shared by' "T5 duplicate VIP octet FAILS" "$TMP/t5.yaml"

# T6 DOCFIX-071 regression: keystone resource stanza removed
mutate t6.yaml 'b["applications"]["keystone"].pop("resources",None)'
run 1 'DOCFIX-071' "T6 missing policyd resource FAILS" "$TMP/t6.yaml"

# T7 DOCFIX-071 drift: zip content differs from the yaml source
mutate t7.yaml 'pass'
printf '\n# drift\n' >> "$TMP/policies/domain-manager-policy.yaml"
run 1 'DIFFERS from policies' "T7 zip/source drift FAILS" "$TMP/t7.yaml"
cp "$REPO/policies/domain-manager-policy.yaml" "$TMP/policies/"   # restore

# T8 original invariant still guarded: octavia VIP off-band
mutate t8.yaml 'b["applications"]["octavia"]["options"]["vip"]="10.12.4.233 10.12.8.233 10.12.12.233"'
run 1 'outside 50-60' "T8 off-band VIP octet FAILS" "$TMP/t8.yaml"

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