trading/scripts/smoke_test.sh
Viktor Barzin e6ae4bdccd
feat: integration tests, seed data, and smoke test script
Add integration tests for the news pipeline (test_news_pipeline.py) and
trading flow (test_trading_flow.py) using real Redis with mocked FinBERT
and Alpaca. Add seed_strategies.py to insert default strategies (momentum,
mean_reversion, news_driven) with equal weights. Add smoke_test.sh for
end-to-end stack validation. Update pyproject.toml with integration marker
and scripts package discovery.
2026-02-22 16:02:44 +00:00

139 lines
4.3 KiB
Bash
Executable file

#!/bin/bash
# Smoke test for the full trading-bot Docker Compose stack.
#
# Usage:
# ./scripts/smoke_test.sh
#
# Prerequisites:
# - Docker Compose stack must be running (docker compose up -d)
#
# This script:
# 1. Waits for services to become healthy
# 2. Hits GET /health -> expects 200
# 3. Hits GET /api/portfolio -> expects 401 (unauthenticated)
# 4. Hits GET /api/strategies -> expects 401 (unauthenticated)
# 5. Checks docker compose ps shows all services running
# 6. Exits 0 on success, 1 on failure
set -euo pipefail
# Configuration
API_BASE="${API_BASE:-http://localhost:8000}"
DASHBOARD_BASE="${DASHBOARD_BASE:-http://localhost:3000}"
MAX_RETRIES="${MAX_RETRIES:-30}"
RETRY_INTERVAL="${RETRY_INTERVAL:-2}"
PASS=0
FAIL=0
# ---------------------------------------------------------------------------
# Helper functions
# ---------------------------------------------------------------------------
log() {
echo "[smoke-test] $*"
}
pass() {
log "PASS: $*"
PASS=$((PASS + 1))
}
fail() {
log "FAIL: $*"
FAIL=$((FAIL + 1))
}
wait_for_endpoint() {
local url="$1"
local expected_code="$2"
local description="$3"
local attempt=0
while [ "$attempt" -lt "$MAX_RETRIES" ]; do
attempt=$((attempt + 1))
status_code=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || echo "000")
if [ "$status_code" = "$expected_code" ]; then
return 0
fi
log "Waiting for $description ($url) ... attempt $attempt/$MAX_RETRIES (got $status_code, want $expected_code)"
sleep "$RETRY_INTERVAL"
done
return 1
}
check_endpoint() {
local url="$1"
local expected_code="$2"
local description="$3"
status_code=$(curl -s -o /dev/null -w "%{http_code}" "$url" 2>/dev/null || echo "000")
if [ "$status_code" = "$expected_code" ]; then
pass "$description -> $status_code"
else
fail "$description -> expected $expected_code, got $status_code"
fi
}
# ---------------------------------------------------------------------------
# 1. Wait for the API gateway health endpoint
# ---------------------------------------------------------------------------
log "Waiting for API gateway to be healthy ..."
if wait_for_endpoint "$API_BASE/health" "200" "API health"; then
pass "API gateway is healthy"
else
fail "API gateway did not become healthy within timeout"
log "Aborting — cannot run further checks without a healthy API"
exit 1
fi
# ---------------------------------------------------------------------------
# 2. Health check
# ---------------------------------------------------------------------------
check_endpoint "$API_BASE/health" "200" "GET /health"
# ---------------------------------------------------------------------------
# 3. Unauthenticated trading endpoints should return 401/403
# ---------------------------------------------------------------------------
check_endpoint "$API_BASE/api/portfolio" "401" "GET /api/portfolio (no auth)"
check_endpoint "$API_BASE/api/strategies" "401" "GET /api/strategies (no auth)"
# ---------------------------------------------------------------------------
# 4. Dashboard responds
# ---------------------------------------------------------------------------
log "Checking dashboard ..."
if wait_for_endpoint "$DASHBOARD_BASE/" "200" "Dashboard"; then
pass "Dashboard is serving"
else
fail "Dashboard did not respond"
fi
# ---------------------------------------------------------------------------
# 5. Docker Compose services status
# ---------------------------------------------------------------------------
log "Checking docker compose service status ..."
if command -v docker &>/dev/null; then
running_count=$(docker compose ps --format json 2>/dev/null | grep -c '"running"' || echo "0")
if [ "$running_count" -gt 0 ]; then
pass "docker compose shows $running_count running services"
else
fail "No running services found in docker compose ps"
fi
else
log "SKIP: docker command not available"
fi
# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
echo ""
log "================================"
log "Results: $PASS passed, $FAIL failed"
log "================================"
if [ "$FAIL" -gt 0 ]; then
exit 1
fi
exit 0