#!/bin/bash # Runs INSIDE the proot-distro Ubuntu container - do not call this directly, # call tests/run_tests.sh from Termux instead. # # It exists as its own file so the whole suite runs in ONE `proot-distro # login`: entering the container costs ~0.5s, which used to be paid 38 times # over. Everything below is the container-side half of the runner. # # Args: ... set -uo pipefail PROJECT_DIR="$1"; shift JOBS="$1"; shift VERBOSE="$1"; shift GODOT_BIN="/root/Godot_v4.7.1-stable_linux.arm64" cd "$PROJECT_DIR" || exit 2 tests=("$@") total=${#tests[@]} if (( total == 0 )); then echo "no tests matched" exit 2 fi outdir="$(mktemp -d)" trap 'rm -rf "$outdir"' EXIT # Import once, serially, before anything runs in parallel. Godot writes to # .godot/ while importing; several instances discovering a cold cache at the # same moment would race on it. After this the workers only read it. "$GODOT_BIN" --headless --import --quit >/dev/null 2>&1 run_one() { local name="$1" local log="$outdir/$name.log" local start end start=$(date +%s%N) # --fixed-fps pins delta to exactly 1/60 instead of measuring the wall # clock. Without it a test's `elapsed` counts REAL seconds, so running # several at once stretches every frame and the gameplay under test sees # deltas it never sees in the game: ships overshoot their braking curve, # settle late, and tests time out for no reason but load. That made # test_camera_settles and test_planet_prompt_map_interaction fail on 2 of # 3 parallel runs. Pinned, a test simulates the same 60fps whatever else # the phone is doing, and its result no longer depends on how busy the # machine was. "$GODOT_BIN" --headless --fixed-fps 60 -s "res://tests/$name" >"$log" 2>&1 local rc=$? end=$(date +%s%N) local ms=$(( (end - start) / 1000000 )) # Two independent criteria, because either one alone can lie: a test that # crashes before reaching its verdict exits non-zero without ever printing # FAIL, and a hypothetical `quit(0)` on a failing path would exit clean # while the log says otherwise. if (( rc == 0 )) && grep -q ": PASS" "$log"; then printf 'PASS %6dms %s\n' "$ms" "$name" > "$outdir/$name.status" else printf 'FAIL %6dms %s (exit %d)\n' "$ms" "$name" "$rc" > "$outdir/$name.status" fi cat "$outdir/$name.status" } running=0 for name in "${tests[@]}"; do run_one "$name" & running=$(( running + 1 )) if (( running >= JOBS )); then wait -n running=$(( running - 1 )) fi done wait failed=0 for name in "${tests[@]}"; do if ! grep -q '^PASS' "$outdir/$name.status" 2>/dev/null; then failed=$(( failed + 1 )) echo echo "=== $name FAILED, full output ===" cat "$outdir/$name.log" 2>/dev/null elif [[ "$VERBOSE" == "1" ]]; then echo echo "=== $name ===" cat "$outdir/$name.log" 2>/dev/null fi done echo echo "$(( total - failed ))/$total passed" (( failed == 0 ))