mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 03:07:37 +00:00
Add tests to the media_player platform of the Squeezebox integration (#125378)
* Squeezebox media_player platform tests * Fix play-pause test * Squeezebox remove stray reference to deprecated property * More tests for squeezebox * Update tests to fix merge conflict with binary_sensor * Refactor tests to use autospec * Use freeze and snapshot * Update media player entity before adding * Consolidate test fixtures for different platforms * Merge in sensor platform * Use deepcopy * Update tests with suggestions from code review
This commit is contained in:
parent
0af913cc9a
commit
a01036760e
@ -14,6 +14,7 @@ import voluptuous as vol
|
|||||||
from homeassistant.components import media_source
|
from homeassistant.components import media_source
|
||||||
from homeassistant.components.media_player import (
|
from homeassistant.components.media_player import (
|
||||||
ATTR_MEDIA_ENQUEUE,
|
ATTR_MEDIA_ENQUEUE,
|
||||||
|
BrowseError,
|
||||||
BrowseMedia,
|
BrowseMedia,
|
||||||
MediaPlayerEnqueue,
|
MediaPlayerEnqueue,
|
||||||
MediaPlayerEntity,
|
MediaPlayerEntity,
|
||||||
@ -26,6 +27,7 @@ from homeassistant.components.media_player import (
|
|||||||
from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY
|
from homeassistant.config_entries import SOURCE_INTEGRATION_DISCOVERY
|
||||||
from homeassistant.const import ATTR_COMMAND, CONF_HOST, CONF_PORT
|
from homeassistant.const import ATTR_COMMAND, CONF_HOST, CONF_PORT
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
from homeassistant.helpers import (
|
from homeassistant.helpers import (
|
||||||
config_validation as cv,
|
config_validation as cv,
|
||||||
discovery_flow,
|
discovery_flow,
|
||||||
@ -138,7 +140,7 @@ async def async_setup_entry(
|
|||||||
_LOGGER.debug("Adding new entity: %s", player)
|
_LOGGER.debug("Adding new entity: %s", player)
|
||||||
entity = SqueezeBoxEntity(player, lms)
|
entity = SqueezeBoxEntity(player, lms)
|
||||||
known_players.append(entity)
|
known_players.append(entity)
|
||||||
async_add_entities([entity])
|
async_add_entities([entity], True)
|
||||||
|
|
||||||
if players := await lms.async_get_players():
|
if players := await lms.async_get_players():
|
||||||
for player in players:
|
for player in players:
|
||||||
@ -248,8 +250,11 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
"""Return the state of the device."""
|
"""Return the state of the device."""
|
||||||
if not self._player.power:
|
if not self._player.power:
|
||||||
return MediaPlayerState.OFF
|
return MediaPlayerState.OFF
|
||||||
if self._player.mode:
|
if self._player.mode and self._player.mode in SQUEEZEBOX_MODE:
|
||||||
return SQUEEZEBOX_MODE.get(self._player.mode)
|
return SQUEEZEBOX_MODE[self._player.mode]
|
||||||
|
_LOGGER.error(
|
||||||
|
"Received unknown mode %s from player %s", self._player.mode, self.name
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def async_update(self) -> None:
|
async def async_update(self) -> None:
|
||||||
@ -278,6 +283,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
"""Volume level of the media player (0..1)."""
|
"""Volume level of the media player (0..1)."""
|
||||||
if self._player.volume:
|
if self._player.volume:
|
||||||
return int(float(self._player.volume)) / 100.0
|
return int(float(self._player.volume)) / 100.0
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -322,7 +328,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
@property
|
@property
|
||||||
def media_image_url(self) -> str | None:
|
def media_image_url(self) -> str | None:
|
||||||
"""Image url of current playing media."""
|
"""Image url of current playing media."""
|
||||||
return str(self._player.image_url)
|
return str(self._player.image_url) if self._player.image_url else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def media_title(self) -> str | None:
|
def media_title(self) -> str | None:
|
||||||
@ -371,11 +377,6 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
if player in player_ids
|
if player in player_ids
|
||||||
]
|
]
|
||||||
|
|
||||||
@property
|
|
||||||
def sync_group(self) -> list[str]:
|
|
||||||
"""List players we are synced with. Deprecated."""
|
|
||||||
return self.group_members
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def query_result(self) -> dict | bool:
|
def query_result(self) -> dict | bool:
|
||||||
"""Return the result from the call_query service."""
|
"""Return the result from the call_query service."""
|
||||||
@ -474,7 +475,7 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
"search_type": MediaType.PLAYLIST,
|
"search_type": MediaType.PLAYLIST,
|
||||||
}
|
}
|
||||||
playlist = await generate_playlist(self._player, payload)
|
playlist = await generate_playlist(self._player, payload)
|
||||||
except ValueError:
|
except BrowseError:
|
||||||
# a list of urls
|
# a list of urls
|
||||||
content = json.loads(media_id)
|
content = json.loads(media_id)
|
||||||
playlist = content["urls"]
|
playlist = content["urls"]
|
||||||
@ -553,8 +554,8 @@ class SqueezeBoxEntity(MediaPlayerEntity):
|
|||||||
if other_player_id := player_ids.get(other_player):
|
if other_player_id := player_ids.get(other_player):
|
||||||
await self._player.async_sync(other_player_id)
|
await self._player.async_sync(other_player_id)
|
||||||
else:
|
else:
|
||||||
_LOGGER.debug(
|
raise ServiceValidationError(
|
||||||
"Could not find player_id for %s. Not syncing", other_player
|
f"Could not join unknown player {other_player}"
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_unjoin_player(self) -> None:
|
async def async_unjoin_player(self) -> None:
|
||||||
|
@ -1,85 +1 @@
|
|||||||
"""Tests for the Logitech Squeezebox integration."""
|
"""Tests for the Logitech Squeezebox integration."""
|
||||||
|
|
||||||
from homeassistant.components.squeezebox.const import (
|
|
||||||
DOMAIN,
|
|
||||||
STATUS_QUERY_LIBRARYNAME,
|
|
||||||
STATUS_QUERY_MAC,
|
|
||||||
STATUS_QUERY_UUID,
|
|
||||||
STATUS_QUERY_VERSION,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_ALBUMS,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_ARTISTS,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_DURATION,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_GENRES,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_SONGS,
|
|
||||||
STATUS_SENSOR_LASTSCAN,
|
|
||||||
STATUS_SENSOR_OTHER_PLAYER_COUNT,
|
|
||||||
STATUS_SENSOR_PLAYER_COUNT,
|
|
||||||
STATUS_SENSOR_RESCAN,
|
|
||||||
)
|
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
|
|
||||||
# from homeassistant.setup import async_setup_component
|
|
||||||
from tests.common import MockConfigEntry
|
|
||||||
|
|
||||||
FAKE_IP = "42.42.42.42"
|
|
||||||
FAKE_MAC = "deadbeefdead"
|
|
||||||
FAKE_UUID = "deadbeefdeadbeefbeefdeafbeef42"
|
|
||||||
FAKE_PORT = 9000
|
|
||||||
FAKE_VERSION = "42.0"
|
|
||||||
|
|
||||||
FAKE_QUERY_RESPONSE = {
|
|
||||||
STATUS_QUERY_UUID: FAKE_UUID,
|
|
||||||
STATUS_QUERY_MAC: FAKE_MAC,
|
|
||||||
STATUS_QUERY_VERSION: FAKE_VERSION,
|
|
||||||
STATUS_SENSOR_RESCAN: 1,
|
|
||||||
STATUS_SENSOR_LASTSCAN: 0,
|
|
||||||
STATUS_QUERY_LIBRARYNAME: "FakeLib",
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_ALBUMS: 4,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_ARTISTS: 2,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_DURATION: 500,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_GENRES: 1,
|
|
||||||
STATUS_SENSOR_INFO_TOTAL_SONGS: 42,
|
|
||||||
STATUS_SENSOR_PLAYER_COUNT: 10,
|
|
||||||
STATUS_SENSOR_OTHER_PLAYER_COUNT: 0,
|
|
||||||
"players_loop": [
|
|
||||||
{
|
|
||||||
"isplaying": 0,
|
|
||||||
"name": "SqueezeLite-HA-Addon",
|
|
||||||
"seq_no": 0,
|
|
||||||
"modelname": "SqueezeLite-HA-Addon",
|
|
||||||
"playerindex": "status",
|
|
||||||
"model": "squeezelite",
|
|
||||||
"uuid": FAKE_UUID,
|
|
||||||
"canpoweroff": 1,
|
|
||||||
"ip": "192.168.78.86:57700",
|
|
||||||
"displaytype": "none",
|
|
||||||
"playerid": "f9:23:cd:37:c5:ff",
|
|
||||||
"power": 0,
|
|
||||||
"isplayer": 1,
|
|
||||||
"connected": 1,
|
|
||||||
"firmware": "v2.0.0-1488",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"count": 1,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def setup_mocked_integration(hass: HomeAssistant) -> MockConfigEntry:
|
|
||||||
"""Mock ConfigEntry in Home Assistant."""
|
|
||||||
|
|
||||||
entry = MockConfigEntry(
|
|
||||||
domain=DOMAIN,
|
|
||||||
unique_id=FAKE_UUID,
|
|
||||||
data={
|
|
||||||
CONF_HOST: FAKE_IP,
|
|
||||||
CONF_PORT: FAKE_PORT,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
entry.add_to_hass(hass)
|
|
||||||
|
|
||||||
await hass.config_entries.async_setup(entry.entry_id)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
return entry
|
|
||||||
|
@ -11,17 +11,82 @@ from homeassistant.components.squeezebox.browse_media import (
|
|||||||
MEDIA_TYPE_TO_SQUEEZEBOX,
|
MEDIA_TYPE_TO_SQUEEZEBOX,
|
||||||
SQUEEZEBOX_ID_BY_TYPE,
|
SQUEEZEBOX_ID_BY_TYPE,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_HOST, CONF_PORT
|
from homeassistant.components.squeezebox.const import (
|
||||||
|
STATUS_QUERY_LIBRARYNAME,
|
||||||
|
STATUS_QUERY_MAC,
|
||||||
|
STATUS_QUERY_UUID,
|
||||||
|
STATUS_QUERY_VERSION,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_ALBUMS,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_ARTISTS,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_DURATION,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_GENRES,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_SONGS,
|
||||||
|
STATUS_SENSOR_LASTSCAN,
|
||||||
|
STATUS_SENSOR_OTHER_PLAYER_COUNT,
|
||||||
|
STATUS_SENSOR_PLAYER_COUNT,
|
||||||
|
STATUS_SENSOR_RESCAN,
|
||||||
|
)
|
||||||
|
from homeassistant.const import CONF_HOST, CONF_PORT, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.device_registry import format_mac
|
from homeassistant.helpers.device_registry import format_mac
|
||||||
|
|
||||||
|
# from homeassistant.setup import async_setup_component
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
TEST_HOST = "1.2.3.4"
|
TEST_HOST = "1.2.3.4"
|
||||||
TEST_PORT = "9000"
|
TEST_PORT = "9000"
|
||||||
TEST_USE_HTTPS = False
|
TEST_USE_HTTPS = False
|
||||||
SERVER_UUID = "12345678-1234-1234-1234-123456789012"
|
SERVER_UUIDS = [
|
||||||
TEST_MAC = "aa:bb:cc:dd:ee:ff"
|
"12345678-1234-1234-1234-123456789012",
|
||||||
|
"87654321-4321-4321-4321-210987654321",
|
||||||
|
]
|
||||||
|
TEST_MAC = ["aa:bb:cc:dd:ee:ff", "ff:ee:dd:cc:bb:aa"]
|
||||||
|
TEST_PLAYER_NAME = "Test Player"
|
||||||
|
TEST_SERVER_NAME = "Test Server"
|
||||||
|
FAKE_VALID_ITEM_ID = "1234"
|
||||||
|
FAKE_INVALID_ITEM_ID = "4321"
|
||||||
|
|
||||||
|
FAKE_IP = "42.42.42.42"
|
||||||
|
FAKE_MAC = "deadbeefdead"
|
||||||
|
FAKE_UUID = "deadbeefdeadbeefbeefdeafbeef42"
|
||||||
|
FAKE_PORT = 9000
|
||||||
|
FAKE_VERSION = "42.0"
|
||||||
|
|
||||||
|
FAKE_QUERY_RESPONSE = {
|
||||||
|
STATUS_QUERY_UUID: FAKE_UUID,
|
||||||
|
STATUS_QUERY_MAC: FAKE_MAC,
|
||||||
|
STATUS_QUERY_VERSION: FAKE_VERSION,
|
||||||
|
STATUS_SENSOR_RESCAN: 1,
|
||||||
|
STATUS_SENSOR_LASTSCAN: 0,
|
||||||
|
STATUS_QUERY_LIBRARYNAME: "FakeLib",
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_ALBUMS: 4,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_ARTISTS: 2,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_DURATION: 500,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_GENRES: 1,
|
||||||
|
STATUS_SENSOR_INFO_TOTAL_SONGS: 42,
|
||||||
|
STATUS_SENSOR_PLAYER_COUNT: 10,
|
||||||
|
STATUS_SENSOR_OTHER_PLAYER_COUNT: 0,
|
||||||
|
"players_loop": [
|
||||||
|
{
|
||||||
|
"isplaying": 0,
|
||||||
|
"name": "SqueezeLite-HA-Addon",
|
||||||
|
"seq_no": 0,
|
||||||
|
"modelname": "SqueezeLite-HA-Addon",
|
||||||
|
"playerindex": "status",
|
||||||
|
"model": "squeezelite",
|
||||||
|
"uuid": FAKE_UUID,
|
||||||
|
"canpoweroff": 1,
|
||||||
|
"ip": "192.168.78.86:57700",
|
||||||
|
"displaytype": "none",
|
||||||
|
"playerid": "f9:23:cd:37:c5:ff",
|
||||||
|
"power": 0,
|
||||||
|
"isplayer": 1,
|
||||||
|
"connected": 1,
|
||||||
|
"firmware": "v2.0.0-1488",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"count": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@ -38,7 +103,7 @@ def config_entry(hass: HomeAssistant) -> MockConfigEntry:
|
|||||||
"""Add the squeezebox mock config entry to hass."""
|
"""Add the squeezebox mock config entry to hass."""
|
||||||
config_entry = MockConfigEntry(
|
config_entry = MockConfigEntry(
|
||||||
domain=const.DOMAIN,
|
domain=const.DOMAIN,
|
||||||
unique_id=SERVER_UUID,
|
unique_id=SERVER_UUIDS[0],
|
||||||
data={
|
data={
|
||||||
CONF_HOST: TEST_HOST,
|
CONF_HOST: TEST_HOST,
|
||||||
CONF_PORT: TEST_PORT,
|
CONF_PORT: TEST_PORT,
|
||||||
@ -69,29 +134,41 @@ async def mock_async_browse(
|
|||||||
fake_items = [
|
fake_items = [
|
||||||
{
|
{
|
||||||
"title": "Fake Item 1",
|
"title": "Fake Item 1",
|
||||||
"id": "1234",
|
"id": FAKE_VALID_ITEM_ID,
|
||||||
"hasitems": False,
|
"hasitems": False,
|
||||||
"item_type": child_types[media_type],
|
"item_type": child_types[media_type],
|
||||||
"artwork_track_id": "b35bb9e9",
|
"artwork_track_id": "b35bb9e9",
|
||||||
|
"url": "file:///var/lib/squeezeboxserver/music/track_1.mp3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Fake Item 2",
|
"title": "Fake Item 2",
|
||||||
"id": "12345",
|
"id": FAKE_VALID_ITEM_ID + "_2",
|
||||||
"hasitems": media_type == "favorites",
|
"hasitems": media_type == "favorites",
|
||||||
"item_type": child_types[media_type],
|
"item_type": child_types[media_type],
|
||||||
"image_url": "http://lms.internal:9000/html/images/favorites.png",
|
"image_url": "http://lms.internal:9000/html/images/favorites.png",
|
||||||
|
"url": "file:///var/lib/squeezeboxserver/music/track_2.mp3",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Fake Item 3",
|
"title": "Fake Item 3",
|
||||||
"id": "123456",
|
"id": FAKE_VALID_ITEM_ID + "_3",
|
||||||
"hasitems": media_type == "favorites",
|
"hasitems": media_type == "favorites",
|
||||||
"album_id": "123456" if media_type == "favorites" else None,
|
"album_id": FAKE_VALID_ITEM_ID if media_type == "favorites" else None,
|
||||||
|
"url": "file:///var/lib/squeezeboxserver/music/track_3.mp3",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
if browse_id:
|
if browse_id:
|
||||||
search_type, search_id = browse_id
|
search_type, search_id = browse_id
|
||||||
if search_id:
|
if search_id:
|
||||||
|
if search_type == "playlist_id":
|
||||||
|
return (
|
||||||
|
{
|
||||||
|
"title": "Fake Item 1",
|
||||||
|
"items": fake_items,
|
||||||
|
}
|
||||||
|
if search_id == FAKE_VALID_ITEM_ID
|
||||||
|
else None
|
||||||
|
)
|
||||||
if search_type in SQUEEZEBOX_ID_BY_TYPE.values():
|
if search_type in SQUEEZEBOX_ID_BY_TYPE.values():
|
||||||
for item in fake_items:
|
for item in fake_items:
|
||||||
if item["id"] == search_id:
|
if item["id"] == search_id:
|
||||||
@ -115,20 +192,96 @@ async def mock_async_browse(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def lms() -> MagicMock:
|
def player() -> MagicMock:
|
||||||
"""Mock a Lyrion Media Server with one mock player attached."""
|
"""Return a mock player."""
|
||||||
lms = MagicMock()
|
return mock_pysqueezebox_player()
|
||||||
player = MagicMock()
|
|
||||||
player.player_id = TEST_MAC
|
|
||||||
player.name = "Test Player"
|
@pytest.fixture
|
||||||
player.power = False
|
def player_factory() -> MagicMock:
|
||||||
player.async_browse = AsyncMock(side_effect=mock_async_browse)
|
"""Return a factory for creating mock players."""
|
||||||
player.async_load_playlist = AsyncMock()
|
return mock_pysqueezebox_player
|
||||||
player.async_update = AsyncMock()
|
|
||||||
player.generate_image_url_from_track_id = MagicMock(
|
|
||||||
return_value="http://lms.internal:9000/html/images/favorites.png"
|
def mock_pysqueezebox_player(uuid: str) -> MagicMock:
|
||||||
|
"""Mock a Lyrion Media Server player."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.squeezebox.media_player.Player", autospec=True
|
||||||
|
) as mock_player:
|
||||||
|
mock_player.async_browse = AsyncMock(side_effect=mock_async_browse)
|
||||||
|
mock_player.generate_image_url_from_track_id = MagicMock(
|
||||||
|
return_value="http://lms.internal:9000/html/images/favorites.png"
|
||||||
|
)
|
||||||
|
mock_player.name = TEST_PLAYER_NAME
|
||||||
|
mock_player.player_id = uuid
|
||||||
|
mock_player.mode = "stop"
|
||||||
|
mock_player.playlist = None
|
||||||
|
mock_player.album = None
|
||||||
|
mock_player.artist = None
|
||||||
|
mock_player.remote_title = None
|
||||||
|
mock_player.title = None
|
||||||
|
mock_player.image_url = None
|
||||||
|
|
||||||
|
return mock_player
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def lms_factory(player_factory: MagicMock) -> MagicMock:
|
||||||
|
"""Return a factory for creating mock Lyrion Media Servers with arbitrary number of players."""
|
||||||
|
return lambda player_count, uuid: mock_pysqueezebox_server(
|
||||||
|
player_factory, player_count, uuid
|
||||||
)
|
)
|
||||||
lms.async_get_players = AsyncMock(return_value=[player])
|
|
||||||
lms.async_query = AsyncMock(return_value={"uuid": format_mac(TEST_MAC)})
|
|
||||||
lms.async_status = AsyncMock(return_value={"uuid": format_mac(TEST_MAC)})
|
@pytest.fixture
|
||||||
return lms
|
def lms(player_factory: MagicMock) -> MagicMock:
|
||||||
|
"""Mock a Lyrion Media Server with one mock player attached."""
|
||||||
|
return mock_pysqueezebox_server(player_factory, 1, uuid=TEST_MAC[0])
|
||||||
|
|
||||||
|
|
||||||
|
def mock_pysqueezebox_server(
|
||||||
|
player_factory: MagicMock, player_count: int, uuid: str
|
||||||
|
) -> MagicMock:
|
||||||
|
"""Create a mock Lyrion Media Server with the given number of mock players attached."""
|
||||||
|
with patch("homeassistant.components.squeezebox.Server", autospec=True) as mock_lms:
|
||||||
|
players = [player_factory(TEST_MAC[index]) for index in range(player_count)]
|
||||||
|
mock_lms.async_get_players = AsyncMock(return_value=players)
|
||||||
|
|
||||||
|
mock_lms.uuid = uuid
|
||||||
|
mock_lms.name = TEST_SERVER_NAME
|
||||||
|
mock_lms.async_query = AsyncMock(return_value={"uuid": format_mac(uuid)})
|
||||||
|
mock_lms.async_status = AsyncMock(return_value={"uuid": format_mac(uuid)})
|
||||||
|
return mock_lms
|
||||||
|
|
||||||
|
|
||||||
|
async def configure_squeezebox_media_player_platform(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
lms: MagicMock,
|
||||||
|
) -> None:
|
||||||
|
"""Configure a squeezebox config entry with appropriate mocks for media_player."""
|
||||||
|
with (
|
||||||
|
patch("homeassistant.components.squeezebox.PLATFORMS", [Platform.MEDIA_PLAYER]),
|
||||||
|
patch("homeassistant.components.squeezebox.Server", return_value=lms),
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def configured_player(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, lms: MagicMock
|
||||||
|
) -> MagicMock:
|
||||||
|
"""Fixture mocking calls to pysqueezebox Player from a configured squeezebox."""
|
||||||
|
await configure_squeezebox_media_player_platform(hass, config_entry, lms)
|
||||||
|
return (await lms.async_get_players())[0]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
async def configured_players(
|
||||||
|
hass: HomeAssistant, config_entry: MockConfigEntry, lms_factory: MagicMock
|
||||||
|
) -> list[MagicMock]:
|
||||||
|
"""Fixture mocking calls to two pysqueezebox Players from a configured squeezebox."""
|
||||||
|
lms = lms_factory(2, uuid=SERVER_UUIDS[0])
|
||||||
|
await configure_squeezebox_media_player_platform(hass, config_entry, lms)
|
||||||
|
return await lms.async_get_players()
|
||||||
|
99
tests/components/squeezebox/snapshots/test_media_player.ambr
Normal file
99
tests/components/squeezebox/snapshots/test_media_player.ambr
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_device_registry
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
tuple(
|
||||||
|
'mac',
|
||||||
|
'aa:bb:cc:dd:ee:ff',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': <DeviceEntryType.SERVICE: 'service'>,
|
||||||
|
'hw_version': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
tuple(
|
||||||
|
'squeezebox',
|
||||||
|
'aa:bb:cc:dd:ee:ff',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'https://lyrion.org/',
|
||||||
|
'model': 'Lyrion Music Server',
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Test Player',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': None,
|
||||||
|
'via_device_id': <ANY>,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_entity_registry[media_player.test_player-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'media_player',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'media_player.test_player',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': None,
|
||||||
|
'platform': 'squeezebox',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': <MediaPlayerEntityFeature: 3077055>,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': 'aa:bb:cc:dd:ee:ff',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_entity_registry[media_player.test_player-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'friendly_name': 'Test Player',
|
||||||
|
'group_members': list([
|
||||||
|
]),
|
||||||
|
'is_volume_muted': True,
|
||||||
|
'media_album_name': 'None',
|
||||||
|
'media_artist': 'None',
|
||||||
|
'media_channel': 'None',
|
||||||
|
'media_duration': 1,
|
||||||
|
'media_position': 1,
|
||||||
|
'media_title': 'None',
|
||||||
|
'query_result': dict({
|
||||||
|
}),
|
||||||
|
'repeat': <RepeatMode.OFF: 'off'>,
|
||||||
|
'shuffle': False,
|
||||||
|
'supported_features': <MediaPlayerEntityFeature: 3077055>,
|
||||||
|
'volume_level': 0.01,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'media_player.test_player',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'idle',
|
||||||
|
})
|
||||||
|
# ---
|
@ -1,22 +1,21 @@
|
|||||||
"""Test squeezebox binary sensors."""
|
"""Test squeezebox binary sensors."""
|
||||||
|
|
||||||
import copy
|
from copy import deepcopy
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import entity_registry as er
|
|
||||||
|
|
||||||
from . import FAKE_QUERY_RESPONSE, setup_mocked_integration
|
from .conftest import FAKE_QUERY_RESPONSE
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_binary_sensor(
|
async def test_binary_sensor(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
entity_registry: er.EntityRegistry,
|
config_entry: MockConfigEntry,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test binary sensor states and attributes."""
|
"""Test binary sensor states and attributes."""
|
||||||
|
|
||||||
# Setup component
|
|
||||||
with (
|
with (
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.squeezebox.PLATFORMS",
|
"homeassistant.components.squeezebox.PLATFORMS",
|
||||||
@ -24,11 +23,13 @@ async def test_binary_sensor(
|
|||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.squeezebox.Server.async_query",
|
"homeassistant.components.squeezebox.Server.async_query",
|
||||||
return_value=copy.deepcopy(FAKE_QUERY_RESPONSE),
|
return_value=deepcopy(FAKE_QUERY_RESPONSE),
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
await setup_mocked_integration(hass)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
state = hass.states.get("binary_sensor.fakelib_library_rescan")
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
|
state = hass.states.get("binary_sensor.fakelib_needs_restart")
|
||||||
|
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert state.state == "on"
|
assert state.state == "off"
|
||||||
|
815
tests/components/squeezebox/test_media_player.py
Normal file
815
tests/components/squeezebox/test_media_player.py
Normal file
@ -0,0 +1,815 @@
|
|||||||
|
"""Tests for the squeezebox media player component."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import json
|
||||||
|
from unittest.mock import AsyncMock, MagicMock, patch
|
||||||
|
|
||||||
|
from freezegun.api import FrozenDateTimeFactory
|
||||||
|
import pytest
|
||||||
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.media_player import (
|
||||||
|
ATTR_GROUP_MEMBERS,
|
||||||
|
ATTR_MEDIA_CONTENT_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE,
|
||||||
|
ATTR_MEDIA_ENQUEUE,
|
||||||
|
ATTR_MEDIA_POSITION,
|
||||||
|
ATTR_MEDIA_POSITION_UPDATED_AT,
|
||||||
|
ATTR_MEDIA_REPEAT,
|
||||||
|
ATTR_MEDIA_SEEK_POSITION,
|
||||||
|
ATTR_MEDIA_SHUFFLE,
|
||||||
|
ATTR_MEDIA_VOLUME_LEVEL,
|
||||||
|
ATTR_MEDIA_VOLUME_MUTED,
|
||||||
|
DOMAIN as MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_CLEAR_PLAYLIST,
|
||||||
|
SERVICE_JOIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
SERVICE_UNJOIN,
|
||||||
|
MediaPlayerEnqueue,
|
||||||
|
MediaPlayerState,
|
||||||
|
MediaType,
|
||||||
|
RepeatMode,
|
||||||
|
)
|
||||||
|
from homeassistant.components.squeezebox.const import DOMAIN, SENSOR_UPDATE_INTERVAL
|
||||||
|
from homeassistant.components.squeezebox.media_player import (
|
||||||
|
ATTR_PARAMETERS,
|
||||||
|
DISCOVERY_INTERVAL,
|
||||||
|
SERVICE_CALL_METHOD,
|
||||||
|
SERVICE_CALL_QUERY,
|
||||||
|
)
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_COMMAND,
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
|
SERVICE_MEDIA_NEXT_TRACK,
|
||||||
|
SERVICE_MEDIA_PAUSE,
|
||||||
|
SERVICE_MEDIA_PLAY,
|
||||||
|
SERVICE_MEDIA_PLAY_PAUSE,
|
||||||
|
SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||||
|
SERVICE_MEDIA_SEEK,
|
||||||
|
SERVICE_MEDIA_STOP,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
SERVICE_SHUFFLE_SET,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
SERVICE_VOLUME_DOWN,
|
||||||
|
SERVICE_VOLUME_MUTE,
|
||||||
|
SERVICE_VOLUME_SET,
|
||||||
|
SERVICE_VOLUME_UP,
|
||||||
|
STATE_UNAVAILABLE,
|
||||||
|
STATE_UNKNOWN,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import ServiceValidationError
|
||||||
|
from homeassistant.helpers.device_registry import DeviceRegistry
|
||||||
|
from homeassistant.helpers.entity_registry import EntityRegistry
|
||||||
|
from homeassistant.util.dt import utcnow
|
||||||
|
|
||||||
|
from .conftest import FAKE_VALID_ITEM_ID, TEST_MAC
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
|
||||||
|
|
||||||
|
|
||||||
|
async def test_device_registry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
device_registry: DeviceRegistry,
|
||||||
|
configured_player: MagicMock,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
) -> None:
|
||||||
|
"""Test squeezebox device registered in the device registry."""
|
||||||
|
reg_device = device_registry.async_get_device(identifiers={(DOMAIN, TEST_MAC[0])})
|
||||||
|
assert reg_device is not None
|
||||||
|
assert reg_device == snapshot
|
||||||
|
|
||||||
|
|
||||||
|
async def test_entity_registry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entity_registry: EntityRegistry,
|
||||||
|
configured_player: MagicMock,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test squeezebox media_player entity registered in the entity registry."""
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, config_entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_player_rediscovery(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test rediscovery of a squeezebox player."""
|
||||||
|
|
||||||
|
assert hass.states.get("media_player.test_player").state == MediaPlayerState.IDLE
|
||||||
|
|
||||||
|
# Make the player appear unavailable
|
||||||
|
configured_player.connected = False
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert hass.states.get("media_player.test_player").state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
# Make the player available again
|
||||||
|
configured_player.connected = True
|
||||||
|
freezer.tick(timedelta(seconds=DISCOVERY_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").state == MediaPlayerState.IDLE
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_turn_on(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test turn on service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_TURN_ON,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_power.assert_called_once_with(True)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_turn_off(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test turn off service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_TURN_OFF,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_power.assert_called_once_with(False)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_state(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test determining the MediaPlayerState."""
|
||||||
|
|
||||||
|
configured_player.power = True
|
||||||
|
configured_player.mode = "stop"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").state == MediaPlayerState.IDLE
|
||||||
|
|
||||||
|
configured_player.mode = "play"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").state == MediaPlayerState.PLAYING
|
||||||
|
|
||||||
|
configured_player.mode = "pause"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").state == MediaPlayerState.PAUSED
|
||||||
|
|
||||||
|
configured_player.power = False
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").state == MediaPlayerState.OFF
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_volume_up(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test volume up service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_VOLUME_UP,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_volume.assert_called_once_with("+5")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_volume_down(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test volume down service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_VOLUME_DOWN,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_volume.assert_called_once_with("-5")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_volume_set(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test volume set service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_VOLUME_SET,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player", ATTR_MEDIA_VOLUME_LEVEL: 0.5},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_volume.assert_called_once_with("50")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_volume_property(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test volume property."""
|
||||||
|
|
||||||
|
configured_player.volume = 50
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_VOLUME_LEVEL]
|
||||||
|
== 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.volume = None
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
ATTR_MEDIA_VOLUME_LEVEL
|
||||||
|
not in hass.states.get("media_player.test_player").attributes
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_mute(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test mute service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_VOLUME_MUTE,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player", ATTR_MEDIA_VOLUME_MUTED: True},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_muting.assert_called_once_with(True)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_unmute(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test unmute service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_VOLUME_MUTE,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player", ATTR_MEDIA_VOLUME_MUTED: False},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_muting.assert_called_once_with(False)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_mute_property(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test the mute property."""
|
||||||
|
|
||||||
|
configured_player.muting = True
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_VOLUME_MUTED]
|
||||||
|
is True
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.muting = False
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_VOLUME_MUTED]
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_repeat_mode(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test set repeat mode service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_REPEAT: RepeatMode.ALL,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_repeat.assert_called_once_with("playlist")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_REPEAT: RepeatMode.ONE,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_repeat.assert_called_with("song")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_REPEAT_SET,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_REPEAT: RepeatMode.OFF,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_repeat.assert_called_with("none")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_repeat_mode_property(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test the repeat mode property."""
|
||||||
|
configured_player.repeat = "playlist"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_REPEAT]
|
||||||
|
== RepeatMode.ALL
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.repeat = "song"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_REPEAT]
|
||||||
|
== RepeatMode.ONE
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.repeat = "none"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_REPEAT]
|
||||||
|
== RepeatMode.OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_shuffle(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test set shuffle service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_SHUFFLE_SET,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_SHUFFLE: True,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_shuffle.assert_called_once_with("song")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_SHUFFLE_SET,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_SHUFFLE: False,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_set_shuffle.assert_called_with("none")
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_SHUFFLE]
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_shuffle_property(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test the shuffle property."""
|
||||||
|
|
||||||
|
configured_player.shuffle = "song"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_SHUFFLE]
|
||||||
|
is True
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.shuffle = "none"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_SHUFFLE]
|
||||||
|
is False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_play(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test play service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_PLAY,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_play.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_play_pause(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test play/pause service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_PLAY_PAUSE,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_toggle_pause.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_pause(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test pause service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_PAUSE,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_pause.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_seek(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test seek service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: FAKE_VALID_ITEM_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_SEEK,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_SEEK_POSITION: 100,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_time.assert_called_once_with(100)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_stop(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test stop service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_STOP,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_stop.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_load_playlist(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test load a playlist."""
|
||||||
|
# load a playlist by number
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: FAKE_VALID_ITEM_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.PLAYLIST,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert configured_player.async_load_playlist.call_count == 1
|
||||||
|
|
||||||
|
# load a list of urls
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: json.dumps(
|
||||||
|
{
|
||||||
|
"urls": [
|
||||||
|
{"url": FAKE_VALID_ITEM_ID},
|
||||||
|
{"url": FAKE_VALID_ITEM_ID + "_2"},
|
||||||
|
],
|
||||||
|
"index": "0",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.PLAYLIST,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
assert configured_player.async_load_playlist.call_count == 2
|
||||||
|
|
||||||
|
# clear the playlist
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_CLEAR_PLAYLIST,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_clear_playlist.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_enqueue(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test the various enqueue service calls."""
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: FAKE_VALID_ITEM_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
|
||||||
|
ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.ADD,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_load_url.assert_called_once_with(FAKE_VALID_ITEM_ID, "add")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: FAKE_VALID_ITEM_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
|
||||||
|
ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.NEXT,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_load_url.assert_called_with(FAKE_VALID_ITEM_ID, "insert")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: FAKE_VALID_ITEM_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.MUSIC,
|
||||||
|
ATTR_MEDIA_ENQUEUE: MediaPlayerEnqueue.PLAY,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_load_url.assert_called_with(FAKE_VALID_ITEM_ID, "play_now")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_skip_tracks(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test track skipping service calls."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_PLAY_MEDIA,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_MEDIA_CONTENT_ID: FAKE_VALID_ITEM_ID,
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE: MediaType.PLAYLIST,
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_NEXT_TRACK,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_index.assert_called_once_with("+1")
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_MEDIA_PREVIOUS_TRACK,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_index.assert_called_with("-1")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_call_query(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test query service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_CALL_QUERY,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_COMMAND: "test_command",
|
||||||
|
ATTR_PARAMETERS: ["param1", "param2"],
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_query.assert_called_once_with(
|
||||||
|
"test_command", "param1", "param2"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_call_method(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test method call service call."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN,
|
||||||
|
SERVICE_CALL_METHOD,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_COMMAND: "test_command",
|
||||||
|
ATTR_PARAMETERS: ["param1", "param2"],
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_query.assert_called_once_with(
|
||||||
|
"test_command", "param1", "param2"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_invalid_state(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test handling an unexpected state from pysqueezebox."""
|
||||||
|
configured_player.mode = "invalid"
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").state == STATE_UNKNOWN
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_server_discovery(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
lms: MagicMock,
|
||||||
|
lms_factory: MagicMock,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test discovery of a squeezebox server."""
|
||||||
|
|
||||||
|
async def mock_async_discover(callback):
|
||||||
|
"""Mock the async_discover function of pysqueezebox."""
|
||||||
|
return callback(lms_factory(2))
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.squeezebox.Server",
|
||||||
|
return_value=lms,
|
||||||
|
),
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.squeezebox.media_player.async_discover",
|
||||||
|
mock_async_discover,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
# how do we check that a config flow started?
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_join(hass: HomeAssistant, configured_players: list) -> None:
|
||||||
|
"""Test joining a squeezebox player."""
|
||||||
|
|
||||||
|
# join a valid player
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_JOIN,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_GROUP_MEMBERS: ["media_player.test_player_2"],
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_players[0].async_sync.assert_called_once_with(
|
||||||
|
configured_players[1].player_id
|
||||||
|
)
|
||||||
|
|
||||||
|
# try to join an invalid player
|
||||||
|
with pytest.raises(ServiceValidationError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_JOIN,
|
||||||
|
{
|
||||||
|
ATTR_ENTITY_ID: "media_player.test_player",
|
||||||
|
ATTR_GROUP_MEMBERS: ["media_player.invalid"],
|
||||||
|
},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_unjoin(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock
|
||||||
|
) -> None:
|
||||||
|
"""Test unjoining a squeezebox player."""
|
||||||
|
await hass.services.async_call(
|
||||||
|
MEDIA_PLAYER_DOMAIN,
|
||||||
|
SERVICE_UNJOIN,
|
||||||
|
{ATTR_ENTITY_ID: "media_player.test_player"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
configured_player.async_unsync.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_media_content_properties(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
configured_player: MagicMock,
|
||||||
|
freezer: FrozenDateTimeFactory,
|
||||||
|
) -> None:
|
||||||
|
"""Test media_content_id and media_content_type properties."""
|
||||||
|
playlist_urls = [
|
||||||
|
{"url": "test_title"},
|
||||||
|
{"url": "test_title_2"},
|
||||||
|
]
|
||||||
|
configured_player.current_index = 0
|
||||||
|
configured_player.playlist = playlist_urls
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert hass.states.get("media_player.test_player").attributes[
|
||||||
|
ATTR_MEDIA_CONTENT_ID
|
||||||
|
] == json.dumps({"index": 0, "urls": playlist_urls})
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_CONTENT_TYPE]
|
||||||
|
== MediaType.PLAYLIST
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.url = "test_url"
|
||||||
|
configured_player.playlist = [{"url": "test_url"}]
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_CONTENT_ID]
|
||||||
|
== "test_url"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_CONTENT_TYPE]
|
||||||
|
== MediaType.MUSIC
|
||||||
|
)
|
||||||
|
|
||||||
|
configured_player.playlist = None
|
||||||
|
configured_player.url = None
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
ATTR_MEDIA_CONTENT_ID
|
||||||
|
not in hass.states.get("media_player.test_player").attributes
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
ATTR_MEDIA_CONTENT_TYPE
|
||||||
|
not in hass.states.get("media_player.test_player").attributes
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_squeezebox_media_position_property(
|
||||||
|
hass: HomeAssistant, configured_player: MagicMock, freezer: FrozenDateTimeFactory
|
||||||
|
) -> None:
|
||||||
|
"""Test media_position property."""
|
||||||
|
configured_player.time = 100
|
||||||
|
configured_player.async_update = AsyncMock(
|
||||||
|
side_effect=lambda: setattr(configured_player, "time", 105)
|
||||||
|
)
|
||||||
|
last_update = utcnow()
|
||||||
|
freezer.tick(timedelta(seconds=SENSOR_UPDATE_INTERVAL))
|
||||||
|
async_fire_time_changed(hass)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("media_player.test_player").attributes[ATTR_MEDIA_POSITION]
|
||||||
|
== 105
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
(
|
||||||
|
hass.states.get("media_player.test_player").attributes[
|
||||||
|
ATTR_MEDIA_POSITION_UPDATED_AT
|
||||||
|
]
|
||||||
|
)
|
||||||
|
> last_update
|
||||||
|
)
|
@ -1,15 +1,18 @@
|
|||||||
"""Test squeezebox sensors."""
|
"""Test squeezebox sensors."""
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from homeassistant.const import Platform
|
from homeassistant.const import Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
from . import FAKE_QUERY_RESPONSE, setup_mocked_integration
|
from .conftest import FAKE_QUERY_RESPONSE
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_sensor(hass: HomeAssistant) -> None:
|
async def test_sensor(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
|
||||||
"""Test binary sensor states and attributes."""
|
"""Test sensor states and attributes."""
|
||||||
|
|
||||||
# Setup component
|
# Setup component
|
||||||
with (
|
with (
|
||||||
@ -19,10 +22,12 @@ async def test_sensor(hass: HomeAssistant) -> None:
|
|||||||
),
|
),
|
||||||
patch(
|
patch(
|
||||||
"homeassistant.components.squeezebox.Server.async_query",
|
"homeassistant.components.squeezebox.Server.async_query",
|
||||||
return_value=FAKE_QUERY_RESPONSE,
|
return_value=deepcopy(FAKE_QUERY_RESPONSE),
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
await setup_mocked_integration(hass)
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done(wait_background_tasks=True)
|
||||||
|
|
||||||
state = hass.states.get("sensor.fakelib_player_count")
|
state = hass.states.get("sensor.fakelib_player_count")
|
||||||
|
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user