import pytest
from typing import Any
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from perf.services import TestEmbeddingService
from perf.api_simulator import BaseAPISimulator, APIClient, create_api_client
from perf.conftest import model_dimension
class APISimulatorImpl(BaseAPISimulator):
pass
@pytest.fixture
def api_simulator() -> APISimulatorImpl:
return APISimulatorImpl(TestEmbeddingService)
@pytest.fixture
def api_client(api_simulator: APISimulatorImpl) -> APIClient:
return create_api_client(api_simulator)
class TestHealthEndpoint:
def test_health_check_normal(self, api_client: Any):
status_code, response = api_client.get("/health")
assert status_code == 200
assert response["status"] == "healthy"
assert response["service"] == "vecboost"
assert response["version"] == "0.1.0"
assert "timestamp" in response
class TestEmbedEndpoint:
def test_embed_normal_request(self, api_client: Any, model_dimension: int):
status_code, response = api_client.post(
"/api/v1/embed", {"text": "Hello, world! This is a test."}
)
assert status_code == 200
assert "embedding" in response
assert "dimension" in response
assert response["dimension"] == model_dimension
assert len(response["embedding"]) == model_dimension
def test_embed_short_text(self, api_client: Any, short_text: str, model_dimension: int):
status_code, response = api_client.post("/api/v1/embed", {"text": short_text})
assert status_code == 200
assert "embedding" in response
assert "dimension" in response
assert response["dimension"] == model_dimension
assert len(response["embedding"]) == model_dimension
def test_embed_empty_text(self, api_client: Any):
status_code, response = api_client.post("/api/v1/embed", {"text": ""})
assert status_code == 400
assert "error" in response
assert "message" in response
def test_embed_missing_text_field(self, api_client: Any):
status_code, response = api_client.post("/api/v1/embed", {})
assert status_code == 400
assert "error" in response
assert "message" in response
def test_embed_special_characters(
self, api_client: Any, special_char_text: str, model_dimension: int
):
status_code, response = api_client.post(
"/api/v1/embed", {"text": special_char_text}
)
assert status_code == 200
assert "embedding" in response
assert "dimension" in response
assert response["dimension"] == model_dimension
assert len(response["embedding"]) == model_dimension
def test_embed_chinese_text(
self, api_client: Any, chinese_text: str, model_dimension: int
):
status_code, response = api_client.post("/api/v1/embed", {"text": chinese_text})
assert status_code == 200
assert "embedding" in response
assert "dimension" in response
assert response["dimension"] == model_dimension
assert len(response["embedding"]) == model_dimension
def test_embed_long_text(self, api_client: Any, long_text: str, model_dimension: int):
status_code, response = api_client.post("/api/v1/embed", {"text": long_text})
assert status_code == 200
assert "embedding" in response
assert "dimension" in response
assert response["dimension"] == model_dimension
assert len(response["embedding"]) == model_dimension
def test_embed_dimension_consistency(
self, api_client: Any, model_dimension: int
):
texts = ["Short text", "A slightly longer text for testing", "中文测试文本"]
for text in texts:
status_code, response = api_client.post("/api/v1/embed", {"text": text})
assert status_code == 200
assert response["dimension"] == model_dimension
assert len(response["embedding"]) == model_dimension
def test_embed_max_length_text(self, api_client: Any):
max_length_text = "a" * 10000
status_code, response = api_client.post(
"/api/v1/embed", {"text": max_length_text}
)
assert status_code == 200
assert "embedding" in response
assert "dimension" in response
def test_embed_exceeds_max_length(self, api_client: Any):
exceeded_text = "a" * 10001
status_code, response = api_client.post(
"/api/v1/embed", {"text": exceeded_text}
)
assert status_code == 400
assert "error" in response
assert "exceeds" in response.get("message", "").lower()
class TestSimilarityEndpoint:
def test_similarity_identical_texts(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity", {"source": "Hello world", "target": "Hello world"}
)
assert status_code == 200
assert "score" in response
assert "metric" in response
assert response["metric"] == "cosine"
assert abs(response["score"] - 1.0) < 0.001
def test_similarity_different_texts(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity", {"source": "Hello world", "target": "Goodbye world"}
)
assert status_code == 200
assert "score" in response
assert 0.0 <= response["score"] < 1.0
def test_similarity_missing_source(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity", {"source": "", "target": "Some text"}
)
assert status_code == 400
assert "error" in response
assert "message" in response
def test_similarity_missing_target(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity", {"source": "Some text", "target": ""}
)
assert status_code == 400
assert "error" in response
assert "message" in response
def test_similarity_missing_both_fields(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity", {"source": "", "target": ""}
)
assert status_code == 400
assert "error" in response
assert "message" in response
def test_similarity_empty_request_body(self, api_client: Any):
status_code, response = api_client.post("/api/v1/similarity", {})
assert status_code == 400
assert "error" in response
assert "message" in response
def test_similarity_chinese_texts(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity", {"source": "你好世界", "target": "你好中国"}
)
assert status_code == 200
assert "score" in response
assert "metric" in response
assert -1.0 <= response["score"] <= 1.0
def test_similarity_similar_chinese_phrases(self, api_client: Any):
status_code, response = api_client.post(
"/api/v1/similarity",
{
"source": "机器学习是人工智能的子领域",
"target": "机器学习属于人工智能范畴",
},
)
assert status_code == 200
assert "score" in response
assert "metric" in response
assert -1.0 <= response["score"] <= 1.0
def test_similarity_score_range(self, api_client: Any):
test_cases = [
{"source": "Hello", "target": "World"},
{"source": "Same text", "target": "Same text"},
{"source": "Apple fruit", "target": "Banana fruit"},
]
for case in test_cases:
status_code, response = api_client.post("/api/v1/similarity", case)
assert status_code == 200
assert -1.0 <= response["score"] <= 1.0
class TestErrorHandling:
def test_404_not_found(self, api_client: Any):
status_code, response = api_client.post("/api/v1/nonexistent", {})
assert status_code == 404
assert "error" in response
assert "message" in response
def test_405_method_not_allowed(self, api_client: Any):
status_code, response = api_client.get("/api/v1/embed")
assert status_code == 404
assert "error" in response
def test_400_bad_request_empty_body(self, api_client: Any):
status_code, response = api_client.post("/api/v1/embed", None)
assert status_code == 400
assert "error" in response