#!/usr/bin/env python3 """ Comprehensive test suite that tests ALL API endpoints in the codebase. This ensures we have coverage for every single endpoint. """ import json import time import pytest from loguru import logger class TestAllEndpoints: """Comprehensive API test suite using Flask test client.""" def test_all_auth_endpoints(self, authenticated_client): """Test ALL authentication endpoints.""" logger.info("\n=== Testing ALL Authentication Endpoints ===") # Test endpoints endpoints = [ ("GET", "/auth/check", None, 200), ("GET", "/auth/integrity-check", None, 200), ] for method, endpoint, data, expected_status in endpoints: if method == "GET": response = authenticated_client.get(endpoint) else: response = authenticated_client.post( endpoint, json=data, content_type="application/json", ) assert response.status_code == expected_status, ( f"{endpoint} failed: {response.data}" ) logger.info("✅ All Auth endpoints tested") def test_all_settings_endpoints(self, authenticated_client): """Test ALL settings endpoints.""" logger.info("\n=== Testing ALL Settings Endpoints ===") # Basic GET endpoints get_endpoints = [ "/settings/api", "/settings/api/categories", "/settings/api/types", "/settings/api/ui_elements", "/settings/api/available-models", "/settings/api/available-search-engines", "/settings/api/warnings", "/settings/api/ollama-status", "/settings/api/rate-limiting/status", "/settings/api/data-location", ] for endpoint in get_endpoints: response = authenticated_client.get(endpoint) assert response.status_code == 200, ( f"{endpoint} failed: {response.data}" ) # Test bulk get response = authenticated_client.get( "/settings/api/bulk?keys=llm.provider,llm.model" ) assert response.status_code == 200, f"Bulk get failed: {response.data}" # Test setting CRUD (use an allow-listed prefix so the # namespace gate permits creation of this throwaway key). test_key = "llm.endpoint_test_value" test_value = {"value": "test_endpoint_123", "editable": True} # Create/Update response = authenticated_client.put( f"/settings/api/{test_key}", json=test_value, content_type="application/json", ) assert response.status_code in [200, 201], ( f"Create setting failed: {response.data}" ) # Get specific setting data = json.loads(response.data) if isinstance(data, dict) and "setting" in data: actual_key = data["setting"].get("key", test_key) else: actual_key = test_key response = authenticated_client.get(f"/settings/api/{actual_key}") assert response.status_code == 200, ( f"Get setting failed: {response.data}" ) # Delete response = authenticated_client.delete(f"/settings/api/{actual_key}") assert response.status_code in [200, 204, 404], ( f"Delete setting failed: {response.data}" ) # Test rate limiting reset response = authenticated_client.post( "/settings/api/rate-limiting/engines/test/reset" ) assert response.status_code in [200, 404], ( f"Rate limit reset failed: {response.data}" ) # Test cleanup response = authenticated_client.post( "/settings/api/rate-limiting/cleanup" ) assert response.status_code == 200, ( f"Rate limit cleanup failed: {response.data}" ) logger.info("✅ All Settings endpoints tested") def test_all_research_endpoints(self, authenticated_client): """Test ALL research-related endpoints.""" # audit: PUNCHLIST reviewed 2026-05 — issue resolved by prior PR (recommendation: REFACTOR_SPLIT). logger.info("\n=== Testing ALL Research Endpoints ===") # Set up logging. try: logger.level("MILESTONE", no=26, color="") except (TypeError, ValueError): pass # Level already registered # Test history endpoint first response = authenticated_client.get("/history/api") assert response.status_code == 200, ( f"History API failed: {response.data}" ) # Start research via main endpoint research_data = { "query": "Test all endpoints comprehensive", "mode": "quick", "model_provider": "OLLAMA", "model": "llama2", "search_engine": "searxng", "max_results": 5, "time_period": "y", "iterations": 1, "questions_per_iteration": 2, "strategy": "rapid", } # Test /api/start_research endpoint response = authenticated_client.post( "/api/start_research", json=research_data, content_type="application/json", ) assert response.status_code == 200, ( f"Start research failed: {response.data}" ) data = json.loads(response.data) assert "research_id" in data research_id = data["research_id"] # Give it a moment to start time.sleep(0.5) # allow: unmarked-sleep # Test various research endpoints research_endpoints = [ ("GET", f"/api/research/{research_id}", None, 200), ("GET", f"/api/research/{research_id}/status", None, 200), ("GET", f"/research/api/status/{research_id}", None, 200), ("GET", f"/history/status/{research_id}", None, 200), ("GET", f"/history/details/{research_id}", None, 200), ("GET", f"/history/log_count/{research_id}", None, 200), ] for method, endpoint, req_data, expected_status in research_endpoints: if method == "GET": response = authenticated_client.get(endpoint) else: response = authenticated_client.post( endpoint, json=req_data, content_type="application/json", ) # Some endpoints might return 404 if research is still initializing assert response.status_code in [expected_status, 404], ( f"{endpoint} failed: {response.data}" ) # Test research API routes response = authenticated_client.get( "/research/api/settings/current-config" ) assert response.status_code == 200, ( f"Current config failed: {response.data}" ) # Test Ollama checks response = authenticated_client.get("/research/api/check/ollama_status") assert response.status_code == 200, ( f"Ollama status check failed: {response.data}" ) # Terminate research response = authenticated_client.post(f"/api/terminate/{research_id}") assert response.status_code in [200, 400, 404], ( f"Terminate research failed: {response.data}" ) # Test alternate terminate endpoint response = authenticated_client.post( f"/research/api/terminate/{research_id}" ) assert response.status_code in [200, 400, 404], ( f"API terminate research failed: {response.data}" ) logger.info("✅ All Research endpoints tested") return research_id def test_all_metrics_endpoints(self, authenticated_client): """Test ALL metrics endpoints.""" logger.info("\n=== Testing ALL Metrics Endpoints ===") # Basic metrics endpoints metrics_endpoints = [ "/metrics/api/metrics", "/metrics/api/metrics/enhanced", "/metrics/api/pricing", "/metrics/api/cost-analytics", "/metrics/api/star-reviews", "/metrics/api/rate-limiting", "/metrics/api/rate-limiting/current", ] for endpoint in metrics_endpoints: response = authenticated_client.get(endpoint) assert response.status_code == 200, ( f"{endpoint} failed: {response.data}" ) # Test specific model pricing response = authenticated_client.get( "/metrics/api/pricing/gpt-3.5-turbo" ) assert response.status_code in [200, 404], ( f"Model pricing failed: {response.data}" ) # Test cost calculation cost_data = { "model_name": "gpt-3.5-turbo", "prompt_tokens": 1000, "completion_tokens": 500, } response = authenticated_client.post( "/metrics/api/cost-calculation", json=cost_data, content_type="application/json", ) assert response.status_code == 200, ( f"Cost calculation failed: {response.data}" ) logger.info("✅ All Metrics endpoints tested") def test_all_benchmark_endpoints(self, authenticated_client): """Test ALL benchmark endpoints.""" logger.info("\n=== Testing ALL Benchmark Endpoints ===") # Basic benchmark endpoints benchmark_endpoints = [ "/benchmark/api/history", "/benchmark/api/configs", "/benchmark/api/running", "/benchmark/api/search-quality", ] for endpoint in benchmark_endpoints: response = authenticated_client.get(endpoint) assert response.status_code == 200, ( f"{endpoint} failed: {response.data}" ) # Test config validation test_config = { "name": "Test Benchmark Config", "queries": ["test query 1", "test query 2"], "models": ["gpt-3.5-turbo"], "search_engines": ["searxng"], "iterations": 1, } response = authenticated_client.post( "/benchmark/api/validate-config", json=test_config, content_type="application/json", ) assert response.status_code == 200, ( f"Validate config failed: {response.data}" ) # Test simple benchmark start (but don't actually run it) simple_benchmark = { "query": "test benchmark", "models": ["gpt-3.5-turbo"], "search_engines": ["searxng"], } # Note: We won't actually start a benchmark as it's resource intensive # Just verify the endpoint exists response = authenticated_client.post( "/benchmark/api/start-simple", json=simple_benchmark, content_type="application/json", ) # Accept 409 (conflict) if another benchmark is running assert response.status_code in [200, 409, 400], ( f"Start simple benchmark status: {response.status_code}, {response.data}" ) logger.info("✅ All Benchmark endpoints tested") def test_all_history_endpoints(self, authenticated_client): """Test ALL history endpoints.""" logger.info("\n=== Testing ALL History Endpoints ===") # Basic history endpoint response = authenticated_client.get("/history/api") assert response.status_code == 200, ( f"History API failed: {response.data}" ) logger.info("✅ All History endpoints tested") @pytest.mark.requires_llm def test_all_api_v1_endpoints(self, authenticated_client): """Test ALL API v1 endpoints.""" logger.info("\n=== Testing ALL API v1 Endpoints ===") # Health check (doesn't require auth) response = authenticated_client.get("/api/v1/health") assert response.status_code == 200, ( f"Health check failed: {response.data}" ) # API documentation response = authenticated_client.get("/api/v1/") assert response.status_code == 200, f"API docs failed: {response.data}" # Quick summary summary_data = {"query": "What is machine learning?", "max_tokens": 100} response = authenticated_client.post( "/api/v1/quick_summary", json=summary_data, content_type="application/json", ) assert response.status_code in [200, 404, 500], ( f"Quick summary status: {response.status_code}" ) # Generate report report_data = { "query": "Test report generation", "research_type": "comprehensive", } response = authenticated_client.post( "/api/v1/generate_report", json=report_data, content_type="application/json", ) assert response.status_code in [200, 404, 500], ( f"Generate report status: {response.status_code}" ) # Analyze documents. The endpoint searches a named local collection; # it does not accept an inline "documents" key (that now yields a 400). doc_data = { "query": "Summarize this document", "collection_name": "test_collection", } response = authenticated_client.post( "/api/v1/analyze_documents", json=doc_data, content_type="application/json", ) assert response.status_code in [200, 404, 500], ( f"Analyze documents status: {response.status_code}" ) logger.info("✅ All API v1 endpoints tested") def test_miscellaneous_endpoints(self, authenticated_client): """Test miscellaneous endpoints not covered in other categories.""" logger.info("\n=== Testing Miscellaneous Endpoints ===") # Test static file serving response = authenticated_client.get("/static/css/style.css") assert response.status_code in [200, 404], "Static file endpoint failed" # Test favicon response = authenticated_client.get("/favicon.ico") assert response.status_code in [200, 404], "Favicon endpoint failed" # Test pages that should exist page_endpoints = [ "/", # Home page "/history", # History page "/settings", # Settings page "/metrics/", # Metrics dashboard "/benchmark/", # Benchmark dashboard ] for endpoint in page_endpoints: response = authenticated_client.get(endpoint) assert response.status_code == 200, ( f"Page {endpoint} failed with status {response.status_code}" ) logger.info("✅ All miscellaneous endpoints tested") def test_error_handling(self, authenticated_client): """Test error handling for invalid endpoints and methods.""" logger.info("\n=== Testing Error Handling ===") # Test non-existent endpoint response = authenticated_client.get("/api/does-not-exist") assert response.status_code == 404, ( f"Non-existent endpoint should return 404, got {response.status_code}" ) # Test wrong method response = authenticated_client.delete("/auth/check") assert response.status_code in [404, 405], ( f"Wrong method should return 404/405, got {response.status_code}" ) # Test invalid JSON response = authenticated_client.post( "/api/start_research", data="invalid json", content_type="application/json", ) assert response.status_code in [400, 500], ( f"Invalid JSON should return 400/500, got {response.status_code}" ) logger.info("✅ Error handling tested")