Files
lmxopcua/scripts/ci/assert-not-all-skipped.sh
T
2026-10-13 11:05:49 -04:00

74 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# assert-not-all-skipped.sh — arch-review 07/S-2 fail-on-skip guard.
#
# A CI test leg that ran but executed ZERO tests reports success, so a whole tier
# silently skipping (fixtures unreachable, a --filter that matched nothing, a probe
# that Assert.Skip'd every case) is indistinguishable from a real pass. This gate
# reads the trx result summary and FAILS when fewer than MIN_EXECUTED tests actually
# ran across the supplied trx files — turning "green means skipped" into a red build.
#
# Usage: scripts/ci/assert-not-all-skipped.sh <trx> [<trx> ...]
# Env: MIN_EXECUTED minimum executed tests required (default 1).
# Set MIN_EXECUTED=0 for a report-only pass (never fails) —
# used by the fixtureless integration leg until its fixtures
# run as workflow services (S-2 option #2 follow-up).
#
set -euo pipefail
min_executed="${MIN_EXECUTED:-1}"
if [ "$#" -eq 0 ]; then
echo "assert-not-all-skipped: no trx files given" >&2
exit 2
fi
total_executed=0
total_skipped=0
seen=0
for f in "$@"; do
if [ ! -f "$f" ]; then
echo "assert-not-all-skipped: trx not found: $f" >&2
exit 2
fi
seen=$((seen + 1))
# Keep the executed-counter floor unchanged; notExecuted is only a fallback
# for malformed XML that this guard historically accepted.
counters="$(grep -oE '<Counters[^>]*/?>' "$f" | head -1)"
ex="$(printf '%s' "$counters" | grep -oE 'executed="[0-9]+"' | grep -oE '[0-9]+' || true)"
ne="$(printf '%s' "$counters" | grep -oE 'notExecuted="[0-9]+"' | grep -oE '[0-9]+' || true)"
ex="${ex:-0}"
ne="${ne:-0}"
# VSTest can emit notExecuted="0" despite individual NotExecuted results.
# Count direct Results/UnitTestResult records in the document's namespace,
# excluding foreign elements, nested records and escaped diagnostic text.
ne="$(python3 - "$f" "$ne" <<'PY'
import sys
import xml.etree.ElementTree as ET
try:
root = ET.parse(sys.argv[1]).getroot()
except ET.ParseError:
# Skip reporting must not introduce a new malformed-XML gate failure.
print(sys.argv[2])
else:
namespace = root.tag.split("}", 1)[0] + "}" if root.tag.startswith("{") else ""
results = root.findall(f"{namespace}Results/{namespace}UnitTestResult")
print(sum(result.get("outcome") == "NotExecuted" for result in results))
PY
)"
total_executed=$((total_executed + ex))
total_skipped=$((total_skipped + ne))
echo " $(basename "$f"): executed=${ex} skipped=${ne}"
done
echo "assert-not-all-skipped: files=${seen} executed=${total_executed} skipped=${total_skipped} (min required=${min_executed})"
if [ "$total_executed" -lt "$min_executed" ]; then
echo "::error::CI executed ${total_executed} test(s) (< ${min_executed}) — the tier ran nothing (all skipped?). Treating as FAILURE, not a pass." >&2
exit 1
fi
echo "assert-not-all-skipped: OK"