""" Test suite for REST API endpoints using minimal queries. Tests programmatic access functionality with fast, simple requests. """ import json import pytest # Test timeout in seconds TEST_TIMEOUT = 30 class TestRestAPI: """Test REST API endpoints with minimal queries.""" def test_health_check(self, client): """Test the health check endpoint.""" response = client.get("/api/v1/health") assert response.status_code == 200 data = json.loads(response.data) assert data["status"] == "ok" assert "timestamp" in data print("✅ Health check passed") def test_api_documentation(self, authenticated_client): """Test the API documentation endpoint (requires auth).""" response = authenticated_client.get("/api/v1/") assert response.status_code == 200 data = json.loads(response.data) assert data["api_version"] == "v1" assert "endpoints" in data assert len(data["endpoints"]) >= 3 # Should have at least 3 endpoints print("✅ API documentation passed") @pytest.mark.requires_llm def test_quick_summary_minimal(self, authenticated_client): """Test quick summary with minimal query.""" payload = { "query": "Python", "search_tool": "wikipedia", "iterations": 1, "temperature": 0.7, } response = authenticated_client.post( "/api/v1/quick_summary", json=payload, content_type="application/json", ) assert response.status_code == 200 data = json.loads(response.data) # Verify response structure assert "query" in data assert "summary" in data assert "findings" in data assert data["query"] == "Python" assert len(data["summary"]) > 10 # Should have actual content assert isinstance(data["findings"], list) print( f"✅ Quick summary passed - got {len(data['summary'])} chars of summary" ) def test_quick_summary_validation(self, authenticated_client): """Test quick summary endpoint validation.""" # Test missing query response = authenticated_client.post( "/api/v1/quick_summary", json={}, content_type="application/json", ) assert response.status_code == 400 data = json.loads(response.data) assert "error" in data print("✅ Quick summary validation passed") def test_analyze_documents_rejects_inline_documents( self, authenticated_client ): """``/api/v1/analyze_documents`` searches a *named local collection*; it does not accept inline ``documents``. The endpoint validates request-body keys against the real ``analyze_documents`` signature (``web/api.py``) and rejects unknown keys with a clear 400 *before* any LLM call, so this needs no real LLM. Previously this test posted an unsupported ``documents`` key and asserted a 200 with an ``analysis``/``processed_documents`` body that the endpoint never returns (the real shape is ``{summary, documents, collection, document_count}``). """ payload = { "documents": ["Python is a programming language."], "query": "What is Python?", "collection_name": "test_collection", } response = authenticated_client.post( "/api/v1/analyze_documents", json=payload, content_type="application/json", ) # Unsupported "documents" key -> clear 400 (not an opaque 500). assert response.status_code == 400 data = json.loads(response.data) # The rejected key is named *as the offender* (after the colon) — not # merely a substring of "analyze_documents" in the message prefix. offenders = data["error"].split(":", 1)[1] assert "documents" in offenders assert "documents" not in data["allowed_parameters"] assert "max_results" in data["allowed_parameters"] print("✅ Analyze documents rejects inline documents") def test_analyze_documents_validation(self, authenticated_client): """Test analyze documents endpoint validation.""" # Test missing collection_name response = authenticated_client.post( "/api/v1/analyze_documents", json={"query": "test"}, content_type="application/json", ) assert response.status_code == 400 data = json.loads(response.data) assert "error" in data # Test missing query response = authenticated_client.post( "/api/v1/analyze_documents", json={"collection_name": "test"}, content_type="application/json", ) assert response.status_code == 400 data = json.loads(response.data) assert "error" in data print("✅ Analyze documents validation passed") @pytest.mark.requires_llm def test_generate_report_minimal(self, authenticated_client): """Test generate report with minimal input.""" payload = { "query": "AI basics", "research_type": "quick", } response = authenticated_client.post( "/api/v1/generate_report", json=payload, content_type="application/json", ) # This endpoint might not be fully implemented assert response.status_code in [200, 404, 500] if response.status_code == 200: data = json.loads(response.data) assert "report" in data or "research_id" in data print("✅ Generate report passed") else: print("⚠️ Generate report endpoint not fully implemented") def test_generate_report_validation(self, authenticated_client): """Test generate report endpoint validation.""" # Test with empty payload response = authenticated_client.post( "/api/v1/generate_report", json={}, content_type="application/json", ) assert response.status_code == 400 data = json.loads(response.data) assert "error" in data print("✅ Generate report validation passed") def test_error_handling(self, authenticated_client): """Test API error handling.""" # Test non-existent endpoint response = authenticated_client.get("/api/v1/nonexistent") assert response.status_code == 404 # Test invalid JSON response = authenticated_client.post( "/api/v1/quick_summary", data="invalid json", content_type="application/json", ) assert response.status_code in [400, 500] print("✅ Error handling passed")