mirror of
https://github.com/home-assistant/core.git
synced 2025-07-13 16:27:08 +00:00
Update HEOS tests to not interact directly with integration internals (#136177)
This commit is contained in:
parent
b11b36b523
commit
9bf2996ea0
@ -2,12 +2,11 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Sequence
|
from collections.abc import AsyncIterator
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, Mock, patch
|
||||||
|
|
||||||
from pyheos import (
|
from pyheos import (
|
||||||
CONTROLS_ALL,
|
CONTROLS_ALL,
|
||||||
Dispatcher,
|
|
||||||
Heos,
|
Heos,
|
||||||
HeosGroup,
|
HeosGroup,
|
||||||
HeosOptions,
|
HeosOptions,
|
||||||
@ -24,15 +23,8 @@ from pyheos import (
|
|||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
|
|
||||||
from homeassistant.components.heos import (
|
from homeassistant.components.heos import DOMAIN
|
||||||
CONF_PASSWORD,
|
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
|
||||||
DOMAIN,
|
|
||||||
ControllerManager,
|
|
||||||
GroupManager,
|
|
||||||
HeosRuntimeData,
|
|
||||||
SourceManager,
|
|
||||||
)
|
|
||||||
from homeassistant.const import CONF_HOST, CONF_USERNAME
|
|
||||||
from homeassistant.helpers.service_info.ssdp import (
|
from homeassistant.helpers.service_info.ssdp import (
|
||||||
ATTR_UPNP_DEVICE_TYPE,
|
ATTR_UPNP_DEVICE_TYPE,
|
||||||
ATTR_UPNP_FRIENDLY_NAME,
|
ATTR_UPNP_FRIENDLY_NAME,
|
||||||
@ -48,54 +40,39 @@ from tests.common import MockConfigEntry
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="config_entry")
|
@pytest.fixture(name="config_entry")
|
||||||
def config_entry_fixture(heos_runtime_data):
|
def config_entry_fixture() -> MockConfigEntry:
|
||||||
"""Create a mock HEOS config entry."""
|
"""Create a mock HEOS config entry."""
|
||||||
entry = MockConfigEntry(
|
return MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
data={CONF_HOST: "127.0.0.1"},
|
data={CONF_HOST: "127.0.0.1"},
|
||||||
title="HEOS System (via 127.0.0.1)",
|
title="HEOS System (via 127.0.0.1)",
|
||||||
unique_id=DOMAIN,
|
unique_id=DOMAIN,
|
||||||
)
|
)
|
||||||
entry.runtime_data = heos_runtime_data
|
|
||||||
return entry
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="config_entry_options")
|
@pytest.fixture(name="config_entry_options")
|
||||||
def config_entry_options_fixture(heos_runtime_data):
|
def config_entry_options_fixture() -> MockConfigEntry:
|
||||||
"""Create a mock HEOS config entry with options."""
|
"""Create a mock HEOS config entry with options."""
|
||||||
entry = MockConfigEntry(
|
return MockConfigEntry(
|
||||||
domain=DOMAIN,
|
domain=DOMAIN,
|
||||||
data={CONF_HOST: "127.0.0.1"},
|
data={CONF_HOST: "127.0.0.1"},
|
||||||
title="HEOS System (via 127.0.0.1)",
|
title="HEOS System (via 127.0.0.1)",
|
||||||
options={CONF_USERNAME: "user", CONF_PASSWORD: "pass"},
|
options={CONF_USERNAME: "user", CONF_PASSWORD: "pass"},
|
||||||
unique_id=DOMAIN,
|
unique_id=DOMAIN,
|
||||||
)
|
)
|
||||||
entry.runtime_data = heos_runtime_data
|
|
||||||
return entry
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="heos_runtime_data")
|
@pytest_asyncio.fixture(name="controller", autouse=True)
|
||||||
def heos_runtime_data_fixture(controller_manager, players):
|
async def controller_fixture(
|
||||||
"""Create a mock HeosRuntimeData fixture."""
|
players: dict[int, HeosPlayer],
|
||||||
return HeosRuntimeData(
|
favorites: dict[int, MediaItem],
|
||||||
controller_manager, Mock(GroupManager), Mock(SourceManager), players
|
input_sources: list[MediaItem],
|
||||||
)
|
playlists: list[MediaItem],
|
||||||
|
change_data: PlayerUpdateResult,
|
||||||
|
group: dict[int, HeosGroup],
|
||||||
@pytest.fixture(name="controller_manager")
|
) -> AsyncIterator[Heos]:
|
||||||
def controller_manager_fixture(controller):
|
|
||||||
"""Create a mock controller manager fixture."""
|
|
||||||
mock_controller_manager = Mock(ControllerManager)
|
|
||||||
mock_controller_manager.controller = controller
|
|
||||||
return mock_controller_manager
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="controller")
|
|
||||||
def controller_fixture(
|
|
||||||
players, favorites, input_sources, playlists, change_data, dispatcher, group
|
|
||||||
):
|
|
||||||
"""Create a mock Heos controller fixture."""
|
"""Create a mock Heos controller fixture."""
|
||||||
mock_heos = Heos(HeosOptions(host="127.0.0.1", dispatcher=dispatcher))
|
mock_heos = Heos(HeosOptions(host="127.0.0.1"))
|
||||||
for player in players.values():
|
for player in players.values():
|
||||||
player.heos = mock_heos
|
player.heos = mock_heos
|
||||||
mock_heos.connect = AsyncMock()
|
mock_heos.connect = AsyncMock()
|
||||||
@ -121,7 +98,7 @@ def controller_fixture(
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="players")
|
@pytest.fixture(name="players")
|
||||||
def player_fixture(quick_selects):
|
def players_fixture(quick_selects: dict[int, str]) -> dict[int, HeosPlayer]:
|
||||||
"""Create two mock HeosPlayers."""
|
"""Create two mock HeosPlayers."""
|
||||||
players = {}
|
players = {}
|
||||||
for i in (1, 2):
|
for i in (1, 2):
|
||||||
@ -179,12 +156,11 @@ def player_fixture(quick_selects):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="group")
|
@pytest.fixture(name="group")
|
||||||
def group_fixture():
|
def group_fixture() -> dict[int, HeosGroup]:
|
||||||
"""Create a HEOS group consisting of two players."""
|
"""Create a HEOS group consisting of two players."""
|
||||||
group = HeosGroup(
|
group = HeosGroup(
|
||||||
name="Group", group_id=999, lead_player_id=1, member_player_ids=[2]
|
name="Group", group_id=999, lead_player_id=1, member_player_ids=[2]
|
||||||
)
|
)
|
||||||
|
|
||||||
return {group.group_id: group}
|
return {group.group_id: group}
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +191,7 @@ def favorites_fixture() -> dict[int, MediaItem]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="input_sources")
|
@pytest.fixture(name="input_sources")
|
||||||
def input_sources_fixture() -> Sequence[MediaItem]:
|
def input_sources_fixture() -> list[MediaItem]:
|
||||||
"""Create a set of input sources for testing."""
|
"""Create a set of input sources for testing."""
|
||||||
source = MediaItem(
|
source = MediaItem(
|
||||||
source_id=1,
|
source_id=1,
|
||||||
@ -230,14 +206,8 @@ def input_sources_fixture() -> Sequence[MediaItem]:
|
|||||||
return [source]
|
return [source]
|
||||||
|
|
||||||
|
|
||||||
@pytest_asyncio.fixture(name="dispatcher")
|
|
||||||
async def dispatcher_fixture() -> Dispatcher:
|
|
||||||
"""Create a dispatcher for testing."""
|
|
||||||
return Dispatcher()
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="discovery_data")
|
@pytest.fixture(name="discovery_data")
|
||||||
def discovery_data_fixture() -> dict:
|
def discovery_data_fixture() -> SsdpServiceInfo:
|
||||||
"""Return mock discovery data for testing."""
|
"""Return mock discovery data for testing."""
|
||||||
return SsdpServiceInfo(
|
return SsdpServiceInfo(
|
||||||
ssdp_usn="mock_usn",
|
ssdp_usn="mock_usn",
|
||||||
@ -256,7 +226,7 @@ def discovery_data_fixture() -> dict:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="discovery_data_bedroom")
|
@pytest.fixture(name="discovery_data_bedroom")
|
||||||
def discovery_data_fixture_bedroom() -> dict:
|
def discovery_data_fixture_bedroom() -> SsdpServiceInfo:
|
||||||
"""Return mock discovery data for testing."""
|
"""Return mock discovery data for testing."""
|
||||||
return SsdpServiceInfo(
|
return SsdpServiceInfo(
|
||||||
ssdp_usn="mock_usn",
|
ssdp_usn="mock_usn",
|
||||||
@ -288,7 +258,7 @@ def quick_selects_fixture() -> dict[int, str]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="playlists")
|
@pytest.fixture(name="playlists")
|
||||||
def playlists_fixture() -> Sequence[MediaItem]:
|
def playlists_fixture() -> list[MediaItem]:
|
||||||
"""Create favorites fixture."""
|
"""Create favorites fixture."""
|
||||||
playlist = MediaItem(
|
playlist = MediaItem(
|
||||||
source_id=const.MUSIC_SOURCE_PLAYLISTS,
|
source_id=const.MUSIC_SOURCE_PLAYLISTS,
|
||||||
|
@ -220,6 +220,7 @@ async def test_options_flow_signs_in(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test options flow signs-in with entered credentials."""
|
"""Test options flow signs-in with entered credentials."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
|
||||||
# Start the options flow. Entry has not current options.
|
# Start the options flow. Entry has not current options.
|
||||||
assert CONF_USERNAME not in config_entry.options
|
assert CONF_USERNAME not in config_entry.options
|
||||||
@ -258,6 +259,7 @@ async def test_options_flow_signs_out(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test options flow signs-out when credentials cleared."""
|
"""Test options flow signs-out when credentials cleared."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
|
||||||
# Start the options flow. Entry has not current options.
|
# Start the options flow. Entry has not current options.
|
||||||
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
||||||
@ -305,6 +307,7 @@ async def test_options_flow_missing_one_param_recovers(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test options flow signs-in after recovering from only username or password being entered."""
|
"""Test options flow signs-in after recovering from only username or password being entered."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
|
||||||
# Start the options flow. Entry has not current options.
|
# Start the options flow. Entry has not current options.
|
||||||
assert CONF_USERNAME not in config_entry.options
|
assert CONF_USERNAME not in config_entry.options
|
||||||
@ -353,6 +356,7 @@ async def test_reauth_signs_in_aborts(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test reauth flow signs-in with entered credentials and aborts."""
|
"""Test reauth flow signs-in with entered credentials and aborts."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
result = await config_entry.start_reauth_flow(hass)
|
result = await config_entry.start_reauth_flow(hass)
|
||||||
|
|
||||||
assert result["step_id"] == "reauth_confirm"
|
assert result["step_id"] == "reauth_confirm"
|
||||||
@ -390,6 +394,7 @@ async def test_reauth_signs_out(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test reauth flow signs-out when credentials cleared and aborts."""
|
"""Test reauth flow signs-out when credentials cleared and aborts."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
result = await config_entry.start_reauth_flow(hass)
|
result = await config_entry.start_reauth_flow(hass)
|
||||||
|
|
||||||
assert result["step_id"] == "reauth_confirm"
|
assert result["step_id"] == "reauth_confirm"
|
||||||
@ -438,6 +443,7 @@ async def test_reauth_flow_missing_one_param_recovers(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test reauth flow signs-in after recovering from only username or password being entered."""
|
"""Test reauth flow signs-in after recovering from only username or password being entered."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
|
||||||
# Start the options flow. Entry has not current options.
|
# Start the options flow. Entry has not current options.
|
||||||
result = await config_entry.start_reauth_flow(hass)
|
result = await config_entry.start_reauth_flow(hass)
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""Tests for the init module."""
|
"""Tests for the init module."""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
from pyheos import (
|
from pyheos import (
|
||||||
@ -71,7 +70,7 @@ async def test_async_setup_entry_auth_failure_starts_reauth(
|
|||||||
# Simulates what happens when the controller can't sign-in during connection
|
# Simulates what happens when the controller can't sign-in during connection
|
||||||
async def connect_send_auth_failure() -> None:
|
async def connect_send_auth_failure() -> None:
|
||||||
controller._signed_in_username = None
|
controller._signed_in_username = None
|
||||||
controller.dispatcher.send(
|
await controller.dispatcher.wait_send(
|
||||||
SignalType.HEOS_EVENT, SignalHeosEvent.USER_CREDENTIALS_INVALID
|
SignalType.HEOS_EVENT, SignalHeosEvent.USER_CREDENTIALS_INVALID
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -151,7 +150,6 @@ async def test_update_sources_retry(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: Heos,
|
||||||
caplog: pytest.LogCaptureFixture,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test update sources retries on failures to max attempts."""
|
"""Test update sources retries on failures to max attempts."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -162,12 +160,10 @@ async def test_update_sources_retry(
|
|||||||
source_manager.retry_delay = 0
|
source_manager.retry_delay = 0
|
||||||
source_manager.max_retry_attempts = 1
|
source_manager.max_retry_attempts = 1
|
||||||
controller.get_favorites.side_effect = CommandFailedError("Test", "test", 0)
|
controller.get_favorites.side_effect = CommandFailedError("Test", "test", 0)
|
||||||
controller.dispatcher.send(
|
await controller.dispatcher.wait_send(
|
||||||
SignalType.CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {}
|
SignalType.CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {}
|
||||||
)
|
)
|
||||||
# Wait until it's finished
|
await hass.async_block_till_done()
|
||||||
while "Unable to update sources" not in caplog.text:
|
|
||||||
await asyncio.sleep(0.1)
|
|
||||||
assert controller.get_favorites.call_count == 2
|
assert controller.get_favorites.call_count == 2
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
"""Tests for the Heos Media Player platform."""
|
"""Tests for the Heos Media Player platform."""
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from collections.abc import Sequence
|
|
||||||
import re
|
import re
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -21,7 +19,7 @@ import pytest
|
|||||||
from syrupy.assertion import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
from syrupy.filters import props
|
from syrupy.filters import props
|
||||||
|
|
||||||
from homeassistant.components.heos.const import DOMAIN, SIGNAL_HEOS_UPDATED
|
from homeassistant.components.heos.const import DOMAIN
|
||||||
from homeassistant.components.media_player import (
|
from homeassistant.components.media_player import (
|
||||||
ATTR_GROUP_MEMBERS,
|
ATTR_GROUP_MEMBERS,
|
||||||
ATTR_INPUT_SOURCE,
|
ATTR_INPUT_SOURCE,
|
||||||
@ -60,12 +58,10 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
from homeassistant.helpers import device_registry as dr, entity_registry as er
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("controller")
|
|
||||||
async def test_state_attributes(
|
async def test_state_attributes(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, snapshot: SnapshotAssertion
|
hass: HomeAssistant, config_entry: MockConfigEntry, snapshot: SnapshotAssertion
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -94,7 +90,7 @@ async def test_updates_from_signals(
|
|||||||
|
|
||||||
# Test player does not update for other players
|
# Test player does not update for other players
|
||||||
player.state = PlayState.PLAY
|
player.state = PlayState.PLAY
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.PLAYER_EVENT, 2, const.EVENT_PLAYER_STATE_CHANGED
|
SignalType.PLAYER_EVENT, 2, const.EVENT_PLAYER_STATE_CHANGED
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -103,7 +99,7 @@ async def test_updates_from_signals(
|
|||||||
|
|
||||||
# Test player_update standard events
|
# Test player_update standard events
|
||||||
player.state = PlayState.PLAY
|
player.state = PlayState.PLAY
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -114,7 +110,7 @@ async def test_updates_from_signals(
|
|||||||
# Test player_update progress events
|
# Test player_update progress events
|
||||||
player.now_playing_media.duration = 360000
|
player.now_playing_media.duration = 360000
|
||||||
player.now_playing_media.current_position = 1000
|
player.now_playing_media.current_position = 1000
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.PLAYER_EVENT,
|
SignalType.PLAYER_EVENT,
|
||||||
player.player_id,
|
player.player_id,
|
||||||
const.EVENT_PLAYER_NOW_PLAYING_PROGRESS,
|
const.EVENT_PLAYER_NOW_PLAYING_PROGRESS,
|
||||||
@ -136,38 +132,36 @@ async def test_updates_from_connection_event(
|
|||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
player = controller.players[1]
|
player = controller.players[1]
|
||||||
event = asyncio.Event()
|
|
||||||
|
|
||||||
async def set_signal():
|
|
||||||
event.set()
|
|
||||||
|
|
||||||
async_dispatcher_connect(hass, SIGNAL_HEOS_UPDATED, set_signal)
|
|
||||||
|
|
||||||
# Connected
|
# Connected
|
||||||
player.available = True
|
player.available = True
|
||||||
player.heos.dispatcher.send(SignalType.HEOS_EVENT, SignalHeosEvent.CONNECTED)
|
await player.heos.dispatcher.wait_send(
|
||||||
await event.wait()
|
SignalType.HEOS_EVENT, SignalHeosEvent.CONNECTED
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
state = hass.states.get("media_player.test_player")
|
state = hass.states.get("media_player.test_player")
|
||||||
assert state.state == STATE_IDLE
|
assert state.state == STATE_IDLE
|
||||||
assert controller.load_players.call_count == 1
|
assert controller.load_players.call_count == 1
|
||||||
|
|
||||||
# Disconnected
|
# Disconnected
|
||||||
event.clear()
|
|
||||||
controller.load_players.reset_mock()
|
controller.load_players.reset_mock()
|
||||||
player.available = False
|
player.available = False
|
||||||
player.heos.dispatcher.send(SignalType.HEOS_EVENT, SignalHeosEvent.DISCONNECTED)
|
await player.heos.dispatcher.wait_send(
|
||||||
await event.wait()
|
SignalType.HEOS_EVENT, SignalHeosEvent.DISCONNECTED
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
state = hass.states.get("media_player.test_player")
|
state = hass.states.get("media_player.test_player")
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
assert controller.load_players.call_count == 0
|
assert controller.load_players.call_count == 0
|
||||||
|
|
||||||
# Connected handles refresh failure
|
# Connected handles refresh failure
|
||||||
event.clear()
|
|
||||||
controller.load_players.reset_mock()
|
controller.load_players.reset_mock()
|
||||||
controller.load_players.side_effect = CommandFailedError(None, "Failure", 1)
|
controller.load_players.side_effect = CommandFailedError(None, "Failure", 1)
|
||||||
player.available = True
|
player.available = True
|
||||||
player.heos.dispatcher.send(SignalType.HEOS_EVENT, SignalHeosEvent.CONNECTED)
|
await player.heos.dispatcher.wait_send(
|
||||||
await event.wait()
|
SignalType.HEOS_EVENT, SignalHeosEvent.CONNECTED
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
state = hass.states.get("media_player.test_player")
|
state = hass.states.get("media_player.test_player")
|
||||||
assert state.state == STATE_IDLE
|
assert state.state == STATE_IDLE
|
||||||
assert controller.load_players.call_count == 1
|
assert controller.load_players.call_count == 1
|
||||||
@ -178,28 +172,23 @@ async def test_updates_from_sources_updated(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: Heos,
|
||||||
input_sources: Sequence[MediaItem],
|
input_sources: list[MediaItem],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests player updates from changes in sources list."""
|
"""Tests player updates from changes in sources list."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
player = controller.players[1]
|
player = controller.players[1]
|
||||||
event = asyncio.Event()
|
|
||||||
|
|
||||||
async def set_signal():
|
|
||||||
event.set()
|
|
||||||
|
|
||||||
async_dispatcher_connect(hass, SIGNAL_HEOS_UPDATED, set_signal)
|
|
||||||
|
|
||||||
input_sources.clear()
|
input_sources.clear()
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {}
|
SignalType.CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {}
|
||||||
)
|
)
|
||||||
await event.wait()
|
await hass.async_block_till_done()
|
||||||
source_list = config_entry.runtime_data.source_manager.source_list
|
|
||||||
assert len(source_list) == 2
|
|
||||||
state = hass.states.get("media_player.test_player")
|
state = hass.states.get("media_player.test_player")
|
||||||
assert state.attributes[ATTR_INPUT_SOURCE_LIST] == source_list
|
assert state.attributes[ATTR_INPUT_SOURCE_LIST] == [
|
||||||
|
"Today's Hits Radio",
|
||||||
|
"Classical MPR (Classical Music)",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
async def test_updates_from_players_changed(
|
async def test_updates_from_players_changed(
|
||||||
@ -212,19 +201,12 @@ async def test_updates_from_players_changed(
|
|||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
player = controller.players[1]
|
player = controller.players[1]
|
||||||
event = asyncio.Event()
|
|
||||||
|
|
||||||
async def set_signal():
|
|
||||||
event.set()
|
|
||||||
|
|
||||||
async_dispatcher_connect(hass, SIGNAL_HEOS_UPDATED, set_signal)
|
|
||||||
|
|
||||||
assert hass.states.get("media_player.test_player").state == STATE_IDLE
|
assert hass.states.get("media_player.test_player").state == STATE_IDLE
|
||||||
player.state = PlayState.PLAY
|
player.state = PlayState.PLAY
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.CONTROLLER_EVENT, const.EVENT_PLAYERS_CHANGED, change_data
|
SignalType.CONTROLLER_EVENT, const.EVENT_PLAYERS_CHANGED, change_data
|
||||||
)
|
)
|
||||||
await event.wait()
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert hass.states.get("media_player.test_player").state == STATE_PLAYING
|
assert hass.states.get("media_player.test_player").state == STATE_PLAYING
|
||||||
|
|
||||||
@ -241,7 +223,6 @@ async def test_updates_from_players_changed_new_ids(
|
|||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
player = controller.players[1]
|
player = controller.players[1]
|
||||||
event = asyncio.Event()
|
|
||||||
|
|
||||||
# Assert device registry matches current id
|
# Assert device registry matches current id
|
||||||
assert device_registry.async_get_device(identifiers={(DOMAIN, "1")})
|
assert device_registry.async_get_device(identifiers={(DOMAIN, "1")})
|
||||||
@ -251,17 +232,12 @@ async def test_updates_from_players_changed_new_ids(
|
|||||||
== "media_player.test_player"
|
== "media_player.test_player"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Trigger update
|
await player.heos.dispatcher.wait_send(
|
||||||
async def set_signal():
|
|
||||||
event.set()
|
|
||||||
|
|
||||||
async_dispatcher_connect(hass, SIGNAL_HEOS_UPDATED, set_signal)
|
|
||||||
player.heos.dispatcher.send(
|
|
||||||
SignalType.CONTROLLER_EVENT,
|
SignalType.CONTROLLER_EVENT,
|
||||||
const.EVENT_PLAYERS_CHANGED,
|
const.EVENT_PLAYERS_CHANGED,
|
||||||
change_data_mapped_ids,
|
change_data_mapped_ids,
|
||||||
)
|
)
|
||||||
await event.wait()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
# Assert device registry identifiers were updated
|
# Assert device registry identifiers were updated
|
||||||
assert len(device_registry.devices) == 2
|
assert len(device_registry.devices) == 2
|
||||||
@ -275,28 +251,23 @@ async def test_updates_from_players_changed_new_ids(
|
|||||||
|
|
||||||
|
|
||||||
async def test_updates_from_user_changed(
|
async def test_updates_from_user_changed(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant,
|
||||||
|
config_entry: MockConfigEntry,
|
||||||
|
controller: Heos,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests player updates from changes in user."""
|
"""Tests player updates from changes in user."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
player = controller.players[1]
|
player = controller.players[1]
|
||||||
event = asyncio.Event()
|
|
||||||
|
|
||||||
async def set_signal():
|
|
||||||
event.set()
|
|
||||||
|
|
||||||
async_dispatcher_connect(hass, SIGNAL_HEOS_UPDATED, set_signal)
|
|
||||||
|
|
||||||
controller._signed_in_username = None
|
controller._signed_in_username = None
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.CONTROLLER_EVENT, const.EVENT_USER_CHANGED, None
|
SignalType.CONTROLLER_EVENT, const.EVENT_USER_CHANGED, None
|
||||||
)
|
)
|
||||||
await event.wait()
|
await hass.async_block_till_done()
|
||||||
source_list = config_entry.runtime_data.source_manager.source_list
|
|
||||||
assert len(source_list) == 1
|
|
||||||
state = hass.states.get("media_player.test_player")
|
state = hass.states.get("media_player.test_player")
|
||||||
assert state.attributes[ATTR_INPUT_SOURCE_LIST] == source_list
|
assert state.attributes[ATTR_INPUT_SOURCE_LIST] == ["HEOS Drive - Line In 1"]
|
||||||
|
|
||||||
|
|
||||||
async def test_clear_playlist(
|
async def test_clear_playlist(
|
||||||
@ -650,7 +621,7 @@ async def test_select_favorite(
|
|||||||
player.play_preset_station.assert_called_once_with(1)
|
player.play_preset_station.assert_called_once_with(1)
|
||||||
# Test state is matched by station name
|
# Test state is matched by station name
|
||||||
player.now_playing_media.station = favorite.name
|
player.now_playing_media.station = favorite.name
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -680,7 +651,7 @@ async def test_select_radio_favorite(
|
|||||||
# Test state is matched by album id
|
# Test state is matched by album id
|
||||||
player.now_playing_media.station = "Classical"
|
player.now_playing_media.station = "Classical"
|
||||||
player.now_playing_media.album_id = favorite.media_id
|
player.now_playing_media.album_id = favorite.media_id
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -721,7 +692,7 @@ async def test_select_input_source(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: Heos,
|
||||||
input_sources: Sequence[MediaItem],
|
input_sources: list[MediaItem],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests selecting input source and state."""
|
"""Tests selecting input source and state."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -742,7 +713,7 @@ async def test_select_input_source(
|
|||||||
# Test state is matched by media id
|
# Test state is matched by media id
|
||||||
player.now_playing_media.source_id = const.MUSIC_SOURCE_AUX_INPUT
|
player.now_playing_media.source_id = const.MUSIC_SOURCE_AUX_INPUT
|
||||||
player.now_playing_media.media_id = const.INPUT_AUX_IN_1
|
player.now_playing_media.media_id = const.INPUT_AUX_IN_1
|
||||||
player.heos.dispatcher.send(
|
await player.heos.dispatcher.wait_send(
|
||||||
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
SignalType.PLAYER_EVENT, player.player_id, const.EVENT_PLAYER_STATE_CHANGED
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -750,7 +721,6 @@ async def test_select_input_source(
|
|||||||
assert state.attributes[ATTR_INPUT_SOURCE] == input_source.name
|
assert state.attributes[ATTR_INPUT_SOURCE] == input_source.name
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("controller")
|
|
||||||
async def test_select_input_unknown_raises(
|
async def test_select_input_unknown_raises(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry
|
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -773,7 +743,7 @@ async def test_select_input_command_error(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: Heos,
|
||||||
input_sources: Sequence[MediaItem],
|
input_sources: list[MediaItem],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Tests selecting an unknown input."""
|
"""Tests selecting an unknown input."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -797,7 +767,6 @@ async def test_select_input_command_error(
|
|||||||
player.play_input_source.assert_called_once_with(input_source.media_id)
|
player.play_input_source.assert_called_once_with(input_source.media_id)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("controller")
|
|
||||||
async def test_unload_config_entry(
|
async def test_unload_config_entry(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry
|
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -926,7 +895,7 @@ async def test_play_media_playlist(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: Heos,
|
||||||
playlists: Sequence[MediaItem],
|
playlists: list[MediaItem],
|
||||||
enqueue: Any,
|
enqueue: Any,
|
||||||
criteria: AddCriteriaType,
|
criteria: AddCriteriaType,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -1026,7 +995,6 @@ async def test_play_media_favorite_error(
|
|||||||
assert player.play_preset_station.call_count == 0
|
assert player.play_preset_station.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("controller")
|
|
||||||
async def test_play_media_invalid_type(
|
async def test_play_media_invalid_type(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry
|
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -81,7 +81,6 @@ async def test_sign_in_unknown_error(
|
|||||||
assert "Unable to sign in" in caplog.text
|
assert "Unable to sign in" in caplog.text
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.usefixtures("controller")
|
|
||||||
async def test_sign_in_not_loaded_raises(
|
async def test_sign_in_not_loaded_raises(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry
|
hass: HomeAssistant, config_entry: MockConfigEntry
|
||||||
) -> None:
|
) -> None:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user