test_api.py 7,99 ko
Newer Older
"""
Test script for the FastAPI endpoints.
Run the API server first: uvicorn src.main:app --reload
Then run this script: python test_api.py
"""
import requests
import json
import time

BASE_URL = "http://localhost:8000"


def print_section(title):
    """Print a section header."""
    print("\n" + "=" * 80)
    print(title)
    print("=" * 80)


def test_root():
    """Test root endpoint."""
    print_section("TEST: Root Endpoint")
    response = requests.get(f"{BASE_URL}/")
    print(f"Status: {response.status_code}")
    print(f"Response: {json.dumps(response.json(), indent=2)}")
    assert response.status_code == 200


def test_list_scenarios():
    """Test listing scenarios."""
    print_section("TEST: List Scenarios")
    response = requests.get(f"{BASE_URL}/api/scenarios/")
    print(f"Status: {response.status_code}")
    data = response.json()
    print(f"Found {len(data)} scenarios:")
    for scenario in data:
        print(f"  - {scenario['id']}: {scenario['name']}")
    assert response.status_code == 200
    assert len(data) == 5


def test_get_scenario():
    """Test getting a specific scenario."""
    print_section("TEST: Get Scenario 1")
    response = requests.get(f"{BASE_URL}/api/scenarios/scenario_1")
    print(f"Status: {response.status_code}")
    data = response.json()
    print(f"Scenario: {data['name']}")
    print(f"Config:")
    print(f"  λ = {data['config']['arrival_rate']}")
    print(f"  μc = {data['config']['coordinator_service_rate']}")
    print(f"  p = {data['config']['coordinator_exit_probability']}")
    print(f"  Servers: {len(data['config']['servers'])}")
    assert response.status_code == 200


def test_run_simulation():
    """Test running a simulation."""
    print_section("TEST: Run Simulation")

    # Simple configuration
    config = {
        "arrival_rate": 0.008,
        "coordinator_service_rate": 0.1,
        "coordinator_exit_probability": 0.5,
        "servers": [
            {
                "id": "server_1",
                "service_rate": 0.00833,
                "routing_probability": 0.5
            }
        ],
        "warmup_time": 1000.0,
        "simulation_time": 5000.0,
        "random_seed": 42
    }

    print("Starting simulation...")
    response = requests.post(f"{BASE_URL}/api/simulation/start", json=config)
    print(f"Status: {response.status_code}")
    data = response.json()
    print(f"Session ID: {data['session_id']}")
    print(f"Status: {data['status']}")

    assert response.status_code == 200
    return data['session_id']


def test_get_results(session_id):
    """Test getting simulation results."""
    print_section("TEST: Get Simulation Results")

    response = requests.get(f"{BASE_URL}/api/simulation/results/{session_id}")
    print(f"Status: {response.status_code}")
    data = response.json()

    print(f"\nResults:")
    print(f"  Total requests: {data['total_requests_completed']}")
    print(f"  Avg system time: {data['average_system_time']:.2f}")
    print(f"  Stable: {data['is_stable']}")

    print(f"\n  Coordinator:")
    coord = data['coordinator_stats']
    print(f"    Utilization: {coord['utilization']:.4f}")
    print(f"    Avg time: {coord['average_system_time']:.2f}")

    print(f"\n  Server 1:")
    server1 = data['server_stats']['server_1']
    print(f"    Utilization: {server1['utilization']:.4f}")
    print(f"    Avg time: {server1['average_system_time']:.2f}")

    assert response.status_code == 200


def test_jackson_analysis():
    """Test Jackson's theorem analysis."""
    print_section("TEST: Jackson's Theorem Analysis")

    config = {
        "arrival_rate": 0.008,
        "coordinator_service_rate": 0.1,
        "coordinator_exit_probability": 0.5,
        "servers": [
            {
                "id": "server_1",
                "service_rate": 0.00833,
                "routing_probability": 0.5
            }
        ]
    }

    response = requests.post(f"{BASE_URL}/api/analytics/jackson", json=config)
    print(f"Status: {response.status_code}")
    data = response.json()

    print(f"\nAnalytical Results:")
    print(f"  Stable: {data['is_stable']}")
    print(f"  Total L: {data['total_average_customers']:.4f}")
    print(f"  Total W: {data['total_average_time']:.4f}")

    print(f"\n  Coordinator:")
    coord = data['coordinator']
    print(f"    ρ = {coord['utilization']:.4f}")
    print(f"    L = {coord['average_customers']:.4f}")
    print(f"    W = {coord['average_time']:.4f}")

    print(f"\n  Server 1:")
    server1 = data['servers']['server_1']
    print(f"    ρ = {server1['utilization']:.4f}")
    print(f"    L = {server1['average_customers']:.4f}")
    print(f"    W = {server1['average_time']:.4f}")

    assert response.status_code == 200


def test_comparison(session_id):
    """Test analytical vs simulation comparison."""
    print_section("TEST: Compare Analytical vs Simulation")

    response = requests.get(f"{BASE_URL}/api/analytics/compare/{session_id}")
    print(f"Status: {response.status_code}")
    data = response.json()

    print(f"\nComparison:")
    print(f"  Total W:")
    print(f"    Analytical: {data['total_W']['analytical']:.4f}")
    print(f"    Simulation: {data['total_W']['simulation']:.4f}")
    print(f"    Difference: {data['total_W']['difference_percent']:.2f}%")

    print(f"\n  Coordinator Utilization:")
    coord_rho = data['coordinator']['utilization']
    print(f"    Analytical: {coord_rho['analytical']:.4f}")
    print(f"    Simulation: {coord_rho['simulation']:.4f}")
    print(f"    Difference: {coord_rho['difference_percent']:.2f}%")

    assert response.status_code == 200


def test_stability_check():
    """Test stability checking."""
    print_section("TEST: Stability Check")

    # Unstable config
    config = {
        "arrival_rate": 1.0,
        "coordinator_service_rate": 0.8,
        "coordinator_exit_probability": 1.0,
        "servers": []
    }

    response = requests.post(f"{BASE_URL}/api/analytics/stability", json=config)
    print(f"Status: {response.status_code}")
    data = response.json()

    print(f"\nStability Check:")
    print(f"  Stable: {data['is_stable']}")
    if not data['is_stable']:
        print(f"  Reason: {data['reason']}")

    print(f"\n  Conditions:")
    for cond in data['conditions']:
        status = "✓" if cond['stable'] else "✗"
        print(f"    {status} {cond['queue']}: ρ = {cond['utilization']:.4f}")

    assert response.status_code == 200


def test_run_scenario():
    """Test running a predefined scenario."""
    print_section("TEST: Run Predefined Scenario")

    response = requests.post(f"{BASE_URL}/api/scenarios/scenario_1/run")
    print(f"Status: {response.status_code}")
    data = response.json()

    print(f"Scenario Run:")
    print(f"  Scenario: {data['scenario_id']}")
    print(f"  Session ID: {data['session_id']}")
    print(f"  Status: {data['status']}")

    assert response.status_code == 200
    return data['session_id']


def main():
    """Run all tests."""
    print("=" * 80)
    print("FASTAPI ENDPOINT TESTS")
    print("=" * 80)
    print("\nMake sure the API server is running:")
    print("  cd apps/backend")
    print("  source venv/bin/activate")
    print("  uvicorn src.main:app --reload")
    print()

    try:
        # Test basic endpoints
        test_root()
        test_list_scenarios()
        test_get_scenario()

        # Test simulation
        session_id = test_run_simulation()
        test_get_results(session_id)

        # Test analytics
        test_jackson_analysis()
        test_comparison(session_id)
        test_stability_check()

        # Test scenario execution
        scenario_session = test_run_scenario()

        print("\n" + "=" * 80)
        print("✅ ALL TESTS PASSED!")
        print("=" * 80)

    except requests.exceptions.ConnectionError:
        print("\n❌ ERROR: Could not connect to API server")
        print("Please start the server first:")
        print("  uvicorn src.main:app --reload")
    except AssertionError as e:
        print(f"\n❌ TEST FAILED: {e}")
    except Exception as e:
        print(f"\n❌ ERROR: {e}")


if __name__ == "__main__":
    main()