Tech Stack Advisor - Code Viewer

← Back to File Tree

test_api.py

Language: python | Path: test_api.py | Lines: 150
"""Test the FastAPI endpoints."""
import asyncio
import httpx
import time


async def test_api() -> None:
    """Test the API endpoints."""
    base_url = "http://localhost:8000"

    print("šŸš€ Testing Tech Stack Advisor API")
    print("=" * 70)
    print(f"\nšŸ“” Base URL: {base_url}")
    print("\nāš ļø  Make sure the API server is running:")
    print("   cd /Users/admin/codeprojects/tech-stack-advisor")
    print("   source .venv/bin/activate")
    print("   python -m backend.src.api.main")
    print("\n" + "=" * 70)

    # Wait for user
    print("\nā³ Waiting 3 seconds for server to be ready...")
    await asyncio.sleep(3)

    async with httpx.AsyncClient(timeout=30.0) as client:
        try:
            # Test 1: Root endpoint
            print("\n1ļøāƒ£  Testing GET / (Root)")
            response = await client.get(f"{base_url}/")
            print(f"   Status: {response.status_code}")
            print(f"   Response: {response.json()}")
            assert response.status_code == 200
            print("   āœ… Root endpoint working")

            # Test 2: Health check
            print("\n2ļøāƒ£  Testing GET /health")
            response = await client.get(f"{base_url}/health")
            print(f"   Status: {response.status_code}")
            data = response.json()
            print(f"   Health: {data['status']}")
            print(f"   Version: {data['version']}")
            print(f"   Agents: {data['agents_loaded']}")
            print(f"   Uptime: {data['uptime_seconds']:.2f}s")
            assert response.status_code == 200
            assert data["status"] == "healthy"
            assert data["agents_loaded"] == 4
            print("   āœ… Health check working")

            # Test 3: Metrics
            print("\n3ļøāƒ£  Testing GET /metrics")
            response = await client.get(f"{base_url}/metrics")
            print(f"   Status: {response.status_code}")
            data = response.json()
            print(f"   Total Requests: {data['total_requests']}")
            print(f"   Daily Queries: {data['daily_queries']}")
            print(f"   Daily Cost: ${data['daily_cost_usd']}")
            print(f"   Budget Remaining: ${data['budget_remaining_usd']}")
            assert response.status_code == 200
            print("   āœ… Metrics endpoint working")

            # Test 4: Recommendation (will fail without real API key)
            print("\n4ļøāƒ£  Testing POST /recommend")
            test_query = {
                "query": "I'm building a real-time chat application for 100K daily active users",
                "dau": 100_000,
            }
            print(f"   Query: {test_query['query'][:60]}...")
            print(f"   DAU Override: {test_query['dau']:,}")

            start_time = time.time()
            response = await client.post(f"{base_url}/recommend", json=test_query)
            duration = time.time() - start_time

            print(f"   Status: {response.status_code}")
            print(f"   Duration: {duration:.2f}s")

            data = response.json()
            print(f"   Response Status: {data.get('status', 'unknown')}")

            if data.get("status") == "success":
                print(f"   Correlation ID: {data.get('correlation_id', 'N/A')}")
                context = data.get("parsed_context", {})
                print(f"   Parsed DAU: {context.get('dau', 0):,}")
                print(f"   Workload: {context.get('workload_type', 'N/A')}")
                print("   āœ… Recommendation endpoint working!")
            else:
                error = data.get("error", "Unknown error")
                print(f"   āš ļø  Expected error (no valid API key): {error[:100]}...")
                print("   ā„¹ļø  This is expected without ANTHROPIC_API_KEY")

            # Test 5: Rate limiting
            print("\n5ļøāƒ£  Testing Rate Limiting (5 requests/hour)")
            print("   Making 6 rapid requests to trigger rate limit...")

            rate_limit_triggered = False
            for i in range(6):
                response = await client.post(
                    f"{base_url}/recommend",
                    json={"query": f"Test query {i+1}"},
                )
                if response.status_code == 429:
                    rate_limit_triggered = True
                    print(f"   Request {i+1}: Rate limited! āœ…")
                    break
                else:
                    print(f"   Request {i+1}: {response.status_code}")

            if rate_limit_triggered:
                print("   āœ… Rate limiting working correctly")
            else:
                print("   āš ļø  Rate limit not triggered (may need more requests)")

            # Test 6: Input validation
            print("\n6ļøāƒ£  Testing Input Validation")
            invalid_query = {"query": "short"}  # Too short (min 10 chars)
            response = await client.post(f"{base_url}/recommend", json=invalid_query)
            print(f"   Short query status: {response.status_code}")
            if response.status_code == 422:
                print("   āœ… Input validation working")
            else:
                print(f"   āš ļø  Expected 422, got {response.status_code}")

        except httpx.ConnectError:
            print("\nāŒ Connection Error!")
            print("\n   The API server is not running. Please start it with:")
            print("   cd /Users/admin/codeprojects/tech-stack-advisor")
            print("   source .venv/bin/activate")
            print("   python -m backend.src.api.main")
            return

        except Exception as e:
            print(f"\nāŒ Test Error: {str(e)}")
            return

    print("\n" + "=" * 70)
    print("\nāœ… API Testing Complete!")
    print("\nšŸ“Š Endpoints Tested:")
    print("   āœ… GET  /           - Root endpoint")
    print("   āœ… GET  /health     - Health check")
    print("   āœ… GET  /metrics    - Usage metrics")
    print("   āœ… POST /recommend  - Tech stack recommendations")
    print("   āœ… Rate limiting    - 5 requests/hour per IP")
    print("   āœ… Input validation - Pydantic schema enforcement")
    print("\nšŸ“– API Documentation:")
    print(f"   Interactive docs: {base_url}/docs")
    print(f"   ReDoc: {base_url}/redoc")
    print()


if __name__ == "__main__":
    asyncio.run(test_api())