/
/
/
1"""Tests for the artists controller."""
2
3from __future__ import annotations
4
5from typing import TYPE_CHECKING
6
7from music_assistant_models.enums import ExternalID, ImageType
8from music_assistant_models.media_items import (
9 Artist,
10 MediaItemImage,
11 ProviderMapping,
12 UniqueList,
13)
14
15from .helpers import create_track
16
17if TYPE_CHECKING:
18 from music_assistant.mass import MusicAssistant
19
20ARTIST_MBID = "aa1b2c3d-1c99-4c1b-b0f1-9f2c1b2a3d44"
21ARTIST_IMAGE = "http://images/artist1.jpg"
22
23
24def _artist_stub() -> Artist:
25 """Return the bare artist providers embed in their track payloads."""
26 return Artist(
27 item_id="track1_artist",
28 provider="spotify_1",
29 name="Test Artist",
30 provider_mappings={
31 ProviderMapping(
32 item_id="track1_artist",
33 provider_domain="spotify",
34 provider_instance="spotify_1",
35 )
36 },
37 )
38
39
40def _detailed_artist() -> Artist:
41 """Return an artist carrying the details only a full provider fetch delivers."""
42 artist = _artist_stub()
43 artist.external_ids = {(ExternalID.MB_ARTIST, ARTIST_MBID)}
44 artist.metadata.description = "A biography"
45 artist.metadata.genres = {"rock"}
46 artist.metadata.images = UniqueList(
47 [MediaItemImage(type=ImageType.THUMB, path=ARTIST_IMAGE, provider="spotify_1")]
48 )
49 return artist
50
51
52async def test_track_overwrite_keeps_artist_details(mass: MusicAssistant) -> None:
53 """A track update carrying a bare artist stub must not blank that artist's details."""
54 db_artist = await mass.music.artists.add_item_to_library(_detailed_artist())
55 db_track = await mass.music.tracks.add_item_to_library(create_track("spotify_1", "track1"))
56
57 update = create_track("spotify_1", "track1")
58 update.artists = UniqueList([_artist_stub()])
59 await mass.music.tracks.update_item_in_library(db_track.item_id, update, overwrite=True)
60
61 refreshed = await mass.music.artists.get_library_item(db_artist.item_id)
62 assert refreshed.external_ids == {(ExternalID.MB_ARTIST, ARTIST_MBID)}
63 assert refreshed.metadata.description == "A biography"
64 assert refreshed.metadata.genres == {"rock"}
65 assert [image.path for image in refreshed.metadata.images or []] == [ARTIST_IMAGE]
66
67
68async def test_track_overwrite_keeps_other_provider_artist_mapping(mass: MusicAssistant) -> None:
69 """A track update must not unlink its artist from the other providers it matched."""
70 db_artist = await mass.music.artists.add_item_to_library(_artist_stub())
71 await mass.music.artists.add_provider_mappings(
72 db_artist.item_id,
73 [
74 ProviderMapping(
75 item_id="tidal_artist1",
76 provider_domain="tidal",
77 provider_instance="tidal_1",
78 )
79 ],
80 )
81 db_track = await mass.music.tracks.add_item_to_library(create_track("spotify_1", "track1"))
82
83 update = create_track("spotify_1", "track1")
84 update.artists = UniqueList([_artist_stub()])
85 await mass.music.tracks.update_item_in_library(db_track.item_id, update, overwrite=True)
86
87 refreshed = await mass.music.artists.get_library_item(db_artist.item_id)
88 assert {mapping.provider_instance for mapping in refreshed.provider_mappings} == {
89 "spotify_1",
90 "tidal_1",
91 }
92
93
94async def test_overwrite_update_replaces_artist_details(mass: MusicAssistant) -> None:
95 """An overwrite update carrying details still replaces the stored ones."""
96 db_artist = await mass.music.artists.add_item_to_library(_detailed_artist())
97
98 update = _detailed_artist()
99 update.external_ids = {(ExternalID.MB_ARTIST, "11111111-2222-3333-4444-555555555555")}
100 update.metadata.description = "A better biography"
101 update.metadata.images = UniqueList(
102 [MediaItemImage(type=ImageType.THUMB, path="http://images/new.jpg", provider="spotify_1")]
103 )
104 await mass.music.artists.update_item_in_library(db_artist.item_id, update, overwrite=True)
105
106 refreshed = await mass.music.artists.get_library_item(db_artist.item_id)
107 assert refreshed.external_ids == {
108 (ExternalID.MB_ARTIST, "11111111-2222-3333-4444-555555555555")
109 }
110 assert refreshed.metadata.description == "A better biography"
111 assert [image.path for image in refreshed.metadata.images or []] == ["http://images/new.jpg"]
112