|
|
|
|
|
"""Basic End-to-End Testing for MVP3 Sprint 5. |
|
|
|
|
|
This module tests basic E2E functionality that should work reliably |
|
|
without complex system dependencies. |
|
|
""" |
|
|
|
|
|
|
|
|
from fastapi.testclient import TestClient |
|
|
|
|
|
from app import app, create_gradio_interface, handle_find_tools |
|
|
|
|
|
|
|
|
class TestBasicE2EFunctionality: |
|
|
"""Test basic end-to-end functionality.""" |
|
|
|
|
|
def test_health_endpoint_basic(self): |
|
|
"""Test basic health endpoint functionality.""" |
|
|
client = TestClient(app) |
|
|
response = client.get("/health") |
|
|
|
|
|
assert response.status_code == 200 |
|
|
data = response.json() |
|
|
assert "status" in data |
|
|
assert "version" in data |
|
|
assert data["status"] == "healthy" |
|
|
assert data["version"] == "0.1.0" |
|
|
|
|
|
def test_gradio_interface_creation_basic(self): |
|
|
"""Test that Gradio interface can be created.""" |
|
|
interface = create_gradio_interface() |
|
|
|
|
|
assert interface is not None |
|
|
|
|
|
assert hasattr(interface, "__class__") |
|
|
|
|
|
def test_handle_find_tools_basic_error_handling(self): |
|
|
"""Test basic error handling in find tools handler.""" |
|
|
|
|
|
result = handle_find_tools("") |
|
|
assert isinstance(result, (dict, tuple)) |
|
|
|
|
|
|
|
|
result = handle_find_tools("test query") |
|
|
assert isinstance(result, (dict, tuple)) |
|
|
|
|
|
def test_api_docs_accessibility(self): |
|
|
"""Test that API documentation is accessible.""" |
|
|
client = TestClient(app) |
|
|
|
|
|
|
|
|
response = client.get("/docs") |
|
|
assert response.status_code == 200 |
|
|
|
|
|
|
|
|
response = client.get("/openapi.json") |
|
|
assert response.status_code == 200 |
|
|
|
|
|
openapi_data = response.json() |
|
|
assert "openapi" in openapi_data |
|
|
assert "info" in openapi_data |
|
|
assert "paths" in openapi_data |
|
|
|
|
|
def test_cors_middleware_present(self): |
|
|
"""Test that CORS middleware is properly configured.""" |
|
|
client = TestClient(app) |
|
|
|
|
|
|
|
|
response = client.options("/health") |
|
|
|
|
|
assert response.status_code in [ |
|
|
200, |
|
|
405, |
|
|
] |
|
|
|
|
|
def test_error_handling_malformed_requests(self): |
|
|
"""Test error handling for malformed requests.""" |
|
|
client = TestClient(app) |
|
|
|
|
|
|
|
|
response = client.post( |
|
|
"/api/plan/generate", |
|
|
data="invalid json", |
|
|
headers={"content-type": "application/json"}, |
|
|
) |
|
|
|
|
|
assert response.status_code in [422, 503] |
|
|
|
|
|
def test_mock_tasks_endpoints(self): |
|
|
"""Test mock task management endpoints.""" |
|
|
client = TestClient(app) |
|
|
|
|
|
|
|
|
response = client.get("/api/tasks") |
|
|
assert response.status_code == 200 |
|
|
|
|
|
data = response.json() |
|
|
assert isinstance(data, list) |
|
|
|
|
|
|
|
|
task_data = { |
|
|
"title": "Test Task", |
|
|
"description": "A test task for E2E testing", |
|
|
"dependencies": [], |
|
|
} |
|
|
response = client.post("/api/tasks", json=task_data) |
|
|
assert response.status_code == 200 |
|
|
|
|
|
created_task = response.json() |
|
|
assert created_task["title"] == task_data["title"] |
|
|
assert created_task["description"] == task_data["description"] |
|
|
|
|
|
def test_gradio_interface_contains_required_elements(self): |
|
|
"""Test that Gradio interface contains expected elements.""" |
|
|
interface = create_gradio_interface() |
|
|
|
|
|
|
|
|
assert interface is not None |
|
|
assert hasattr(interface, "css") |
|
|
|
|
|
|
|
|
css_content = getattr(interface, "css", "") |
|
|
if css_content: |
|
|
|
|
|
assert any( |
|
|
term in css_content |
|
|
for term in ["primary-blue", "success-green", "error-red"] |
|
|
) |
|
|
|
|
|
|
|
|
interface_str = str(interface) |
|
|
assert "Gradio Blocks instance" in interface_str |
|
|
assert "backend functions" in interface_str |
|
|
|
|
|
def test_ui_performance_basic(self): |
|
|
"""Test basic UI performance characteristics.""" |
|
|
import time |
|
|
|
|
|
|
|
|
start_time = time.time() |
|
|
interface = create_gradio_interface() |
|
|
creation_time = time.time() - start_time |
|
|
|
|
|
assert creation_time < 5.0 |
|
|
assert interface is not None |
|
|
|
|
|
def test_find_tools_response_structure(self): |
|
|
"""Test that find_tools returns consistent structure.""" |
|
|
|
|
|
test_queries = [ |
|
|
"sentiment analysis", |
|
|
"", |
|
|
"test", |
|
|
"very specific technical query that probably won't match anything", |
|
|
] |
|
|
|
|
|
for query in test_queries: |
|
|
result = handle_find_tools(query) |
|
|
|
|
|
|
|
|
assert isinstance(result, (dict, tuple)) |
|
|
|
|
|
|
|
|
if isinstance(result, dict): |
|
|
assert "status" in result or len(result) > 0 |
|
|
|
|
|
|
|
|
elif isinstance(result, tuple): |
|
|
assert len(result) in [8, 9] |
|
|
|
|
|
|
|
|
class TestBasicE2EIntegration: |
|
|
"""Test basic integration scenarios.""" |
|
|
|
|
|
def test_api_and_ui_consistency(self): |
|
|
"""Test consistency between API and UI responses.""" |
|
|
|
|
|
|
|
|
|
|
|
ui_result = handle_find_tools("test query") |
|
|
assert isinstance(ui_result, (dict, tuple)) |
|
|
|
|
|
|
|
|
client = TestClient(app) |
|
|
response = client.get("/health") |
|
|
assert response.status_code == 200 |
|
|
|
|
|
def test_error_propagation(self): |
|
|
"""Test that errors are properly propagated.""" |
|
|
|
|
|
test_cases = [ |
|
|
None, |
|
|
"", |
|
|
"x" * 10000, |
|
|
] |
|
|
|
|
|
for case in test_cases: |
|
|
try: |
|
|
if case is None: |
|
|
|
|
|
continue |
|
|
result = handle_find_tools(case) |
|
|
|
|
|
assert result is not None |
|
|
except Exception as e: |
|
|
|
|
|
assert isinstance(e, (ValueError, TypeError, AttributeError)) |
|
|
|
|
|
def test_system_resilience(self): |
|
|
"""Test system resilience under basic stress.""" |
|
|
|
|
|
for i in range(10): |
|
|
result = handle_find_tools(f"test query {i}") |
|
|
assert result is not None |
|
|
|
|
|
def test_configuration_validation(self): |
|
|
"""Test that basic configuration is valid.""" |
|
|
import os |
|
|
|
|
|
|
|
|
|
|
|
log_level = os.getenv("LOG_LEVEL", "INFO") |
|
|
assert log_level in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] |
|
|
|
|
|
app_env = os.getenv("APP_ENV", "development") |
|
|
assert isinstance(app_env, str) |
|
|
assert len(app_env) > 0 |
|
|
|
|
|
|
|
|
class TestBasicE2EAccessibility: |
|
|
"""Test basic accessibility features.""" |
|
|
|
|
|
def test_gradio_accessibility_basics(self): |
|
|
"""Test basic accessibility in Gradio interface.""" |
|
|
interface = create_gradio_interface() |
|
|
interface_str = str(interface) |
|
|
|
|
|
|
|
|
accessibility_indicators = [ |
|
|
"sr-only", |
|
|
"focus", |
|
|
"outline", |
|
|
"aria", |
|
|
] |
|
|
|
|
|
|
|
|
any( |
|
|
indicator in interface_str.lower() for indicator in accessibility_indicators |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_responsive_design_basics(self): |
|
|
"""Test basic responsive design features.""" |
|
|
interface = create_gradio_interface() |
|
|
|
|
|
|
|
|
css_content = getattr(interface, "css", "") |
|
|
if css_content: |
|
|
responsive_indicators = ["max-width", "@media", "768px", "100%"] |
|
|
|
|
|
responsive_present = any( |
|
|
indicator in css_content for indicator in responsive_indicators |
|
|
) |
|
|
|
|
|
if responsive_present: |
|
|
assert True |
|
|
else: |
|
|
|
|
|
|
|
|
assert True |
|
|
else: |
|
|
|
|
|
assert True |
|
|
|
|
|
|
|
|
class TestBasicE2EReliability: |
|
|
"""Test basic reliability and robustness.""" |
|
|
|
|
|
def test_concurrent_interface_creation(self): |
|
|
"""Test creating multiple interfaces sequentially (Gradio has threading limitations).""" |
|
|
|
|
|
|
|
|
interfaces = [] |
|
|
|
|
|
try: |
|
|
for i in range(3): |
|
|
interface = create_gradio_interface() |
|
|
interfaces.append(interface) |
|
|
assert interface is not None |
|
|
except Exception: |
|
|
|
|
|
pass |
|
|
|
|
|
|
|
|
for interface in interfaces: |
|
|
del interface |
|
|
|
|
|
def test_memory_usage_basic(self): |
|
|
"""Test basic memory usage patterns.""" |
|
|
import gc |
|
|
import os |
|
|
|
|
|
import psutil |
|
|
|
|
|
process = psutil.Process(os.getpid()) |
|
|
initial_memory = process.memory_info().rss / 1024 / 1024 |
|
|
|
|
|
|
|
|
try: |
|
|
for i in range(3): |
|
|
interface = create_gradio_interface() |
|
|
del interface |
|
|
gc.collect() |
|
|
except Exception: |
|
|
|
|
|
|
|
|
pass |
|
|
|
|
|
final_memory = process.memory_info().rss / 1024 / 1024 |
|
|
memory_increase = final_memory - initial_memory |
|
|
|
|
|
|
|
|
assert memory_increase < 200 |
|
|
|
|
|
def test_repeated_operations(self): |
|
|
"""Test repeated operations for consistency.""" |
|
|
query = "test query for consistency" |
|
|
|
|
|
results = [] |
|
|
for _ in range(3): |
|
|
result = handle_find_tools(query) |
|
|
results.append(result) |
|
|
|
|
|
|
|
|
for result in results: |
|
|
assert type(result) == type(results[0]) |
|
|
|
|
|
if isinstance(result, dict): |
|
|
|
|
|
assert set(result.keys()) == set(results[0].keys()) |
|
|
elif isinstance(result, tuple): |
|
|
|
|
|
assert len(result) == len(results[0]) |
|
|
|