this repo has no description
at master 391 lines 15 kB view raw
1#!/usr/bin/env bash 2# run-tests.sh — Compile and run all regression tests inside a Darling prefix 3# 4# This script copies the test source files into the Darling prefix, compiles 5# them using Darling's macOS toolchain (cc), and executes them. It collects 6# results from all test suites and produces a summary. 7# 8# Usage: 9# ./scripts/run-tests.sh [OPTIONS] 10# 11# Options: 12# --prefix <path> Darling prefix path (default: ~/.darling or $DPREFIX) 13# --suite <name> Run only the named suite (can be repeated) 14# Available: renameatx_np, setattrlist_flags, utimensat, 15# sandbox_api, sandbox_exec, dirserv 16# --keep Keep compiled test binaries in the prefix after running 17# --verbose Show full test output even on success 18# --help Show this help message 19# 20# Prerequisites: 21# - Darling must be installed and `darling shell echo ok` must work 22# - The Darling prefix must be initialized 23# 24# Exit code: 25# 0 — all tests passed 26# 1 — one or more tests failed 27# 2 — infrastructure error (Darling not working, compilation failure, etc.) 28# 29# See: plan/PLAN.md "What's Next" item 1 30 31set -euo pipefail 32 33SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 34REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" 35 36# ── Defaults ──────────────────────────────────────────────────────────────── 37 38DARLING_PREFIX="${DPREFIX:-$HOME/.darling}" 39KEEP_BINARIES=0 40VERBOSE=0 41SELECTED_SUITES=() 42 43# Test directory inside the Darling prefix 44DARLING_TEST_DIR="/tmp/darling-nix-tests" 45 46# ── Colors ────────────────────────────────────────────────────────────────── 47 48if [ -t 1 ]; then 49 RED='\033[0;31m' 50 GREEN='\033[0;32m' 51 YELLOW='\033[0;33m' 52 BLUE='\033[0;34m' 53 BOLD='\033[1m' 54 DIM='\033[2m' 55 RESET='\033[0m' 56else 57 RED='' GREEN='' YELLOW='' BLUE='' BOLD='' DIM='' RESET='' 58fi 59 60# ── Helpers ───────────────────────────────────────────────────────────────── 61 62log() { echo -e "${GREEN}[run-tests]${RESET} $*"; } 63warn() { echo -e "${YELLOW}[run-tests] WARNING:${RESET} $*" >&2; } 64err() { echo -e "${RED}[run-tests] ERROR:${RESET} $*" >&2; } 65fatal() { err "$@"; exit 2; } 66 67dsh() { 68 darling shell "$@" 69} 70 71usage() { 72 cat <<'EOF' 73Usage: ./scripts/run-tests.sh [OPTIONS] 74 75Compile and run all Darling regression tests. 76 77Options: 78 --prefix <path> Darling prefix (default: ~/.darling or $DPREFIX) 79 --suite <name> Run only the named suite (repeatable) 80 Available: renameatx_np, setattrlist_flags, utimensat, 81 sandbox_api, sandbox_exec, dirserv 82 --keep Keep compiled binaries in the prefix after running 83 --verbose Show full test output even on success 84 --help Show this help 85 86Suites: 87 renameatx_np — renameatx_np syscall 488 (5 tests) 88 setattrlist_flags — setattrlist/getattrlist ATTR_CMN_FLAGS (10 tests) 89 utimensat — utimensat/setattrlistat timestamps (16 tests) 90 sandbox_api — sandbox C API stubs 91 sandbox_exec — sandbox-exec integration (shell tests) 92 dirserv — Directory Services stubs (dseditgroup, sysadminctl, dscl) 93EOF 94 exit 0 95} 96 97# ── Argument Parsing ──────────────────────────────────────────────────────── 98 99while [ $# -gt 0 ]; do 100 case "$1" in 101 --prefix) 102 [ $# -ge 2 ] || fatal "--prefix requires an argument" 103 DARLING_PREFIX="$2" 104 shift 2 105 ;; 106 --suite) 107 [ $# -ge 2 ] || fatal "--suite requires an argument" 108 SELECTED_SUITES+=("$2") 109 shift 2 110 ;; 111 --keep) 112 KEEP_BINARIES=1 113 shift 114 ;; 115 --verbose|-v) 116 VERBOSE=1 117 shift 118 ;; 119 --help|-h) 120 usage 121 ;; 122 *) 123 fatal "Unknown option: $1 (try --help)" 124 ;; 125 esac 126done 127 128# ── Suite Definitions ─────────────────────────────────────────────────────── 129 130# Each suite is defined as: 131# SUITE_<name>_TYPE = "c" | "sh" 132# SUITE_<name>_SOURCE = relative path from repo root 133# SUITE_<name>_DESC = human description 134# SUITE_<name>_CFLAGS = extra compiler flags (C suites only) 135 136declare -A SUITE_TYPE SUITE_SOURCE SUITE_DESC SUITE_CFLAGS 137 138SUITE_TYPE[renameatx_np]="c" 139SUITE_SOURCE[renameatx_np]="tests/syscall/test_renameatx_np.c" 140SUITE_DESC[renameatx_np]="renameatx_np (syscall 488) — plain rename, SWAP, EXCL, invalid flags" 141SUITE_CFLAGS[renameatx_np]="" 142 143SUITE_TYPE[setattrlist_flags]="c" 144SUITE_SOURCE[setattrlist_flags]="tests/syscall/test_setattrlist_flags.c" 145SUITE_DESC[setattrlist_flags]="setattrlist/getattrlist ATTR_CMN_FLAGS — lchflags, chflags, combined attrs" 146SUITE_CFLAGS[setattrlist_flags]="" 147 148SUITE_TYPE[utimensat]="c" 149SUITE_SOURCE[utimensat]="tests/syscall/test_utimensat.c" 150SUITE_DESC[utimensat]="utimensat/setattrlistat — timestamps, MODTIME, ACCTIME, CRTIME, symlinks" 151SUITE_CFLAGS[utimensat]="" 152 153SUITE_TYPE[sandbox_api]="c" 154SUITE_SOURCE[sandbox_api]="tests/sandbox/test_sandbox_api.c" 155SUITE_DESC[sandbox_api]="sandbox C API — sandbox_init, sandbox_free_error" 156SUITE_CFLAGS[sandbox_api]="" 157 158SUITE_TYPE[sandbox_exec]="sh" 159SUITE_SOURCE[sandbox_exec]="tests/sandbox/test_sandbox_exec.sh" 160SUITE_DESC[sandbox_exec]="sandbox-exec stub — flag parsing, exec, exit codes, Nix patterns" 161SUITE_CFLAGS[sandbox_exec]="" 162 163SUITE_TYPE[dirserv]="sh" 164SUITE_SOURCE[dirserv]="tests/dirserv/test_dirserv.sh" 165SUITE_DESC[dirserv]="Directory Services stubs — dseditgroup, sysadminctl, dscl (Phase 5.1)" 166SUITE_CFLAGS[dirserv]="" 167 168ALL_SUITES=(renameatx_np setattrlist_flags utimensat sandbox_api sandbox_exec dirserv) 169 170# ── Determine which suites to run ────────────────────────────────────────── 171 172if [ ${#SELECTED_SUITES[@]} -eq 0 ]; then 173 RUN_SUITES=("${ALL_SUITES[@]}") 174else 175 RUN_SUITES=() 176 for s in "${SELECTED_SUITES[@]}"; do 177 if [ -z "${SUITE_TYPE[$s]+x}" ]; then 178 fatal "Unknown suite: $s (available: ${ALL_SUITES[*]})" 179 fi 180 RUN_SUITES+=("$s") 181 done 182fi 183 184# ── Preflight ─────────────────────────────────────────────────────────────── 185 186log "${BOLD}Preflight checks...${RESET}" 187 188if ! command -v darling &>/dev/null; then 189 fatal "darling is not installed or not in PATH" 190fi 191 192if [ ! -d "$DARLING_PREFIX" ]; then 193 fatal "Darling prefix not found at $DARLING_PREFIX\n" \ 194 " Initialize with: darling shell true" 195fi 196 197if ! dsh echo ok &>/dev/null; then 198 fatal "darling shell is not functional\n" \ 199 " Try: darling shell echo ok" 200fi 201 202log " Prefix: $DARLING_PREFIX" 203log " Suites: ${RUN_SUITES[*]}" 204 205# Verify source files exist 206for suite in "${RUN_SUITES[@]}"; do 207 src="$REPO_DIR/${SUITE_SOURCE[$suite]}" 208 if [ ! -f "$src" ]; then 209 fatal "Source file not found: ${SUITE_SOURCE[$suite]}\n" \ 210 " Expected at: $src" 211 fi 212done 213 214# ── Copy test sources into the prefix ─────────────────────────────────────── 215 216log "${BOLD}Copying test sources into Darling prefix...${RESET}" 217 218PREFIX_TEST_DIR="$DARLING_PREFIX/private/tmp/darling-nix-tests" 219mkdir -p "$PREFIX_TEST_DIR" 220 221for suite in "${RUN_SUITES[@]}"; do 222 src="$REPO_DIR/${SUITE_SOURCE[$suite]}" 223 cp "$src" "$PREFIX_TEST_DIR/" 224 log " Copied ${SUITE_SOURCE[$suite]}" 225done 226 227# ── Compile C test suites ────────────────────────────────────────────────── 228 229log "${BOLD}Compiling C test suites inside Darling...${RESET}" 230 231COMPILE_FAILURES=0 232 233for suite in "${RUN_SUITES[@]}"; do 234 if [ "${SUITE_TYPE[$suite]}" != "c" ]; then 235 continue 236 fi 237 238 src_basename="$(basename "${SUITE_SOURCE[$suite]}")" 239 bin_name="${src_basename%.c}" 240 241 log " Compiling $src_basename ..." 242 243 compile_output=$(dsh bash -c \ 244 "cd $DARLING_TEST_DIR && cc -Wall -Wextra -o '$bin_name' '$src_basename' ${SUITE_CFLAGS[$suite]} 2>&1" \ 245 2>&1) || { 246 err " Compilation of $src_basename FAILED:" 247 echo "$compile_output" | sed 's/^/ /' >&2 248 COMPILE_FAILURES=$((COMPILE_FAILURES + 1)) 249 continue 250 } 251 252 if [ "$VERBOSE" -eq 1 ] && [ -n "$compile_output" ]; then 253 echo "$compile_output" | sed 's/^/ /' 254 fi 255 256 log " ${GREEN}${RESET} $bin_name compiled" 257done 258 259if [ "$COMPILE_FAILURES" -gt 0 ]; then 260 err "$COMPILE_FAILURES suite(s) failed to compile" 261 if [ "$COMPILE_FAILURES" -eq "${#RUN_SUITES[@]}" ]; then 262 fatal "All suites failed to compile — is the Darling toolchain working?" 263 fi 264fi 265 266# ── Run test suites ───────────────────────────────────────────────────────── 267 268echo "" 269log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 270log "${BOLD} Running Darling regression tests${RESET}" 271log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 272echo "" 273 274SUITES_PASSED=0 275SUITES_FAILED=0 276SUITES_SKIPPED=0 277 278declare -A SUITE_RESULTS # "pass", "fail", "skip" 279declare -A SUITE_OUTPUT 280 281for suite in "${RUN_SUITES[@]}"; do 282 src_basename="$(basename "${SUITE_SOURCE[$suite]}")" 283 echo -e "${BLUE}━━━ Suite: $suite ━━━${RESET}" 284 echo -e "${DIM}${SUITE_DESC[$suite]}${RESET}" 285 echo "" 286 287 if [ "${SUITE_TYPE[$suite]}" = "c" ]; then 288 bin_name="${src_basename%.c}" 289 290 # Check the binary was compiled 291 compile_check=$(dsh test -x "$DARLING_TEST_DIR/$bin_name" 2>&1 && echo "yes" || echo "no") 292 if [ "$compile_check" != "yes" ]; then 293 echo -e " ${YELLOW}SKIPPED${RESET} — compilation failed" 294 echo "" 295 SUITES_SKIPPED=$((SUITES_SKIPPED + 1)) 296 SUITE_RESULTS[$suite]="skip" 297 continue 298 fi 299 300 # Run the test binary 301 output="" 302 exit_code=0 303 output=$(dsh bash -c "cd $DARLING_TEST_DIR && ./$bin_name 2>&1" 2>&1) || exit_code=$? 304 305 elif [ "${SUITE_TYPE[$suite]}" = "sh" ]; then 306 # Shell tests run directly 307 output="" 308 exit_code=0 309 output=$(dsh bash -c "cd $DARLING_TEST_DIR && sh '$src_basename' 2>&1" 2>&1) || exit_code=$? 310 fi 311 312 SUITE_OUTPUT[$suite]="$output" 313 314 if [ "$exit_code" -eq 0 ]; then 315 SUITES_PASSED=$((SUITES_PASSED + 1)) 316 SUITE_RESULTS[$suite]="pass" 317 if [ "$VERBOSE" -eq 1 ]; then 318 echo "$output" 319 echo "" 320 fi 321 echo -e " ${GREEN}✓ PASSED${RESET}" 322 else 323 SUITES_FAILED=$((SUITES_FAILED + 1)) 324 SUITE_RESULTS[$suite]="fail" 325 # Always show output on failure 326 echo "$output" 327 echo "" 328 echo -e " ${RED}✗ FAILED${RESET} (exit code: $exit_code)" 329 fi 330 331 echo "" 332done 333 334# ── Cleanup ───────────────────────────────────────────────────────────────── 335 336if [ "$KEEP_BINARIES" -eq 0 ]; then 337 log "Cleaning up test files from prefix..." 338 rm -rf "$PREFIX_TEST_DIR" 339else 340 log "Test binaries preserved at: $DARLING_TEST_DIR (inside prefix)" 341 log " Host path: $PREFIX_TEST_DIR" 342fi 343 344# ── Summary ───────────────────────────────────────────────────────────────── 345 346TOTAL=$((SUITES_PASSED + SUITES_FAILED + SUITES_SKIPPED)) 347 348echo "" 349log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 350log "${BOLD} Test Summary${RESET}" 351log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 352echo "" 353 354# Per-suite results table 355printf " %-25s %s\n" "Suite" "Result" 356printf " %-25s %s\n" "─────────────────────────" "──────" 357for suite in "${RUN_SUITES[@]}"; do 358 result="${SUITE_RESULTS[$suite]:-skip}" 359 case "$result" in 360 pass) printf " %-25s ${GREEN}✓ PASS${RESET}\n" "$suite" ;; 361 fail) printf " %-25s ${RED}✗ FAIL${RESET}\n" "$suite" ;; 362 skip) printf " %-25s ${YELLOW}⊘ SKIP${RESET}\n" "$suite" ;; 363 esac 364done 365 366echo "" 367printf " Total: %d suites\n" "$TOTAL" 368printf " Passed: ${GREEN}%d${RESET}\n" "$SUITES_PASSED" 369printf " Failed: ${RED}%d${RESET}\n" "$SUITES_FAILED" 370printf " Skipped: ${YELLOW}%d${RESET}\n" "$SUITES_SKIPPED" 371echo "" 372 373if [ "$SUITES_FAILED" -gt 0 ]; then 374 err "Some test suites failed." 375 echo "" 376 echo "Debugging tips:" >&2 377 echo " • Re-run with --verbose to see full output for passing tests" >&2 378 echo " • Run a single suite: $0 --suite <name>" >&2 379 echo " • Run with --keep to preserve binaries, then inspect inside:" >&2 380 echo " darling shell $DARLING_TEST_DIR/<test_binary>" >&2 381 echo " • Trace syscalls: strace -f -p \$(pidof darlingserver) 2>&1 | head" >&2 382 echo " • Darling xtrace: DARLING_XTRACE=1 darling shell $DARLING_TEST_DIR/<test_binary>" >&2 383 echo "" 384 exit 1 385elif [ "$SUITES_SKIPPED" -gt 0 ] && [ "$SUITES_PASSED" -eq 0 ]; then 386 warn "All suites were skipped — check compilation errors above." 387 exit 2 388else 389 log "${GREEN}All tests passed!${RESET}" 390 exit 0 391fi