diff --git a/tests/test_e2e.sh b/tests/test_e2e.sh index 1d133b5..4e3fc3d 100755 --- a/tests/test_e2e.sh +++ b/tests/test_e2e.sh @@ -10,6 +10,49 @@ PASSED=0 FAILED=0 PORT=19800 # Use high port to avoid conflicts BASE="http://127.0.0.1:$PORT" +TEST_HOME=$(mktemp -d "${TMPDIR:-/tmp}/nullhub-e2e.XXXXXX") +SERVER_LOG="$TEST_HOME/nullhub-server.log" +SERVER_PID="" + +# Cleanup on exit +cleanup() { + if [ -n "${SERVER_PID:-}" ]; then + echo "Stopping server..." + kill "$SERVER_PID" 2>/dev/null || true + wait "$SERVER_PID" 2>/dev/null || true + fi + rm -rf "$TEST_HOME" +} +trap cleanup EXIT + +server_is_running() { + if [ -z "${SERVER_PID:-}" ]; then + return 1 + fi + kill -0 "$SERVER_PID" 2>/dev/null +} + +fail_if_server_exited() { + local context="$1" + + if server_is_running; then + return 0 + fi + + local exit_code=0 + set +e + wait "$SERVER_PID" + exit_code=$? + set -e + + echo -e "${RED}FAIL${NC}: nullhub exited unexpectedly during $context (exit $exit_code)" + if [ -f "$SERVER_LOG" ]; then + echo "--- nullhub server log ---" + cat "$SERVER_LOG" + echo "--- end nullhub server log ---" + fi + exit 1 +} # Build echo "Building nullhub..." @@ -18,20 +61,13 @@ EXPECTED_VERSION=$(./zig-out/bin/nullhub --version 2>&1 | awk '{print $2}' | sed # Start server in background echo "Starting nullhub on port $PORT..." -./zig-out/bin/nullhub serve --port $PORT --no-open & +HOME="$TEST_HOME" ./zig-out/bin/nullhub serve --port "$PORT" --no-open >"$SERVER_LOG" 2>&1 & SERVER_PID=$! -# Cleanup on exit -cleanup() { - echo "Stopping server..." - kill $SERVER_PID 2>/dev/null || true - wait $SERVER_PID 2>/dev/null || true -} -trap cleanup EXIT - # Wait for server to be ready (retry loop instead of fixed sleep) echo "Waiting for server..." for i in $(seq 1 20); do + fail_if_server_exited "startup" if curl -s -o /dev/null -w "%{http_code}" "$BASE/health" 2>/dev/null | grep -q "200"; then echo "Server ready after ${i} attempt(s)." break @@ -50,12 +86,25 @@ assert_status() { local method="$3" local url="$4" local body="${5:-}" + local actual="" + local curl_exit=0 + + fail_if_server_exited "$description (before request)" + set +e if [ -n "$body" ]; then actual=$(curl -s -o /dev/null -w "%{http_code}" -X "$method" -H "Content-Type: application/json" -d "$body" "$url") else actual=$(curl -s -o /dev/null -w "%{http_code}" -X "$method" "$url") fi + curl_exit=$? + set -e + + fail_if_server_exited "$description (after request)" + + if [ "$curl_exit" -ne 0 ]; then + actual="CURL_ERROR($curl_exit, HTTP ${actual:-000})" + fi if [ "$actual" = "$expected" ]; then echo -e "${GREEN}PASS${NC}: $description (HTTP $actual)" @@ -71,9 +120,22 @@ assert_json_field() { local url="$2" local field="$3" local expected="$4" - - local response=$(curl -s "$url") - local actual=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin)$field)" 2>/dev/null || echo "PARSE_ERROR") + local response="" + local curl_exit=0 + local actual="" + + fail_if_server_exited "$description (before request)" + set +e + response=$(curl -s "$url") + curl_exit=$? + set -e + fail_if_server_exited "$description (after request)" + + if [ "$curl_exit" -ne 0 ]; then + actual="CURL_ERROR($curl_exit)" + else + actual=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin)$field)" 2>/dev/null || echo "PARSE_ERROR") + fi if [ "$actual" = "$expected" ]; then echo -e "${GREEN}PASS${NC}: $description ($field = $actual)" @@ -129,6 +191,8 @@ echo "================================" echo -e "Results: ${GREEN}$PASSED passed${NC}, ${RED}$FAILED failed${NC}" echo "================================" +fail_if_server_exited "final result collection" + if [ $FAILED -gt 0 ]; then exit 1 fi