soulsync/tests/wishlist/test_service.py
Antti Kettunen b1a9c1b458
Accept wishlist track_data aliases
- Let the wishlist service accept both track_data and spotify_track_data
- Preserve the backward-compatible wrapper while avoiding the keyword argument crash
- Add a regression test for the alias path
2026-04-30 07:59:43 +03:00

324 lines
11 KiB
Python

from types import SimpleNamespace
from core.wishlist.service import WishlistService
class _FakeWishlistDatabase:
def __init__(self, tracks=None, count=None):
self.tracks = list(tracks or [])
self.count = len(self.tracks) if count is None else count
self.add_calls = []
self.track_queries = []
def add_to_wishlist(self, **kwargs):
self.add_calls.append(kwargs)
return True
def get_wishlist_tracks(self, limit=None, profile_id=1):
self.track_queries.append(("get_wishlist_tracks", limit, profile_id))
tracks = list(self.tracks)
return tracks if limit is None else tracks[:limit]
def get_wishlist_count(self, profile_id=1):
self.track_queries.append(("get_wishlist_count", profile_id))
return self.count
def _build_service(fake_db):
service = WishlistService(database_path="test.db")
service._database = fake_db
return service
def test_add_failed_track_from_modal_normalizes_candidates_and_forwards_payload():
fake_db = _FakeWishlistDatabase()
service = _build_service(fake_db)
track_info = {
"failure_reason": "Download cancelled",
"download_index": 4,
"table_index": 4,
"candidates": [
SimpleNamespace(title="Candidate Song", artist="Candidate Artist", filename="track.flac"),
{"title": "kept"},
],
"spotify_track": {
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
},
}
source_context = {"playlist_name": "Playlist One"}
result = service.add_failed_track_from_modal(
track_info,
source_type="playlist",
source_context=source_context,
profile_id=3,
)
assert result is True
assert fake_db.add_calls[0]["spotify_track_data"]["id"] == "sp-1"
assert fake_db.add_calls[0]["failure_reason"] == "Download cancelled"
assert fake_db.add_calls[0]["source_type"] == "playlist"
assert fake_db.add_calls[0]["profile_id"] == 3
assert fake_db.add_calls[0]["source_info"]["playlist_name"] == "Playlist One"
assert fake_db.add_calls[0]["source_info"]["original_modal_data"] == {
"download_index": 4,
"table_index": 4,
"candidates": [
{
"title": "Candidate Song",
"artist": "Candidate Artist",
"filename": "track.flac",
},
{"title": "kept"},
],
}
def test_add_failed_track_from_modal_returns_false_when_no_spotify_track_found():
fake_db = _FakeWishlistDatabase()
service = _build_service(fake_db)
result = service.add_failed_track_from_modal({"track_info": {}}, profile_id=1)
assert result is False
assert fake_db.add_calls == []
def test_add_spotify_track_to_wishlist_accepts_track_data_alias():
fake_db = _FakeWishlistDatabase()
service = _build_service(fake_db)
result = service.add_spotify_track_to_wishlist(
track_data={
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
},
failure_reason="Download failed",
source_type="manual",
profile_id=2,
)
assert result is True
assert fake_db.add_calls[0]["track_data"]["id"] == "sp-1"
assert fake_db.add_calls[0]["failure_reason"] == "Download failed"
assert fake_db.add_calls[0]["source_type"] == "manual"
assert fake_db.add_calls[0]["profile_id"] == 2
def test_get_wishlist_tracks_for_download_formats_modal_shape():
fake_db = _FakeWishlistDatabase(
tracks=[
{
"id": "wl-1",
"spotify_track_id": "sp-1",
"spotify_data": {
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
"duration_ms": 321,
"preview_url": "https://example.test/preview",
"external_urls": {"spotify": "https://open.spotify.com/track/sp-1"},
"popularity": 88,
"track_number": 7,
"disc_number": 2,
},
"failure_reason": "Download failed",
"retry_count": 2,
"date_added": "2024-01-01",
"last_attempted": "2024-01-02",
"source_type": "playlist",
"source_info": {"playlist_name": "Playlist One"},
}
]
)
service = _build_service(fake_db)
formatted_tracks = service.get_wishlist_tracks_for_download(limit=1, profile_id=7)
assert fake_db.track_queries == [("get_wishlist_tracks", 1, 7)]
assert formatted_tracks == [
{
"wishlist_id": "wl-1",
"track_id": "sp-1",
"spotify_track_id": "sp-1",
"track_data": {
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
"duration_ms": 321,
"preview_url": "https://example.test/preview",
"external_urls": {"spotify": "https://open.spotify.com/track/sp-1"},
"popularity": 88,
"track_number": 7,
"disc_number": 2,
},
"track_name": "Song One",
"artist_name": "Artist One",
"album_name": "Album One",
"provider": None,
"spotify_data": {
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
"duration_ms": 321,
"preview_url": "https://example.test/preview",
"external_urls": {"spotify": "https://open.spotify.com/track/sp-1"},
"popularity": 88,
"track_number": 7,
"disc_number": 2,
},
"failure_reason": "Download failed",
"retry_count": 2,
"date_added": "2024-01-01",
"last_attempted": "2024-01-02",
"source_type": "playlist",
"source_info": {"playlist_name": "Playlist One"},
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
"duration_ms": 321,
"preview_url": "https://example.test/preview",
"external_urls": {"spotify": "https://open.spotify.com/track/sp-1"},
"popularity": 88,
"track_number": 7,
"disc_number": 2,
}
]
def test_check_track_in_wishlist_and_find_matching_wishlist_track_handle_id_variants():
fake_db = _FakeWishlistDatabase(
tracks=[
{
"id": "wl-1",
"spotify_track_id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"spotify_data": {
"id": "sp-1",
"name": "Song One",
"artists": [{"name": "Artist One"}],
"album": {"name": "Album One"},
},
"failure_reason": "Download failed",
"retry_count": 1,
"date_added": "2024-01-01",
"last_attempted": None,
"source_type": "playlist",
"source_info": {},
},
{
"id": "sp-2",
"spotify_track_id": "sp-2",
"name": "Song Two",
"artists": ["Artist Two"],
"spotify_data": {
"id": "sp-2",
"name": "Song Two",
"artists": [{"name": "Artist Two"}],
"album": {"name": "Album Two"},
},
"failure_reason": "Download failed",
"retry_count": 1,
"date_added": "2024-01-02",
"last_attempted": None,
"source_type": "manual",
"source_info": {},
},
]
)
service = _build_service(fake_db)
formatted_tracks = service.get_wishlist_tracks_for_download()
assert service.check_track_in_wishlist("sp-1") is True
assert service.check_track_in_wishlist("sp-2") is True
assert service.check_track_in_wishlist("missing") is False
assert service.find_matching_wishlist_track("Song One", "Artist One") == formatted_tracks[0]
assert service.find_matching_wishlist_track("Song Two", "Artist Two") == formatted_tracks[1]
assert service.find_matching_wishlist_track("Missing", "Nobody") is None
def test_get_wishlist_summary_returns_empty_summary_when_count_is_zero():
fake_db = _FakeWishlistDatabase(tracks=[], count=0)
service = _build_service(fake_db)
assert service.get_wishlist_summary(profile_id=2) == {
"total_tracks": 0,
"by_source_type": {},
"recent_failures": [],
}
def test_get_wishlist_summary_groups_by_source_type_and_limits_recent_failures():
fake_db = _FakeWishlistDatabase(
tracks=[
{
"source_type": "playlist",
"failure_reason": "f1",
"retry_count": 1,
"date_added": "2024-01-01",
"spotify_data": {"name": "Song A", "artists": [{"name": "Artist A"}]},
},
{
"source_type": "playlist",
"failure_reason": "f2",
"retry_count": 2,
"date_added": "2024-01-02",
"spotify_data": {"name": "Song B", "artists": ["Artist B"]},
},
{
"source_type": "album",
"failure_reason": "f3",
"retry_count": 3,
"date_added": "2024-01-03",
"spotify_data": {"name": "Song C", "artists": [{"name": "Artist C"}]},
},
{
"source_type": "manual",
"failure_reason": "f4",
"retry_count": 4,
"date_added": "2024-01-04",
"spotify_data": {"name": "Song D", "artists": [{"name": "Artist D"}]},
},
{
"source_type": "manual",
"failure_reason": "f5",
"retry_count": 5,
"date_added": "2024-01-05",
"spotify_data": {"name": "Song E", "artists": [{"name": "Artist E"}]},
},
{
"source_type": "manual",
"failure_reason": "f6",
"retry_count": 6,
"date_added": "2024-01-06",
"spotify_data": {"name": "Song F", "artists": [{"name": "Artist F"}]},
},
]
)
service = _build_service(fake_db)
summary = service.get_wishlist_summary(profile_id=4)
assert summary["total_tracks"] == 6
assert summary["by_source_type"] == {"playlist": 2, "album": 1, "manual": 3}
assert len(summary["recent_failures"]) == 5
assert summary["recent_failures"][0] == {
"name": "Song A",
"artist": "Artist A",
"failure_reason": "f1",
"retry_count": 1,
"date_added": "2024-01-01",
}
assert summary["recent_failures"][1]["artist"] == "Artist B"
assert summary["recent_failures"][-1]["name"] == "Song E"