Files
musicseerr/backend/tests/routes/test_search_routes.py
T
Harvey a69a26852e Cut down unnecessary logging (#48)
* Cut down unnecessary logging

* fix format etc

* fix checks

* fix tests
2026-04-14 00:02:38 +01:00

136 lines
4.6 KiB
Python

import pytest
from unittest.mock import AsyncMock, MagicMock
from fastapi import FastAPI
from fastapi.testclient import TestClient
from api.v1.schemas.search import SuggestResponse, SuggestResult, SearchResponse, SearchResult
from api.v1.routes.search import router
from core.dependencies import get_search_service, get_coverart_repository, get_search_enrichment_service
@pytest.fixture
def mock_search_service():
mock_svc = MagicMock()
mock_svc.suggest = AsyncMock(return_value=SuggestResponse(results=[]))
return mock_svc
@pytest.fixture
def client(mock_search_service):
test_app = FastAPI()
test_app.include_router(router)
test_app.dependency_overrides[get_search_service] = lambda: mock_search_service
return TestClient(test_app)
def test_suggest_rejects_single_char_query(client, mock_search_service):
response = client.get("/search/suggest?q=a")
assert response.status_code == 422
mock_search_service.suggest.assert_not_called()
def test_suggest_rejects_empty_query(client, mock_search_service):
response = client.get("/search/suggest?q=")
assert response.status_code == 422
mock_search_service.suggest.assert_not_called()
def test_suggest_rejects_missing_query(client, mock_search_service):
response = client.get("/search/suggest")
assert response.status_code == 422
mock_search_service.suggest.assert_not_called()
def test_suggest_accepts_two_char_query(client, mock_search_service):
response = client.get("/search/suggest?q=ab")
assert response.status_code == 200
assert response.json() == {"results": []}
def test_suggest_limit_lower_bound(client, mock_search_service):
response = client.get("/search/suggest?q=test&limit=0")
assert response.status_code == 422
def test_suggest_limit_upper_bound(client, mock_search_service):
response = client.get("/search/suggest?q=test&limit=11")
assert response.status_code == 422
def test_suggest_limit_defaults_to_five(client, mock_search_service):
response = client.get("/search/suggest?q=test")
assert response.status_code == 200
mock_search_service.suggest.assert_called_once_with(query="test", limit=5)
def test_suggest_custom_limit(client, mock_search_service):
response = client.get("/search/suggest?q=test&limit=3")
assert response.status_code == 200
mock_search_service.suggest.assert_called_once_with(query="test", limit=3)
def test_suggest_whitespace_padded_short_input_returns_empty(client, mock_search_service):
"""Whitespace-padded query that is < 2 chars after strip returns empty at route level."""
response = client.get("/search/suggest?q=%20%20a%20%20")
assert response.status_code == 200
assert response.json() == {"results": []}
mock_search_service.suggest.assert_not_called()
def test_suggest_whitespace_padded_valid_input_strips(client, mock_search_service):
"""Whitespace-padded query that is >= 2 chars after strip passes stripped value to service."""
response = client.get("/search/suggest?q=%20%20ab%20%20")
assert response.status_code == 200
mock_search_service.suggest.assert_called_once_with(query="ab", limit=5)
def test_search_response_tolerates_additive_score_field():
"""Existing /api/search consumers tolerate the additive score field on SearchResult."""
mock_search_service = MagicMock()
mock_search_service.search = AsyncMock(return_value=SearchResponse(
artists=[
SearchResult(
type="artist", title="Muse", musicbrainz_id="mb-1",
in_library=False, requested=False, score=90,
)
],
albums=[
SearchResult(
type="album", title="Absolution", musicbrainz_id="mb-2",
artist="Muse", in_library=True, requested=False, score=85,
)
],
))
mock_search_service.schedule_cover_prefetch = MagicMock(return_value=[])
mock_coverart = MagicMock()
mock_enrichment = MagicMock()
test_app = FastAPI()
test_app.include_router(router)
test_app.dependency_overrides[get_search_service] = lambda: mock_search_service
test_app.dependency_overrides[get_coverart_repository] = lambda: mock_coverart
test_app.dependency_overrides[get_search_enrichment_service] = lambda: mock_enrichment
search_client = TestClient(test_app)
response = search_client.get("/search?q=muse")
assert response.status_code == 200
data = response.json()
assert "artists" in data
assert "albums" in data
assert data["artists"][0]["score"] == 90
assert data["albums"][0]["score"] == 85
assert data["artists"][0]["title"] == "Muse"