#!/bin/sh # test/run — driver for `make test`. Plan 9 rc-flavoured but plain sh. # # Walks test/wcc/_.c → out/bin/test_ binary, fans out # across $JOBS (default $(nproc)) workers via xargs -P. Each worker # writes its status to a per-job file; the collector enumerates them in # lexicographic order so output stays deterministic across runs even # though execution interleaves. Exit non-zero if any worker failed. BIN=${BIN:-out/bin} WW=${WW:-$BIN/ww} # Worker mode: invoked once per test by xargs. Argv: --one . # Writes .status; touches .fail on a non-zero binary exit. if [ "$1" = "--one" ]; then prefix=$2 t=$3 name=${t##*/} name=${name%.c} short=${name#[0-9][0-9][0-9]_} bin=$BIN/test_$short if [ ! -x "$bin" ]; then printf 'SKIP %s (no binary %s)\n' "$name" "$bin" > "$prefix.status" exit 0 fi if "$bin" > "$prefix.out" 2> "$prefix.err"; then printf 'ok %s\n' "$name" > "$prefix.status" else rc=$? { printf 'FAIL %s (rc=%d)\n' "$name" "$rc" echo '--- stdout ---' cat "$prefix.out" echo '--- stderr ---' cat "$prefix.err" } > "$prefix.status" : > "$prefix.fail" fi exit 0 fi set -e RESULTS=$(mktemp -d "${TMPDIR:-/tmp}/wwtest.XXXXXX") trap 'rm -rf "$RESULTS"' EXIT JOBS=${JOBS:-$(nproc 2>/dev/null || echo 4)} # Phase 2 runs the wwstage byte-id gates (990-997) + 950_selfcheck. # ww_ww writes intermediates next to every traversed source (task #15), # so 991/992/994's reads of selfhost/cmd//main.{s,o,combined.ww} # race against any concurrent driver-using test that emits a sibling # .combined.ww (task #16). Phase 1 stays parallel for unit coverage; the # wwstage-driver tests stay out of phase 1 to keep those reads honest. for t in test/wcc/*.c; do [ -f "$t" ] || continue case ${t##*/} in 950_*|990_*|991_*|992_*|993_*|994_*|995_*|996_*|997_*) continue ;; esac name=${t##*/}; name=${name%.c} printf '%s/%s\0%s\0' "$RESULTS" "$name" "$t" done | xargs -0 -n2 -P "$JOBS" "$0" --one || true # UNIT=1 (make test-unit) is the inner-loop short path: skip the wwstage # byte-id gates (990-997) and 950_selfcheck entirely. Pre-push uses # `make test` for the full suite. if [ "${UNIT:-0}" != "1" ]; then # Phase 2 is partitioned (#3): the pure-reader byte-id gates run in # parallel; the source-tree writers run in a serial tail afterward. # # PARALLEL GROUP — 990/991/992/994/996/997. Each reads only committed # or make-all-produced files and writes only /tmp or a disjoint tracked # stem (990→out smoke.*, 996→examples/mandelbrot/*, 997→/tmp fixture # copy). No group member writes a stem another member reads (per-gate FS # footprint audited race-free, #3), so they fan out via the same # xargs -P "$JOBS" machinery as phase 1. for t in test/wcc/990_*.c test/wcc/991_*.c test/wcc/992_*.c \ test/wcc/994_*.c test/wcc/996_*.c test/wcc/997_*.c; do [ -f "$t" ] || continue name=${t##*/}; name=${name%.c} printf '%s/%s\0%s\0' "$RESULTS" "$name" "$t" done | xargs -0 -n2 -P "$JOBS" "$0" --one || true # SERIAL TAIL — 993/995/950, the only source-tree writers. 993 & 995 # both write cmd/wwdump/main.* (995 writes all 5 cmd/*/main.*), so they # run sequentially w.r.t. each other AND after the parallel group, so # the group's readers see stable make-all output, never a torn write. for t in test/wcc/993_*.c test/wcc/995_*.c test/wcc/950_*.c; do [ -f "$t" ] || continue name=${t##*/}; name=${name%.c} "$0" --one "$RESULTS/$name" "$t" || true done # combined.ww freshness gate (#110): 990/995 above unconditionally # regenerate every tracked combined.ww amalgamation, so a diff vs HEAD # here means an embedded source changed without its derived artifact # being regenerated + committed (the #28 staleness hole the per-file # byte-id gates were blind to). git ls-files keeps new combined.ww # auto-covered (rule-13 SSoT). Lives inside the UNIT guard because # test-unit skips 990/995 and thus the regen. name=combined_ww_fresh if git diff --exit-code -- $(git ls-files '*.combined.ww') > /dev/null 2>&1; then printf 'ok %s\n' "$name" > "$RESULTS/$name.status" else { printf 'FAIL %s (stale; regen + commit the derived amalgamation)\n' "$name" echo '--- stale combined.ww ---' git diff --name-only -- $(git ls-files '*.combined.ww') } > "$RESULTS/$name.status" : > "$RESULTS/$name.fail" fi fi fail=0 ran=0 for s in "$RESULTS"/*.status; do [ -f "$s" ] || continue cat "$s" ran=$((ran + 1)) prefix=${s%.status} [ -f "$prefix.fail" ] && fail=$((fail + 1)) done # ---- ww source-level tests ---------------------------------------------- if [ -d test/lang ]; then for f in test/lang/*/*.ww; do [ -f "$f" ] || continue echo "skip $f (ww run not online yet)" done fi if [ $ran -eq 0 ]; then echo "no tests were run" exit 1 fi if [ $fail -gt 0 ]; then echo "$fail test(s) failed" exit 1 fi echo "all $ran tests passed"