#!/usr/bin/env bash ## Test runner for the missions service (blackbox + unit tests). ## Documented in _docs/02_document/tests/environment.md (Hardware Assessment -> Docker mode). ## Naming: post-rename target. Pre-rename code path runs the same script -- tests ## will be RED until B5-B8 land. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" COMPOSE_FILE="$PROJECT_ROOT/docker-compose.test.yml" RESULTS_DIR="$PROJECT_ROOT/test-results" TEST_PROJECT_DIR="$PROJECT_ROOT/tests/Azaion.Missions.E2E.Tests" UNIT_ONLY=false KEEP_RUNNING=false for arg in "$@"; do case "$arg" in --unit-only) UNIT_ONLY=true ;; --keep-running) KEEP_RUNNING=true ;; -h|--help) cat <&2 exit 64 ;; esac done cleanup() { local exit_code=$? if [ "$KEEP_RUNNING" = "true" ]; then echo "[run-tests] --keep-running set; leaving compose stack up." >&2 else echo "[run-tests] tearing down compose stack..." >&2 docker compose -f "$COMPOSE_FILE" down -v --remove-orphans >/dev/null 2>&1 || true fi exit "$exit_code" } trap cleanup EXIT mkdir -p "$RESULTS_DIR" ## --- Install dependencies --- ## docker compose handles per-image dependency resolution (dotnet restore inside ## the missions Dockerfile, dotnet restore inside the e2e-consumer Dockerfile). ## Verify Docker + Compose are available on the host. command -v docker >/dev/null 2>&1 || { echo "[run-tests] ERROR: docker is required but not installed on PATH." >&2 exit 2 } docker compose version >/dev/null 2>&1 || { echo "[run-tests] ERROR: docker compose v2 plugin is required." >&2 exit 2 } if [ ! -d "$TEST_PROJECT_DIR" ]; then cat >&2 <&2 docker compose -f "$COMPOSE_FILE" up -d postgres-test missions docker compose -f "$COMPOSE_FILE" ps exit 0 fi ## --- Build images and start system under test --- echo "[run-tests] building images..." >&2 docker compose -f "$COMPOSE_FILE" build postgres-test missions echo "[run-tests] starting postgres-test + missions..." >&2 docker compose -f "$COMPOSE_FILE" up -d postgres-test missions echo "[run-tests] waiting for missions /health (timeout 60s)..." >&2 ATTEMPTS=0 until [ "$ATTEMPTS" -ge 60 ]; do if curl -sf http://localhost:5002/health >/dev/null 2>&1; then echo "[run-tests] missions is healthy." >&2 break fi ATTEMPTS=$((ATTEMPTS + 1)) sleep 1 done if [ "$ATTEMPTS" -ge 60 ]; then echo "[run-tests] ERROR: missions did not become healthy within 60s." >&2 docker compose -f "$COMPOSE_FILE" logs missions >&2 || true exit 3 fi if [ "$UNIT_ONLY" = "true" ]; then echo "[run-tests] --unit-only: missions service has no unit tests today." >&2 echo "[run-tests] (Step 6 may add a tests/Azaion.Missions.UnitTests/ project later.)" >&2 exit 0 fi ## --- Blackbox / e2e tests --- echo "[run-tests] building e2e-consumer..." >&2 docker compose -f "$COMPOSE_FILE" --profile test build e2e-consumer echo "[run-tests] running e2e suite via dotnet test..." >&2 ## --abort-on-container-exit + --exit-code-from propagate the e2e-consumer exit ## code back to this script so the CI gate fires correctly. docker compose -f "$COMPOSE_FILE" --profile test up \ --abort-on-container-exit \ --exit-code-from e2e-consumer \ e2e-consumer postgres-test missions TEST_EXIT=$? ## --- Summary --- if [ "$TEST_EXIT" -eq 0 ]; then echo "[run-tests] ALL PASS." >&2 else echo "[run-tests] FAILURES detected (exit code $TEST_EXIT)." >&2 echo "[run-tests] missions logs (last 50 lines):" >&2 docker compose -f "$COMPOSE_FILE" logs --tail=50 missions >&2 || true echo "[run-tests] e2e-consumer logs (last 100 lines):" >&2 docker compose -f "$COMPOSE_FILE" logs --tail=100 e2e-consumer >&2 || true fi exit "$TEST_EXIT"