""" Тесты API endpoints /similar и /submitted. """ from unittest.mock import AsyncMock, MagicMock import pytest from fastapi.testclient import TestClient from app.main import app @pytest.fixture def mock_rag_service(): """Mock RAGService для тестов API без загрузки модели.""" service = MagicMock() service.is_model_loaded = True service.vector_store.submitted_count = 0 return service @pytest.fixture def client(mock_rag_service): """TestClient с переопределённым RAG сервисом.""" from app.api.routes import get_service def override_get_service(): return mock_rag_service app.dependency_overrides[get_service] = override_get_service # get_rag_service используется при создании сервиса - get_service вызывает get_rag_service # Смотрю routes: get_service возвращает get_rag_service(). Значит override get_service достаточно. with TestClient(app) as c: yield c app.dependency_overrides.clear() def test_similar_endpoint(client, mock_rag_service): """POST /api/v1/similar возвращает похожие посты.""" mock_rag_service.find_similar_posts = AsyncMock( return_value=[ { "similarity": 0.95, "created_at": 1706270000, "post_id": 123, "text": "Похожий пост", "rag_score": 0.85, } ] ) response = client.post( "/api/v1/similar", json={"text": "Текст для поиска", "threshold": 0.9, "hours": 24}, ) assert response.status_code == 200 data = response.json() assert data["similar_count"] == 1 assert len(data["similar_posts"]) == 1 assert data["similar_posts"][0]["similarity"] == 0.95 assert data["similar_posts"][0]["post_id"] == 123 assert data["similar_posts"][0]["text"] == "Похожий пост" assert data["similar_posts"][0]["rag_score"] == 0.85 def test_similar_endpoint_empty(client, mock_rag_service): """POST /api/v1/similar с пустым результатом.""" mock_rag_service.find_similar_posts = AsyncMock(return_value=[]) response = client.post( "/api/v1/similar", json={"text": "Уникальный текст", "threshold": 0.99, "hours": 1}, ) assert response.status_code == 200 assert response.json()["similar_count"] == 0 assert response.json()["similar_posts"] == [] def test_similar_endpoint_default_params(client, mock_rag_service): """POST /api/v1/similar с дефолтными параметрами.""" mock_rag_service.find_similar_posts = AsyncMock(return_value=[]) response = client.post( "/api/v1/similar", json={"text": "Текст"}, ) assert response.status_code == 200 mock_rag_service.find_similar_posts.assert_called_once_with( text="Текст", threshold=0.9, hours=24, ) def test_submitted_endpoint_success(client, mock_rag_service): """POST /api/v1/submitted успешно добавляет пост.""" mock_rag_service.add_submitted_post = AsyncMock(return_value=True) mock_rag_service.vector_store.submitted_count = 5 response = client.post( "/api/v1/submitted", json={"text": "Новый пост", "post_id": 42, "rag_score": 0.8}, ) assert response.status_code == 200 data = response.json() assert data["success"] is True assert "добавлен" in data["message"].lower() assert data["submitted_count"] == 5 mock_rag_service.add_submitted_post.assert_called_once_with( text="Новый пост", post_id=42, rag_score=0.8, ) def test_submitted_endpoint_duplicate(client, mock_rag_service): """POST /api/v1/submitted при дубликате возвращает success=False.""" mock_rag_service.add_submitted_post = AsyncMock(return_value=False) mock_rag_service.vector_store.submitted_count = 10 response = client.post( "/api/v1/submitted", json={"text": "Дубликат поста"}, ) assert response.status_code == 200 data = response.json() assert data["success"] is False assert data["submitted_count"] == 10 def test_submitted_endpoint_optional_fields(client, mock_rag_service): """POST /api/v1/submitted с только текстом (post_id, rag_score опциональны).""" mock_rag_service.add_submitted_post = AsyncMock(return_value=True) mock_rag_service.vector_store.submitted_count = 1 response = client.post( "/api/v1/submitted", json={"text": "Только текст"}, ) assert response.status_code == 200 mock_rag_service.add_submitted_post.assert_called_once_with( text="Только текст", post_id=None, rag_score=None, ) def test_similar_validation_empty_text(client): """POST /api/v1/similar с пустым текстом возвращает 422.""" response = client.post( "/api/v1/similar", json={"text": "", "threshold": 0.9, "hours": 24}, ) assert response.status_code == 422 def test_submitted_validation_empty_text(client): """POST /api/v1/submitted с пустым текстом возвращает 422.""" response = client.post( "/api/v1/submitted", json={"text": ""}, ) assert response.status_code == 422