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 @@
"""Tests for embeddings module."""

View file

@ -0,0 +1,82 @@
"""Pytest fixtures for embeddings tests."""
from unittest.mock import AsyncMock
import pytest
from fastapi.testclient import TestClient
from embeddings.api.app import create_app
from embeddings.api.dependencies import init_concurrency_limiter
from embeddings.client import EmbeddingClient
from embeddings.config import EmbeddingSettings, SettingsCache
from embeddings.schemas import EmbeddingResponse
from embeddings.types import BackendType, EmbeddingData, EmbeddingUsage
@pytest.fixture(autouse=True)
def clear_settings_cache() -> None:
"""Clear settings cache before each test."""
SettingsCache.clear()
@pytest.fixture
def test_settings() -> EmbeddingSettings:
"""Create test settings with mocked values."""
return EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
host="127.0.0.1",
port=54100,
api_tokens=None,
)
@pytest.fixture
def mock_embedding_response() -> EmbeddingResponse:
"""Create a mock embedding response."""
return EmbeddingResponse(
data=[
EmbeddingData(
index=0,
embedding=[0.1, 0.2, 0.3, 0.4, 0.5],
)
],
model="test-model",
usage=EmbeddingUsage(prompt_tokens=5, total_tokens=5),
backend="vllm",
)
@pytest.fixture
def client_with_mock_backend(
test_settings: EmbeddingSettings, mock_embedding_response: EmbeddingResponse
) -> EmbeddingClient:
"""Create an EmbeddingClient with mocked backend."""
SettingsCache.set(test_settings)
client = EmbeddingClient(settings=test_settings)
# Mock the backend's embed method
backend = client.registry.get(BackendType.VLLM)
embeddings = [d.embedding for d in mock_embedding_response.data]
usage = mock_embedding_response.usage
backend.embed = AsyncMock(return_value=(embeddings, usage))
return client
@pytest.fixture
def app_client(test_settings: EmbeddingSettings) -> TestClient:
"""Create a FastAPI TestClient with test settings."""
SettingsCache.set(test_settings)
init_concurrency_limiter(test_settings.max_concurrent_requests)
app = create_app()
app.state.settings = test_settings
app.state.client = EmbeddingClient(settings=test_settings)
return TestClient(app)

View file

@ -0,0 +1,179 @@
"""Tests for configuration module."""
import os
from unittest.mock import patch
import pytest
from pydantic import ValidationError
from embeddings.config import EmbeddingSettings, SettingsCache
class TestEmbeddingSettings:
"""Tests for EmbeddingSettings."""
def test_required_fields(self) -> None:
"""Test that required fields must be provided."""
with pytest.raises(ValidationError):
EmbeddingSettings()
def test_with_required_fields(self) -> None:
"""Test settings with all required fields provided."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
assert settings.default_backend == "vllm"
assert settings.enable_vllm is True
assert settings.enable_llamacpp is False
assert settings.external_url == "http://localhost:54100"
def test_optional_defaults(self) -> None:
"""Test optional fields have sensible defaults."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
assert settings.host == "0.0.0.0"
assert settings.port == 54100
assert settings.request_timeout == 120.0
assert settings.rate_limit_rps == 20.0
assert settings.max_concurrent_requests == 20
def test_env_override(self) -> None:
"""Test environment variable overrides."""
env_vars = {
"EMB_DEFAULT_BACKEND": "llamacpp",
"EMB_ENABLE_VLLM": "false",
"EMB_ENABLE_LLAMACPP": "true",
"EMB_EXTERNAL_URL": "http://example.com",
"EMB_PORT": "14100",
}
with patch.dict(os.environ, env_vars, clear=False):
settings = EmbeddingSettings()
assert settings.default_backend == "llamacpp"
assert settings.enable_vllm is False
assert settings.enable_llamacpp is True
assert settings.port == 14100
def test_vllm_url_default(self) -> None:
"""Test vLLM URL default value."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
assert settings.vllm_base_url == "http://localhost:54101"
def test_llamacpp_url_default(self) -> None:
"""Test llama.cpp URL default value."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
assert settings.llamacpp_base_url == "http://localhost:54110"
def test_api_tokens_parsing(self) -> None:
"""Test API tokens are parsed from comma-separated string."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
api_tokens="token1,token2,token3", # type: ignore[arg-type]
)
assert settings.api_tokens is not None
assert "token1" in settings.api_tokens
assert "token2" in settings.api_tokens
assert "token3" in settings.api_tokens
assert settings.auth_enabled is True
def test_auth_disabled_by_default(self) -> None:
"""Test authentication is disabled when no tokens set."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
assert settings.api_tokens is None
assert settings.auth_enabled is False
class TestSettingsCache:
"""Tests for SettingsCache class."""
def test_set_and_get(self) -> None:
"""Test setting and getting cached settings."""
SettingsCache.clear()
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
SettingsCache.set(settings)
retrieved = SettingsCache.get()
assert retrieved is settings
def test_get_without_set_creates_instance(self) -> None:
"""Test that get() creates instance from environment if not set."""
SettingsCache.clear()
env_vars = {
"EMB_DEFAULT_BACKEND": "vllm",
"EMB_ENABLE_VLLM": "true",
"EMB_ENABLE_LLAMACPP": "false",
"EMB_EXTERNAL_URL": "http://localhost:54100",
}
with patch.dict(os.environ, env_vars, clear=False):
settings = SettingsCache.get()
assert isinstance(settings, EmbeddingSettings)
assert settings.default_backend == "vllm"
def test_cached_returns_same_instance(self) -> None:
"""Test that SettingsCache returns cached instance."""
SettingsCache.clear()
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
SettingsCache.set(settings)
settings1 = SettingsCache.get()
settings2 = SettingsCache.get()
assert settings1 is settings2
def test_clear_removes_cached_instance(self) -> None:
"""Test that clear() removes the cached instance."""
settings = EmbeddingSettings(
default_backend="vllm",
enable_vllm=True,
enable_llamacpp=False,
external_url="http://localhost:54100",
)
SettingsCache.set(settings)
SettingsCache.clear()
assert SettingsCache._instance is None

View file

@ -0,0 +1,124 @@
"""Tests for schemas module."""
import pytest
from pydantic import ValidationError
from embeddings.schemas import (
EmbeddingRequest,
EmbeddingResponse,
encode_embedding_base64,
)
from embeddings.types import BackendType, EmbeddingData, EmbeddingUsage
class TestEmbeddingRequest:
"""Tests for EmbeddingRequest schema."""
def test_single_string_input(self) -> None:
"""Test that single string input is converted to list."""
request = EmbeddingRequest(input="hello", model="test-model")
assert request.input == ["hello"]
def test_list_input(self) -> None:
"""Test list input is preserved."""
request = EmbeddingRequest(input=["hello", "world"], model="test-model")
assert request.input == ["hello", "world"]
def test_empty_input_rejected(self) -> None:
"""Test that empty input is rejected."""
with pytest.raises(ValidationError):
EmbeddingRequest(input=[], model="test-model")
def test_empty_string_in_list_rejected(self) -> None:
"""Test that empty strings in list are rejected."""
with pytest.raises(ValidationError):
EmbeddingRequest(input=["hello", ""], model="test-model")
def test_default_encoding_format(self) -> None:
"""Test default encoding format is float."""
request = EmbeddingRequest(input="hello", model="test-model")
assert request.encoding_format == "float"
def test_base64_encoding_format(self) -> None:
"""Test base64 encoding format."""
request = EmbeddingRequest(
input="hello", model="test-model", encoding_format="base64"
)
assert request.encoding_format == "base64"
def test_backend_override(self) -> None:
"""Test backend override."""
request = EmbeddingRequest(
input="hello", model="test-model", backend=BackendType.LLAMACPP
)
assert request.backend == BackendType.LLAMACPP
def test_dimensions_parameter(self) -> None:
"""Test dimensions parameter."""
request = EmbeddingRequest(input="hello", model="test-model", dimensions=256)
assert request.dimensions == 256
def test_invalid_dimensions(self) -> None:
"""Test that invalid dimensions are rejected."""
with pytest.raises(ValidationError):
EmbeddingRequest(input="hello", model="test-model", dimensions=0)
class TestEmbeddingResponse:
"""Tests for EmbeddingResponse schema."""
def test_creation(self) -> None:
"""Test creating response."""
response = EmbeddingResponse(
data=[EmbeddingData(index=0, embedding=[0.1, 0.2, 0.3])],
model="test-model",
usage=EmbeddingUsage(prompt_tokens=5, total_tokens=5),
backend="vllm",
)
assert response.object == "list"
assert len(response.data) == 1
assert response.model == "test-model"
assert response.backend == "vllm"
def test_multiple_embeddings(self) -> None:
"""Test response with multiple embeddings."""
response = EmbeddingResponse(
data=[
EmbeddingData(index=0, embedding=[0.1, 0.2]),
EmbeddingData(index=1, embedding=[0.3, 0.4]),
],
model="test-model",
usage=EmbeddingUsage(prompt_tokens=10, total_tokens=10),
backend="vllm",
)
assert len(response.data) == 2
assert response.data[0].index == 0
assert response.data[1].index == 1
class TestEncodeEmbeddingBase64:
"""Tests for base64 encoding function."""
def test_encode_simple(self) -> None:
"""Test encoding simple embedding."""
embedding = [1.0, 2.0, 3.0]
encoded = encode_embedding_base64(embedding)
assert isinstance(encoded, str)
# Should be base64 encoded
assert len(encoded) > 0
def test_encode_decode_roundtrip(self) -> None:
"""Test that encoding can be reversed."""
import base64
import struct
embedding = [0.1, 0.2, 0.3, 0.4, 0.5]
encoded = encode_embedding_base64(embedding)
# Decode
decoded_bytes = base64.b64decode(encoded)
decoded = list(struct.unpack(f"<{len(embedding)}f", decoded_bytes))
# Compare with tolerance for float precision
for original, decoded_val in zip(embedding, decoded):
assert abs(original - decoded_val) < 1e-6

View file

@ -0,0 +1,98 @@
"""Tests for types module."""
import pytest
from embeddings.types import BackendType, EmbeddingData, EmbeddingUsage, ModelInfo
class TestBackendType:
"""Tests for BackendType enum."""
def test_vllm_value(self) -> None:
"""Test vLLM backend type value."""
assert BackendType.VLLM.value == "vllm"
def test_llamacpp_value(self) -> None:
"""Test llama.cpp backend type value."""
assert BackendType.LLAMACPP.value == "llamacpp"
def test_from_string(self) -> None:
"""Test creating backend type from string."""
assert BackendType("vllm") == BackendType.VLLM
assert BackendType("llamacpp") == BackendType.LLAMACPP
def test_invalid_backend(self) -> None:
"""Test that invalid backend raises ValueError."""
with pytest.raises(ValueError):
BackendType("invalid")
class TestEmbeddingUsage:
"""Tests for EmbeddingUsage model."""
def test_default_values(self) -> None:
"""Test default values."""
usage = EmbeddingUsage()
assert usage.prompt_tokens == 0
assert usage.total_tokens == 0
def test_with_values(self) -> None:
"""Test with provided values."""
usage = EmbeddingUsage(prompt_tokens=10, total_tokens=10)
assert usage.prompt_tokens == 10
assert usage.total_tokens == 10
class TestEmbeddingData:
"""Tests for EmbeddingData model."""
def test_creation(self) -> None:
"""Test creating embedding data."""
data = EmbeddingData(
index=0,
embedding=[0.1, 0.2, 0.3],
)
assert data.object == "embedding"
assert data.index == 0
assert data.embedding == [0.1, 0.2, 0.3]
def test_forbids_extra_fields(self) -> None:
"""Test that extra fields are forbidden."""
from pydantic import ValidationError
with pytest.raises(ValidationError):
EmbeddingData(
index=0,
embedding=[0.1],
extra_field="not allowed", # type: ignore[call-arg]
)
class TestModelInfo:
"""Tests for ModelInfo model."""
def test_required_fields(self) -> None:
"""Test required fields."""
model = ModelInfo(id="test-model", backend="vllm")
assert model.id == "test-model"
assert model.backend == "vllm"
def test_optional_fields(self) -> None:
"""Test optional fields with defaults."""
model = ModelInfo(id="test-model", backend="vllm")
assert model.loaded is True
assert model.dimensions is None
assert model.max_input_tokens is None
def test_with_all_fields(self) -> None:
"""Test with all fields provided."""
model = ModelInfo(
id="test-model",
backend="vllm",
loaded=False,
dimensions=768,
max_input_tokens=8192,
)
assert model.loaded is False
assert model.dimensions == 768
assert model.max_input_tokens == 8192