""" Integration tests for complete API workflows """ import pytest from fastapi.testclient import TestClient from datetime import datetime, timedelta def test_complete_api_workflow(client: TestClient): """Test complete API workflow from health check to data retrieval""" # 1. Health check health_response = client.get("/api/v1/health") assert health_response.status_code == 200 # 2. Get data catalog catalog_response = client.get("/api/v1/metadata/catalog") assert catalog_response.status_code == 200 catalog_data = catalog_response.json() assert "categories" in catalog_data # 3. Try to get financial data financial_request = { "ticker": "AAPL", "start_date": "2023-01-01T00:00:00", "end_date": "2023-03-31T23:59:59", "period_type": "quarterly", "include_metrics": True } financial_response = client.post("/api/v1/financial/data", json=financial_request) # Should succeed or return specific error (not validation error) assert financial_response.status_code in [200, 404, 500] # 4. Try OHLCV endpoint (should be not implemented) ohlcv_request = { "ticker": "AAPL", "start_date": "2023-01-01T00:00:00", "end_date": "2023-03-31T23:59:59", "interval": "1d" } ohlcv_response = client.post("/api/v1/market/ohlcv", json=ohlcv_request) assert ohlcv_response.status_code in [200, 404, 501] def test_api_error_handling_consistency(client: TestClient): """Test that error responses are consistent across endpoints""" # Test validation errors validation_errors = [] # Financial endpoint validation error response = client.post("/api/v1/financial/data", json={"ticker": ""}) if response.status_code == 422: validation_errors.append(response.json()) # OHLCV endpoint validation error response = client.post("/api/v1/market/ohlcv", json={"ticker": ""}) if response.status_code == 422: validation_errors.append(response.json()) # Check validation errors have consistent structure for error in validation_errors: assert "detail" in error # FastAPI validation errors have specific structure if isinstance(error["detail"], list): for item in error["detail"]: assert "type" in item assert "msg" in item def test_date_range_validation_consistency(client: TestClient): """Test that date range validation is consistent across endpoints""" # Invalid date range (end before start) invalid_dates = { "start_date": "2023-12-31T00:00:00", "end_date": "2023-01-01T00:00:00" } # Test financial endpoint financial_request = { "ticker": "AAPL", **invalid_dates, "period_type": "quarterly" } response = client.post("/api/v1/financial/data", json=financial_request) assert response.status_code == 400 # Test OHLCV endpoint ohlcv_request = { "ticker": "AAPL", **invalid_dates, "interval": "1d" } response = client.post("/api/v1/market/ohlcv", json=ohlcv_request) assert response.status_code == 400 def test_ticker_validation_consistency(client: TestClient): """Test that ticker validation is consistent across endpoints""" valid_date_range = { "start_date": "2023-01-01T00:00:00", "end_date": "2023-03-31T23:59:59" } # Test empty ticker financial_request = { "ticker": "", **valid_date_range, "period_type": "quarterly" } response = client.post("/api/v1/financial/data", json=financial_request) assert response.status_code == 422 ohlcv_request = { "ticker": "", **valid_date_range, "interval": "1d" } response = client.post("/api/v1/market/ohlcv", json=ohlcv_request) assert response.status_code == 422 def test_response_structure_consistency(client: TestClient): """Test that successful responses have consistent structure""" # Get catalog (should always work) catalog_response = client.get("/api/v1/metadata/catalog") assert catalog_response.status_code == 200 catalog_data = catalog_response.json() # Check common response patterns assert isinstance(catalog_data, dict) assert "last_updated" in catalog_data # Health check health_response = client.get("/api/v1/health") assert health_response.status_code == 200 health_data = health_response.json() assert isinstance(health_data, dict) assert "timestamp" in health_data assert "status" in health_data def test_content_type_headers(client: TestClient): """Test that all endpoints return proper content-type headers""" endpoints = [ "/api/v1/health", "/api/v1/metadata/catalog" ] for endpoint in endpoints: response = client.get(endpoint) assert response.status_code == 200 assert response.headers["content-type"] == "application/json" def test_cors_and_security_headers(client: TestClient): """Test CORS and basic security considerations""" # Test that endpoints don't expose sensitive information in headers response = client.get("/api/v1/health") assert response.status_code == 200 # Should not expose server information assert "server" not in response.headers or "FastAPI" not in response.headers.get("server", "") def test_openapi_documentation(client: TestClient): """Test that OpenAPI documentation is accessible""" # OpenAPI JSON should be accessible response = client.get("/api/v1/openapi.json") assert response.status_code == 200 openapi_spec = response.json() assert "openapi" in openapi_spec assert "info" in openapi_spec assert "paths" in openapi_spec # Check that main endpoints are documented paths = openapi_spec["paths"] assert "/api/v1/health" in paths assert "/api/v1/financial/data" in paths assert "/api/v1/metadata/catalog" in paths def test_rate_limiting_headers(client: TestClient): """Test for rate limiting indicators (if implemented)""" response = client.get("/api/v1/health") assert response.status_code == 200 # Rate limiting headers are optional but good to check # X-RateLimit-* headers would be present if rate limiting is implemented # This test just ensures we don't break if they're added later def test_api_versioning(client: TestClient): """Test API versioning is properly implemented""" # All endpoints should be under /api/v1 response = client.get("/api/v1/health") assert response.status_code == 200 # Root should redirect to docs response = client.get("/", follow_redirects=False) assert response.status_code == 307 # Redirect assert "api/v1" in response.headers.get("location", "")