157 lines
6.4 KiB
Python
157 lines
6.4 KiB
Python
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from repositories.audiodb_models import AudioDBArtistImages, AudioDBAlbumImages
|
|
from services.audiodb_image_service import AudioDBImageService
|
|
|
|
|
|
TEST_MBID = "cc197bad-dc9c-440d-a5b5-d52ba2e14234"
|
|
TEST_ALBUM_MBID = "1dc4c347-a1db-32aa-b14f-bc9cc507b843"
|
|
|
|
|
|
def _make_settings(
|
|
enabled: bool = True,
|
|
name_search_fallback: bool = False,
|
|
) -> MagicMock:
|
|
s = MagicMock()
|
|
s.audiodb_enabled = enabled
|
|
s.audiodb_name_search_fallback = name_search_fallback
|
|
s.cache_ttl_audiodb_found = 604800
|
|
s.cache_ttl_audiodb_not_found = 86400
|
|
s.cache_ttl_audiodb_library = 1209600
|
|
return s
|
|
|
|
|
|
def _make_service(
|
|
settings: MagicMock | None = None,
|
|
disk_cache: AsyncMock | None = None,
|
|
repo: AsyncMock | None = None,
|
|
) -> AudioDBImageService:
|
|
if settings is None:
|
|
settings = _make_settings()
|
|
prefs = MagicMock()
|
|
prefs.get_advanced_settings.return_value = settings
|
|
if disk_cache is None:
|
|
disk_cache = AsyncMock()
|
|
disk_cache.get_audiodb_artist = AsyncMock(return_value=None)
|
|
disk_cache.get_audiodb_album = AsyncMock(return_value=None)
|
|
disk_cache.set_audiodb_artist = AsyncMock()
|
|
disk_cache.set_audiodb_album = AsyncMock()
|
|
if repo is None:
|
|
repo = AsyncMock()
|
|
repo.get_artist_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_artist_by_name = AsyncMock(return_value=None)
|
|
repo.get_album_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_album_by_name = AsyncMock(return_value=None)
|
|
return AudioDBImageService(
|
|
audiodb_repo=repo,
|
|
disk_cache=disk_cache,
|
|
preferences_service=prefs,
|
|
)
|
|
|
|
|
|
class TestNameSearchFallbackGating:
|
|
@pytest.mark.asyncio
|
|
async def test_monitored_artist_always_gets_fallback(self):
|
|
"""Monitored artists get name-search fallback even when setting is False."""
|
|
settings = _make_settings(name_search_fallback=False)
|
|
repo = AsyncMock()
|
|
repo.get_artist_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_artist_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, repo=repo)
|
|
|
|
await svc.fetch_and_cache_artist_images(TEST_MBID, "Coldplay", is_monitored=True)
|
|
|
|
repo.search_artist_by_name.assert_called_once_with("Coldplay")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_non_monitored_artist_no_fallback_when_disabled(self):
|
|
"""Non-monitored artists don't get fallback when setting is False."""
|
|
settings = _make_settings(name_search_fallback=False)
|
|
repo = AsyncMock()
|
|
repo.get_artist_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_artist_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, repo=repo)
|
|
|
|
await svc.fetch_and_cache_artist_images(TEST_MBID, "Coldplay", is_monitored=False)
|
|
|
|
repo.search_artist_by_name.assert_not_called()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_non_monitored_artist_gets_fallback_when_enabled(self):
|
|
"""Non-monitored artists get fallback when setting is True."""
|
|
settings = _make_settings(name_search_fallback=True)
|
|
repo = AsyncMock()
|
|
repo.get_artist_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_artist_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, repo=repo)
|
|
|
|
await svc.fetch_and_cache_artist_images(TEST_MBID, "Coldplay", is_monitored=False)
|
|
|
|
repo.search_artist_by_name.assert_called_once_with("Coldplay")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_monitored_album_always_gets_fallback(self):
|
|
"""Monitored albums get name-search fallback even when setting is False."""
|
|
settings = _make_settings(name_search_fallback=False)
|
|
repo = AsyncMock()
|
|
repo.get_album_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_album_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, repo=repo)
|
|
|
|
await svc.fetch_and_cache_album_images(
|
|
TEST_ALBUM_MBID, artist_name="Coldplay", album_name="Parachutes", is_monitored=True,
|
|
)
|
|
|
|
repo.search_album_by_name.assert_called_once()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_non_monitored_album_no_fallback_when_disabled(self):
|
|
"""Non-monitored albums don't get fallback when setting is False."""
|
|
settings = _make_settings(name_search_fallback=False)
|
|
repo = AsyncMock()
|
|
repo.get_album_by_mbid = AsyncMock(return_value=None)
|
|
repo.search_album_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, repo=repo)
|
|
|
|
await svc.fetch_and_cache_album_images(
|
|
TEST_ALBUM_MBID, artist_name="Coldplay", album_name="Parachutes", is_monitored=False,
|
|
)
|
|
|
|
repo.search_album_by_name.assert_not_called()
|
|
|
|
|
|
class TestNameSearchFallbackWithCachedNegative:
|
|
@pytest.mark.asyncio
|
|
async def test_monitored_retries_with_name_on_mbid_negative(self):
|
|
"""When cached negative is from MBID lookup, monitored items retry with name."""
|
|
settings = _make_settings(name_search_fallback=False)
|
|
negative = AudioDBArtistImages.negative(lookup_source="mbid")
|
|
disk_cache = AsyncMock()
|
|
disk_cache.get_audiodb_artist = AsyncMock(return_value=negative)
|
|
disk_cache.set_audiodb_artist = AsyncMock()
|
|
repo = AsyncMock()
|
|
repo.search_artist_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, disk_cache=disk_cache, repo=repo)
|
|
|
|
await svc.fetch_and_cache_artist_images(TEST_MBID, "Coldplay", is_monitored=True)
|
|
|
|
repo.search_artist_by_name.assert_called_once_with("Coldplay")
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_non_monitored_skips_name_retry_on_mbid_negative(self):
|
|
"""When cached negative is from MBID lookup, non-monitored items skip name retry (setting=False)."""
|
|
settings = _make_settings(name_search_fallback=False)
|
|
negative = AudioDBArtistImages.negative(lookup_source="mbid")
|
|
disk_cache = AsyncMock()
|
|
disk_cache.get_audiodb_artist = AsyncMock(return_value=negative)
|
|
disk_cache.set_audiodb_artist = AsyncMock()
|
|
repo = AsyncMock()
|
|
repo.search_artist_by_name = AsyncMock(return_value=None)
|
|
svc = _make_service(settings=settings, disk_cache=disk_cache, repo=repo)
|
|
|
|
await svc.fetch_and_cache_artist_images(TEST_MBID, "Coldplay", is_monitored=False)
|
|
|
|
repo.search_artist_by_name.assert_not_called()
|