kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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