kit_corpus_selftest.sh (4483B)
1 #!/usr/bin/env bash 2 # test/lib/kit_corpus_selftest.sh — hermetic proof of the kit_corpus.sh engine. 3 # 4 # No kit binary, no podman/qemu: stubs exec_target_queue/flush and uses fake 5 # lanes over a throwaway corpus. Asserts the properties that make the engine 6 # safe to build runners on: 7 # 1. serial and parallel runs produce IDENTICAL counts + failing-name order 8 # + identical output (modulo timing) — determinism; 9 # 2. SKIP-NA is uncounted and never gates; 10 # 3. deferred-exec (kit_queue_e) flushes correctly and detects a wrong rc; 11 # 4. exec_target_queue is called exactly once per E item DURING THE PARENT 12 # (serial replay), never in a worker — if a worker queued, the parent 13 # count would be 0 (background-subshell mutations are lost). This is the 14 # invariant the whole parallel model rests on. 15 # 16 # Run: bash test/lib/kit_corpus_selftest.sh (exit 0 = ok) 17 18 set -u 19 SELF_DIR=$(cd "$(dirname "$0")" && pwd) 20 export KIT_LIB_DIR="$SELF_DIR" 21 . "$SELF_DIR/kit_corpus.sh" 22 23 WORK=$(mktemp -d "${TMPDIR:-/tmp}/cf-corpus-selftest.XXXXXX") 24 trap 'rm -rf "$WORK"' EXIT 25 CORPUS="$WORK/corpus"; mkdir -p "$CORPUS" 26 i=1; while [ "$i" -le 12 ]; do printf 'x' > "$CORPUS/$(printf 'case%02d' "$i").t"; i=$((i+1)); done 27 # case05 is not-applicable to the test tuple. 28 printf 'other-z\n' > "$CORPUS/case05.targets" 29 30 # ---- exec_target stubs (count parent-side queue calls) --------------------- 31 ET_QUEUE_CALLS=0 32 _et_pairs= 33 exec_target_queue() { # TAG NAME EXE OUT ERR RC 34 ET_QUEUE_CALLS=$((ET_QUEUE_CALLS + 1)) 35 _et_pairs="$_et_pairs $3:$6" # exe:rcfile (exe file content = rc to emit) 36 } 37 exec_target_flush() { 38 local pair exe rcf 39 for pair in $_et_pairs; do exe="${pair%%:*}"; rcf="${pair#*:}"; cat "$exe" > "$rcf"; done 40 _et_pairs= 41 } 42 43 # ---- fake lanes ------------------------------------------------------------ 44 kit_lane_P() { kit_pass "$KIT_NAME/P"; kit_time P 1; } 45 kit_lane_S() { 46 if [ "$KIT_BASE" = "case03" ]; then kit_skip "$KIT_NAME/S" "deliberate"; else kit_pass "$KIT_NAME/S"; fi 47 } 48 kit_lane_E() { 49 local exe="$KIT_WORK/run" rcf="$KIT_WORK/rc" 50 if [ "$KIT_BASE" = "case07" ]; then echo 9 > "$exe"; else echo 0 > "$exe"; fi 51 kit_queue_e "$KIT_NAME/E" "$exe" "$KIT_WORK/o" "$KIT_WORK/e" "$rcf" "$KIT_EXPECTED" "faketag" 52 } 53 54 # Run in the CURRENT shell (NOT $(...) — command substitution is a subshell 55 # that would discard the counter globals); redirect output to a file instead. 56 export KIT_TEST_FILTER= 57 run_corpus() { # $1 = KIT_PARALLELIZABLE $2 = jobs $3 = outfile 58 kit_report_init 59 CFQ_LABELS=(); CFQ_RCS=(); CFQ_EXPS=(); CFQ_PAYLOADS=() 60 ET_QUEUE_CALLS=0; _et_pairs= 61 KIT_LABEL=selftest KIT_BUILD_DIR="$WORK/b$1" KIT_CORPUS_GLOBS="$CORPUS/*.t" \ 62 KIT_CORPUS_EXT=t KIT_SIDECAR_DIR="$CORPUS" KIT_LANES="P S E" KIT_OPT_LEVELS="0" \ 63 KIT_TUPLES="aa64-elf" KIT_TARGETS_EXT=.targets KIT_PARALLELIZABLE="$1" \ 64 KIT_TEST_JOBS="$2" kit_corpus_run > "$3" 2>&1 65 kit_summary selftest >> "$3" 2>&1 66 } 67 68 NORM='s/[0-9]\{1,\}ms/Nms/g' # erase timing for output comparison 69 70 run_corpus 0 1 "$WORK/ser.out" 71 ser_out=$(cat "$WORK/ser.out") 72 ser_counts="$KIT_PASS/$KIT_FAIL/$KIT_SKIP/$KIT_SKIP_NA"; ser_fails="$KIT_FAILURES"; ser_q=$ET_QUEUE_CALLS 73 74 run_corpus 1 4 "$WORK/par.out" 75 par_out=$(cat "$WORK/par.out") 76 par_counts="$KIT_PASS/$KIT_FAIL/$KIT_SKIP/$KIT_SKIP_NA"; par_fails="$KIT_FAILURES"; par_q=$ET_QUEUE_CALLS 77 78 fail=0 79 check() { if [ "$2" = "$3" ]; then echo " ok $1 ($2)"; else echo " FAIL $1: got '$2' want '$3'"; fail=1; fi; } 80 81 echo "kit_corpus selftest:" 82 check "serial counts pass/fail/skip/na" "$ser_counts" "31/1/1/1" 83 check "parallel counts pass/fail/skip/na" "$par_counts" "31/1/1/1" 84 check "serial == parallel counts" "$ser_counts" "$par_counts" 85 check "serial == parallel failing names" "$ser_fails" "$par_fails" 86 check "failing name is case07/O0/E" "$(echo "$ser_fails" | tr -s ' ')" " case07/O0/E" 87 check "serial queue calls (parent)" "$ser_q" "11" 88 check "parallel queue calls (parent, not worker)" "$par_q" "11" 89 # Determinism of full output (counts/order/summary), timing erased. 90 if [ "$(printf '%s' "$ser_out" | sed "$NORM")" = "$(printf '%s' "$par_out" | sed "$NORM")" ]; then 91 echo " ok serial output == parallel output (timing-normalized)" 92 else 93 echo " FAIL serial/parallel output differ:"; diff <(printf '%s' "$ser_out" | sed "$NORM") <(printf '%s' "$par_out" | sed "$NORM") | head -30; fail=1 94 fi 95 96 [ "$fail" -eq 0 ] && echo "kit_corpus selftest: OK" || echo "kit_corpus selftest: FAILED" 97 exit $fail