#!/usr/bin/env bash
# tests/dc-mirror/run-tests.sh -- guard for scripts/dc-mirror.sh (D-135 item 1:
# the per-DC apt+UCA mirror, D-107 build-out). Static: syntax, both sites'
# identity values (D-134 utility .4 + ruled edge gateways -- changing one
# silently breaks the mirror address or the sync egress), stable-identity
# keying (libvirt net names, never virbrN), GPG-verified sync (keyrings
# present in both debmirror calls, no --ignore-release-gpg), read-only check
# path, and the MEASURED-tag discipline on site rows.
# Exit: 0 all pass | 1 any case failed. ASCII + LF.
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="$(cd "$HERE/../.." && pwd)/scripts/dc-mirror.sh"
PASS=0; FAIL=0
ok(){ echo "  PASS  $1"; PASS=$((PASS+1)); }
no(){ echo "  FAIL  $1"; FAIL=$((FAIL+1)); }

[ -f "$SCRIPT" ] && ok "T1 script present" || { no "T1 script present"; echo; echo "dc-mirror: $PASS passed, $FAIL failed"; exit 1; }
bash -n "$SCRIPT" 2>/dev/null && ok "T2 bash -n clean" || no "T2 bash -n clean"

# T3-T4: dc0 identity values (D-134 utility .4 + ruled edge gw)
grep -q 'LISTEN_CIDR="10.12.8.4/22"' "$SCRIPT" \
  && grep -q 'MIRROR_NET="vr1-dc0-metal-admin"' "$SCRIPT" \
  && ok "T3 dc0 LISTEN 10.12.8.4/22 on metal-admin (utility .4)" \
  || no "T3 dc0 LISTEN 10.12.8.4/22 on metal-admin (utility .4)"
awk '/^  dc0\)/{f=1} f{print} f&&/;;/{exit}' "$SCRIPT" | grep -q 'EDGE_GW="10.12.4.1"' \
  && ok "T4 dc0 edge gw 10.12.4.1" || no "T4 dc0 edge gw 10.12.4.1"

# T5-T6: dc1 identity values
grep -q 'LISTEN_CIDR="10.12.68.4/22"' "$SCRIPT" \
  && grep -q 'MIRROR_NET="vr1-dc1-metal-admin"' "$SCRIPT" \
  && ok "T5 dc1 LISTEN 10.12.68.4/22 on metal-admin (utility .4)" \
  || no "T5 dc1 LISTEN 10.12.68.4/22 on metal-admin (utility .4)"
awk '/^  dc1\)/{f=1} f{print} f&&/;;/{exit}' "$SCRIPT" | grep -q 'EDGE_GW="10.12.64.1"' \
  && ok "T6 dc1 edge gw 10.12.64.1" || no "T6 dc1 edge gw 10.12.64.1"

# T7: stable-identity keying -- no virbrN literal; bridges from net names
grep -q 'net-dumpxml' "$SCRIPT" && ! grep -q 'virbr[0-9]' "$SCRIPT" \
  && ok "T7 bridges resolved from net names; no virbrN literal" \
  || no "T7 bridges resolved from net names; no virbrN literal"

# T8: both debmirror calls carry a keyring; gpg verification never disabled
KEYRING_COUNT="$(grep -c -- '--keyring=' "$SCRIPT")"
[ "$KEYRING_COUNT" -ge 2 ] && ! grep -q 'ignore-release-gpg' "$SCRIPT" \
  && ok "T8 both debmirror calls GPG-verified (no ignore-release-gpg)" \
  || no "T8 both debmirror calls GPG-verified (keyrings=$KEYRING_COUNT)"

# T9: binary-only mirror -- no sources pulled
[ "$(grep -c -- '--nosource' "$SCRIPT")" -ge 2 ] \
  && ok "T9 both mirrors --nosource (binary only)" \
  || no "T9 both mirrors --nosource (binary only)"

# T10: the ruled dist set -- jammy triple + UCA caracal
# T10 RE-POINTED 2026-07-31 (D-135 AMENDMENT, operator: "Sync the backports into the
# mirror"). It previously asserted the exact string '--dist=jammy,jammy-updates,
# jammy-security'. That assertion was CORRECT for the old scope and had to move, not be
# deleted, when the scope changed -- the standing rule that a test asserting a literal
# finding gets RE-POINTED to the new invariant. WHY the suite is mandatory: the MAAS jammy
# image ships jammy-backports in its sources.list and juju's apt-mirror model-config
# rewrites EVERY suite to this mirror, so a mirror without it 404s and every charm install
# hook fails. That cost 22 units on the 2026-07-31 dc0 deploy.
grep -q -- '--dist=jammy,jammy-updates,jammy-security,jammy-backports' "$SCRIPT" \
  && grep -q -- '--dist=jammy-updates/caracal' "$SCRIPT" \
  && ok "T10 dists: jammy triple + backports + UCA jammy-updates/caracal" \
  || no "T10 dists: jammy triple + backports + UCA jammy-updates/caracal"

# T11: unknown site refuses with exit 2 and demands measured rows
OUT="$(bash "$SCRIPT" check nosuchsite 2>&1)"; RC=$?
[ "$RC" -eq 2 ] && grep -q 'MEASURED' <<<"$OUT" \
  && ok "T11 unknown site exits 2 and demands measured rows" \
  || no "T11 unknown site exits 2 and demands measured rows (rc=$RC)"

# T12: bad mode refuses
bash "$SCRIPT" frobnicate dc0 >/dev/null 2>&1; RC=$?
[ "$RC" -eq 2 ] && ok "T12 bad mode exits 2" || no "T12 bad mode exits 2 (rc=$RC)"

# T13: sync unit ordered after + requires the net unit (egress must exist)
grep -q 'After=\${SITE}-mirror-net.service' "$SCRIPT" \
  && grep -q 'Requires=\${SITE}-mirror-net.service' "$SCRIPT" \
  && ok "T13 sync unit Requires/After net unit" \
  || no "T13 sync unit Requires/After net unit"

# T14: check path never mutates
CHECK_BLOCK="$(awk '/^do_check\(\)/{f=1} f{print} f&&/^}/{exit}' "$SCRIPT")"
grep -qE 'addr (add|replace|del)|route (add|replace|del)|systemctl (enable|restart|start|disable|reload)|daemon-reload|ln -|mkdir' <<<"$CHECK_BLOCK" \
  && no "T14 do_check is read-only" \
  || ok "T14 do_check is read-only"

# T15: install requires root (non-root exits 4 before any mutation)
if [ "$(id -u)" != "0" ]; then
  bash "$SCRIPT" install dc0 >/dev/null 2>&1; RC=$?
  [ "$RC" -eq 4 ] && ok "T15 non-root install exits 4" || no "T15 non-root install exits 4 (rc=$RC)"
else
  ok "T15 skipped (running as root)"
fi

# T16: site rows carry MEASURED citations (hard rule 2)
DC0_BLOCK="$(awk '/^  dc0\)/{f=1} f{print} f&&/;;/{exit}' "$SCRIPT")"
DC1_BLOCK="$(awk '/^  dc1\)/{f=1} f{print} f&&/;;/{exit}' "$SCRIPT")"
grep -q 'MEASURED' <<<"$DC0_BLOCK" && grep -q 'MEASURED' <<<"$DC1_BLOCK" \
  && ok "T16 both site rows cite MEASURED provenance" \
  || no "T16 both site rows cite MEASURED provenance"

# T17: nginx vhost binds the LISTEN address only (not 0.0.0.0)
grep -q 'listen \${LISTEN}:80;' "$SCRIPT" \
  && ok "T17 nginx binds the utility address only" \
  || no "T17 nginx binds the utility address only"

# T18: sync is niced/idle-IO (a background job on a load-bearing rack host)
grep -q 'IOSchedulingClass=idle' "$SCRIPT" && grep -q 'Nice=10' "$SCRIPT" \
  && ok "T18 sync unit is niced + idle IO" \
  || no "T18 sync unit is niced + idle IO"

# T19: sync unit sets HOME -- debmirror dies without it under systemd's empty
# environment (measured on the first dc0 run, 2026-07-23)
grep -q 'Environment=HOME=/root' "$SCRIPT" \
  && ok "T19 sync unit sets HOME (debmirror GPG home)" \
  || no "T19 sync unit sets HOME (debmirror GPG home)"

# T20-T24: the last-sync verdict. MEASURED false green, 2026-07-27, at the Stage 4 mirror
# gate: the check tested `[ -f last-sync.status ]` and printed the contents behind an
# unconditional "OK", so dc0's "FAIL ... ubuntu=255" and dc1's four-day-stale "RUNNING"
# (left by the debmirror the D-135 amendment killed with a signal) BOTH read green and the
# check exited PASS. This is the check a stage gate closes on (GA-R6), so each status word
# gets its own regression lock.

# T20: a FAILED sync must fail the check, not decorate it.
awk '/FAIL\*\)/{f=1} f&&/miss /{print "hit"; exit}' "$SCRIPT" | grep -q hit \
  && ok "T20 last-sync FAIL routes to miss (the measured dc0 false green)" \
  || no "T20 last-sync FAIL routes to miss (the measured dc0 false green)"

# T21: RUNNING is never a pass -- in flight and died-mid-run are indistinguishable from the
# file alone, so BOTH branches must be misses (the measured dc1 stale-marker false green).
[ "$(awk '/RUNNING\*\)/{f=1} f&&/^[[:space:]]*(esac|FAIL\*\))/{exit} f&&/miss /{n++} END{print n+0}' "$SCRIPT")" -ge 2 ] \
  && ok "T21 last-sync RUNNING is never a pass, in-flight AND stale-marker both miss" \
  || no "T21 last-sync RUNNING is never a pass, in-flight AND stale-marker both miss"

# T22: an ABSENT status file means no sync ever completed -- previously a `say note`, i.e. a
# pass. Nothing has attested the mirror content, so it must fail.
awk '/! -f "\$LSS"/{f=1} f&&/miss /{print "hit"; exit}' "$SCRIPT" | grep -q hit \
  && ok "T22 absent last-sync.status is a miss (was a passing note)" \
  || no "T22 absent last-sync.status is a miss (was a passing note)"

# T23: no silent default. An unrecognised status word must refuse rather than be read as OK
# -- the same no-silent-default discipline the D-137 checker enforces on stage tokens.
awk '/UNRECOGNISED/{print "hit"; exit}' "$SCRIPT" | grep -q hit \
  && ok "T23 an unrecognised status word refuses (no silent default to success)" \
  || no "T23 an unrecognised status word refuses (no silent default to success)"

# T24: the exact defective shape must not come back -- an OK printed straight from a cat of
# the status file, with no case analysis in between.
grep -q 'say "OK   last-sync: \$(cat' "$SCRIPT" \
  && no "T24 the existence-only last-sync shape is gone" \
  || ok "T24 the existence-only last-sync shape is gone"

echo; echo "dc-mirror: $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]
