| """ |
| Integration tests for key ClarityAI API endpoints. |
| |
| These tests use a lightweight async HTTP client backed by the FastAPI app |
| directly (no real server needed). Heavy ML models are intentionally not |
| loaded during the test run — tests focus on routing, schema validation, and |
| error-handling behaviour. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import pytest |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.asyncio |
| async def test_health_returns_200(client): |
| """Health endpoint must return HTTP 200 with a 'healthy' status.""" |
| resp = await client.get("/api/v1/health") |
| assert resp.status_code == 200 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_health_response_schema(client): |
| """Health response must include all required fields.""" |
| resp = await client.get("/api/v1/health") |
| body = resp.json() |
| required_fields = { |
| "status", "model_version", "uptime_seconds", |
| "loaded_models", "ollama_available", "database", "timestamp", |
| } |
| assert required_fields.issubset(body.keys()) |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_health_status_value(client): |
| """Health endpoint status field must be 'healthy'.""" |
| resp = await client.get("/api/v1/health") |
| assert resp.json()["status"] == "healthy" |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.asyncio |
| async def test_history_returns_200(client): |
| """History endpoint returns 200 even when the database is empty.""" |
| resp = await client.get("/api/v1/history") |
| assert resp.status_code == 200 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_history_response_schema(client): |
| """History response must contain pagination fields.""" |
| resp = await client.get("/api/v1/history") |
| body = resp.json() |
| assert "page" in body |
| assert "limit" in body |
| assert "total" in body |
| assert "results" in body |
| assert isinstance(body["results"], list) |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_history_default_pagination(client): |
| """History endpoint default page is 1.""" |
| resp = await client.get("/api/v1/history") |
| assert resp.json()["page"] == 1 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_history_invalid_page_raises_422(client): |
| """Passing page=0 (below minimum) must return 422 Unprocessable Entity.""" |
| resp = await client.get("/api/v1/history?page=0") |
| assert resp.status_code == 422 |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.asyncio |
| async def test_detect_empty_text_returns_422(client): |
| """Sending an empty text string must return 422.""" |
| resp = await client.post("/api/v1/detect", json={"text": ""}) |
| assert resp.status_code == 422 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_detect_invalid_mode_returns_422(client): |
| """Sending an invalid mode must return 422.""" |
| resp = await client.post( |
| "/api/v1/detect", |
| json={"text": "Some valid text here.", "mode": "invalid_mode"}, |
| ) |
| assert resp.status_code == 422 |
|
|
|
|
| @pytest.mark.asyncio |
| async def test_detect_missing_text_returns_422(client): |
| """Sending a request with no text field must return 422.""" |
| resp = await client.post("/api/v1/detect", json={"mode": "fast"}) |
| assert resp.status_code == 422 |
|
|
|
|
| |
| |
| |
|
|
| @pytest.mark.asyncio |
| async def test_openapi_schema_accessible(client): |
| """OpenAPI JSON schema endpoint must be reachable.""" |
| resp = await client.get("/api/v1/openapi.json") |
| assert resp.status_code == 200 |
| assert "paths" in resp.json() |
|
|