core/tests/components/heos/conftest.py

322 lines
9.2 KiB
Python
Raw Normal View History

"""Configuration for HEOS tests."""
2021-03-18 14:13:22 +00:00
from __future__ import annotations
from collections.abc import Callable, Iterator
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,
)
import pytest
import pytest_asyncio
from homeassistant.components.heos import DOMAIN
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
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,
)
from . import MockHeos
from tests.common import MockConfigEntry
@pytest.fixture(name="config_entry")
def config_entry_fixture() -> MockConfigEntry:
"""Create a mock HEOS config entry."""
return MockConfigEntry(
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
)
@pytest.fixture(name="config_entry_options")
def config_entry_options_fixture() -> MockConfigEntry:
"""Create a mock HEOS config entry with options."""
return MockConfigEntry(
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,
)
@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
@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],
quick_selects: dict[int, str],
) -> MockHeos:
"""Create a mock Heos controller fixture."""
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
2025-01-28 13:02:15 +00:00
@pytest.fixture(name="system")
def system_info_fixture() -> HeosSystem:
2025-01-28 13:02:15 +00:00
"""Create a system info fixture."""
main_host = HeosHost(
"Test Player",
"HEOS Drive HS2",
"123456",
"1.0.0",
"127.0.0.1",
NetworkType.WIRED,
True,
)
2025-01-28 13:02:15 +00:00
return HeosSystem(
"user@user.com",
main_host,
2025-01-28 13:02:15 +00:00
hosts=[
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,
True,
2025-01-28 13:02:15 +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,
group_id=999,
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",
supported_version=True,
2025-01-12 05:06:06 +00:00
line_out=LineOutLevelType.VARIABLE,
is_muted=False,
available=True,
state=PlayState.STOP,
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,
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
)
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"),
}
Add support for HEOS groups (#32568) * Add support for grouping HEOS media players * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Handle groups at controller level, refine tests. Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Fix linting issues * Update homeassistant/components/heos/media_player.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Rename variables and improve resolving of entity_ids Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Don't patch internal methods Use the pytest fixtures which have already been defined for this. * Fix linting issues * Remove unused property * Ignore groups with unknown leader This makes sure that the group_members attribute won't contain a `None` value as a leader entity_id. * Don't call force_update_groups() from tests * Don't pass `None` player ids to HEOS API * Use signal for group manager communication * Use imports for async_dispatcher_send/async_dispatcher_connect * Raise exception when leader/player could not be resolved * Disconnect signal handlers, avoid calling async_update_groups too early * Update homeassistant/components/heos/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-11-21 11:57:31 +00:00
@pytest.fixture(name="group")
def group_fixture() -> dict[int, HeosGroup]:
Add support for HEOS groups (#32568) * Add support for grouping HEOS media players * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Handle groups at controller level, refine tests. Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Fix linting issues * Update homeassistant/components/heos/media_player.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Rename variables and improve resolving of entity_ids Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Don't patch internal methods Use the pytest fixtures which have already been defined for this. * Fix linting issues * Remove unused property * Ignore groups with unknown leader This makes sure that the group_members attribute won't contain a `None` value as a leader entity_id. * Don't call force_update_groups() from tests * Don't pass `None` player ids to HEOS API * Use signal for group manager communication * Use imports for async_dispatcher_send/async_dispatcher_connect * Raise exception when leader/player could not be resolved * Disconnect signal handlers, avoid calling async_update_groups too early * Update homeassistant/components/heos/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-11-21 11:57:31 +00:00
"""Create a HEOS group consisting of two players."""
group = HeosGroup(
name="Group", group_id=999, lead_player_id=1, member_player_ids=[2]
)
Add support for HEOS groups (#32568) * Add support for grouping HEOS media players * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Handle groups at controller level, refine tests. Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> * Fix linting issues * Update homeassistant/components/heos/media_player.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Update homeassistant/components/heos/media_player.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Rename variables and improve resolving of entity_ids Co-authored-by: Martin Hjelmare <marhje52@gmail.com> * Don't patch internal methods Use the pytest fixtures which have already been defined for this. * Fix linting issues * Remove unused property * Ignore groups with unknown leader This makes sure that the group_members attribute won't contain a `None` value as a leader entity_id. * Don't call force_update_groups() from tests * Don't pass `None` player ids to HEOS API * Use signal for group manager communication * Use imports for async_dispatcher_send/async_dispatcher_connect * Raise exception when leader/player could not be resolved * Disconnect signal handlers, avoid calling async_update_groups too early * Update homeassistant/components/heos/__init__.py Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Andrew Sayre (he/his/him) <6730289+andrewsayre@users.noreply.github.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
2021-11-21 11:57:31 +00:00
return {group.group_id: group}
@pytest.fixture(name="favorites")
def favorites_fixture() -> dict[int, MediaItem]:
"""Create favorites fixture."""
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,
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,
playable=True,
browsable=False,
image_url="",
heos=None,
)
2019-07-31 19:25:30 +00:00
return {1: station, 2: radio}
@pytest.fixture(name="input_sources")
def input_sources_fixture() -> list[MediaItem]:
"""Create a set of input sources for testing."""
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,
),
]
@pytest.fixture(name="discovery_data")
def discovery_data_fixture() -> SsdpServiceInfo:
"""Return mock discovery data for testing."""
return SsdpServiceInfo(
ssdp_usn="mock_usn",
ssdp_st="mock_st",
ssdp_location="http://127.0.0.1:60006/upnp/desc/aios_device/aios_device.xml",
upnp={
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")
def discovery_data_fixture_bedroom() -> SsdpServiceInfo:
2024-12-13 08:46:52 +00:00
"""Return mock discovery data for testing."""
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={
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",
},
)
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")
def playlists_fixture() -> list[MediaItem]:
2019-05-03 00:54:36 +00:00
"""Create favorites fixture."""
playlist = MediaItem(
source_id=const.MUSIC_SOURCE_PLAYLISTS,
name="Awesome Music",
2025-01-12 05:06:06 +00:00
type=MediaType.PLAYLIST,
playable=True,
browsable=True,
image_url="",
heos=None,
)
2019-05-03 00:54:36 +00:00
return [playlist]
@pytest.fixture(name="change_data")
def change_data_fixture() -> PlayerUpdateResult:
"""Create player change data for testing."""
2025-01-12 05:06:06 +00:00
return PlayerUpdateResult()
@pytest.fixture(name="change_data_mapped_ids")
def change_data_mapped_ids_fixture() -> PlayerUpdateResult:
"""Create player change data for testing."""
2025-01-12 05:06:06 +00:00
return PlayerUpdateResult(updated_player_ids={1: 101})