Files
pulse/scripts/tests/run.sh
T
pulse-triage[bot] db76f62798 Balance isolated smoke suites with measured scheduling hints
A complete passing PR run spent 318 and 567 seconds inside the two smoke inventories. Filename parity places the long deadline controls together. Partition every discovered suite by measured duration while preserving sorted per-shard execution, real deadlines, failure collection and the existing checks. New suites use a default weight; stale hints cannot add or omit coverage, and incomplete selection fails before execution.

Contract-Neutral: CI scheduling of unchanged complete script suites only; product, installer, release and verification acceptance contracts are unchanged.
Change-source: pulse-maintainer
2026-10-26 17:32:06 +00:00

180 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Simple harness to execute smoke tests under scripts/tests/.
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
TEST_DIR="${ROOT_DIR}/scripts/tests"
usage() {
cat <<'EOF'
Usage: scripts/tests/run.sh [test-script ...]
scripts/tests/run.sh --smoke-shard <0|1>
scripts/tests/run.sh --docs-shard <0|1|2|3>
Run all scripts/tests/test-*.sh and scripts/tests/test_*.py tests or a subset
when specified. Documentation CI discovers every documentation suite and runs
one of four disjoint, sorted shards; it does not maintain a second suite list.
Smoke CI balances the complete inventory across two isolated, sorted shards
using measured suite durations. New suites receive a default scheduling weight.
EOF
}
discover_tests() {
local -n ref=$1
local mode="${2:-all}"
local inventory
local -a patterns=(-name 'test-*.sh' -o -name 'test_*.py')
if [[ "${mode}" == docs ]]; then
# Keep the established safety helpers whose names predate the docs suffix.
patterns=(-name 'test_*docs*.py' -o -name 'test_vm_disk_diagnostics.py'
-o -name 'test_troubleshooting_logs.py'
-o -name 'test-retired-trial-acquisition-docs.sh')
fi
# Process substitution hides producer failures from mapfile. Admit the
# complete discovery pipeline before running any tests, never a partial list.
if ! inventory="$(
find "${TEST_DIR}" -maxdepth 1 -type f \
\( "${patterns[@]}" \) | LC_ALL=C sort
)"; then
echo "Failed to discover the complete smoke test inventory under ${TEST_DIR}" >&2
return 1
fi
ref=()
if [[ -n "${inventory}" ]]; then
mapfile -t ref <<< "${inventory}"
fi
}
resolve_test_path() {
local input="$1"
if [[ "${input}" == /* ]]; then
printf '%s\n' "${input}"
return 0
fi
if [[ -f "${TEST_DIR}/${input}" ]]; then
printf '%s\n' "${TEST_DIR}/${input}"
return 0
fi
if [[ -f "${input}" ]]; then
printf '%s\n' "${input}"
return 0
fi
return 1
}
run_tests() {
local -a tests=("$@")
local total=0
local passed=0
local failed=0
for test in "${tests[@]}"; do
((total += 1))
local display="${test#${ROOT_DIR}/}"
printf '==> %s\n' "${display}"
if [[ "${test}" == *.py ]]; then
if (cd "${ROOT_DIR}" && python3 "${test}"); then
echo "PASS"
((passed += 1))
else
echo "FAIL"
((failed += 1))
fi
elif (cd "${ROOT_DIR}" && "${test}"); then
echo "PASS"
((passed += 1))
else
echo "FAIL"
((failed += 1))
fi
echo
done
echo "Summary: ${passed}/${total} passed"
if (( failed > 0 )); then
echo "Failures: ${failed}"
return 1
fi
return 0
}
main() {
if [[ $# -gt 0 ]]; then
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
usage
exit 0
fi
fi
local -a tests=()
if [[ "${1:-}" == --docs-shard ]]; then
if [[ $# -ne 2 || ! "${2:-}" =~ ^[0-3]$ ]]; then
echo "Usage: scripts/tests/run.sh --docs-shard <0|1|2|3>" >&2
return 1
fi
local -a doc_tests=()
if ! discover_tests doc_tests docs; then
return 1
fi
local index
for ((index = $2; index < ${#doc_tests[@]}; index += 4)); do
tests+=("${doc_tests[index]}")
done
printf 'Documentation shard %s/4: %s of %s suites\n' "$2" "${#tests[@]}" "${#doc_tests[@]}"
elif [[ "${1:-}" == --smoke-shard ]]; then
if [[ $# -ne 2 || ! "${2:-}" =~ ^[0-1]$ ]]; then
echo "Usage: scripts/tests/run.sh --smoke-shard <0|1>" >&2
return 1
fi
local -a smoke_tests=()
if ! discover_tests smoke_tests; then
return 1
fi
local selection
if (( ${#smoke_tests[@]} > 0 )); then
# Capture the entire successful selector before admitting any suite. A
# partial output from a failed selector is not a complete shard. Timing
# hints only place discovered suites; they cannot add or omit coverage.
if ! selection="$(
printf '%s\n' "${smoke_tests[@]}" | python3 \
"${ROOT_DIR}/scripts/select-smoke-test-shard.py" \
"${ROOT_DIR}/.github/scripts/smoke-test-seconds.txt" 2 "$2"
)"; then
echo "Failed to partition the complete smoke test inventory" >&2
return 1
fi
if [[ -n "${selection}" ]]; then
mapfile -t tests <<< "${selection}"
fi
fi
printf 'Smoke shard %s/2: %s of %s suites\n' "$2" "${#tests[@]}" "${#smoke_tests[@]}"
elif [[ $# -gt 0 ]]; then
local arg resolved
for arg in "$@"; do
if ! resolved="$(resolve_test_path "${arg}")"; then
echo "Unknown test: ${arg}" >&2
exit 1
fi
tests+=("${resolved}")
done
else
if ! discover_tests tests; then
return 1
fi
fi
if [[ ${#tests[@]} -eq 0 ]]; then
echo "No tests found under ${TEST_DIR}" >&2
exit 1
fi
run_tests "${tests[@]}"
}
main "$@"