diff --git a/scripts/ci/wait-for-url.sh b/scripts/ci/wait-for-url.sh new file mode 100755 index 00000000..48535157 --- /dev/null +++ b/scripts/ci/wait-for-url.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# wait-for-url.sh — curl with retry until success or attempts exhausted. +# +# Usage: wait-for-url.sh [] [] +# Env (optional): BASIC_AUTH_USER, BASIC_AUTH_PASS — if set, sent as basic auth. +set -euo pipefail + +URL="${1:-}" +MAX_ATTEMPTS="${2:-30}" +DELAY="${3:-2}" + +if [ -z "$URL" ]; then + echo "usage: $0 [] []" >&2 + exit 2 +fi + +# bash 3.2-safe: expand array only when non-empty. +AUTH_ARGS=() +if [ -n "${BASIC_AUTH_USER:-}" ] && [ -n "${BASIC_AUTH_PASS:-}" ]; then + AUTH_ARGS=(--user "${BASIC_AUTH_USER}:${BASIC_AUTH_PASS}") +fi + +attempt=1 +while [ "$attempt" -le "$MAX_ATTEMPTS" ]; do + if curl -fsS ${AUTH_ARGS[@]+"${AUTH_ARGS[@]}"} -o /dev/null "$URL"; then + echo "ok: $URL ($attempt attempt(s))" + exit 0 + fi + if [ "$attempt" -lt "$MAX_ATTEMPTS" ]; then + sleep "$DELAY" + fi + attempt=$((attempt + 1)) +done + +echo "fail: $URL did not return 2xx after $MAX_ATTEMPTS attempts" >&2 +exit 1 diff --git a/tests/ci/test-wait-for-url.sh b/tests/ci/test-wait-for-url.sh new file mode 100755 index 00000000..ce49d66d --- /dev/null +++ b/tests/ci/test-wait-for-url.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT="$(cd "$(dirname "$0")/../.." && pwd)/scripts/ci/wait-for-url.sh" +[ -x "$SCRIPT" ] || { echo "FAIL: $SCRIPT not executable"; exit 1; } + +# Spin up a tiny HTTP server on a random free port. +PORT=$(python3 -c 'import socket; s=socket.socket(); s.bind(("",0)); print(s.getsockname()[1]); s.close()') +TMPDIR=$(mktemp -d) +echo "ok" > "$TMPDIR/index.html" +( cd "$TMPDIR" && python3 -m http.server "$PORT" >/dev/null 2>&1 ) & +SERVER_PID=$! +trap "kill $SERVER_PID 2>/dev/null; rm -rf $TMPDIR" EXIT + +# Wait for server to come up +for _ in 1 2 3 4 5 6 7 8 9 10; do + if curl -fsS "http://127.0.0.1:$PORT/" >/dev/null 2>&1; then break; fi + sleep 0.2 +done + +# 200 case — should pass quickly +"$SCRIPT" "http://127.0.0.1:$PORT/" 5 1 || { echo "FAIL: expected 200 to succeed"; exit 1; } + +# 404 case — script should fail (curl -f returns non-zero on 4xx) +if "$SCRIPT" "http://127.0.0.1:$PORT/no-such-path" 3 1 2>/dev/null; then + echo "FAIL: expected 404 to fail"; exit 1 +fi + +# Network failure case — wrong port +if "$SCRIPT" "http://127.0.0.1:1/" 2 1 2>/dev/null; then + echo "FAIL: expected unreachable URL to fail"; exit 1 +fi + +# Bad usage +if "$SCRIPT" 2>/dev/null; then + echo "FAIL: expected usage error"; exit 1 +fi + +echo "PASS: wait-for-url.sh"