#!/usr/bin/env bash set -euo pipefail; repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" export FETCHML_REPO_ROOT="$repo_root" # Parse arguments env="dev" native_mode=false while [[ $# -gt 0 ]]; do case "$1" in --native) native_mode=true shift ;; dev|prod) env="$1" shift ;; --help|-h) echo "Usage: $0 [dev|prod] [--native]" echo "" echo "Options:" echo " dev|prod Environment to test (default: dev)" echo " --native Also test native libraries (C++ integration)" echo " --help Show this help" exit 0 ;; *) echo "Unknown option: $1" >&2 echo "Usage: $0 [dev|prod] [--native]" >&2 exit 2 ;; esac done # Native library smoke test (merged from smoke-test-native.sh) if [[ "$native_mode" == true ]]; then echo "=== FetchML Native Libraries Smoke Test ===" echo "" cd "$repo_root" # Build native libraries echo "1. Building native libraries..." if [[ -d native/build ]]; then cd native/build cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_ASAN=OFF >/dev/null 2>&1 || true make -j4 2>&1 | grep -E "(Built|Error|error)" || true cd ../.. echo " Native libraries built" else echo " ⚠ native/build not found, skipping native build" fi echo "" # Run C++ unit tests echo "2. Running C++ smoke tests..." local tests_run=0 for test_bin in ./native/build/test_*; do if [[ -x "$test_bin" ]]; then local test_name=$(basename "$test_bin") echo " Running $test_name..." "$test_bin" 2>/dev/null && echo " ✓ $test_name passed" || echo " ⚠ $test_name skipped/failed" ((tests_run++)) fi done if [[ $tests_run -eq 0 ]]; then echo " ⚠ No C++ tests found" else echo " Ran $tests_run C++ test(s)" fi echo "" echo "3. Building Go applications with native libs..." go build -tags native_libs -o /dev/null ./cmd/api-server 2>&1 | grep -v "ignoring duplicate" || true echo " api-server builds" go build -tags native_libs -o /dev/null ./cmd/worker 2>&1 | grep -v "ignoring duplicate" || true 2>/dev/null || echo " (worker optional)" echo "" fi probe_https_health_openssl() { host="$1" port="$2" path="$3" req="GET ${path} HTTP/1.1\r\nHost: ${host}\r\nConnection: close\r\n\r\n" resp=$(printf "%b" "$req" | openssl s_client -connect "127.0.0.1:${port}" -servername "${host}" -tls1_2 -quiet 2>/dev/null || true) printf "%s" "$resp" | tr -d '\r' | head -n 1 | grep -Eq '^HTTP/1\.[01] 200' } compose_cmd="docker-compose"; if ! command -v docker-compose >/dev/null 2>&1; then compose_cmd="docker compose"; fi compose_files=() compose_project_args=("--project-directory" "$repo_root") api_base="" prometheus_base="" stack_name="" api_wait_seconds=90 prometheus_wait_seconds=90 if [ "$env" = "dev" ]; then mkdir -p \ "$repo_root/data/dev/redis" \ "$repo_root/data/dev/minio" \ "$repo_root/data/dev/prometheus" \ "$repo_root/data/dev/grafana" \ "$repo_root/data/dev/loki" \ "$repo_root/data/dev/logs" \ "$repo_root/data/dev/experiments" \ "$repo_root/data/dev/active" \ "$repo_root/data/dev/workspaces" # Verify Docker can access the data directory (macOS file sharing check) if ! docker run --rm -v "$repo_root/data/dev:/test-data:ro" alpine:3.19 ls /test-data >/dev/null 2>&1; then echo "ERROR: Docker cannot access $repo_root/data/dev" echo "" echo "This is a Docker Desktop file sharing issue. To fix:" echo "1. Open Docker Desktop -> Settings -> Resources -> File sharing" echo "2. Add or verify: $repo_root" echo "3. Click 'Apply & Restart'" echo "" echo "Alternatively, run: mkdir -p $repo_root/data/dev/{redis,minio,prometheus,grafana,loki,logs,experiments,active,workspaces}" exit 1 fi stack_name="dev" api_wait_seconds=180 prometheus_wait_seconds=180 compose_files=("-f" "$repo_root/deployments/docker-compose.dev.yml") api_base="https://localhost:9101" if ! curl -skf "$api_base/health" >/dev/null 2>&1; then api_base="http://localhost:9101" fi prometheus_base="http://localhost:9090" else mkdir -p \ "$repo_root/data/prod-smoke/caddy/data" \ "$repo_root/data/prod-smoke/caddy/config" \ "$repo_root/data/prod-smoke/redis" \ "$repo_root/data/prod-smoke/logs" \ "$repo_root/data/prod-smoke/experiments" \ "$repo_root/data/prod-smoke/active" stack_name="prod" compose_files=("-f" "$repo_root/deployments/docker-compose.prod.smoke.yml") api_base="https://localhost:8443" export FETCHML_DOMAIN=localhost export CADDY_EMAIL=smoke@example.invalid fi cleanup() { status=$?; if [ "$status" -ne 0 ]; then $compose_cmd "${compose_project_args[@]}" "${compose_files[@]}" logs --no-color || true; fi if [ "${KEEP_STACK:-0}" != "1" ]; then $compose_cmd "${compose_project_args[@]}" "${compose_files[@]}" down -v >/dev/null 2>&1 || true; fi exit "$status"; } trap cleanup EXIT; echo "Starting $stack_name stack for smoke test..."; $compose_cmd "${compose_project_args[@]}" "${compose_files[@]}" up -d --build >/dev/null; echo "Waiting for API to become healthy..."; deadline=$(($(date +%s) + $api_wait_seconds)); while true; do if [ "$env" = "dev" ]; then if curl -skf "$api_base/health" >/dev/null 2>&1; then break; fi; else if probe_https_health_openssl "localhost" "8443" "/health"; then break; fi; fi if [ $(date +%s) -ge $deadline ]; then echo "Timed out waiting for $api_base/health"; exit 1; fi; sleep 2; done; if [ "$env" = "dev" ]; then echo "Checking metrics endpoint..."; curl -skf "$api_base/metrics" >/dev/null; echo "Waiting for Prometheus target api-server to be up..."; deadline=$(($(date +%s) + $prometheus_wait_seconds)); query_url="$prometheus_base/api/v1/query?query=up%7Bjob%3D%22api-server%22%7D"; while true; do resp=$(curl -sf "$query_url" || true); resp_compact=$(printf "%s" "$resp" | tr -d '\n' | tr -d '\r'); if echo "$resp_compact" | grep -Fq '"instance":"api-server:9101"' && echo "$resp_compact" | grep -Fq ',"1"]'; then break; fi; if [ $(date +%s) -ge $deadline ]; then echo "Timed out waiting for Prometheus api-server target to be up"; echo "$resp"; exit 1; fi; sleep 2; done; fi