import os import tempfile import unittest from uuid import UUID from unittest.mock import patch from fastapi import HTTPException # Importing the API initializes its SQLite schema. Keep this test process isolated # from the real local conversation database. _TEST_DATA_DIR = tempfile.TemporaryDirectory(prefix="sovereignai-api-tests-") os.environ["SOVEREIGNAI_DATA_DIR"] = _TEST_DATA_DIR.name from app.main import app from tests.api_client import authenticated_client class ApiErrorContractTests(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.client = authenticated_client(app) def test_health_response_has_correlation_id(self) -> None: response = self.client.get("/health") self.assertEqual(response.status_code, 200) UUID(response.headers["x-request-id"]) self.assertEqual(response.json()["status"], "ok") def test_not_found_uses_normalized_error_contract(self) -> None: response = self.client.get("/no-such-route") self.assertEqual(response.status_code, 404) self.assertEqual(response.json()["error"]["code"], "not_found") self.assertEqual(response.json()["request_id"], response.headers["x-request-id"]) def test_validation_error_is_normalized_and_does_not_echo_input(self) -> None: sentinel = "sensitive-validation-input" response = self.client.post( "/v1/chat/completions", json={"messages": sentinel} ) self.assertEqual(response.status_code, 422) payload = response.json() self.assertEqual(payload["error"]["code"], "invalid_request") self.assertEqual(payload["request_id"], response.headers["x-request-id"]) self.assertNotIn(sentinel, response.text) self.assertNotIn("input", payload["detail"][0]) def test_upstream_timeout_uses_gateway_timeout_contract(self) -> None: with patch( "app.main.get_completion", side_effect=HTTPException( status_code=504, detail="انتهت مهلة انتظار خادم النموذج المحلي." ), ): response = self.client.post( "/v1/chat/completions", json={"messages": [{"role": "user", "content": "مرحبا"}]}, ) self.assertEqual(response.status_code, 504) self.assertEqual(response.json()["error"]["code"], "upstream_timeout") self.assertEqual(response.json()["request_id"], response.headers["x-request-id"]) def test_model_list_exposes_verified_capabilities(self) -> None: class MetadataProvider: name = "test" default_model = "vision-test" base_url = "http://local" async def list_models(self): return ["vision-test", "unknown-test"] async def describe_models(self, model_names): return { "vision-test": { "verified": True, "capabilities": ["completion", "vision"], }, "unknown-test": {"verified": False, "capabilities": []}, } with patch("app.main.get_model_provider", return_value=MetadataProvider()): response = self.client.get("/v1/models") self.assertEqual(response.status_code, 200) models = {item["id"]: item for item in response.json()["data"]} self.assertEqual(models["vision-test"]["capabilities"], ["completion", "vision"]) self.assertTrue(models["vision-test"]["capabilities_verified"]) self.assertFalse(models["unknown-test"]["capabilities_verified"]) if __name__ == "__main__": unittest.main()