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.
139 lines
4.3 KiB
Bash
Executable file
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
|