Spaces:
Sleeping
Sleeping
| """ | |
| Integration tests for FastAPI endpoints. | |
| Mocks src.main.recommender and rec_service so endpoints use fakes without loading models. | |
| """ | |
| from unittest.mock import patch, MagicMock, AsyncMock | |
| import pytest | |
| from fastapi.testclient import TestClient | |
| from src.main import app | |
| def _make_mock_recommender(): | |
| """Create mock recommender with all endpoint needs.""" | |
| mock = MagicMock() | |
| mock.get_recommendations = AsyncMock(return_value=[ | |
| { | |
| "isbn": "123", | |
| "title": "Test Book", | |
| "authors": "Test Author", | |
| "description": "A test book description", | |
| "thumbnail": "test.jpg", | |
| "caption": "Test Book by Test Author", | |
| } | |
| ]) | |
| mock.get_categories.return_value = ["All", "Fiction"] | |
| mock.get_tones.return_value = ["All", "Happy"] | |
| mock.get_similar_books.return_value = [] | |
| mock.vector_db = MagicMock() | |
| return mock | |
| def _make_mock_rec_service(): | |
| """Create mock rec_service for personalized endpoints.""" | |
| mock = MagicMock() | |
| mock.get_recommendations.return_value = [] | |
| mock.get_popular_books.return_value = [] | |
| return mock | |
| def test_health(): | |
| """Health check returns 200 and healthy status.""" | |
| client = TestClient(app) | |
| response = client.get("/health") | |
| assert response.status_code == 200 | |
| assert response.json() == {"status": "healthy"} | |
| def test_recommend_mocked(): | |
| """POST /recommend returns recommendations when recommender is mocked.""" | |
| mock_rec = _make_mock_recommender() | |
| mock_svc = _make_mock_rec_service() | |
| with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc): | |
| client = TestClient(app) | |
| response = client.post( | |
| "/recommend", | |
| json={"query": "a romantic comedy", "category": "All"}, | |
| ) | |
| assert response.status_code == 200 | |
| data = response.json() | |
| assert "recommendations" in data | |
| assert len(data["recommendations"]) > 0 | |
| assert data["recommendations"][0]["isbn"] == "123" | |
| def test_categories_mocked(): | |
| """GET /categories returns category list.""" | |
| mock_rec = _make_mock_recommender() | |
| mock_svc = _make_mock_rec_service() | |
| with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc): | |
| client = TestClient(app) | |
| response = client.get("/categories") | |
| assert response.status_code == 200 | |
| assert "categories" in response.json() | |
| assert "All" in response.json()["categories"] | |
| def test_recommend_empty_query(): | |
| """POST /recommend with empty query returns empty or error.""" | |
| mock_rec = _make_mock_recommender() | |
| mock_rec.get_recommendations = AsyncMock(return_value=[]) | |
| mock_svc = _make_mock_rec_service() | |
| with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc): | |
| client = TestClient(app) | |
| response = client.post( | |
| "/recommend", | |
| json={"query": "", "category": "All"}, | |
| ) | |
| assert response.status_code == 200 | |
| assert response.json()["recommendations"] == [] | |
| def test_similar_books_mocked(): | |
| """GET /api/recommend/similar/{isbn} delegates to recommender.""" | |
| mock_rec = _make_mock_recommender() | |
| mock_rec.get_similar_books.return_value = [ | |
| {"isbn": "456", "title": "Similar Book", "authors": "Author B", "description": "", "thumbnail": ""} | |
| ] | |
| mock_svc = _make_mock_rec_service() | |
| with patch("src.main.recommender", mock_rec), patch("src.main.rec_service", mock_svc): | |
| client = TestClient(app) | |
| response = client.get("/api/recommend/similar/123?k=5") | |
| assert response.status_code == 200 | |
| assert response.json()["recommendations"][0]["isbn"] == "456" | |
| def test_metrics_endpoint(): | |
| """GET /metrics returns Prometheus format.""" | |
| client = TestClient(app) | |
| response = client.get("/metrics") | |
| assert response.status_code == 200 | |
| assert "http_requests_total" in response.text or "HELP" in response.text | |