Skip to content

Commit 1ae5fcb

Browse files
committed
fix(ci): robust pre-flight checks and docker cleanup in run-tests.sh
root causes of Docker Desktop crash + E2E failures: 1. docker-compose unosim-server occupied port 3000 (restart: unless-stopped). lsof kill only removed docker-proxy, container kept running/restarting. 2. stale exited sandbox containers piled up across runs (8 found). cleanup only filtered by current ancestor image, missing old image IDs. 3. no container cleanup between Docker tests (74s) and E2E server start. Docker Desktop became overloaded and temporarily unresponsive. fixes: - add pre-flight section: checks node, docker, sonarqube, port 3000 - stop docker-compose unosim-server before tests (port 3000 conflict) - find_sandbox_containers() helper: name + command-based matching catches containers from any image version (including unnamed/old-ID ones) - clean stale containers in pre-flight and after Docker tests - export FORCE_DOCKER=1 (not just inline) for reliable propagation - docker recovery retry loop only when docker was available initially proven: ./run-tests.sh passes all 7 steps + sonarqube quality gate 1402 unit tests, 32 docker tests, 16 E2E tests, 0 issues
1 parent 978d390 commit 1ae5fcb

1 file changed

Lines changed: 91 additions & 20 deletions

File tree

run-tests.sh

Lines changed: 91 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,26 @@ OK="${G}✔${RS}"; FAIL="${R}✘${RS}"; RUN="${Y}◌${RS}"; WARN="${Y}⚠${RS}"
2828

2929
div() { printf "${D}────────────────────────────────────────────────${RS}\n"; }
3030

31+
# Helfer: Alle Sandbox-Container finden (Name- UND Kommando-basiert,
32+
# damit auch namenlose Container mit alten Image-IDs erfasst werden).
33+
find_sandbox_containers() {
34+
local filter="${1:---filter status=exited}" # default: nur beendete
35+
{
36+
docker ps -aq $filter --filter "name=unosim-sandbox" 2>/dev/null
37+
docker ps -a $filter --format '{{.ID}} {{.Command}}' 2>/dev/null \
38+
| grep 'g++ /sandbox' | awk '{print $1}'
39+
} | sort -u
40+
}
41+
3142
# Aufräum-Funktion bei Abbruch oder Ende
3243
cleanup() {
3344
if [ -n "$SERVER_PID" ]; then
3445
kill "$SERVER_PID" 2>/dev/null
3546
fi
36-
# Sandbox-Container aufräumen (ephemeral, aus unosim-sandbox:latest entstanden)
3747
if docker info > /dev/null 2>&1; then
3848
local containers
39-
containers=$(docker ps -aq --filter "ancestor=$DOCKER_SANDBOX_IMAGE" 2>/dev/null)
49+
containers=$(find_sandbox_containers)
4050
if [ -n "$containers" ]; then
41-
echo "$containers" | xargs docker stop --time 5 > /dev/null 2>&1 || true
4251
echo "$containers" | xargs docker rm -f > /dev/null 2>&1 || true
4352
fi
4453
fi
@@ -106,7 +115,63 @@ div
106115
rm -f "$LOG_FILE"
107116
[ -d temp ] && rm -rf temp/*
108117

109-
# Pre-Flight: Altlasten bereinigen (kein nummerierter Schritt)
118+
# ─────── PRE-FLIGHT: Systemvoraussetzungen ───────
119+
echo -e "\n${B}▸ [Pre-Flight] Systemvoraussetzungen${RS}"
120+
121+
# Node.js / npm
122+
if ! command -v npm &>/dev/null; then
123+
echo -e " ${FAIL} npm nicht gefunden – bitte Node.js installieren"
124+
exit 1
125+
fi
126+
echo -e " ${OK} Node.js $(node -v)"
127+
128+
# Docker
129+
DOCKER_AVAILABLE=0
130+
if command -v docker &>/dev/null && docker info >/dev/null 2>&1; then
131+
DOCKER_AVAILABLE=1
132+
echo -e " ${OK} Docker $(docker version --format '{{.Client.Version}}' 2>/dev/null)"
133+
134+
# docker-compose unosim-server prüfen (Port-3000-Konflikt mit dem E2E-Dev-Server)
135+
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^unosim-server$"; then
136+
echo -e " ${WARN} docker-compose unosim-server blockiert Port 3000 – wird für Tests gestoppt"
137+
docker stop unosim-server >/dev/null 2>&1 || true
138+
fi
139+
140+
# Stale Sandbox-Container aufräumen (Name + Kommando-basiert → fängt auch alte Image-IDs)
141+
stale=$(find_sandbox_containers)
142+
if [ -n "$stale" ]; then
143+
count=$(echo "$stale" | wc -l | tr -d ' ')
144+
echo "$stale" | xargs docker rm -f >/dev/null 2>&1
145+
echo -e " ${OK} $count alte Sandbox-Container bereinigt"
146+
fi
147+
148+
# Sandbox Image
149+
if docker image inspect "$DOCKER_SANDBOX_IMAGE" >/dev/null 2>&1; then
150+
echo -e " ${OK} Sandbox Image vorhanden"
151+
else
152+
echo -e " ${WARN} Sandbox Image fehlt – wird bei Bedarf gebaut"
153+
fi
154+
else
155+
echo -e " ${WARN} Docker nicht verfügbar – Docker-Tests und Sandbox werden übersprungen"
156+
fi
157+
158+
# Port 3000 freigeben (nach Docker-Stop, damit kein docker-proxy mehr übrig ist)
159+
if lsof -ti:3000 >/dev/null 2>&1; then
160+
lsof -ti:3000 | xargs kill -9 2>/dev/null || true
161+
sleep 1
162+
echo -e " ${OK} Port 3000 freigegeben"
163+
else
164+
echo -e " ${OK} Port 3000 frei"
165+
fi
166+
167+
# SonarQube (optional, informativ)
168+
if [ -n "$SONAR_TOKEN" ] && curl -sf http://localhost:9000/api/system/status >/dev/null 2>&1; then
169+
echo -e " ${OK} SonarQube erreichbar"
170+
else
171+
echo -e " ${D}ℹ SonarQube nicht verfügbar (optional)${RS}"
172+
fi
173+
174+
# ─────── PRE-FLIGHT: Compiler-Prozess-Leaks ───────
110175
echo -e "\n${B}▸ [Pre-Flight] Cleanup leaked compiler processes${RS}"
111176
./check-leaks.sh --cleanup >> "$LOG_FILE" 2>&1 && echo -e " ${OK} Bereinigung abgeschlossen" || true
112177

@@ -118,9 +183,7 @@ run_task "Unit-Tests" "NODE_OPTIONS='--no-warnings' npm run test:fast -- --repor
118183
parse_test_results "Tests.*passed"
119184

120185
# 3+4. Sandbox Image Build & Docker-Tests (optional, wenn Docker verfügbar)
121-
# HINWEIS: unosim-server:latest wird von docker compose gebaut, nicht hier.
122-
# Nur das Sandbox-Image wird benötigt und nur wenn es noch nicht existiert.
123-
if docker info > /dev/null 2>&1; then
186+
if [ "$DOCKER_AVAILABLE" -eq 1 ]; then
124187
# Sandbox Image nur bauen wenn es noch nicht existiert
125188
if ! docker image inspect "$DOCKER_SANDBOX_IMAGE" > /dev/null 2>&1; then
126189
run_task "Sandbox Image Build" "docker build -f Dockerfile.sandbox -t $DOCKER_SANDBOX_IMAGE ."
@@ -141,6 +204,12 @@ if docker info > /dev/null 2>&1; then
141204
tests/server/services/sandbox-lifecycle.integration.test.ts \
142205
tests/server/services/serial-backpressure.test.ts"
143206
parse_test_results "Tests.*passed"
207+
208+
# Container-Cleanup nach Docker-Tests: entlastet Docker Desktop vor E2E-Phase
209+
stale_after=$(find_sandbox_containers)
210+
if [ -n "$stale_after" ]; then
211+
echo "$stale_after" | xargs docker rm -f >/dev/null 2>&1
212+
fi
144213
else
145214
echo -e " ${WARN} Docker nicht verfügbar – Docker-Tests werden übersprungen (Steps 3+4)"
146215
STEP=$((STEP+2))
@@ -150,25 +219,27 @@ fi
150219
echo -e "\n${B}▸ [Vorbereitung] Server-Start${RS}"
151220
lsof -ti:3000 | xargs kill -9 2>/dev/null || true
152221

153-
# Docker-Stabilisierung: Nach intensiven Container-Tests kurz auf Erholung warten.
154-
# Docker Desktop auf macOS wird nach 74s Heavy-Load temporär unresponsive; 30s Retry.
222+
# Docker-Gesundheitsprüfung: Docker Desktop auf macOS braucht nach Heavy-Load
223+
# manchmal einige Sekunden bis der Daemon wieder stabil antwortet.
155224
DOCKER_FOR_E2E=0
156-
for _i in {1..10}; do
157-
if docker info > /dev/null 2>&1; then
158-
DOCKER_FOR_E2E=1
159-
[ "$_i" -gt 1 ] && echo -e " ${OK} Docker nach $((_i * 3))s wiederhergestellt"
160-
break
161-
fi
162-
[ "$_i" -eq 1 ] && echo -e " ${RUN} Docker antwortet nicht – warte auf Erholung (max. 30s)..."
163-
sleep 3
164-
done
225+
if [ "$DOCKER_AVAILABLE" -eq 1 ]; then
226+
for _i in {1..10}; do
227+
if docker info > /dev/null 2>&1; then
228+
DOCKER_FOR_E2E=1
229+
[ "$_i" -gt 1 ] && echo -e " ${OK} Docker nach $((_i * 3))s wiederhergestellt"
230+
break
231+
fi
232+
[ "$_i" -eq 1 ] && echo -e " ${RUN} Docker antwortet nicht – warte auf Erholung (max. 30s)..."
233+
sleep 3
234+
done
235+
fi
165236

166237
export PORT=3000
167238
# Server startet im Hintergrund (NODE_ENV=development für Vite-Snapshots)
168-
# FORCE_DOCKER + DOCKER_SANDBOX_IMAGE werden gesetzt, wenn Docker stabil verfügbar ist
169239
if [ "$DOCKER_FOR_E2E" -eq 1 ]; then
170240
echo -e " ${OK} Docker verfügbar – E2E mit Sandbox-Unterstützung"
171-
FORCE_DOCKER=1 DOCKER_SANDBOX_IMAGE=$DOCKER_SANDBOX_IMAGE UNOSIM_SHARED_TEMP_DIR=$UNOSIM_SHARED_TEMP_DIR NODE_ENV=development npm run dev >> "$LOG_FILE" 2>&1 &
241+
export FORCE_DOCKER=1
242+
DOCKER_SANDBOX_IMAGE=$DOCKER_SANDBOX_IMAGE UNOSIM_SHARED_TEMP_DIR=$UNOSIM_SHARED_TEMP_DIR NODE_ENV=development npm run dev >> "$LOG_FILE" 2>&1 &
172243
else
173244
echo -e " ${WARN} Docker nicht verfügbar – E2E im Lokal-Modus"
174245
NODE_ENV=development npm run dev >> "$LOG_FILE" 2>&1 &

0 commit comments

Comments
 (0)