run-bats.sh's new bounded parallel dispatcher used nproc/wait -n, which are bash 4.3+/GNU-only and silently drop the concurrency cap on macOS's stock bash 3.2 (the wait -n error is swallowed by `|| true`). Its sibling tests/run-tests.sh, changed in the same PR and explicitly bash-3.2-safe, already solves this with getconf + a batched wait. Ported that same pattern here for consistency and to actually meet the compatibility goal. Refs: #95
83 lines
2.6 KiB
Bash
Executable File
83 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run all bats test files in the repo.
|
|
# Usage: bash tests/run-bats.sh
|
|
set -euo pipefail
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
BATS="$REPO_ROOT/tests/bats/bin/bats"
|
|
|
|
if [[ ! -x "$BATS" ]]; then
|
|
echo "bats not found at $BATS — initializing submodules..." >&2
|
|
git -C "$REPO_ROOT" submodule update --init --recursive
|
|
fi
|
|
|
|
if [[ ! -x "$BATS" ]]; then
|
|
echo "Error: bats still not found at $BATS after submodule init" >&2
|
|
exit 1
|
|
fi
|
|
|
|
mapfile -t TEST_FILES < <(
|
|
find "$REPO_ROOT" -name "*.bats" \
|
|
-not -path "*/tests/bats/*" \
|
|
-not -path "*/test_helper/*" \
|
|
-not -path "*/.claude/worktrees/*" \
|
|
| sort
|
|
)
|
|
|
|
if [[ ${#TEST_FILES[@]} -eq 0 ]]; then
|
|
echo "No .bats test files found." >&2
|
|
exit 0
|
|
fi
|
|
|
|
# Each file gets its own `bats` process, run concurrently (bounded by core
|
|
# count) instead of one `bats` invocation working through all files serially.
|
|
# A single test file is still serial internally -- this only overlaps the
|
|
# fixed per-process startup cost (git/apm subprocess spawns dominate several
|
|
# of these suites) across files, which is where the wall-clock actually goes.
|
|
# Output is buffered per file so concurrent TAP streams can't interleave, then
|
|
# flushed in stable sorted order once every job has finished.
|
|
SCRATCH_ROOT="$(mktemp -d)"
|
|
trap 'rm -rf "$SCRATCH_ROOT"' EXIT
|
|
|
|
# Batches (not a rolling pool) because a bounded rolling pool needs `wait -n`,
|
|
# which is bash 4.3+ and this script is explicitly bash-3.2-safe like
|
|
# run-tests.sh; plain `wait` -- waiting for every job in the current batch --
|
|
# is available since ancient bash. `getconf` over `nproc` for the same
|
|
# reason: `nproc` doesn't exist on macOS.
|
|
JOBS="$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)"
|
|
running=0
|
|
i=0
|
|
for f in "${TEST_FILES[@]}"; do
|
|
i=$((i + 1))
|
|
( "$BATS" "$f" >"$SCRATCH_ROOT/$i.log" 2>&1; echo $? >"$SCRATCH_ROOT/$i.status" ) &
|
|
running=$((running + 1))
|
|
if [[ "$running" -ge "$JOBS" ]]; then
|
|
wait
|
|
running=0
|
|
fi
|
|
done
|
|
wait
|
|
|
|
FAIL=0
|
|
TOTAL_OK=0
|
|
TOTAL_NOT_OK=0
|
|
i=0
|
|
for f in "${TEST_FILES[@]}"; do
|
|
i=$((i + 1))
|
|
rel="${f#"$REPO_ROOT"/}"
|
|
echo "=== $rel ==="
|
|
cat "$SCRATCH_ROOT/$i.log"
|
|
echo ""
|
|
file_ok="$(grep -c '^ok ' "$SCRATCH_ROOT/$i.log" || true)"
|
|
file_not_ok="$(grep -c '^not ok ' "$SCRATCH_ROOT/$i.log" || true)"
|
|
status="$(cat "$SCRATCH_ROOT/$i.status" 2>/dev/null || echo 1)"
|
|
TOTAL_OK=$((TOTAL_OK + file_ok))
|
|
TOTAL_NOT_OK=$((TOTAL_NOT_OK + file_not_ok))
|
|
if [[ "$file_not_ok" -gt 0 || "$status" -ne 0 ]]; then
|
|
FAIL=1
|
|
fi
|
|
done
|
|
|
|
echo "$((TOTAL_OK + TOTAL_NOT_OK)) tests, $TOTAL_NOT_OK failures"
|
|
exit "$FAIL"
|