Livrare LOT 1 - Didi

This commit is contained in:
Dezvoltari Evotech 2026-06-25 14:13:25 -07:00
commit 5380c3fc63
990 changed files with 133308 additions and 0 deletions

View file

@ -0,0 +1,209 @@
"""Tests for FastAPI routes."""
from unittest.mock import AsyncMock, patch
import pytest
from fastapi.testclient import TestClient
from llm_inference.api.app import create_app
from llm_inference.api.dependencies import init_concurrency_limiter
from llm_inference.client import LLMClient
from llm_inference.config import LLMSettings, SettingsCache
from llm_inference.schemas import CompletionResponse
@pytest.fixture
def app_client(test_settings: LLMSettings) -> TestClient:
"""Create a test client with mocked client."""
# Inject test settings into cache BEFORE creating app
SettingsCache.set(test_settings)
# Initialize concurrency limiter for tests
init_concurrency_limiter(test_settings.max_concurrent_completions)
app = create_app()
app.state.settings = test_settings
app.state.client = LLMClient(settings=test_settings)
return TestClient(app)
class TestHealthRoutes:
"""Tests for health check routes."""
def test_health_endpoint(self, app_client: TestClient) -> None:
"""Test /health endpoint."""
response = app_client.get("/health")
assert response.status_code == 200
data = response.json()
assert "status" in data
assert "backends" in data
assert data["status"] in ["healthy", "degraded", "unhealthy"]
def test_ready_endpoint(self, app_client: TestClient) -> None:
"""Test /ready endpoint."""
response = app_client.get("/ready")
assert response.status_code == 200
data = response.json()
assert data["ready"] is True
class TestModelsRoutes:
"""Tests for model management routes."""
def test_list_models(self, app_client: TestClient) -> None:
"""Test GET /v1/models."""
response = app_client.get("/v1/models")
assert response.status_code == 200
data = response.json()
assert "data" in data
assert "object" in data
assert data["object"] == "list"
def test_list_models_with_backend_filter(self, app_client: TestClient) -> None:
"""Test GET /v1/models with backend filter."""
response = app_client.get("/v1/models?backend=litellm")
assert response.status_code == 200
data = response.json()
# All models should be from litellm backend
for model in data["data"]:
assert model["backend"] == "litellm"
def test_list_models_invalid_backend(self, app_client: TestClient) -> None:
"""Test GET /v1/models with invalid backend."""
response = app_client.get("/v1/models?backend=invalid")
assert response.status_code == 400
def test_list_backends(self, app_client: TestClient) -> None:
"""Test GET /v1/backends."""
response = app_client.get("/v1/backends")
assert response.status_code == 200
data = response.json()
assert "backends" in data
assert "litellm" in data["backends"]
class TestCompletionsRoutes:
"""Tests for completion routes."""
def test_chat_completions(
self,
app_client: TestClient,
mock_completion_response: CompletionResponse,
) -> None:
"""Test POST /v1/chat/completions."""
# Mock the client's complete method
with patch.object(
app_client.app.state.client,
"complete",
new_callable=AsyncMock,
return_value=mock_completion_response,
):
response = app_client.post(
"/v1/chat/completions",
json={
"messages": [{"role": "user", "content": "Hello"}],
"model": "gpt-3.5-turbo",
},
)
assert response.status_code == 200
data = response.json()
assert "id" in data
assert "choices" in data
assert "model" in data
def test_chat_completions_with_parameters(
self,
app_client: TestClient,
mock_completion_response: CompletionResponse,
) -> None:
"""Test completion with optional parameters."""
with patch.object(
app_client.app.state.client,
"complete",
new_callable=AsyncMock,
return_value=mock_completion_response,
):
response = app_client.post(
"/v1/chat/completions",
json={
"messages": [{"role": "user", "content": "Hello"}],
"model": "gpt-4",
"temperature": 0.5,
"max_tokens": 100,
"top_p": 0.9,
},
)
assert response.status_code == 200
def test_chat_completions_with_backend_override(
self,
app_client: TestClient,
mock_completion_response: CompletionResponse,
) -> None:
"""Test completion with backend override."""
with patch.object(
app_client.app.state.client,
"complete",
new_callable=AsyncMock,
return_value=mock_completion_response,
):
response = app_client.post(
"/v1/chat/completions",
json={
"messages": [{"role": "user", "content": "Hello"}],
"model": "gpt-3.5-turbo",
"backend": "litellm",
},
)
assert response.status_code == 200
def test_chat_completions_missing_messages(self, app_client: TestClient) -> None:
"""Test completion without messages returns error."""
response = app_client.post(
"/v1/chat/completions",
json={"model": "gpt-3.5-turbo"},
)
assert response.status_code == 422 # Validation error
def test_chat_completions_missing_model(self, app_client: TestClient) -> None:
"""Test completion without model returns error."""
response = app_client.post(
"/v1/chat/completions",
json={"messages": [{"role": "user", "content": "Hello"}]},
)
assert response.status_code == 422 # Validation error
class TestModelLoadRoutes:
"""Tests for model load/unload routes."""
def test_load_model_unsupported_backend(self, app_client: TestClient) -> None:
"""Test loading model on backend that doesn't support it."""
response = app_client.post(
"/v1/models/load",
json={"model": "test-model", "backend": "litellm"},
)
# LiteLLM doesn't support model loading
assert response.status_code == 400
def test_unload_model_unsupported_backend(self, app_client: TestClient) -> None:
"""Test unloading model on backend that doesn't support it."""
response = app_client.post(
"/v1/models/unload",
json={"model": "test-model", "backend": "litellm"},
)
# LiteLLM doesn't support model unloading
assert response.status_code == 400