/
/
/
1"""Unit tests for the Apple Music setup flow helpers."""
2
3from unittest.mock import MagicMock
4
5import pytest
6from aiohttp import ClientError
7
8from music_assistant.providers.apple_music.setup_flow import _app_token_accepted
9
10
11class _FakeRequestCtx:
12 """Minimal async context manager mimicking aiohttp's request context."""
13
14 def __init__(self, status: int) -> None:
15 self._response = MagicMock(status=status)
16
17 async def __aenter__(self) -> MagicMock:
18 return self._response
19
20 async def __aexit__(self, *_exc: object) -> bool:
21 return False
22
23
24def _make_mass(status: int) -> MagicMock:
25 mass = MagicMock()
26 mass.http_session.get = MagicMock(return_value=_FakeRequestCtx(status))
27 return mass
28
29
30@pytest.mark.parametrize(
31 ("status", "expected"),
32 [
33 (200, True),
34 (401, False),
35 (403, False),
36 # a throttled or broken /v1/test says nothing about the token itself
37 (429, None),
38 (500, None),
39 (503, None),
40 ],
41)
42@pytest.mark.asyncio
43async def test_app_token_accepted_per_status(status: int, expected: bool | None) -> None:
44 """Only an explicit rejection by Apple marks the developer token as invalid."""
45 assert await _app_token_accepted(_make_mass(status), "app-token") is expected
46
47
48@pytest.mark.asyncio
49async def test_app_token_accepted_empty_token_is_rejected() -> None:
50 """An empty (e.g. not provisioned) token is rejected without calling the API."""
51 mass = _make_mass(200)
52 assert await _app_token_accepted(mass, "") is False
53 mass.http_session.get.assert_not_called()
54
55
56@pytest.mark.asyncio
57async def test_app_token_accepted_network_error_is_inconclusive() -> None:
58 """An unreachable API does not make a valid token look invalid."""
59 mass = MagicMock()
60 mass.http_session.get = MagicMock(side_effect=ClientError("boom"))
61 assert await _app_token_accepted(mass, "app-token") is None
62