12# Run the scenarios in test/scenarios/, each in a throwaway forge of its own3# (test/lib.sh), several at once. A scenario is one behavior, end to end4# through the real hooks and forced command, so a regression names itself.5#6# sh test/run.sh every scenario7# sh test/run.sh private release the ones whose names contain a word8# FORGE_TEST_JOBS=1 sh test/run.sh one at a time9# FORGE_TEST_KEEP=1 sh test/run.sh x keep the temp forge to look at10set -eu11here=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)12jobs=${FORGE_TEST_JOBS:-$(getconf _NPROCESSORS_ONLN 2>/dev/null || echo 4)}13out=$(mktemp -d "${TMPDIR:-/tmp}/forge-tests.XXXXXX")14trap 'rm -rf "$out"' EXIT1516list=17for s in "$here"/scenarios/*.sh; do18 n=$(basename "$s" .sh)19 if [ $# -gt 0 ]; then20 hit=021 for w in "$@"; do case $n in *"$w"*) hit=1 ;; esac; done22 [ "$hit" = 1 ] || continue23 fi24 list="$list$s25"26done27[ -n "$list" ] || { echo "no scenarios match: $*" >&2; exit 1; }2829# The lake's DuckDB extensions go into a cache shared by every scenario;30# fetch them once here rather than in several scenarios at the same time.31node "$here/../lib/lake.ts" install >/dev/null 2>&1 || true3233# One scenario: its result line, and its output kept for a failure.34export out35printf '%s' "$list" | xargs -P "$jobs" -I{} sh -c '36 s=$1 n=$(basename "$1" .sh) t0=$(date +%s)37 if sh "$s" >"$out/$n.log" 2>&1; then r=ok; else r=FAIL; fi38 printf "%-4s %s (%ss)\n" "$r" "$n" "$(($(date +%s) - t0))"39 [ "$r" = ok ] || : >"$out/$n.failed"40' sh {}4142failed=$(cd "$out" && ls ./*.failed 2>/dev/null | sed 's|^\./||; s|\.failed$||') || true43total=$(printf '%s' "$list" | grep -c .)44if [ -n "$failed" ]; then45 for n in $failed; do46 printf '\n--- %s\n' "$n"47 cat "$out/$n.log"48 done49 printf '\n%s of %s scenarios failed\n' "$(printf '%s\n' "$failed" | wc -l | tr -d ' ')" "$total"50 exit 151fi52printf '%s scenarios passed\n' "$total"