2025-12-18 07:37:39 +01:00
|
|
|
|
"""Tests for Pydantic models validation."""
|
|
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
from pydantic import ValidationError
|
|
|
|
|
|
from app.models.auth import LoginRequest, UserResponse, LoginResponse
|
|
|
|
|
|
from app.models.query import QuestionRequest, BenchQueryRequest, BackendQueryRequest, QueryResponse
|
2025-12-25 07:44:52 +01:00
|
|
|
|
from app.models.settings import EnvironmentSettings, EnvironmentSettingsUpdate, UserSettingsUpdate
|
|
|
|
|
|
from app.models.analysis import SessionCreate, SessionUpdate
|
2025-12-18 07:37:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestAuthModels:
|
|
|
|
|
|
"""Tests for authentication models."""
|
|
|
|
|
|
|
|
|
|
|
|
def test_login_request_valid(self):
|
|
|
|
|
|
"""Test valid LoginRequest."""
|
|
|
|
|
|
request = LoginRequest(
|
|
|
|
|
|
login="12345678",
|
|
|
|
|
|
client_ip="192.168.1.1"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert request.login == "12345678"
|
|
|
|
|
|
assert request.client_ip == "192.168.1.1"
|
|
|
|
|
|
|
|
|
|
|
|
def test_login_request_invalid_format(self):
|
|
|
|
|
|
"""Test LoginRequest with invalid login format."""
|
2025-12-18 09:36:24 +01:00
|
|
|
|
|
2025-12-18 07:37:39 +01:00
|
|
|
|
with pytest.raises(ValidationError):
|
|
|
|
|
|
LoginRequest(login="1234567", client_ip="192.168.1.1")
|
|
|
|
|
|
|
2025-12-18 09:36:24 +01:00
|
|
|
|
|
2025-12-18 07:37:39 +01:00
|
|
|
|
with pytest.raises(ValidationError):
|
|
|
|
|
|
LoginRequest(login="abcd1234", client_ip="192.168.1.1")
|
|
|
|
|
|
|
|
|
|
|
|
def test_user_response(self):
|
|
|
|
|
|
"""Test UserResponse model."""
|
|
|
|
|
|
user = UserResponse(
|
|
|
|
|
|
user_id="user-123",
|
|
|
|
|
|
login="12345678",
|
|
|
|
|
|
last_login_at="2024-01-01T00:00:00Z",
|
|
|
|
|
|
created_at="2024-01-01T00:00:00Z"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert user.user_id == "user-123"
|
|
|
|
|
|
assert user.login == "12345678"
|
|
|
|
|
|
|
|
|
|
|
|
def test_login_response(self):
|
|
|
|
|
|
"""Test LoginResponse model."""
|
|
|
|
|
|
user = UserResponse(
|
|
|
|
|
|
user_id="user-123",
|
|
|
|
|
|
login="12345678",
|
|
|
|
|
|
last_login_at="2024-01-01T00:00:00Z",
|
|
|
|
|
|
created_at="2024-01-01T00:00:00Z"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
response = LoginResponse(
|
|
|
|
|
|
access_token="token123",
|
|
|
|
|
|
token_type="bearer",
|
|
|
|
|
|
user=user
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert response.access_token == "token123"
|
|
|
|
|
|
assert response.token_type == "bearer"
|
|
|
|
|
|
assert response.user.user_id == "user-123"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestQueryModels:
|
|
|
|
|
|
"""Tests for query models."""
|
|
|
|
|
|
|
|
|
|
|
|
def test_question_request_valid(self):
|
|
|
|
|
|
"""Test valid QuestionRequest."""
|
|
|
|
|
|
question = QuestionRequest(
|
|
|
|
|
|
body="What is the weather?",
|
|
|
|
|
|
with_docs=True
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert question.body == "What is the weather?"
|
|
|
|
|
|
assert question.with_docs is True
|
|
|
|
|
|
|
|
|
|
|
|
def test_question_request_default_with_docs(self):
|
|
|
|
|
|
"""Test QuestionRequest with default with_docs."""
|
|
|
|
|
|
question = QuestionRequest(body="Test question")
|
|
|
|
|
|
|
2025-12-18 09:36:24 +01:00
|
|
|
|
assert question.with_docs is True
|
2025-12-18 07:37:39 +01:00
|
|
|
|
|
|
|
|
|
|
def test_bench_query_request_valid(self):
|
|
|
|
|
|
"""Test valid BenchQueryRequest."""
|
|
|
|
|
|
request = BenchQueryRequest(
|
|
|
|
|
|
environment="ift",
|
|
|
|
|
|
questions=[
|
|
|
|
|
|
QuestionRequest(body="Q1", with_docs=True),
|
|
|
|
|
|
QuestionRequest(body="Q2", with_docs=False)
|
|
|
|
|
|
]
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert request.environment == "ift"
|
|
|
|
|
|
assert len(request.questions) == 2
|
|
|
|
|
|
assert request.questions[0].body == "Q1"
|
|
|
|
|
|
|
|
|
|
|
|
def test_backend_query_request_valid(self):
|
|
|
|
|
|
"""Test valid BackendQueryRequest."""
|
|
|
|
|
|
request = BackendQueryRequest(
|
|
|
|
|
|
environment="psi",
|
|
|
|
|
|
questions=[
|
|
|
|
|
|
QuestionRequest(body="Q1", with_docs=True)
|
|
|
|
|
|
],
|
|
|
|
|
|
reset_session=True
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert request.environment == "psi"
|
|
|
|
|
|
assert len(request.questions) == 1
|
|
|
|
|
|
assert request.reset_session is True
|
|
|
|
|
|
|
|
|
|
|
|
def test_backend_query_request_default_reset(self):
|
|
|
|
|
|
"""Test BackendQueryRequest with default reset_session."""
|
|
|
|
|
|
request = BackendQueryRequest(
|
|
|
|
|
|
environment="prod",
|
|
|
|
|
|
questions=[QuestionRequest(body="Q1")]
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2025-12-18 09:36:24 +01:00
|
|
|
|
assert request.reset_session is True
|
2025-12-18 07:37:39 +01:00
|
|
|
|
|
|
|
|
|
|
def test_query_response(self):
|
|
|
|
|
|
"""Test QueryResponse model."""
|
2025-12-25 07:44:52 +01:00
|
|
|
|
# Test with RagResponseBenchList (parsed from dict)
|
2025-12-18 07:37:39 +01:00
|
|
|
|
response = QueryResponse(
|
|
|
|
|
|
request_id="req-123",
|
|
|
|
|
|
timestamp="2024-01-01T00:00:00Z",
|
|
|
|
|
|
environment="ift",
|
2025-12-25 07:44:52 +01:00
|
|
|
|
response={"answers": []} # Auto-parsed to RagResponseBenchList
|
2025-12-18 07:37:39 +01:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert response.request_id == "req-123"
|
|
|
|
|
|
assert response.environment == "ift"
|
2025-12-25 07:44:52 +01:00
|
|
|
|
# When dict with "answers" is provided, it's parsed as RagResponseBenchList
|
|
|
|
|
|
from app.models.query import RagResponseBenchList
|
|
|
|
|
|
assert isinstance(response.response, RagResponseBenchList)
|
|
|
|
|
|
|
|
|
|
|
|
def test_query_response_with_dict(self):
|
|
|
|
|
|
"""Test QueryResponse model with plain dict (backend mode)."""
|
|
|
|
|
|
# Use dict that doesn't match RagResponseBenchList schema
|
|
|
|
|
|
response = QueryResponse(
|
|
|
|
|
|
request_id="req-456",
|
|
|
|
|
|
timestamp="2024-01-01T00:00:00Z",
|
|
|
|
|
|
environment="psi",
|
|
|
|
|
|
response={"result": "some data", "status": "ok"}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert response.request_id == "req-456"
|
|
|
|
|
|
assert response.environment == "psi"
|
2025-12-18 07:37:39 +01:00
|
|
|
|
assert isinstance(response.response, dict)
|
2025-12-25 07:44:52 +01:00
|
|
|
|
assert response.response["status"] == "ok"
|
2025-12-18 07:37:39 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestSettingsModels:
|
|
|
|
|
|
"""Tests for settings models."""
|
|
|
|
|
|
|
|
|
|
|
|
def test_environment_settings_valid(self):
|
|
|
|
|
|
"""Test valid EnvironmentSettings."""
|
|
|
|
|
|
settings = EnvironmentSettings(
|
|
|
|
|
|
apiMode="bench",
|
|
|
|
|
|
bearerToken="token123",
|
|
|
|
|
|
systemPlatform="platform",
|
|
|
|
|
|
systemPlatformUser="user",
|
|
|
|
|
|
platformUserId="user-123",
|
|
|
|
|
|
platformId="platform-123",
|
|
|
|
|
|
withClassify=True,
|
|
|
|
|
|
resetSessionMode=False
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert settings.apiMode == "bench"
|
|
|
|
|
|
assert settings.bearerToken == "token123"
|
|
|
|
|
|
assert settings.withClassify is True
|
|
|
|
|
|
assert settings.resetSessionMode is False
|
|
|
|
|
|
|
|
|
|
|
|
def test_environment_settings_defaults(self):
|
2025-12-25 07:44:52 +01:00
|
|
|
|
"""Test EnvironmentSettings with default values (nullable fields)."""
|
|
|
|
|
|
settings = EnvironmentSettings()
|
2025-12-18 07:37:39 +01:00
|
|
|
|
|
2025-12-25 07:44:52 +01:00
|
|
|
|
assert settings.apiMode == "bench"
|
|
|
|
|
|
assert settings.bearerToken is None
|
|
|
|
|
|
assert settings.systemPlatform is None
|
|
|
|
|
|
assert settings.systemPlatformUser is None
|
|
|
|
|
|
assert settings.platformUserId is None
|
|
|
|
|
|
assert settings.platformId is None
|
2025-12-18 07:37:39 +01:00
|
|
|
|
assert settings.withClassify is False
|
|
|
|
|
|
assert settings.resetSessionMode is True
|
|
|
|
|
|
|
2025-12-25 07:44:52 +01:00
|
|
|
|
def test_environment_settings_nullable_fields(self):
|
|
|
|
|
|
"""Test EnvironmentSettings with explicit None values."""
|
|
|
|
|
|
settings = EnvironmentSettings(
|
|
|
|
|
|
apiMode="backend",
|
|
|
|
|
|
bearerToken=None,
|
|
|
|
|
|
systemPlatform=None,
|
|
|
|
|
|
withClassify=True
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert settings.apiMode == "backend"
|
|
|
|
|
|
assert settings.bearerToken is None
|
|
|
|
|
|
assert settings.systemPlatform is None
|
|
|
|
|
|
assert settings.withClassify is True
|
|
|
|
|
|
|
|
|
|
|
|
def test_environment_settings_update_partial(self):
|
|
|
|
|
|
"""Test EnvironmentSettingsUpdate for partial updates."""
|
|
|
|
|
|
update = EnvironmentSettingsUpdate(
|
|
|
|
|
|
bearerToken="new-token",
|
|
|
|
|
|
withClassify=True
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert update.bearerToken == "new-token"
|
|
|
|
|
|
assert update.withClassify is True
|
|
|
|
|
|
assert update.apiMode is None # Not provided, should be None
|
|
|
|
|
|
assert update.systemPlatform is None
|
|
|
|
|
|
|
|
|
|
|
|
def test_environment_settings_update_all_none(self):
|
|
|
|
|
|
"""Test EnvironmentSettingsUpdate with all fields as None."""
|
|
|
|
|
|
update = EnvironmentSettingsUpdate()
|
|
|
|
|
|
|
|
|
|
|
|
assert update.apiMode is None
|
|
|
|
|
|
assert update.bearerToken is None
|
|
|
|
|
|
assert update.systemPlatform is None
|
|
|
|
|
|
assert update.withClassify is None
|
|
|
|
|
|
|
2025-12-18 07:37:39 +01:00
|
|
|
|
def test_user_settings_update(self):
|
2025-12-25 07:44:52 +01:00
|
|
|
|
"""Test UserSettingsUpdate model with partial updates."""
|
2025-12-18 07:37:39 +01:00
|
|
|
|
update = UserSettingsUpdate(
|
|
|
|
|
|
settings={
|
2025-12-25 07:44:52 +01:00
|
|
|
|
"ift": EnvironmentSettingsUpdate(apiMode="bench", withClassify=True),
|
|
|
|
|
|
"psi": EnvironmentSettingsUpdate(bearerToken="token123")
|
2025-12-18 07:37:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert "ift" in update.settings
|
|
|
|
|
|
assert "psi" in update.settings
|
|
|
|
|
|
assert update.settings["ift"].apiMode == "bench"
|
2025-12-25 07:44:52 +01:00
|
|
|
|
assert update.settings["ift"].withClassify is True
|
|
|
|
|
|
assert update.settings["psi"].bearerToken == "token123"
|
|
|
|
|
|
assert update.settings["psi"].apiMode is None # Not provided
|
2025-12-18 07:37:39 +01:00
|
|
|
|
|
|
|
|
|
|
def test_user_settings_update_empty(self):
|
|
|
|
|
|
"""Test UserSettingsUpdate with empty settings."""
|
|
|
|
|
|
update = UserSettingsUpdate(settings={})
|
|
|
|
|
|
|
|
|
|
|
|
assert update.settings == {}
|
2025-12-25 07:44:52 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TestAnalysisModels:
|
|
|
|
|
|
"""Tests for analysis session models."""
|
|
|
|
|
|
|
|
|
|
|
|
def test_session_create_valid(self):
|
|
|
|
|
|
"""Test valid SessionCreate."""
|
|
|
|
|
|
session = SessionCreate(
|
|
|
|
|
|
environment="ift",
|
|
|
|
|
|
api_mode="bench",
|
|
|
|
|
|
request=[{"body": "question 1", "with_docs": True}],
|
|
|
|
|
|
response={"answers": ["answer 1"]},
|
|
|
|
|
|
annotations={"0": {"rating": "correct"}}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert session.environment == "ift"
|
|
|
|
|
|
assert session.api_mode == "bench"
|
|
|
|
|
|
assert len(session.request) == 1
|
|
|
|
|
|
assert session.annotations == {"0": {"rating": "correct"}}
|
|
|
|
|
|
|
|
|
|
|
|
def test_session_create_default_annotations(self):
|
|
|
|
|
|
"""Test SessionCreate with default empty annotations."""
|
|
|
|
|
|
session = SessionCreate(
|
|
|
|
|
|
environment="psi",
|
|
|
|
|
|
api_mode="backend",
|
|
|
|
|
|
request=[],
|
|
|
|
|
|
response={}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert session.annotations == {}
|
|
|
|
|
|
|
|
|
|
|
|
def test_session_update_valid(self):
|
|
|
|
|
|
"""Test valid SessionUpdate."""
|
|
|
|
|
|
update = SessionUpdate(
|
|
|
|
|
|
annotations={
|
|
|
|
|
|
"0": {
|
|
|
|
|
|
"overall": {
|
|
|
|
|
|
"rating": "incorrect",
|
|
|
|
|
|
"comment": "Ответ неполный"
|
|
|
|
|
|
},
|
|
|
|
|
|
"body_research": {
|
|
|
|
|
|
"issues": ["missing_info"],
|
|
|
|
|
|
"comment": "Не указаны процентные ставки"
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"1": {
|
|
|
|
|
|
"overall": {
|
|
|
|
|
|
"rating": "correct",
|
|
|
|
|
|
"comment": "Ответ корректный"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert "0" in update.annotations
|
|
|
|
|
|
assert "1" in update.annotations
|
|
|
|
|
|
assert update.annotations["0"]["overall"]["rating"] == "incorrect"
|
|
|
|
|
|
assert update.annotations["1"]["overall"]["rating"] == "correct"
|
|
|
|
|
|
|
|
|
|
|
|
def test_session_update_empty_annotations(self):
|
|
|
|
|
|
"""Test SessionUpdate with empty annotations."""
|
|
|
|
|
|
update = SessionUpdate(annotations={})
|
|
|
|
|
|
|
|
|
|
|
|
assert update.annotations == {}
|