/
/
/
1"""
2Tests for progress being frozen before the push stream is torn down (support#5813).
3
4Pausing a Sendspin group falls back to STOP, and group.stop() can only snapshot
5the live position while the group still has an active stream. See the ordering
6comment in SendspinPlayer.stop() for why cancelling the session first breaks it.
7"""
8
9from __future__ import annotations
10
11from types import SimpleNamespace
12from unittest.mock import AsyncMock, MagicMock
13
14import pytest
15
16from music_assistant.providers.sendspin.player import SendspinPlayer
17
18
19def _player_mock() -> MagicMock:
20 """Create a mock with the real method under test bound to it."""
21 mock = MagicMock()
22 mock.playback_session.cancel = AsyncMock()
23 mock.api.group.stop = AsyncMock()
24 return mock
25
26
27async def test_stop_freezes_progress_while_transport_is_still_live() -> None:
28 """group.stop() must be awaited before the push stream is torn down."""
29 mock = _player_mock()
30 transport = SimpleNamespace(stream_active=True)
31 stream_active_at_freeze: list[bool] = []
32
33 async def group_stop() -> None:
34 stream_active_at_freeze.append(transport.stream_active)
35 transport.stream_active = False
36
37 async def session_cancel(_reason: str) -> None:
38 transport.stream_active = False
39
40 mock.api.group.stop = group_stop
41 mock.playback_session.cancel = session_cancel
42
43 await SendspinPlayer.stop(mock)
44
45 assert stream_active_at_freeze == [True]
46
47
48async def test_stop_still_cancels_the_playback_session() -> None:
49 """Freezing first must not drop the session teardown."""
50 mock = _player_mock()
51
52 await SendspinPlayer.stop(mock)
53
54 mock.playback_session.cancel.assert_awaited_once_with("stop command")
55 mock.api.group.stop.assert_awaited_once()
56
57
58async def test_session_is_cancelled_even_if_the_group_stop_fails() -> None:
59 """A failing group stop must not strand the playback task and its pipelines."""
60 mock = _player_mock()
61 mock.api.group.stop = AsyncMock(side_effect=RuntimeError("transport gone"))
62
63 with pytest.raises(RuntimeError):
64 await SendspinPlayer.stop(mock)
65
66 mock.playback_session.cancel.assert_awaited_once_with("stop command")
67