#!/bin/sh # script/test: run the test suite. # # -timeout is applied by `go test` per package, not to the run as a whole, so # it only has to clear the slowest single package. That is internal/handlers, # measured in a cache-defeated builder stage on the 48-core shared build host # (2026-08-18); load- and host-dependent, not invariants: # # 16.9s host load 5-20, GOMAXPROCS 48 # 45.9s / 47.3s / 49.0s three runs at deliberate host load 31-73 # 30.6s / 39.7s host load 5-20, GOMAXPROCS 6 / 4 # 67.3s / 97.5s host load 5-20, GOMAXPROCS 2 / 1 # 67.3s GOMAXPROCS 4 at deliberate host load 52-68 # # The old 30s budget was breached by every loaded run and by every GOMAXPROCS # at or below 6; at GOMAXPROCS 4 it failed outright ("panic: test timed out # after 30s"), reproduced on 33e4fa4 with no other change. # # 90s matches the org-wide backstop in REPO_POLICIES.md and is sized here # against the figures above: the worst case under native parallelism is 49.0s, # and the compound GOMAXPROCS-4-under-load case at 67.3s sits at 75% of it. # The one figure above 90s is GOMAXPROCS 1, a synthetic core floor rather than # a condition CI runs under. If a CPU-limited runner ever puts a real run near # 67s, that is the datum to revisit the org figure with. # # -p 4 -parallel 8 keep the run under 2 GB of memory: at most four test # binaries build or run at once, each with at most eight parallel tests. Under # -race every test binary and every link costs a few hundred MB, so the # defaults (one per core) add up to several GB on a many-core host. # # The first run has no -v: go test then prints one result line per package, # with its coverage, and for a package that fails, everything its tests wrote, # application log lines included. Verbose output from the whole suite passes # the 2 MiB at which the Docker build cuts off each step's log, so on a failure # only the tests that failed run again, with -v. The script exits 1 after that # rerun whatever its result: the first run already showed the suite is broken. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" main() { cd "$ROOT" "$ROOT/script/assets" log="$(mktemp -t webhooker-test.XXXXXXXX)" rcfile="$(mktemp -t webhooker-test-rc.XXXXXXXX)" trap 'rm -f "$log" "$rcfile"' EXIT INT TERM # The pipeline's status is tee's, and POSIX sh has no pipefail, so go # test's status travels via a file. Output still streams live. { go test -race -cover -p 4 -parallel 8 -timeout 90s ./... 2>&1 \ && echo 0 >"$rcfile" || echo $? >"$rcfile" } | tee "$log" if [ "$(cat "$rcfile")" -eq 0 ]; then return fi # go test reports a failed test as a line starting "--- FAIL: TestName" # (a failed subtest's line is indented, and reruns with its parent), and # a failed package as "FAILpackage/path...". A failure that # names no test, such as a build error or a timeout, is already shown in # full above, so there is nothing to rerun. tests="$(awk '/^--- FAIL: / { print $3 }' "$log" | paste -s -d '|' -)" packages="$(awk '/^FAIL\t/ { print $2 }' "$log")" if [ -n "$tests" ]; then echo "--- Rerunning the failed tests with -v for details ---" go test -race -v -p 4 -parallel 8 -timeout 90s \ -run "^($tests)\$" $packages || true fi exit 1 } main "$@"