chore(e2e): run the e2e dev server on native Linux

e2e.sh and gen_fixtures.py assumed WSL driving the Windows toolchain.
They now detect WSL (a microsoft kernel with cargo.exe available) and
otherwise use native tools:

- e2e.sh: cargo/curl instead of cargo.exe/curl.exe, pgrep/pkill
  instead of tasklist/taskkill, Linux paths in the generated .env, and
  binaries without the .exe suffix.
- gen_fixtures.py: picks the first ffmpeg that has the drawtext filter
  (a minimal build earlier on PATH may not; E2E_FFMPEG overrides), finds
  a monospace font with fc-match, and only translates paths with wslpath
  for .exe tools.
- Quote USER_NAME in the generated .env: the unquoted space made the
  dotenv parser reject the line.
- Mark the scripts executable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Cameron CordesandClaude Opus 5.5 committed 2026-10-15 21:27:47 -04:00
1 parent 50dd9aa016
commit b7943be022
3 files changed
+92 -28

No files matched your search

Regular → Executable
+39 -21
View File
@@ -3,14 +3,14 @@
#
# Runs a second, fully isolated server next to any real one: its own build
# dir (target/e2e — a running target/debug exe is file-locked on Windows),
# its own process name (image-api-e2e.exe, so `stop` can never touch the
# real server), its own port, database, thumbnails and HLS output. The
# media library is a *copy* of the pristine fixtures, so tests may upload,
# move and delete freely; `reset` restores the known baseline.
# its own process name (image-api-e2e, so `stop` can never touch the real
# server), its own port, database, thumbnails and HLS output. The media
# library is a *copy* of the pristine fixtures, so tests may upload, move
# and delete freely; `reset` restores the known baseline.
#
# Written for WSL driving the Windows toolchain (cargo.exe, curl.exe,
# ffmpeg.exe). WSL2's default NAT networking can't reach Windows'
# 127.0.0.1, hence curl.exe for every HTTP call.
# Works on native Linux, and in WSL driving the Windows toolchain
# (cargo.exe, curl.exe, ffmpeg.exe). WSL2's default NAT networking can't
# reach Windows' 127.0.0.1, hence curl.exe for every HTTP call there.
#
# Usage: dev/e2e/e2e.sh <command> (see `help`)
set -euo pipefail
@@ -21,7 +21,14 @@ WORK="$HERE/.work"
FIXTURES="$WORK/fixtures"
STATE="$WORK/state"
BIN_DIR="$WORK/bin"
EXE_NAME="image-api-e2e.exe"
# WSL drives the Windows toolchain; anything else uses native tools.
if grep -qi microsoft /proc/version 2>/dev/null && command -v cargo.exe >/dev/null; then
WSL=1; EXT=".exe"; CARGO=cargo.exe; CURL=curl.exe
else
WSL=0; EXT=""; CARGO=cargo; CURL=curl
fi
EXE_NAME="image-api-e2e$EXT"
LOG="$WORK/server.log"
E2E_PORT="${E2E_PORT:-8090}"
@@ -33,23 +40,30 @@ E2E_USER="${E2E_USER:-e2e}"
E2E_PASS="${E2E_PASS:-E2eTest#2026pass}"
URL="http://127.0.0.1:$E2E_PORT"
win() { wslpath -w "$1"; }
# A path as the server sees it (Windows path for the WSL-driven exe).
win() { if [ "$WSL" = 1 ]; then wslpath -w "$1"; else printf '%s' "$1"; fi; }
# Join a directory from win() with a file name.
win_join() { if [ "$WSL" = 1 ]; then printf '%s\\%s' "$(win "$1")" "$2"; else printf '%s/%s' "$1" "$2"; fi; }
log() { printf '\033[1;34m[e2e]\033[0m %s\n' "$*" >&2; }
die() { printf '\033[1;31m[e2e]\033[0m %s\n' "$*" >&2; exit 1; }
is_running() {
tasklist.exe /FI "IMAGENAME eq $EXE_NAME" /NH 2>/dev/null | grep -qi "$EXE_NAME"
if [ "$WSL" = 1 ]; then
tasklist.exe /FI "IMAGENAME eq $EXE_NAME" /NH 2>/dev/null | grep -qi "$EXE_NAME"
else
pgrep -x "$EXE_NAME" >/dev/null
fi
}
cmd_build() {
log "building bins into target/e2e"
(cd "$REPO" && cargo.exe build --target-dir target/e2e --bin image-api --bin create_user)
(cd "$REPO" && $CARGO build --target-dir target/e2e --bin image-api --bin create_user)
mkdir -p "$BIN_DIR"
# Run from a copy so rebuilding never fights a running (locked) exe.
local was_running=0
if is_running; then was_running=1; cmd_stop; fi
cp "$REPO/target/e2e/debug/image-api.exe" "$BIN_DIR/$EXE_NAME"
cp "$REPO/target/e2e/debug/create_user.exe" "$BIN_DIR/create_user.exe"
cp "$REPO/target/e2e/debug/image-api$EXT" "$BIN_DIR/$EXE_NAME"
cp "$REPO/target/e2e/debug/create_user$EXT" "$BIN_DIR/create_user$EXT"
if [ "$was_running" = 1 ]; then cmd_start; fi
}
@@ -74,7 +88,7 @@ cmd_fixtures() {
write_env() {
cat > "$STATE/.env" <<EOF
# Generated by dev/e2e/e2e.sh — edit dev/e2e/env.local instead (appended below).
DATABASE_URL='$(win "$STATE")\\e2e.db'
DATABASE_URL='$(win_join "$STATE" e2e.db)'
BASE_PATH='$(win "$STATE/media")'
THUMBNAILS='$(win "$STATE/thumbs")'
VIDEO_PATH='$(win "$STATE/hls")'
@@ -96,7 +110,7 @@ WATCH_QUICK_INTERVAL_SECONDS=3
WATCH_FULL_INTERVAL_SECONDS=60
EXCLUDED_DIRS=/private
HLS_CONCURRENCY=2
USER_NAME=E2E Tester
USER_NAME='E2E Tester'
REEL_PREGEN_ENABLED=0
REEL_CACHE_SWEEP_ENABLED=0
# AI / sibling services are off by default: point Ollama at a closed port so
@@ -118,12 +132,12 @@ cmd_reset() {
cp -a "$FIXTURES/media" "$STATE/media"
cp "$FIXTURES/manifest.json" "$STATE/manifest.json"
write_env
[ -x "$BIN_DIR/create_user.exe" ] || cmd_build
(cd "$STATE" && "$BIN_DIR/create_user.exe" "$E2E_USER" "$E2E_PASS")
[ -x "$BIN_DIR/create_user$EXT" ] || cmd_build
(cd "$STATE" && "$BIN_DIR/create_user$EXT" "$E2E_USER" "$E2E_PASS")
}
login() {
curl.exe -sf -X POST "$URL/login" -H "Content-Type: application/json" \
$CURL -sf -X POST "$URL/login" -H "Content-Type: application/json" \
-d "{\"username\":\"$E2E_USER\",\"password\":\"$E2E_PASS\"}" 2>/dev/null \
| grep -o '"token":"[^"]*"' | cut -d'"' -f4
}
@@ -131,7 +145,7 @@ login() {
api() { # api METHOD PATH [JSON]; reuses $E2E_TOKEN when set (login is a bcrypt verify)
local tok="${E2E_TOKEN:-$(login)}"
# </dev/null: curl.exe otherwise drains stdin, eating a caller's `while read` input.
curl.exe -sf -X "$1" "$URL/$2" -H "Authorization: Bearer $tok" \
$CURL -sf -X "$1" "$URL/$2" -H "Authorization: Bearer $tok" \
-H "Content-Type: application/json" ${3:+-d "$3"} </dev/null
}
@@ -192,7 +206,11 @@ cmd_start() {
cmd_stop() {
if is_running; then
log "stopping $EXE_NAME"
taskkill.exe /IM "$EXE_NAME" /F >/dev/null
if [ "$WSL" = 1 ]; then
taskkill.exe /IM "$EXE_NAME" /F >/dev/null
else
pkill -x "$EXE_NAME"
fi
for _ in $(seq 1 20); do is_running || break; sleep 0.5; done
else
log "not running"
@@ -210,7 +228,7 @@ cmd_status() {
cmd_info() {
cat <<EOF
URL (Windows browser / curl.exe): $URL
URL (browser / curl): $URL
URL (Android emulator): http://10.0.2.2:$E2E_PORT
URL (USB device, after reverse): adb reverse tcp:$E2E_PORT tcp:$E2E_PORT -> $URL
Login: $E2E_USER / $E2E_PASS