Files
whisper-local/tests/test_media_mpris.py
T
2026-04-15 18:58:42 +02:00

176 lines
5.1 KiB
Python

"""Tests für MprisController (Linux/MPRIS)."""
import sys
from unittest.mock import AsyncMock, MagicMock
import pytest
pytestmark = pytest.mark.skipif(sys.platform != "linux", reason="MPRIS is Linux-only")
def _make_player(status: str) -> MagicMock:
"""Erzeugt einen gemockten Player-Proxy mit gegebenem PlaybackStatus."""
player = MagicMock()
player.get_playback_status = AsyncMock(return_value=status)
player.call_pause = AsyncMock()
player.call_play = AsyncMock()
return player
@pytest.mark.asyncio
async def test_pause_with_no_players_is_noop(monkeypatch):
from whisper_local.media._mpris import MprisController
controller = MprisController()
monkeypatch.setattr(
controller, "_list_player_names", AsyncMock(return_value=[])
)
monkeypatch.setattr(
controller, "_get_player_interface", AsyncMock()
)
await controller.pause()
assert controller._paused == []
@pytest.mark.asyncio
async def test_pause_pauses_only_playing_players(monkeypatch):
from whisper_local.media._mpris import MprisController
playing = _make_player("Playing")
paused = _make_player("Paused")
async def fake_get_player(name: str):
return {"org.mpris.MediaPlayer2.spotify": playing,
"org.mpris.MediaPlayer2.vlc": paused}[name]
controller = MprisController()
monkeypatch.setattr(
controller,
"_list_player_names",
AsyncMock(return_value=[
"org.mpris.MediaPlayer2.spotify",
"org.mpris.MediaPlayer2.vlc",
]),
)
monkeypatch.setattr(controller, "_get_player_interface", fake_get_player)
await controller.pause()
playing.call_pause.assert_awaited_once()
paused.call_pause.assert_not_awaited()
assert controller._paused == ["org.mpris.MediaPlayer2.spotify"]
@pytest.mark.asyncio
async def test_resume_plays_only_previously_paused(monkeypatch):
from whisper_local.media._mpris import MprisController
spotify = _make_player("Paused")
vlc = _make_player("Paused")
async def fake_get_player(name: str):
return {"org.mpris.MediaPlayer2.spotify": spotify,
"org.mpris.MediaPlayer2.vlc": vlc}[name]
controller = MprisController()
controller._paused = ["org.mpris.MediaPlayer2.spotify"]
monkeypatch.setattr(controller, "_get_player_interface", fake_get_player)
await controller.resume()
spotify.call_play.assert_awaited_once()
vlc.call_play.assert_not_awaited()
assert controller._paused == []
@pytest.mark.asyncio
async def test_resume_with_empty_paused_list_is_noop(monkeypatch):
from whisper_local.media._mpris import MprisController
controller = MprisController()
controller._paused = []
get_player = AsyncMock()
monkeypatch.setattr(controller, "_get_player_interface", get_player)
await controller.resume()
get_player.assert_not_awaited()
@pytest.mark.asyncio
async def test_pause_logs_and_continues_when_single_player_fails(monkeypatch, caplog):
from whisper_local.media._mpris import MprisController
good = _make_player("Playing")
async def fake_get_player(name: str):
if name.endswith("broken"):
raise RuntimeError("player disappeared")
return good
controller = MprisController()
monkeypatch.setattr(
controller,
"_list_player_names",
AsyncMock(return_value=[
"org.mpris.MediaPlayer2.broken",
"org.mpris.MediaPlayer2.good",
]),
)
monkeypatch.setattr(controller, "_get_player_interface", fake_get_player)
with caplog.at_level("WARNING"):
await controller.pause()
good.call_pause.assert_awaited_once()
assert controller._paused == ["org.mpris.MediaPlayer2.good"]
assert any("broken" in r.message for r in caplog.records)
@pytest.mark.asyncio
async def test_resume_logs_and_continues_when_single_player_fails(monkeypatch, caplog):
from whisper_local.media._mpris import MprisController
good = _make_player("Paused")
async def fake_get_player(name: str):
if name.endswith("broken"):
raise RuntimeError("player disappeared")
return good
controller = MprisController()
controller._paused = [
"org.mpris.MediaPlayer2.broken",
"org.mpris.MediaPlayer2.good",
]
monkeypatch.setattr(controller, "_get_player_interface", fake_get_player)
with caplog.at_level("WARNING"):
await controller.resume()
good.call_play.assert_awaited_once()
assert controller._paused == []
assert any("broken" in r.message for r in caplog.records)
@pytest.mark.asyncio
async def test_pause_is_noop_when_bus_unreachable(monkeypatch, caplog):
from whisper_local.media._mpris import MprisController
async def failing_connect(self):
raise RuntimeError("no session bus")
monkeypatch.setattr(
"dbus_next.aio.MessageBus.connect", failing_connect, raising=False
)
controller = MprisController()
with caplog.at_level("WARNING"):
await controller.pause()
assert controller._paused == []
assert any("D-Bus" in r.message or "bus" in r.message.lower()
for r in caplog.records)