Newer
Older
openstack-caracal-ipv4 / tests / lib-validate / run-tests.sh
#!/usr/bin/env bash
# tests/lib-validate/run-tests.sh -- unit tests for scripts/lib-validate.sh
# Exercises: exit-contract constants, emit() line format + timing, vr_json
# stdout/stderr separation (the DOCFIX-085 invariant), run() capture-then-test,
# env scrub/scope (incl. missing-field HOLD), validators, disruptive gate.
set -u
SD="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"; LIB="$SD/../../scripts/lib-validate.sh"
P=0; F=0
ok(){ echo "PASS: $1"; P=$((P+1)); }
no(){ echo "FAIL: $1"; F=$((F+1)); }
chk(){ [ "$2" = "$3" ] && ok "$1" || no "$1 (got '$2' want '$3')"; }

# guard: sourcing OK, direct-exec refused
( bash "$LIB" >/dev/null 2>&1 ); chk "direct-exec-refused" "$?" 2

# shellcheck source=/dev/null
. "$LIB"

# exit constants
chk "const PASS"  "$VR_PASS"   0
chk "const FAIL"  "$VR_FAIL"   1
chk "const HOLD"  "$VR_HOLD"   2
chk "const MANUAL" "$VR_MANUAL" 3
chk "const SKIP"  "$VR_SKIP"   4
chk "word MANUAL" "${VR_WORD[3]}" PASS_PENDING_MANUAL

# emit format: RESULT <id> <WORD> <code> <elapsed> <msg...>
L="$(emit d011-XX 1 the message here)"
set -- $L
chk "emit tag"   "$1" RESULT
chk "emit id"    "$2" d011-XX
chk "emit word"  "$3" FAIL
chk "emit code"  "$4" 1
chk "emit elapsed-unset" "$5" "-"
grep -q 'the message here$' <<<"$L" && ok "emit msg-tail" || no "emit msg-tail"
# with timer running, elapsed is Ns
vr_begin d011-YY >/dev/null; EL="$(emit d011-YY 0 x | awk '{print $5}')"
grep -qE '^[0-9]+s$' <<<"$EL" && ok "emit elapsed-timed" || no "emit elapsed-timed ($EL)"

# vr_json: stdout captured, stderr NOT merged (the DOCFIX-085 invariant)
mkfake(){ printf '#!/usr/bin/env bash\necho "{\\"k\\":1}"\necho "a deprecation warning" >&2\n' > "$1"; chmod +x "$1"; }
FK="$(mktemp)"; mkfake "$FK"
vr_json GOT "$FK"; RC=$?
chk "vr_json rc" "$RC" 0
chk "vr_json stdout-only" "$GOT" '{"k":1}'
python3 -c "import json,sys; json.loads(sys.argv[1])" "$GOT" && ok "vr_json parses (no stderr contamination)" || no "vr_json parses"
grep -q 'deprecation' <<<"$(vr_err_tail)" && ok "vr_json stderr-captured-separately" || no "vr_json stderr-captured"
rm -f "$FK"

# vr_json propagates failure status
FK2="$(mktemp)"; printf '#!/usr/bin/env bash\necho oops >&2\nexit 5\n' > "$FK2"; chmod +x "$FK2"
vr_json X "$FK2"; chk "vr_json propagates-rc" "$?" 5; rm -f "$FK2"

# run(): capture-then-test returns the COMMAND's status, not a pipeline's
run true;  chk "run true-rc"  "$?" 0
run false; chk "run false-rc" "$?" 1
OUT="$(run echo hello 2>&1)"; grep -q '    hello' <<<"$OUT" && ok "run indents-output" || no "run indents-output"

# env scrub + tenant scope (missing-field HOLD)
export OS_STALE=1 OS_AUTH_URL=stale
CF="$(mktemp)"; printf 'auth_url=https://x:5000/v3\nusername=beta-cluster\nuser_domain_id=%s\nproject_id=%s\npassword=pw\n' "$(python3 -c 'print("b"*32)')" "$(python3 -c 'print("a"*32)')" > "$CF"
( vr_tenant_env "$CF"; RC=$?
  [ "$RC" = 0 ] && [ "$OS_USERNAME" = beta-cluster ] && [ -z "${OS_STALE:-}" ] && [ "$OS_PROJECT_ID" = "$(python3 -c 'print("a"*32)')" ] && echo GOOD ) | grep -q GOOD && ok "vr_tenant_env scopes+scrubs" || no "vr_tenant_env scopes+scrubs"
BAD="$(mktemp)"; printf 'auth_url=https://x\nusername=u\n' > "$BAD"   # missing project/password
( vr_tenant_env "$BAD" 2>/dev/null ); chk "vr_tenant_env missing-field HOLD" "$?" 2
( vr_tenant_env /nonexistent 2>/dev/null ); chk "vr_tenant_env missing-file HOLD" "$?" 2
rm -f "$CF" "$BAD"; unset OS_STALE OS_AUTH_URL

# vr_admin_env missing file -> HOLD
( HOME="$(mktemp -d)" vr_admin_env 2>/dev/null ); chk "vr_admin_env missing HOLD" "$?" 2

# validators
vr_is_hex32 "$(python3 -c 'print("a"*32)')" && ok "hex32 yes" || no "hex32 yes"
vr_is_hex32 "abc" ; chk "hex32 no" "$?" 1
vr_is_hex32 "$(python3 -c 'print("g"*32)')"; chk "hex32 nonhex" "$?" 1
vr_is_ipv4 "10.12.4.154" && ok "ipv4 yes" || no "ipv4 yes"
vr_is_ipv4 "10.12.4" ; chk "ipv4 no" "$?" 1
vr_need bash awk sed && ok "need present" || no "need present"
( vr_need definitely_not_a_tool_xyz 2>/dev/null ); chk "need missing HOLD" "$?" 2

# disruptive gate
( VR_DISRUPTIVE=0; vr_disruptive_ok ); chk "disruptive off" "$?" 1
( VR_DISRUPTIVE=1; vr_disruptive_ok ); chk "disruptive on"  "$?" 0

echo; [ "$F" = 0 ] && { echo "ALL PASS ($P checks)"; exit 0; } || { echo "FAILURES: $F"; exit 1; }