Files
musicseerr/backend/tests/routes/test_discover_queue_routes.py
T
2026-04-03 15:53:00 +01:00

180 lines
7.2 KiB
Python

import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from fastapi import FastAPI
from fastapi.testclient import TestClient
from api.v1.schemas.discover import DiscoverQueueResponse, DiscoverQueueItemLight
from api.v1.routes.discover import router
from core.dependencies import get_discover_service, get_discover_queue_manager
def _make_queue_response(source: str) -> DiscoverQueueResponse:
return DiscoverQueueResponse(
items=[
DiscoverQueueItemLight(
release_group_mbid="rg-mbid-1",
album_name="Test Album",
artist_name="Test Artist",
artist_mbid="artist-mbid-1",
cover_url="/covers/release-group/rg-mbid-1?size=500",
recommendation_reason=f"From {source}",
in_library=False,
)
],
queue_id="test-queue-id",
)
@pytest.fixture
def mock_discover_service():
mock = AsyncMock()
mock.build_queue = AsyncMock(return_value=_make_queue_response("listenbrainz"))
mock.resolve_source = MagicMock(side_effect=lambda s: s or "listenbrainz")
return mock
@pytest.fixture
def mock_queue_manager():
mock = AsyncMock()
mock.consume_queue = AsyncMock(return_value=None)
mock.build_hydrated_queue = AsyncMock(return_value=_make_queue_response("listenbrainz"))
return mock
@pytest.fixture
def client(mock_discover_service, mock_queue_manager):
app = FastAPI()
app.include_router(router)
app.dependency_overrides[get_discover_service] = lambda: mock_discover_service
app.dependency_overrides[get_discover_queue_manager] = lambda: mock_queue_manager
return TestClient(app)
class TestDiscoverQueueSourceRoute:
def test_queue_passes_source_param_to_service(self, client, mock_discover_service):
resp = client.get("/discover/queue?source=lastfm")
assert resp.status_code == 200
mock_discover_service.build_queue.assert_not_called()
def test_queue_passes_source_param_to_manager(self, client, mock_queue_manager):
resp = client.get("/discover/queue?source=lastfm")
assert resp.status_code == 200
mock_queue_manager.build_hydrated_queue.assert_awaited_once_with("lastfm", None)
def test_queue_passes_listenbrainz_source(self, client, mock_discover_service):
resp = client.get("/discover/queue?source=listenbrainz")
assert resp.status_code == 200
mock_discover_service.build_queue.assert_not_called()
def test_queue_no_source_uses_resolved_source(self, client, mock_discover_service, mock_queue_manager):
resp = client.get("/discover/queue")
assert resp.status_code == 200
mock_queue_manager.build_hydrated_queue.assert_awaited_once_with("listenbrainz", None)
mock_discover_service.resolve_source.assert_called_once_with(None)
def test_queue_respects_count_param(self, client, mock_queue_manager):
resp = client.get("/discover/queue?count=5&source=lastfm")
assert resp.status_code == 200
mock_queue_manager.build_hydrated_queue.assert_awaited_once_with("lastfm", 5)
def test_queue_caps_count_at_20(self, client, mock_queue_manager):
resp = client.get("/discover/queue?count=50")
assert resp.status_code == 200
mock_queue_manager.build_hydrated_queue.assert_awaited_once_with("listenbrainz", 20)
def test_queue_returns_items(self, client, mock_discover_service):
resp = client.get("/discover/queue?source=lastfm")
assert resp.status_code == 200
data = resp.json()
assert "items" in data
assert "queue_id" in data
assert len(data["items"]) == 1
assert data["items"][0]["artist_name"] == "Test Artist"
class TestQueueStatusRoute:
def test_status_returns_ok(self, client, mock_queue_manager):
mock_queue_manager.get_status = MagicMock(
return_value={"status": "idle", "source": "listenbrainz"}
)
resp = client.get("/discover/queue/status?source=listenbrainz")
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "idle"
assert data["source"] == "listenbrainz"
def test_status_defaults_source_via_resolve(self, client, mock_discover_service, mock_queue_manager):
mock_queue_manager.get_status = MagicMock(
return_value={"status": "idle", "source": "listenbrainz"}
)
resp = client.get("/discover/queue/status")
assert resp.status_code == 200
mock_discover_service.resolve_source.assert_called_once_with(None)
def test_status_ready_includes_queue_info(self, client, mock_queue_manager):
mock_queue_manager.get_status = MagicMock(
return_value={
"status": "ready",
"source": "listenbrainz",
"queue_id": "abc",
"item_count": 5,
"built_at": 1000.0,
"stale": False,
}
)
resp = client.get("/discover/queue/status?source=listenbrainz")
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "ready"
assert data["item_count"] == 5
assert data["stale"] is False
class TestQueueGenerateRoute:
def test_generate_triggers_build(self, client, mock_queue_manager):
mock_queue_manager.start_build = AsyncMock(
return_value={"action": "started", "status": "building", "source": "listenbrainz"}
)
resp = client.post(
"/discover/queue/generate",
json={"source": "listenbrainz", "force": False},
)
assert resp.status_code == 200
data = resp.json()
assert data["action"] == "started"
mock_queue_manager.start_build.assert_awaited_once_with("listenbrainz", force=False)
def test_generate_already_building(self, client, mock_queue_manager):
mock_queue_manager.start_build = AsyncMock(
return_value={"action": "already_building", "status": "building", "source": "listenbrainz"}
)
resp = client.post(
"/discover/queue/generate",
json={"source": "listenbrainz", "force": False},
)
assert resp.status_code == 200
assert resp.json()["action"] == "already_building"
def test_generate_force_rebuild(self, client, mock_queue_manager):
mock_queue_manager.start_build = AsyncMock(
return_value={"action": "started", "status": "building", "source": "listenbrainz"}
)
resp = client.post(
"/discover/queue/generate",
json={"source": "listenbrainz", "force": True},
)
assert resp.status_code == 200
mock_queue_manager.start_build.assert_awaited_once_with("listenbrainz", force=True)
def test_generate_defaults_source(self, client, mock_discover_service, mock_queue_manager):
mock_queue_manager.start_build = AsyncMock(
return_value={"action": "started", "status": "building", "source": "listenbrainz"}
)
resp = client.post(
"/discover/queue/generate",
json={"force": False},
)
assert resp.status_code == 200
mock_discover_service.resolve_source.assert_called_once_with(None)