#!/usr/bin/env bash # host-on-sx conformance runner — loads the kernel stdlib, the subsystem # libraries the host wires to, the host modules, and the host test suites in one # sx_server process, then reports pass/fail per suite. Mirrors lib/dream's runner. # # Usage: # bash lib/host/conformance.sh # run all suites # bash lib/host/conformance.sh -v # verbose (list each suite) set -uo pipefail cd "$(git rev-parse --show-toplevel)" SX_SERVER="${SX_SERVER:-hosts/ocaml/_build/default/bin/sx_server.exe}" if [ ! -x "$SX_SERVER" ]; then SX_SERVER="/root/rose-ash/hosts/ocaml/_build/default/bin/sx_server.exe" fi if [ ! -x "$SX_SERVER" ]; then echo "ERROR: sx_server.exe not found." >&2 exit 1 fi VERBOSE="${1:-}" # Kernel + subsystem dependencies, then the host modules. Order matters: # stdlib/r7rs first; the Datalog engine + ACL subsystem (authorisation); the feed # subsystem (the first migrated domain); Dream (types/json/auth/error/router) the # host builds on; then the host layer itself. MODULES=( "spec/stdlib.sx" "lib/r7rs.sx" "lib/apl/runtime.sx" "lib/datalog/tokenizer.sx" "lib/datalog/parser.sx" "lib/datalog/unify.sx" "lib/datalog/db.sx" "lib/datalog/builtins.sx" "lib/datalog/aggregates.sx" "lib/datalog/strata.sx" "lib/datalog/eval.sx" "lib/datalog/api.sx" "lib/datalog/magic.sx" "lib/acl/schema.sx" "lib/acl/facts.sx" "lib/acl/engine.sx" "lib/acl/explain.sx" "lib/acl/audit.sx" "lib/acl/federation.sx" "lib/acl/api.sx" "lib/relations/schema.sx" "lib/relations/engine.sx" "lib/relations/api.sx" "lib/relations/explain.sx" "lib/relations/federation.sx" "lib/relations/tree.sx" "lib/feed/normalize.sx" "lib/feed/stream.sx" "lib/feed/api.sx" "lib/smalltalk/tokenizer.sx" "lib/smalltalk/parser.sx" "lib/guest/reflective/class-chain.sx" "lib/smalltalk/runtime.sx" "lib/guest/reflective/env.sx" "lib/smalltalk/eval.sx" "lib/persist/event.sx" "lib/persist/backend.sx" "lib/persist/log.sx" "lib/persist/kv.sx" "lib/persist/api.sx" "lib/content/block.sx" "lib/content/doc.sx" "lib/content/render.sx" "lib/content/api.sx" "lib/dream/types.sx" "lib/dream/json.sx" "lib/dream/auth.sx" "lib/dream/error.sx" "lib/dream/router.sx" "lib/host/handler.sx" "lib/host/middleware.sx" "lib/host/sxtp.sx" "lib/host/router.sx" "lib/host/feed.sx" "lib/host/relations.sx" "lib/host/blog.sx" "lib/host/server.sx" "lib/host/ledger.sx" ) # Suites: NAME RUNNER-FN PATH SUITES=( "handler host-hd-tests-run! lib/host/tests/handler.sx" "middleware host-mw-tests-run! lib/host/tests/middleware.sx" "sxtp host-sx-tests-run! lib/host/tests/sxtp.sx" "router host-rt-tests-run! lib/host/tests/router.sx" "feed host-fd-tests-run! lib/host/tests/feed.sx" "relations host-rl-tests-run! lib/host/tests/relations.sx" "blog host-bl-tests-run! lib/host/tests/blog.sx" "server host-sv-tests-run! lib/host/tests/server.sx" "ledger host-lg-tests-run! lib/host/tests/ledger.sx" ) TMPFILE=$(mktemp); trap "rm -f $TMPFILE" EXIT EPOCH=1 emit_load () { echo "(epoch $EPOCH)"; echo "(load \"$1\")"; EPOCH=$((EPOCH+1)); } emit_eval () { echo "(epoch $EPOCH)"; echo "(eval \"$1\")"; EPOCH=$((EPOCH+1)); } { for M in "${MODULES[@]}"; do emit_load "$M"; done for SUITE in "${SUITES[@]}"; do read -r _NAME _RUNNER FILE <<< "$SUITE" emit_load "$FILE" emit_eval "($_RUNNER)" done } > "$TMPFILE" OUTPUT=$(timeout 300 "$SX_SERVER" < "$TMPFILE" 2>&1 || true) TOTAL_PASS=0 TOTAL_FAIL=0 FAILED_SUITES=() LAST_DICT_LINES=$(echo "$OUTPUT" | grep -E '^\{:' || true) I=0 while read -r LINE; do [ -z "$LINE" ] && continue P=$(echo "$LINE" | grep -oE ':passed [0-9]+' | awk '{print $2}') F=$(echo "$LINE" | grep -oE ':failed [0-9]+' | awk '{print $2}') [ -z "$P" ] && P=0 [ -z "$F" ] && F=0 SUITE_INFO="${SUITES[$I]}" SUITE_NAME=$(echo "$SUITE_INFO" | awk '{print $1}') TOTAL_PASS=$((TOTAL_PASS + P)) TOTAL_FAIL=$((TOTAL_FAIL + F)) if [ "$F" -gt 0 ]; then FAILED_SUITES+=("$SUITE_NAME: $P/$((P+F))") printf 'X %-12s %d/%d\n' "$SUITE_NAME" "$P" "$((P+F))" echo "$LINE" | grep -oE ':name "[^"]*"' | sed 's/:name / fail: /' elif [ "$VERBOSE" = "-v" ]; then printf 'ok %-12s %d passed\n' "$SUITE_NAME" "$P" fi I=$((I+1)) done <<< "$LAST_DICT_LINES" TOTAL=$((TOTAL_PASS + TOTAL_FAIL)) if [ "$TOTAL" -eq 0 ]; then echo "ERROR: no suite results parsed. Raw output:" >&2 echo "$OUTPUT" >&2 exit 1 fi if [ $TOTAL_FAIL -eq 0 ]; then echo "ok $TOTAL_PASS/$TOTAL host-on-sx tests passed (${#SUITES[@]} suites)" else echo "FAIL $TOTAL_PASS/$TOTAL passed, $TOTAL_FAIL failed:" for S in "${FAILED_SUITES[@]}"; do echo " $S"; done exit 1 fi