Skip to content

Commit 3710f42

Browse files
authored
Merge pull request #234 from PsychQuant/idd/217-test-suite-automation
feat: test-suite aggregator + CI workflow (drift-guard enforcement last mile)
2 parents 6f123a1 + 2c31730 commit 3710f42

4 files changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"issue": 217,
3+
"fetched_at": "2026-07-05T22:32:39Z",
4+
"fetched_by": "idd-diagnose",
5+
"files": []
6+
}

.github/workflows/tests.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# tests.yml — run every fixture suite on push + PR (#217).
2+
# The enforcement link for the repo's drift-guard hard locks: suites only
3+
# guarded what someone remembered to run (#214 R2 DA finding 15).
4+
#
5+
# NOTE: init.defaultBranch is deliberately NOT configured here — fixtures must
6+
# be self-sufficient (#224); masking that class in CI would hide real bugs.
7+
name: tests
8+
on:
9+
push:
10+
branches: [main]
11+
pull_request:
12+
jobs:
13+
suites:
14+
runs-on: ubuntu-latest
15+
timeout-minutes: 20
16+
steps:
17+
- uses: actions/checkout@v4
18+
- name: Run all fixture suites
19+
run: bash plugins/issue-driven-dev/scripts/run-all-tests.sh
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env bash
2+
# run-all-tests.sh — aggregate entry for every fixture suite under
3+
# scripts/tests/*/test.sh (#217). This is the missing enforcement link for the
4+
# repo's drift-guard hard locks: suites existed but nothing ran them
5+
# automatically (#214 R2 DA finding 15).
6+
#
7+
# Behavior:
8+
# - runs EVERY suite (no fail-fast) and prints a per-suite summary table
9+
# - per-suite timeout (default 180s, IDD_SUITE_TIMEOUT to override) so a
10+
# hung suite (FIFO writer class, #117 incident) cannot wedge CI
11+
# - exit 0 iff every suite passed; 1 otherwise
12+
#
13+
# Env:
14+
# IDD_TESTS_DIR override the suites dir (aggregator self-tests use this)
15+
# IDD_SUITE_TIMEOUT per-suite seconds (default 180)
16+
17+
set -u
18+
19+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20+
TESTS_DIR="${IDD_TESTS_DIR:-$HERE/tests}"
21+
SUITE_TIMEOUT="${IDD_SUITE_TIMEOUT:-180}"
22+
23+
if [ ! -d "$TESTS_DIR" ]; then
24+
echo "✗ tests dir not found: $TESTS_DIR" >&2
25+
exit 2
26+
fi
27+
28+
run_with_timeout() { # seconds cmd... — portable watchdog (macOS has no coreutils timeout)
29+
local secs="$1"; shift
30+
if command -v timeout >/dev/null 2>&1; then
31+
timeout "$secs" "$@"
32+
return $?
33+
fi
34+
"$@" &
35+
local pid=$!
36+
( sleep "$secs"; kill -TERM "$pid" 2>/dev/null ) &
37+
local wd=$!
38+
wait "$pid" 2>/dev/null
39+
local rc=$?
40+
kill -TERM "$wd" 2>/dev/null; wait "$wd" 2>/dev/null
41+
return $rc
42+
}
43+
44+
TOTAL=0; FAILED=0
45+
declare -a ROWS=()
46+
shopt -s nullglob
47+
for t in "$TESTS_DIR"/*/test.sh; do
48+
name="$(basename "$(dirname "$t")")"
49+
TOTAL=$((TOTAL + 1))
50+
start=$(date +%s)
51+
if run_with_timeout "$SUITE_TIMEOUT" bash "$t" > /tmp/idd-suite-"$name".log 2>&1; then
52+
rc=0; verdict="PASS"
53+
else
54+
rc=$?; FAILED=$((FAILED + 1))
55+
if [ "$rc" -ge 124 ]; then verdict="TIMEOUT(${SUITE_TIMEOUT}s)"; else verdict="FAIL(rc=$rc)"; fi
56+
fi
57+
dur=$(( $(date +%s) - start ))
58+
ROWS+=("$(printf '%-32s %-14s %3ss' "$name" "$verdict" "$dur")")
59+
# surface the tail of failing suites immediately (CI log ergonomics)
60+
[ "$rc" -ne 0 ] && { echo "── $name output tail ──"; tail -15 /tmp/idd-suite-"$name".log; echo; }
61+
done
62+
shopt -u nullglob
63+
64+
echo "══════ run-all-tests summary ══════"
65+
printf '%s\n' "${ROWS[@]:-"(no suites found)"}"
66+
echo "───────────────────────────────────"
67+
echo "suites: $TOTAL, failed: $FAILED"
68+
[ "$TOTAL" -gt 0 ] && [ "$FAILED" -eq 0 ]
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env bash
2+
# test.sh — aggregator self-tests (#217): pass / fail / timeout branches.
3+
# NOTE: lives OUTSIDE the aggregator's default sweep only logically — the
4+
# aggregator WILL run this suite too; the fixtures below use IDD_TESTS_DIR to
5+
# point the aggregator at a sandbox, so no recursion occurs.
6+
set -u
7+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
AGG="$HERE/../../run-all-tests.sh"
9+
. "$HERE/../../lib/assert-helpers.sh"
10+
W="$(mktemp -d)"; trap 'rm -rf "$W"' EXIT
11+
12+
mk_suite() { # name body
13+
mkdir -p "$W/tests/$1"
14+
printf '#!/usr/bin/env bash\n%s\n' "$2" > "$W/tests/$1/test.sh"
15+
}
16+
17+
# all-pass → exit 0
18+
mk_suite ok 'exit 0'
19+
IDD_TESTS_DIR="$W/tests" bash "$AGG" > "$W/out1" 2>&1
20+
assert_exit "all-pass → 0" 0 $?
21+
assert_grep "summary lists suite" "ok" "$(cat "$W/out1")"
22+
23+
# one failing → exit 1 + tail surfaced
24+
mk_suite bad 'echo boom-detail; exit 1'
25+
IDD_TESTS_DIR="$W/tests" bash "$AGG" > "$W/out2" 2>&1
26+
assert_exit "any-fail → 1" 1 $?
27+
assert_grep "failing tail surfaced" "boom-detail" "$(cat "$W/out2")"
28+
29+
# hung suite → timeout branch, aggregator still completes
30+
rm -rf "$W/tests/bad"
31+
mk_suite hang 'sleep 30'
32+
IDD_TESTS_DIR="$W/tests" IDD_SUITE_TIMEOUT=2 bash "$AGG" > "$W/out3" 2>&1
33+
assert_exit "hung suite → 1 (timeout)" 1 $?
34+
assert_grep "timeout verdict shown" "TIMEOUT" "$(cat "$W/out3")"
35+
36+
# empty dir → non-zero (zero suites must not read as success)
37+
mkdir -p "$W/empty"
38+
IDD_TESTS_DIR="$W/empty" bash "$AGG" > "$W/out4" 2>&1
39+
assert_exit "zero suites → non-zero" 1 $?
40+
41+
print_summary "run-all-tests-self"

0 commit comments

Comments
 (0)