In library rework + Monitored/Unmonitored statuses (#50)
* In library rework + Monitored/Unmonitored statuses * address comments + format
This commit is contained in:
@@ -8,6 +8,10 @@ from infrastructure.cache.disk_cache import DiskMetadataCache
|
||||
from repositories.audiodb_models import AudioDBArtistImages, AudioDBAlbumImages
|
||||
|
||||
|
||||
def _cache_hash(identifier: str) -> str:
|
||||
return hashlib.sha1(f"{DiskMetadataCache._CACHE_VERSION}:{identifier}".encode()).hexdigest()
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_set_album_serializes_msgspec_struct_as_mapping(tmp_path):
|
||||
cache = DiskMetadataCache(base_path=tmp_path)
|
||||
@@ -22,7 +26,7 @@ async def test_set_album_serializes_msgspec_struct_as_mapping(tmp_path):
|
||||
|
||||
await cache.set_album(mbid, album_info, is_monitored=True)
|
||||
|
||||
cache_hash = hashlib.sha1(mbid.encode()).hexdigest()
|
||||
cache_hash = _cache_hash(mbid)
|
||||
cache_file = tmp_path / "persistent" / "albums" / f"{cache_hash}.json"
|
||||
payload = json.loads(cache_file.read_text())
|
||||
|
||||
@@ -39,7 +43,7 @@ async def test_get_album_deletes_corrupt_string_payload(tmp_path):
|
||||
cache = DiskMetadataCache(base_path=tmp_path)
|
||||
mbid = "8e1e9e51-38dc-4df3-8027-a0ada37d4674"
|
||||
|
||||
cache_hash = hashlib.sha1(mbid.encode()).hexdigest()
|
||||
cache_hash = _cache_hash(mbid)
|
||||
cache_file = tmp_path / "persistent" / "albums" / f"{cache_hash}.json"
|
||||
cache_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
cache_file.write_text(json.dumps("AlbumInfo(title='Corrupt')"))
|
||||
@@ -69,7 +73,7 @@ async def test_audiodb_artist_entity_routing(tmp_path):
|
||||
assert result["fanart_url"] == "https://example.com/fanart.jpg"
|
||||
assert result["lookup_source"] == "mbid"
|
||||
|
||||
cache_hash = hashlib.sha1(mbid.encode()).hexdigest()
|
||||
cache_hash = _cache_hash(mbid)
|
||||
data_file = tmp_path / "recent" / "audiodb_artists" / f"{cache_hash}.json"
|
||||
assert data_file.exists()
|
||||
|
||||
@@ -93,7 +97,7 @@ async def test_audiodb_album_entity_routing(tmp_path):
|
||||
assert result["album_back_url"] == "https://example.com/album_back.jpg"
|
||||
assert result["lookup_source"] == "name"
|
||||
|
||||
cache_hash = hashlib.sha1(mbid.encode()).hexdigest()
|
||||
cache_hash = _cache_hash(mbid)
|
||||
persistent_file = tmp_path / "persistent" / "audiodb_albums" / f"{cache_hash}.json"
|
||||
assert persistent_file.exists()
|
||||
|
||||
@@ -160,7 +164,7 @@ async def test_audiodb_monitored_persistent_vs_recent(tmp_path):
|
||||
|
||||
await cache._set_entity("audiodb_artist", mbid, images, is_monitored=True, ttl_seconds=None)
|
||||
|
||||
cache_hash = hashlib.sha1(mbid.encode()).hexdigest()
|
||||
cache_hash = _cache_hash(mbid)
|
||||
persistent_file = tmp_path / "persistent" / "audiodb_artists" / f"{cache_hash}.json"
|
||||
recent_file = tmp_path / "recent" / "audiodb_artists" / f"{cache_hash}.json"
|
||||
assert persistent_file.exists()
|
||||
|
||||
@@ -26,6 +26,7 @@ def _sample_album_data() -> list[dict]:
|
||||
"releaseDate": "2023-01-15",
|
||||
"added": "2023-01-10T12:00:00Z",
|
||||
"images": [],
|
||||
"statistics": {"trackFileCount": 5},
|
||||
"artist": {
|
||||
"artistName": "Artist A",
|
||||
"foreignArtistId": "artist-a-mbid",
|
||||
@@ -39,6 +40,7 @@ def _sample_album_data() -> list[dict]:
|
||||
"releaseDate": "2024-06-01",
|
||||
"added": "2024-06-01T08:00:00Z",
|
||||
"images": [],
|
||||
"statistics": {"trackFileCount": 8},
|
||||
"artist": {
|
||||
"artistName": "Artist B",
|
||||
"foreignArtistId": "artist-b-mbid",
|
||||
@@ -52,6 +54,7 @@ def _sample_album_data() -> list[dict]:
|
||||
"releaseDate": "2020-03-01",
|
||||
"added": "2020-03-01T00:00:00Z",
|
||||
"images": [],
|
||||
"statistics": {"trackFileCount": 3},
|
||||
"artist": {
|
||||
"artistName": "Artist C",
|
||||
"foreignArtistId": "artist-c-mbid",
|
||||
|
||||
@@ -93,7 +93,7 @@ async def test_get_album_basic_info_does_not_use_library_cache_when_lidarr_paylo
|
||||
|
||||
result = await service.get_album_basic_info("8e1e9e51-38dc-4df3-8027-a0ada37d4674")
|
||||
|
||||
assert result.in_library is False
|
||||
assert result.in_library is True
|
||||
library_db.get_album_by_mbid.assert_not_awaited()
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ async def test_get_album_tracks_info_preserves_disc_numbers_from_lidarr():
|
||||
service, lidarr_repo, _ = _make_service()
|
||||
service._get_cached_album_info = AsyncMock(return_value=None)
|
||||
lidarr_repo.is_configured.return_value = True
|
||||
lidarr_repo.get_album_details = AsyncMock(return_value={"id": 42, "monitored": True})
|
||||
lidarr_repo.get_album_details = AsyncMock(return_value={"id": 42, "monitored": True, "statistics": {"trackFileCount": 1}})
|
||||
lidarr_repo.get_album_tracks = AsyncMock(
|
||||
return_value=[
|
||||
{
|
||||
@@ -135,7 +135,7 @@ async def test_get_album_tracks_info_multi_disc_same_track_numbers():
|
||||
service, lidarr_repo, _ = _make_service()
|
||||
service._get_cached_album_info = AsyncMock(return_value=None)
|
||||
lidarr_repo.is_configured.return_value = True
|
||||
lidarr_repo.get_album_details = AsyncMock(return_value={"id": 42, "monitored": True})
|
||||
lidarr_repo.get_album_details = AsyncMock(return_value={"id": 42, "monitored": True, "statistics": {"trackFileCount": 1}})
|
||||
lidarr_repo.get_album_tracks = AsyncMock(
|
||||
return_value=[
|
||||
{"track_number": 1, "disc_number": 1, "title": "Intro", "duration_ms": 1000},
|
||||
|
||||
@@ -42,6 +42,7 @@ def _make_service(*, cached_artist: ArtistInfo | None = None) -> tuple[ArtistSer
|
||||
lidarr_repo.is_configured.return_value = False
|
||||
lidarr_repo.get_library_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_requested_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_artist_mbids = AsyncMock(return_value=set())
|
||||
|
||||
wikidata_repo = AsyncMock()
|
||||
|
||||
@@ -53,6 +53,7 @@ def _make_service(
|
||||
lidarr_repo.get_artist_details = AsyncMock(return_value=lidarr_artist)
|
||||
lidarr_repo.get_library_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_requested_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_artist_mbids = AsyncMock(return_value=set())
|
||||
|
||||
wikidata_repo = AsyncMock()
|
||||
|
||||
@@ -52,6 +52,7 @@ def _search_service(audiodb: MagicMock | None = None) -> SearchService:
|
||||
lidarr_repo = MagicMock()
|
||||
lidarr_repo.get_library_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_queue = AsyncMock(return_value=[])
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
coverart_repo = MagicMock()
|
||||
prefs = MagicMock()
|
||||
prefs.get_preferences.return_value = MagicMock(secondary_types=[])
|
||||
|
||||
@@ -56,6 +56,7 @@ def _search_service(audiodb=None) -> SearchService:
|
||||
lidarr_repo = MagicMock()
|
||||
lidarr_repo.get_library_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_queue = AsyncMock(return_value=[])
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
coverart_repo = MagicMock()
|
||||
prefs = MagicMock()
|
||||
prefs.get_preferences.return_value = MagicMock(secondary_types=[])
|
||||
|
||||
@@ -59,6 +59,8 @@ def _make_service(
|
||||
else:
|
||||
lidarr_repo.get_queue = AsyncMock(return_value=queue_items or [])
|
||||
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
|
||||
coverart_repo = MagicMock()
|
||||
preferences_service = MagicMock()
|
||||
preferences_service.get_preferences.return_value = _make_preferences()
|
||||
@@ -300,6 +302,7 @@ async def test_suggest_deduplication_single_mb_call():
|
||||
lidarr_repo = MagicMock()
|
||||
lidarr_repo.get_library_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_queue = AsyncMock(return_value=[])
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
|
||||
coverart_repo = MagicMock()
|
||||
preferences_service = MagicMock()
|
||||
|
||||
@@ -156,6 +156,7 @@ def _make_search_service(audiodb_service=None) -> SearchService:
|
||||
lidarr_repo = MagicMock()
|
||||
lidarr_repo.get_library_mbids = AsyncMock(return_value=set())
|
||||
lidarr_repo.get_queue = AsyncMock(return_value=[])
|
||||
lidarr_repo.get_monitored_no_files_mbids = AsyncMock(return_value=set())
|
||||
coverart_repo = MagicMock()
|
||||
prefs = MagicMock()
|
||||
prefs.get_preferences.return_value = MagicMock(secondary_types=[])
|
||||
|
||||
@@ -66,7 +66,7 @@ class TestCooldownOnlyOnSuccess:
|
||||
async def test_retry_after_failed_sync_is_not_cooldown_blocked(self):
|
||||
call_count = 0
|
||||
|
||||
async def fail_then_succeed():
|
||||
async def fail_then_succeed(**kwargs):
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
if call_count == 1:
|
||||
@@ -94,7 +94,7 @@ class TestSyncFutureDedup:
|
||||
call_count = 0
|
||||
sync_event = asyncio.Event()
|
||||
|
||||
async def slow_get_library():
|
||||
async def slow_get_library(**kwargs):
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
sync_event.set()
|
||||
@@ -118,7 +118,7 @@ class TestSyncFutureDedup:
|
||||
@pytest.mark.asyncio
|
||||
async def test_concurrent_sync_failure_propagates_to_waiter(self):
|
||||
"""When the producer fails, deduped waiters get the real exception."""
|
||||
async def failing_get_library():
|
||||
async def failing_get_library(**kwargs):
|
||||
await asyncio.sleep(0.05)
|
||||
raise RuntimeError("Lidarr DNS failure")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user