run.sh (6670B)
1 #!/bin/sh 2 ## tests/run.sh — host-side dispatcher for the unified test runner. 3 ## 4 ## All build/run/diff work happens inside the container via 5 ## tests/run-suite.sh: this script just starts one podman 6 ## process per requested arch and aggregates the per-arch 7 ## PASS/FAIL totals. Prior versions of this runner re-entered the 8 ## container per fixture (and per build/run within a fixture); now 9 ## a whole arch's suite is one podman invocation. 10 ## 11 ## The one bit of work that stays on the host is the lint preflight 12 ## for the m1pp and p1 suites: tools/lint.sh runs python, which the 13 ## busybox container doesn't carry. Names that fail lint are reported 14 ## here (FAIL + diagnostic) and excluded from the in-container batch. 15 ## 16 ## Suites: 17 ## m1pp tests/M1pp/<name>.M1pp — m1pp expander parity test. 18 ## p1 tests/P1/<name>.P1pp — built via tests/build-p1pp.sh 19 ## and run; stdout diffed. 20 ## tests/P1/<name>.P1 — raw P1, built via 21 ## tests/build-p1.sh (no expander). 22 ## scheme1 tests/scheme1/<name>.scm — run by per-arch scheme1. 23 ## cc-util tests/cc-util/<name>.scm — scheme1 prelude+util byte-diff. 24 ## cc-lex tests/cc-lex/<name>.c — lex pipeline byte-diff. 25 ## cc-pp tests/cc-pp/<name>.c — pp pipeline byte-diff (+ .scm). 26 ## cc-cg tests/cc-cg/<name>.scm — cg emit -> P1pp -> ELF -> run. 27 ## cc tests/cc/<name>.c — cc -> P1pp -> ELF -> run. 28 ## cc-ext vendor/c-testsuite/single-exec/<name>.c — broad subset 29 ## coverage from the upstream 30 ## c-testsuite. needs-libc tests 31 ## link the mes-libc chain (same 32 ## as cc-libc); plain tests use 33 ## the bare cc pipeline. Any 34 ## compile/assemble/runtime error 35 ## counts as FAIL. 36 ## tcc-cc tests/cc/<name>.c — tcc-boot2 -> ELF -> run. 37 ## tcc-libc tests/cc-libc/<name>.c — tcc-boot2 builds mes-libc into 38 ## libc.o, then compiles + links 39 ## each fixture against it -> run. 40 ## 41 ## All three arches by default; --arch restricts to one. 42 ## 43 ## Usage: tests/run.sh --suite <suite> [--arch ARCH] [name ...] 44 45 set -eu 46 47 SUITE= 48 ARCH= 49 NAMES= 50 STAGE= 51 52 while [ "$#" -gt 0 ]; do 53 case "$1" in 54 --suite) shift; SUITE=$1 ;; 55 --suite=*) SUITE=${1#--suite=} ;; 56 --arch) shift; ARCH=$1 ;; 57 --arch=*) ARCH=${1#--arch=} ;; 58 --stage) shift; STAGE=$1 ;; 59 --stage=*) STAGE=${1#--stage=} ;; 60 --) shift; while [ "$#" -gt 0 ]; do NAMES="$NAMES $1"; shift; done; break ;; 61 -*) echo "$0: unknown flag '$1'" >&2; exit 2 ;; 62 *) NAMES="$NAMES $1" ;; 63 esac 64 shift 65 done 66 67 case "$SUITE" in 68 m1pp|p1|scheme1|cc-util|cc-lex|cc-pp|cc-cg|cc|cc-libc|cc-ext|tcc-cc|tcc-libc) ;; 69 "") echo "$0: --suite required (m1pp | p1 | scheme1 | cc-util | cc-lex | cc-pp | cc-cg | cc | cc-libc | cc-ext | tcc-cc | tcc-libc)" >&2; exit 2 ;; 70 *) echo "$0: unknown suite '$SUITE'" >&2; exit 2 ;; 71 esac 72 73 REPO=$(cd "$(dirname "$0")/.." && pwd) 74 cd "$REPO" 75 76 platform_of() { 77 case "$1" in 78 aarch64) echo linux/arm64 ;; 79 amd64) echo linux/amd64 ;; 80 riscv64) echo linux/riscv64 ;; 81 *) echo "$0: unknown arch '$1'" >&2; return 1 ;; 82 esac 83 } 84 85 run_in_container() { 86 arch=$1; shift 87 podman run --rm --pull=never --platform "$(platform_of "$arch")" \ 88 --tmpfs /tmp:size=512M \ 89 -e "ARCH=$arch" \ 90 -e "CC_TRACE_EMIT=${CC_TRACE_EMIT:-0}" \ 91 -e "CC_DEBUG=${CC_DEBUG:-0}" \ 92 -e "STAGE=${STAGE:-}" \ 93 -v "$REPO":/work -w /work \ 94 "boot2-busybox-test:$arch" "$@" 95 } 96 97 if [ -z "$ARCH" ]; then 98 ARCHES="aarch64 amd64 riscv64" 99 else 100 ARCHES=$ARCH 101 fi 102 103 PASS=0 104 FAIL=0 105 106 # Lint preflight: lint.sh uses python (host-only). Discover the 107 # fixture set if --names was empty, lint each raw fixture (.M1pp / .P1), 108 # emit a host-side FAIL + diagnostic for any miss, write the kept name 109 # list to $keep_file. FAIL line goes to stdout to interleave with the 110 # container's PASS/FAIL output; the FAIL counter updates in-scope. 111 # 112 # Suite layout: 113 # m1pp: tests/M1pp/<name>.M1pp (no raw .M1 fixtures any more) 114 # p1: tests/P1/<name>.P1pp (lint skipped — expander output) 115 # tests/P1/<name>.P1 (lint runs) 116 lint_preflight() { 117 arch=$1; keep_file=$2; dir=$3; raw_ext=$4; pp_ext=$5 118 : > "$keep_file" 119 if [ -z "$NAMES" ]; then 120 raw=$(ls "$dir" 2>/dev/null \ 121 | sed -n "s/^\([^_][^.]*\)\.${raw_ext}\$/\1/p") 122 pp=$(ls "$dir" 2>/dev/null \ 123 | sed -n "s/^\([^_][^.]*\)\.${pp_ext}\$/\1/p") 124 all=$(printf '%s\n%s\n' "$raw" "$pp" | sort -u | tr '\n' ' ') 125 else 126 all=$NAMES 127 fi 128 for name in $all; do 129 raw_src=$dir/$name.$raw_ext 130 if [ -e "$raw_src" ] \ 131 && ! ARCH=$arch sh tools/lint.sh "$raw_src" >/dev/null 2>&1; then 132 echo " FAIL [$arch] $name" 133 ARCH=$arch sh tools/lint.sh "$raw_src" 2>&1 \ 134 | sed 's/^/ /' >&2 || true 135 FAIL=$((FAIL + 1)) 136 else 137 printf '%s ' "$name" >> "$keep_file" 138 fi 139 done 140 } 141 142 for arch in $ARCHES; do 143 case "$SUITE" in 144 m1pp) preflight_args="tests/M1pp M1 M1pp" ;; 145 p1) preflight_args="tests/P1 P1 P1pp" ;; 146 *) preflight_args= ;; 147 esac 148 if [ -n "$preflight_args" ]; then 149 keep_file=$(mktemp) 150 # shellcheck disable=SC2086 # $preflight_args is intentionally word-split. 151 lint_preflight "$arch" "$keep_file" $preflight_args 152 names=$(cat "$keep_file") 153 rm -f "$keep_file" 154 # Skip the container call only when the user gave names AND 155 # all of them failed lint. With no names, an empty kept set 156 # would mean nothing to run anyway. 157 names_trimmed=$(echo "$names" | tr -d ' \t\n') 158 if [ -z "$names_trimmed" ]; then 159 continue 160 fi 161 else 162 names=$NAMES 163 fi 164 165 out=$(mktemp) 166 # shellcheck disable=SC2086 # $names is intentionally word-split. 167 run_in_container "$arch" sh tests/run-suite.sh \ 168 --suite="$SUITE" $names | tee "$out" 169 p=$(grep -c '^ PASS ' "$out" 2>/dev/null || true) 170 f=$(grep -c '^ FAIL ' "$out" 2>/dev/null || true) 171 PASS=$((PASS + ${p:-0})) 172 FAIL=$((FAIL + ${f:-0})) 173 rm -f "$out" 174 done 175 176 echo "$PASS passed, $FAIL failed" 177 [ "$FAIL" -eq 0 ]