2019-03-30 04:10:00 +00:00
|
|
|
"""Configuration for HEOS tests."""
|
2024-03-08 13:50:04 +00:00
|
|
|
|
2021-03-18 14:13:22 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2025-02-17 15:28:55 +00:00
|
|
|
from collections.abc import Callable, Iterator
|
2025-01-29 03:44:57 +00:00
|
|
|
from unittest.mock import Mock, patch
|
2025-01-12 05:06:06 +00:00
|
|
|
|
|
|
|
from pyheos import (
|
|
|
|
HeosGroup,
|
2025-01-28 13:02:15 +00:00
|
|
|
HeosHost,
|
|
|
|
HeosNowPlayingMedia,
|
2025-01-12 05:06:06 +00:00
|
|
|
HeosOptions,
|
|
|
|
HeosPlayer,
|
2025-01-28 13:02:15 +00:00
|
|
|
HeosSystem,
|
2025-01-12 05:06:06 +00:00
|
|
|
LineOutLevelType,
|
|
|
|
MediaItem,
|
|
|
|
MediaType,
|
|
|
|
NetworkType,
|
|
|
|
PlayerUpdateResult,
|
|
|
|
PlayState,
|
|
|
|
RepeatType,
|
|
|
|
const,
|
|
|
|
)
|
2019-03-30 04:10:00 +00:00
|
|
|
import pytest
|
2024-12-27 17:01:35 +00:00
|
|
|
import pytest_asyncio
|
2019-03-30 04:10:00 +00:00
|
|
|
|
2025-01-21 15:00:34 +00:00
|
|
|
from homeassistant.components.heos import DOMAIN
|
|
|
|
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
|
2025-01-20 12:16:59 +00:00
|
|
|
from homeassistant.helpers.service_info.ssdp import (
|
|
|
|
ATTR_UPNP_DEVICE_TYPE,
|
|
|
|
ATTR_UPNP_FRIENDLY_NAME,
|
|
|
|
ATTR_UPNP_MANUFACTURER,
|
|
|
|
ATTR_UPNP_MODEL_NAME,
|
|
|
|
ATTR_UPNP_MODEL_NUMBER,
|
|
|
|
ATTR_UPNP_SERIAL,
|
|
|
|
ATTR_UPNP_UDN,
|
|
|
|
SsdpServiceInfo,
|
|
|
|
)
|
2019-03-30 04:10:00 +00:00
|
|
|
|
2025-01-29 03:44:57 +00:00
|
|
|
from . import MockHeos
|
|
|
|
|
2019-03-30 04:10:00 +00:00
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="config_entry")
|
2025-01-21 15:00:34 +00:00
|
|
|
def config_entry_fixture() -> MockConfigEntry:
|
2019-03-30 04:10:00 +00:00
|
|
|
"""Create a mock HEOS config entry."""
|
2025-01-21 15:00:34 +00:00
|
|
|
return MockConfigEntry(
|
2024-12-16 16:08:14 +00:00
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_HOST: "127.0.0.1"},
|
|
|
|
title="HEOS System (via 127.0.0.1)",
|
|
|
|
unique_id=DOMAIN,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2025-01-02 08:07:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="config_entry_options")
|
2025-01-21 15:00:34 +00:00
|
|
|
def config_entry_options_fixture() -> MockConfigEntry:
|
2025-01-02 08:07:34 +00:00
|
|
|
"""Create a mock HEOS config entry with options."""
|
2025-01-21 15:00:34 +00:00
|
|
|
return MockConfigEntry(
|
2025-01-02 08:07:34 +00:00
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_HOST: "127.0.0.1"},
|
|
|
|
title="HEOS System (via 127.0.0.1)",
|
|
|
|
options={CONF_USERNAME: "user", CONF_PASSWORD: "pass"},
|
|
|
|
unique_id=DOMAIN,
|
|
|
|
)
|
|
|
|
|
2019-03-30 04:10:00 +00:00
|
|
|
|
2025-01-29 03:44:57 +00:00
|
|
|
@pytest.fixture(name="new_mock", autouse=True)
|
|
|
|
def new_heos_mock_fixture(controller: MockHeos) -> Iterator[Mock]:
|
|
|
|
"""Patch the Heos class to return the mock instance."""
|
|
|
|
new_mock = Mock(return_value=controller)
|
|
|
|
with (
|
|
|
|
patch("homeassistant.components.heos.coordinator.Heos", new=new_mock),
|
|
|
|
patch("homeassistant.components.heos.config_flow.Heos", new=new_mock),
|
|
|
|
):
|
|
|
|
yield new_mock
|
|
|
|
|
|
|
|
|
2025-01-21 15:00:34 +00:00
|
|
|
@pytest_asyncio.fixture(name="controller", autouse=True)
|
|
|
|
async def controller_fixture(
|
|
|
|
players: dict[int, HeosPlayer],
|
|
|
|
favorites: dict[int, MediaItem],
|
|
|
|
input_sources: list[MediaItem],
|
|
|
|
playlists: list[MediaItem],
|
|
|
|
change_data: PlayerUpdateResult,
|
|
|
|
group: dict[int, HeosGroup],
|
2025-01-29 03:44:57 +00:00
|
|
|
quick_selects: dict[int, str],
|
|
|
|
) -> MockHeos:
|
2019-03-30 04:10:00 +00:00
|
|
|
"""Create a mock Heos controller fixture."""
|
2025-01-29 03:44:57 +00:00
|
|
|
|
|
|
|
mock_heos = MockHeos(HeosOptions(host="127.0.0.1"))
|
|
|
|
mock_heos.mock_set_signed_in_username("user@user.com")
|
|
|
|
mock_heos.mock_set_players(players)
|
|
|
|
mock_heos.mock_set_groups(group)
|
|
|
|
mock_heos.get_favorites.return_value = favorites
|
|
|
|
mock_heos.get_input_sources.return_value = input_sources
|
|
|
|
mock_heos.get_playlists.return_value = playlists
|
|
|
|
mock_heos.load_players.return_value = change_data
|
|
|
|
mock_heos.player_get_quick_selects.return_value = quick_selects
|
|
|
|
return mock_heos
|
2019-03-30 04:10:00 +00:00
|
|
|
|
|
|
|
|
2025-01-28 13:02:15 +00:00
|
|
|
@pytest.fixture(name="system")
|
2025-01-29 03:44:57 +00:00
|
|
|
def system_info_fixture() -> HeosSystem:
|
2025-01-28 13:02:15 +00:00
|
|
|
"""Create a system info fixture."""
|
2025-01-29 03:44:57 +00:00
|
|
|
main_host = HeosHost(
|
|
|
|
"Test Player",
|
|
|
|
"HEOS Drive HS2",
|
|
|
|
"123456",
|
|
|
|
"1.0.0",
|
|
|
|
"127.0.0.1",
|
|
|
|
NetworkType.WIRED,
|
2025-02-10 19:18:12 +00:00
|
|
|
True,
|
2025-01-29 03:44:57 +00:00
|
|
|
)
|
2025-01-28 13:02:15 +00:00
|
|
|
return HeosSystem(
|
|
|
|
"user@user.com",
|
2025-01-29 03:44:57 +00:00
|
|
|
main_host,
|
2025-01-28 13:02:15 +00:00
|
|
|
hosts=[
|
2025-01-29 03:44:57 +00:00
|
|
|
main_host,
|
2025-01-28 13:02:15 +00:00
|
|
|
HeosHost(
|
|
|
|
"Test Player 2",
|
|
|
|
"Speaker",
|
|
|
|
"123456",
|
|
|
|
"1.0.0",
|
|
|
|
"127.0.0.2",
|
|
|
|
NetworkType.WIFI,
|
2025-02-10 19:18:12 +00:00
|
|
|
True,
|
2025-01-28 13:02:15 +00:00
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2025-02-17 15:28:55 +00:00
|
|
|
@pytest.fixture(name="player_factory")
|
|
|
|
def player_factory_fixture() -> Callable[[int, str, str], HeosPlayer]:
|
|
|
|
"""Return a method that creates players."""
|
|
|
|
|
|
|
|
def factory(player_id: int, name: str, model: str) -> HeosPlayer:
|
|
|
|
"""Create a player."""
|
|
|
|
return HeosPlayer(
|
|
|
|
player_id=player_id,
|
2025-01-25 17:04:33 +00:00
|
|
|
group_id=999,
|
2025-02-17 15:28:55 +00:00
|
|
|
name=name,
|
|
|
|
model=model,
|
2025-01-19 14:07:00 +00:00
|
|
|
serial="123456",
|
2025-01-12 05:06:06 +00:00
|
|
|
version="1.0.0",
|
2025-02-10 19:18:12 +00:00
|
|
|
supported_version=True,
|
2025-01-12 05:06:06 +00:00
|
|
|
line_out=LineOutLevelType.VARIABLE,
|
|
|
|
is_muted=False,
|
|
|
|
available=True,
|
|
|
|
state=PlayState.STOP,
|
2025-02-17 15:28:55 +00:00
|
|
|
ip_address=f"127.0.0.{player_id}",
|
2025-01-12 05:06:06 +00:00
|
|
|
network=NetworkType.WIRED,
|
|
|
|
shuffle=False,
|
|
|
|
repeat=RepeatType.OFF,
|
|
|
|
volume=25,
|
2025-02-17 15:28:55 +00:00
|
|
|
now_playing_media=HeosNowPlayingMedia(
|
|
|
|
type=MediaType.STATION,
|
|
|
|
song="Song",
|
|
|
|
station="Station Name",
|
|
|
|
album="Album",
|
|
|
|
artist="Artist",
|
|
|
|
image_url="http://",
|
|
|
|
album_id="1",
|
|
|
|
media_id="1",
|
|
|
|
queue_id=1,
|
|
|
|
source_id=10,
|
|
|
|
),
|
2025-01-12 05:06:06 +00:00
|
|
|
)
|
2025-02-17 15:28:55 +00:00
|
|
|
|
|
|
|
return factory
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="players")
|
|
|
|
def players_fixture(
|
|
|
|
player_factory: Callable[[int, str, str], HeosPlayer],
|
|
|
|
) -> dict[int, HeosPlayer]:
|
|
|
|
"""Create two mock HeosPlayers."""
|
|
|
|
return {
|
|
|
|
1: player_factory(1, "Test Player", "HEOS Drive HS2"),
|
|
|
|
2: player_factory(2, "Test Player 2", "Speaker"),
|
|
|
|
}
|
2021-11-21 11:57:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="group")
|
2025-01-21 15:00:34 +00:00
|
|
|
def group_fixture() -> dict[int, HeosGroup]:
|
2021-11-21 11:57:31 +00:00
|
|
|
"""Create a HEOS group consisting of two players."""
|
2025-01-08 08:36:02 +00:00
|
|
|
group = HeosGroup(
|
|
|
|
name="Group", group_id=999, lead_player_id=1, member_player_ids=[2]
|
|
|
|
)
|
2021-11-21 11:57:31 +00:00
|
|
|
return {group.group_id: group}
|
2019-04-01 16:58:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="favorites")
|
2025-01-08 08:36:02 +00:00
|
|
|
def favorites_fixture() -> dict[int, MediaItem]:
|
2019-04-01 16:58:52 +00:00
|
|
|
"""Create favorites fixture."""
|
2025-01-08 08:36:02 +00:00
|
|
|
station = MediaItem(
|
|
|
|
source_id=const.MUSIC_SOURCE_PANDORA,
|
|
|
|
name="Today's Hits Radio",
|
|
|
|
media_id="123456789",
|
2025-01-12 05:06:06 +00:00
|
|
|
type=MediaType.STATION,
|
2025-01-08 08:36:02 +00:00
|
|
|
playable=True,
|
|
|
|
browsable=False,
|
|
|
|
image_url="",
|
|
|
|
heos=None,
|
|
|
|
)
|
|
|
|
radio = MediaItem(
|
|
|
|
source_id=const.MUSIC_SOURCE_TUNEIN,
|
|
|
|
name="Classical MPR (Classical Music)",
|
|
|
|
media_id="s1234",
|
2025-01-12 05:06:06 +00:00
|
|
|
type=MediaType.STATION,
|
2025-01-08 08:36:02 +00:00
|
|
|
playable=True,
|
|
|
|
browsable=False,
|
|
|
|
image_url="",
|
|
|
|
heos=None,
|
|
|
|
)
|
2019-07-31 19:25:30 +00:00
|
|
|
return {1: station, 2: radio}
|
2019-04-01 16:58:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="input_sources")
|
2025-01-21 15:00:34 +00:00
|
|
|
def input_sources_fixture() -> list[MediaItem]:
|
2019-04-01 16:58:52 +00:00
|
|
|
"""Create a set of input sources for testing."""
|
2025-01-24 10:56:41 +00:00
|
|
|
return [
|
|
|
|
MediaItem(
|
|
|
|
source_id=const.MUSIC_SOURCE_AUX_INPUT,
|
|
|
|
name="HEOS Drive - Line In 1",
|
|
|
|
media_id=const.INPUT_AUX_IN_1,
|
|
|
|
type=MediaType.STATION,
|
|
|
|
playable=True,
|
|
|
|
browsable=False,
|
|
|
|
image_url="",
|
|
|
|
heos=None,
|
|
|
|
),
|
|
|
|
MediaItem(
|
|
|
|
source_id=const.MUSIC_SOURCE_AUX_INPUT,
|
|
|
|
name="Speaker - Line In 1",
|
|
|
|
media_id=const.INPUT_AUX_IN_1,
|
|
|
|
type=MediaType.STATION,
|
|
|
|
playable=True,
|
|
|
|
browsable=False,
|
|
|
|
image_url="",
|
|
|
|
heos=None,
|
|
|
|
),
|
|
|
|
]
|
2019-04-01 16:58:52 +00:00
|
|
|
|
|
|
|
|
2019-04-09 02:24:40 +00:00
|
|
|
@pytest.fixture(name="discovery_data")
|
2025-01-21 15:00:34 +00:00
|
|
|
def discovery_data_fixture() -> SsdpServiceInfo:
|
2019-04-09 02:24:40 +00:00
|
|
|
"""Return mock discovery data for testing."""
|
2025-01-20 12:16:59 +00:00
|
|
|
return SsdpServiceInfo(
|
2021-11-25 13:35:19 +00:00
|
|
|
ssdp_usn="mock_usn",
|
|
|
|
ssdp_st="mock_st",
|
|
|
|
ssdp_location="http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml",
|
|
|
|
upnp={
|
2025-01-20 12:16:59 +00:00
|
|
|
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-denon-com:device:AiosDevice:1",
|
|
|
|
ATTR_UPNP_FRIENDLY_NAME: "Office",
|
|
|
|
ATTR_UPNP_MANUFACTURER: "Denon",
|
|
|
|
ATTR_UPNP_MODEL_NAME: "HEOS Drive",
|
|
|
|
ATTR_UPNP_MODEL_NUMBER: "DWSA-10 4.0",
|
|
|
|
ATTR_UPNP_SERIAL: None,
|
|
|
|
ATTR_UPNP_UDN: "uuid:e61de70c-2250-1c22-0080-0005cdf512be",
|
2024-12-13 08:46:52 +00:00
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="discovery_data_bedroom")
|
2025-01-21 15:00:34 +00:00
|
|
|
def discovery_data_fixture_bedroom() -> SsdpServiceInfo:
|
2024-12-13 08:46:52 +00:00
|
|
|
"""Return mock discovery data for testing."""
|
2025-01-20 12:16:59 +00:00
|
|
|
return SsdpServiceInfo(
|
2024-12-13 08:46:52 +00:00
|
|
|
ssdp_usn="mock_usn",
|
|
|
|
ssdp_st="mock_st",
|
|
|
|
ssdp_location="http://127.0.0.2:60006/upnp/desc/aios_device/aios_device.xml",
|
|
|
|
upnp={
|
2025-01-20 12:16:59 +00:00
|
|
|
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-denon-com:device:AiosDevice:1",
|
|
|
|
ATTR_UPNP_FRIENDLY_NAME: "Bedroom",
|
|
|
|
ATTR_UPNP_MANUFACTURER: "Denon",
|
|
|
|
ATTR_UPNP_MODEL_NAME: "HEOS Drive",
|
|
|
|
ATTR_UPNP_MODEL_NUMBER: "DWSA-10 4.0",
|
|
|
|
ATTR_UPNP_SERIAL: None,
|
|
|
|
ATTR_UPNP_UDN: "uuid:e61de70c-2250-1c22-0080-0005cdf512be",
|
2021-11-25 13:35:19 +00:00
|
|
|
},
|
|
|
|
)
|
2019-05-03 00:54:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="quick_selects")
|
2021-03-18 14:13:22 +00:00
|
|
|
def quick_selects_fixture() -> dict[int, str]:
|
2019-05-03 00:54:36 +00:00
|
|
|
"""Create a dict of quick selects for testing."""
|
|
|
|
return {
|
|
|
|
1: "Quick Select 1",
|
|
|
|
2: "Quick Select 2",
|
|
|
|
3: "Quick Select 3",
|
|
|
|
4: "Quick Select 4",
|
|
|
|
5: "Quick Select 5",
|
2019-07-31 19:25:30 +00:00
|
|
|
6: "Quick Select 6",
|
2019-05-03 00:54:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="playlists")
|
2025-01-21 15:00:34 +00:00
|
|
|
def playlists_fixture() -> list[MediaItem]:
|
2019-05-03 00:54:36 +00:00
|
|
|
"""Create favorites fixture."""
|
2025-01-08 08:36:02 +00:00
|
|
|
playlist = MediaItem(
|
|
|
|
source_id=const.MUSIC_SOURCE_PLAYLISTS,
|
|
|
|
name="Awesome Music",
|
2025-01-12 05:06:06 +00:00
|
|
|
type=MediaType.PLAYLIST,
|
2025-01-08 08:36:02 +00:00
|
|
|
playable=True,
|
|
|
|
browsable=True,
|
|
|
|
image_url="",
|
|
|
|
heos=None,
|
|
|
|
)
|
2019-05-03 00:54:36 +00:00
|
|
|
return [playlist]
|
2019-05-06 15:53:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="change_data")
|
2025-01-20 21:18:46 +00:00
|
|
|
def change_data_fixture() -> PlayerUpdateResult:
|
2019-05-06 15:53:11 +00:00
|
|
|
"""Create player change data for testing."""
|
2025-01-12 05:06:06 +00:00
|
|
|
return PlayerUpdateResult()
|
2019-05-06 15:53:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.fixture(name="change_data_mapped_ids")
|
2025-01-20 21:18:46 +00:00
|
|
|
def change_data_mapped_ids_fixture() -> PlayerUpdateResult:
|
2019-05-06 15:53:11 +00:00
|
|
|
"""Create player change data for testing."""
|
2025-01-12 05:06:06 +00:00
|
|
|
return PlayerUpdateResult(updated_player_ids={1: 101})
|