Add a WSL path to the test runner

run_tests.sh only knew one way to reach a Godot: `proot-distro login ubuntu`
and the arm64 build at /root. On WSL there is no container and no arm64
binary, so the suite could not be run from a desktop at all.

The platform is detected from /proc/version, and decides two things. Which
Godot: on WSL a Linux `godot` on PATH if there is one, otherwise the newest
Windows build already sitting on /mnt/c - the *_console.exe specifically,
since the plain .exe is a GUI-subsystem binary that detaches from the
terminal and would leave every test log empty. And whether to copy the
project first: that copy exists to get off Android's FUSE bridge, and a
Windows Godot already reads C: natively, so WSL runs in place.

_run_inside.sh now takes the binary as its first argument instead of
hardcoding it, and run_tests.sh calls it directly where there is no
container to enter. The scheduling, timeouts and verdicts are unchanged and
shared by both paths.

120/120 on WSL in 48s with JOBS=6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Loïc Wisniewski 2026-08-22 14:40:44 +02:00
commit b1d179ec9c
3 changed files with 87 additions and 16 deletions

View file

@ -1,15 +1,27 @@
#!/data/data/com.termux/files/usr/bin/bash
# Runs the headless GDScript gameplay tests from Termux, via the Godot
# 4.7.1 Linux arm64 build installed inside the proot-distro Ubuntu container.
#!/usr/bin/env bash
# Runs the headless GDScript gameplay tests.
#
# bash tests/run_tests.sh # everything
# bash tests/run_tests.sh formation # only tests matching a substring
# JOBS=1 bash tests/run_tests.sh # serial, for debugging a hang
# VERBOSE=1 bash tests/run_tests.sh # print passing tests' output too
# IN_PLACE=1 bash tests/run_tests.sh # run from the project dir itself
# GODOT_BIN=/path/to/godot bash tests/run_tests.sh # pick the binary
#
# Three things make this fast, in descending order of how much they matter
# (measured, not guessed - see tests/_profile_startup.gd):
# There are two ways to get a Godot to run them with, picked automatically:
#
# Termux the Godot 4.7 Linux arm64 build installed inside the
# proot-distro Ubuntu container, which is the only way to run
# a desktop Godot on the phone at all.
# WSL the Windows Godot build, run straight from /mnt/c. A Linux
# `godot` on PATH is used first if there is one.
#
# The platform decides which Godot runs and whether the project is copied
# first; the worker count and tests/_run_inside.sh, which does the actual
# running, are shared.
#
# On Termux, three things make this fast, in descending order of how much
# they matter (measured, not guessed - see tests/_profile_startup.gd):
#
# 1. It runs from a COPY on Termux's own filesystem, not from the project
# directory. The project lives under ~/storage/shared, which is Android's
@ -17,7 +29,9 @@
# alone took 8.5s per test, against ~2s from a native path. Nearly every
# test loads Main.tscn, and none of that time is gameplay. The copy is
# ~1.4s for the whole suite and its .godot import cache is kept between
# runs.
# runs. WSL skips the copy: a Windows Godot reads C: natively, and the
# only thing copying to ext4 would achieve is putting the project behind
# the \\wsl$ share instead.
# 2. Tests run JOBS at a time. Each is its own Godot process - they call
# quit() and stamp on the GameState autoload, so they cannot share one -
# which makes the suite a pile of independent, single-core-bound jobs on
@ -32,6 +46,32 @@ set -uo pipefail
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PLATFORM="termux"
if [[ -n "${WSL_DISTRO_NAME:-}" ]] || grep -qi microsoft /proc/version 2>/dev/null; then
PLATFORM="wsl"
fi
# Finding a Godot on WSL. A Linux build on PATH wins - no interop, no drive
# letters - but there usually is not one, and the Windows build the editor
# already runs from is right there on /mnt/c. Two things about picking that
# one up:
# - it must be the *_console.exe. The plain .exe is built as a Windows GUI
# subsystem binary: it detaches from the terminal, so every test would
# produce an empty log and the runner would call all of them failures.
# - sort -V so 4.7.2 beats 4.6.1 when several versions are downloaded.
_find_godot_wsl() {
local found
found="$(command -v godot 2>/dev/null)"
if [[ -n "$found" ]]; then
echo "$found"
return
fi
found="$(find /mnt/c/Users/*/Downloads /mnt/c/Users/*/AppData/Local/Programs \
"/mnt/c/Program Files" -maxdepth 2 -name 'Godot_v*_console.exe' \
2>/dev/null | sort -V | tail -1)"
echo "$found"
}
# Worker count comes from FREE MEMORY, not core count. Each Godot instance is
# ~400MB and this phone shares its RAM with everything else running on it.
# Getting it wrong is bad in both directions:
@ -63,9 +103,28 @@ _pick_jobs() {
}
JOBS="${JOBS:-$(_pick_jobs)}"
VERBOSE="${VERBOSE:-0}"
IN_PLACE="${IN_PLACE:-0}"
# The copy only buys anything on Termux (see 1. above), so on WSL the project
# directory IS the run directory whatever IN_PLACE says.
if [[ "$PLATFORM" == "wsl" ]]; then
IN_PLACE=1
else
IN_PLACE="${IN_PLACE:-0}"
fi
WORK_DIR="${WORK_DIR:-$HOME/.cache/spaceship-tests}"
if [[ -z "${GODOT_BIN:-}" ]]; then
if [[ "$PLATFORM" == "wsl" ]]; then
GODOT_BIN="$(_find_godot_wsl)"
if [[ -z "$GODOT_BIN" ]]; then
echo "no Godot found. Install one on PATH, or download a Windows" >&2
echo "build and point GODOT_BIN at its *_console.exe." >&2
exit 2
fi
else
GODOT_BIN="/root/Godot_v4.7.1-stable_linux.arm64"
fi
fi
filter="${1:-}"
tests=()
for path in "$PROJECT_DIR"/tests/test_*.gd; do
@ -97,8 +156,13 @@ if [[ "$IN_PLACE" != "1" ]]; then
-cf - . 2>/dev/null | tar -C "$run_dir" -xf -
fi
proot-distro login ubuntu -- bash "$run_dir/tests/_run_inside.sh" \
"$run_dir" "$JOBS" "$VERBOSE" "${tests[@]}"
if [[ "$PLATFORM" == "wsl" ]]; then
bash "$run_dir/tests/_run_inside.sh" \
"$GODOT_BIN" "$run_dir" "$JOBS" "$VERBOSE" "${tests[@]}"
else
proot-distro login ubuntu -- bash "$run_dir/tests/_run_inside.sh" \
"$GODOT_BIN" "$run_dir" "$JOBS" "$VERBOSE" "${tests[@]}"
fi
status=$?
echo "in $(( $(date +%s) - start ))s with JOBS=$JOBS"