132 lines
3.4 KiB
Bash
132 lines
3.4 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
COMPOSE_FILE="${ROOT_DIR}/docker-compose.yml"
|
|
|
|
BACKEND_URL="${BACKEND_URL:-http://localhost:8000}"
|
|
RUNNER_URL="${RUNNER_URL:-http://localhost:8010}"
|
|
FRONTEND_URL="${FRONTEND_URL:-http://localhost:3000}"
|
|
WAIT_SECONDS="${WAIT_SECONDS:-60}"
|
|
PYTHON_BIN="${PYTHON_BIN:-python3}"
|
|
|
|
cleanup() {
|
|
docker compose -f "${COMPOSE_FILE}" down --remove-orphans >/dev/null 2>&1 || true
|
|
}
|
|
|
|
fetch_health() {
|
|
local name="$1"
|
|
local url="$2"
|
|
local deadline=$((SECONDS + WAIT_SECONDS))
|
|
local body
|
|
|
|
while (( SECONDS < deadline )); do
|
|
if body="$(curl -fsS "${url}" 2>/dev/null)"; then
|
|
printf '%s' "${body}"
|
|
return 0
|
|
fi
|
|
|
|
sleep 1
|
|
done
|
|
|
|
echo "Timed out waiting for ${name} at ${url}" >&2
|
|
return 1
|
|
}
|
|
|
|
assert_service_health() {
|
|
local name="$1"
|
|
local url="$2"
|
|
local expected_service="$3"
|
|
local body
|
|
|
|
body="$(fetch_health "${name}" "${url}")"
|
|
HEALTH_NAME="${name}" EXPECTED_SERVICE="${expected_service}" HEALTH_BODY="${body}" "${PYTHON_BIN}" - <<'PY'
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
name = os.environ["HEALTH_NAME"]
|
|
expected_service = os.environ["EXPECTED_SERVICE"]
|
|
body = os.environ["HEALTH_BODY"]
|
|
|
|
try:
|
|
payload = json.loads(body)
|
|
except json.JSONDecodeError as error:
|
|
print(f"{name}: expected JSON response, got: {body!r}", file=sys.stderr)
|
|
raise SystemExit(1) from error
|
|
|
|
if payload.get("service") != expected_service:
|
|
print(
|
|
f"{name}: expected service={expected_service!r}, got {payload.get('service')!r}",
|
|
file=sys.stderr,
|
|
)
|
|
raise SystemExit(1)
|
|
|
|
if payload.get("status") != "ok":
|
|
print(f"{name}: expected status='ok', got {payload.get('status')!r}", file=sys.stderr)
|
|
raise SystemExit(1)
|
|
PY
|
|
echo "${name} health ok"
|
|
}
|
|
|
|
assert_backend_dependencies() {
|
|
local body
|
|
|
|
body="$(fetch_health "backend dependencies" "${BACKEND_URL}/health/dependencies")"
|
|
HEALTH_BODY="${body}" "${PYTHON_BIN}" - <<'PY'
|
|
import json
|
|
import os
|
|
import sys
|
|
|
|
body = os.environ["HEALTH_BODY"]
|
|
required = ("postgres", "redis", "object_storage")
|
|
|
|
try:
|
|
payload = json.loads(body)
|
|
except json.JSONDecodeError as error:
|
|
print(f"backend dependencies: expected JSON response, got: {body!r}", file=sys.stderr)
|
|
raise SystemExit(1) from error
|
|
|
|
if payload.get("service") != "backend":
|
|
print(
|
|
f"backend dependencies: expected service='backend', got {payload.get('service')!r}",
|
|
file=sys.stderr,
|
|
)
|
|
raise SystemExit(1)
|
|
|
|
if payload.get("status") != "ok":
|
|
print(
|
|
f"backend dependencies: expected status='ok', got {payload.get('status')!r}",
|
|
file=sys.stderr,
|
|
)
|
|
raise SystemExit(1)
|
|
|
|
dependencies = payload.get("dependencies")
|
|
if not isinstance(dependencies, dict):
|
|
print("backend dependencies: expected dependencies object", file=sys.stderr)
|
|
raise SystemExit(1)
|
|
|
|
failed = [name for name in required if dependencies.get(name) != "ok"]
|
|
if failed:
|
|
print(
|
|
"backend dependencies: expected ok for " + ", ".join(failed),
|
|
file=sys.stderr,
|
|
)
|
|
raise SystemExit(1)
|
|
PY
|
|
echo "backend dependencies ok"
|
|
}
|
|
|
|
cd "${ROOT_DIR}"
|
|
trap cleanup EXIT
|
|
|
|
echo "Starting stack with docker compose..."
|
|
docker compose -f "${COMPOSE_FILE}" up --build -d
|
|
|
|
assert_service_health "backend" "${BACKEND_URL}/health" "backend"
|
|
assert_service_health "runner" "${RUNNER_URL}/health" "runner"
|
|
assert_service_health "frontend" "${FRONTEND_URL}/health" "frontend"
|
|
assert_backend_dependencies
|
|
|
|
echo "public health smoke ok"
|