"""Tests for LibraryService._resolve_album_tracks and resolve_tracks_batch.""" from unittest.mock import AsyncMock, MagicMock, patch import pytest from api.v1.schemas.library import TrackResolveRequest, TrackResolveResponse, ResolvedTrack from services.library_service import LibraryService def _item(mbid: str, disc: int = 1, track: int = 1): """Shorthand to build a TrackResolveRequest.Item-like object.""" from api.v1.schemas.library import TrackResolveItem return TrackResolveItem(release_group_mbid=mbid, disc_number=disc, track_number=track) def _make_service( *, local_service=None, jf_service=None, nd_service=None, preferences=None, cache=None, ): lidarr_repo = MagicMock() library_db = MagicMock() memory_cache = cache or MagicMock() disk_cache = MagicMock() prefs = preferences or MagicMock() audiodb_image_service = MagicMock() cover_repo = MagicMock() service = LibraryService( lidarr_repo=lidarr_repo, library_db=library_db, cover_repo=cover_repo, preferences_service=prefs, memory_cache=memory_cache, disk_cache=disk_cache, audiodb_image_service=audiodb_image_service, local_files_service=local_service, jellyfin_library_service=jf_service, navidrome_library_service=nd_service, ) return service @pytest.mark.asyncio async def test_resolve_tracks_batch_empty_items(): service = _make_service() result = await service.resolve_tracks_batch([]) assert isinstance(result, TrackResolveResponse) assert result.items == [] @pytest.mark.asyncio async def test_resolve_tracks_batch_respects_max_items(): service = _make_service() items = [_item(f"mbid-{i}", track=i) for i in range(60)] cache = MagicMock() cache.get = AsyncMock(return_value=None) cache.set = AsyncMock() service._memory_cache = cache local_service = MagicMock() local_match = MagicMock() local_match.found = False local_match.tracks = [] local_service.match_album_by_mbid = AsyncMock(return_value=local_match) service._local_files_service = local_service prefs = MagicMock() prefs.get_navidrome_connection_raw = MagicMock(side_effect=Exception("unconfigured")) prefs.get_jellyfin_connection = MagicMock(side_effect=Exception("unconfigured")) service._preferences_service = prefs result = await service.resolve_tracks_batch(items) assert len(result.items) <= 50 @pytest.mark.asyncio async def test_resolve_tracks_batch_missing_mbid_returns_base(): service = _make_service() items = [_item("", disc=1, track=1)] result = await service.resolve_tracks_batch(items) assert len(result.items) == 1 assert result.items[0].source is None assert result.items[0].stream_url is None @pytest.mark.asyncio async def test_resolve_tracks_batch_uses_cache_hit(): cache = MagicMock() cached_map = {"1:1": ("local", "file-123", "flac", 240.0)} cache.get = AsyncMock(return_value=cached_map) cache.set = AsyncMock() service = _make_service(cache=cache) items = [_item("mbid-abc", disc=1, track=1)] result = await service.resolve_tracks_batch(items) assert len(result.items) == 1 assert result.items[0].source == "local" assert result.items[0].stream_url == "/api/v1/stream/local/file-123" assert result.items[0].format == "flac" assert result.items[0].duration == 240.0