/
/
/
1"""Test Tidal Recommendation Manager."""
2
3from unittest.mock import AsyncMock, Mock, patch
4
5import pytest
6from music_assistant_models.enums import MediaType
7
8from music_assistant.providers.tidal.recommendations import TidalRecommendationManager
9
10
11@pytest.fixture
12def provider_mock() -> Mock:
13 """Return a mock provider."""
14 provider = Mock()
15 provider.domain = "tidal"
16 provider.instance_id = "tidal_instance"
17 provider.auth.user_id = "12345"
18 provider.auth.country_code = "US"
19 provider.api = AsyncMock()
20 provider.logger = Mock()
21
22 # Mock mass
23 provider.mass = Mock()
24 provider.mass.config.get_provider_configs = AsyncMock(return_value=[])
25 provider.mass.metadata.locale = "en_US"
26 provider.mass.cache.set = AsyncMock()
27
28 return provider
29
30
31@pytest.fixture
32def recommendation_manager(provider_mock: Mock) -> TidalRecommendationManager:
33 """Return a TidalRecommendationManager instance."""
34 return TidalRecommendationManager(provider_mock)
35
36
37@pytest.mark.usefixtures("provider_mock")
38async def test_get_recommendations(
39 recommendation_manager: TidalRecommendationManager,
40) -> None:
41 """Test get_recommendations."""
42 # Mock get_page_content to return a mock parser
43 mock_parser = Mock()
44 mock_parser._module_map = [{"title": "Test Module"}]
45 mock_parser.get_module_items.return_value = (
46 [Mock(item_id="rec_1", name="Recommendation 1")],
47 MediaType.PLAYLIST,
48 )
49
50 with patch.object(
51 recommendation_manager, "get_page_content", new_callable=AsyncMock
52 ) as mock_get_page:
53 mock_get_page.return_value = mock_parser
54
55 recommendations = await recommendation_manager.get_recommendations()
56
57 assert len(recommendations) == 1
58 assert recommendations[0].name == "Test Module"
59 assert len(recommendations[0].items) == 1
60
61 # Should fetch pages
62 assert mock_get_page.call_count >= 1
63
64
65async def test_get_page_content(
66 recommendation_manager: TidalRecommendationManager, provider_mock: Mock
67) -> None:
68 """Test get_page_content."""
69 with patch(
70 "music_assistant.providers.tidal.recommendations.TidalPageParser"
71 ) as mock_parser_cls:
72 # Configure from_cache to be async and return None
73 mock_parser_cls.from_cache = AsyncMock(return_value=None)
74
75 # Configure parser instance
76 mock_parser_instance = mock_parser_cls.return_value
77 mock_parser_instance._module_map = []
78 mock_parser_instance._content_map = {}
79 mock_parser_instance._parsed_at = 1234567890
80 mock_parser_instance.parse_page_structure = Mock() # Ensure it's a synchronous mock
81
82 # Mock API response
83 provider_mock.api.get.return_value = ({"rows": []}, "etag")
84
85 parser = await recommendation_manager.get_page_content("pages/home")
86
87 assert parser == mock_parser_instance
88
89 # Should check cache
90 mock_parser_cls.from_cache.assert_called_with(provider_mock, "pages/home")
91
92 # Should fetch from API
93 provider_mock.api.get.assert_called()
94
95 # Should parse structure
96 mock_parser_instance.parse_page_structure.assert_called()
97
98 # Should cache result
99 provider_mock.mass.cache.set.assert_called()
100