mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 05:07:41 +00:00
Fix typing errors in HEOS tests (#136795)
* Correct typing errors of mocked heos * Fix player related typing issues * Sort mocks
This commit is contained in:
parent
9f586ea547
commit
bc7c5fbc86
@ -1 +1,58 @@
|
|||||||
"""Tests for the Heos component."""
|
"""Tests for the Heos component."""
|
||||||
|
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
from pyheos import Heos, HeosGroup, HeosOptions, HeosPlayer
|
||||||
|
|
||||||
|
|
||||||
|
class MockHeos(Heos):
|
||||||
|
"""Defines a mocked HEOS API."""
|
||||||
|
|
||||||
|
def __init__(self, options: HeosOptions) -> None:
|
||||||
|
"""Initialize the mock."""
|
||||||
|
super().__init__(options)
|
||||||
|
# Overwrite the methods with async mocks, changing type
|
||||||
|
self.add_to_queue: AsyncMock = AsyncMock()
|
||||||
|
self.connect: AsyncMock = AsyncMock()
|
||||||
|
self.disconnect: AsyncMock = AsyncMock()
|
||||||
|
self.get_favorites: AsyncMock = AsyncMock()
|
||||||
|
self.get_groups: AsyncMock = AsyncMock()
|
||||||
|
self.get_input_sources: AsyncMock = AsyncMock()
|
||||||
|
self.get_playlists: AsyncMock = AsyncMock()
|
||||||
|
self.get_players: AsyncMock = AsyncMock()
|
||||||
|
self.load_players: AsyncMock = AsyncMock()
|
||||||
|
self.play_media: AsyncMock = AsyncMock()
|
||||||
|
self.play_preset_station: AsyncMock = AsyncMock()
|
||||||
|
self.play_url: AsyncMock = AsyncMock()
|
||||||
|
self.player_clear_queue: AsyncMock = AsyncMock()
|
||||||
|
self.player_get_quick_selects: AsyncMock = AsyncMock()
|
||||||
|
self.player_play_next: AsyncMock = AsyncMock()
|
||||||
|
self.player_play_previous: AsyncMock = AsyncMock()
|
||||||
|
self.player_play_quick_select: AsyncMock = AsyncMock()
|
||||||
|
self.player_set_mute: AsyncMock = AsyncMock()
|
||||||
|
self.player_set_play_mode: AsyncMock = AsyncMock()
|
||||||
|
self.player_set_play_state: AsyncMock = AsyncMock()
|
||||||
|
self.player_set_volume: AsyncMock = AsyncMock()
|
||||||
|
self.set_group: AsyncMock = AsyncMock()
|
||||||
|
self.sign_in: AsyncMock = AsyncMock()
|
||||||
|
self.sign_out: AsyncMock = AsyncMock()
|
||||||
|
|
||||||
|
def mock_set_players(self, players: dict[int, HeosPlayer]) -> None:
|
||||||
|
"""Set the players on the mock instance."""
|
||||||
|
for player in players.values():
|
||||||
|
player.heos = self
|
||||||
|
self._players = players
|
||||||
|
self._players_loaded = bool(players)
|
||||||
|
self.get_players.return_value = players
|
||||||
|
|
||||||
|
def mock_set_groups(self, groups: dict[int, HeosGroup]) -> None:
|
||||||
|
"""Set the groups on the mock instance."""
|
||||||
|
for group in groups.values():
|
||||||
|
group.heos = self
|
||||||
|
self._groups = groups
|
||||||
|
self._groups_loaded = bool(groups)
|
||||||
|
self.get_groups.return_value = groups
|
||||||
|
|
||||||
|
def mock_set_signed_in_username(self, signed_in_username: str | None) -> None:
|
||||||
|
"""Set the signed in status on the mock instance."""
|
||||||
|
self._signed_in_username = signed_in_username
|
||||||
|
@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import AsyncIterator
|
from collections.abc import Iterator
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
from pyheos import (
|
from pyheos import (
|
||||||
Heos,
|
|
||||||
HeosGroup,
|
HeosGroup,
|
||||||
HeosHost,
|
HeosHost,
|
||||||
HeosNowPlayingMedia,
|
HeosNowPlayingMedia,
|
||||||
@ -38,6 +37,8 @@ from homeassistant.helpers.service_info.ssdp import (
|
|||||||
SsdpServiceInfo,
|
SsdpServiceInfo,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from . import MockHeos
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
@ -64,6 +65,17 @@ def config_entry_options_fixture() -> MockConfigEntry:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@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)
|
@pytest_asyncio.fixture(name="controller", autouse=True)
|
||||||
async def controller_fixture(
|
async def controller_fixture(
|
||||||
players: dict[int, HeosPlayer],
|
players: dict[int, HeosPlayer],
|
||||||
@ -72,49 +84,38 @@ async def controller_fixture(
|
|||||||
playlists: list[MediaItem],
|
playlists: list[MediaItem],
|
||||||
change_data: PlayerUpdateResult,
|
change_data: PlayerUpdateResult,
|
||||||
group: dict[int, HeosGroup],
|
group: dict[int, HeosGroup],
|
||||||
) -> AsyncIterator[Heos]:
|
quick_selects: dict[int, str],
|
||||||
|
) -> MockHeos:
|
||||||
"""Create a mock Heos controller fixture."""
|
"""Create a mock Heos controller fixture."""
|
||||||
mock_heos = Heos(HeosOptions(host="127.0.0.1"))
|
|
||||||
for player in players.values():
|
mock_heos = MockHeos(HeosOptions(host="127.0.0.1"))
|
||||||
player.heos = mock_heos
|
mock_heos.mock_set_signed_in_username("user@user.com")
|
||||||
mock_heos.connect = AsyncMock()
|
mock_heos.mock_set_players(players)
|
||||||
mock_heos.disconnect = AsyncMock()
|
mock_heos.mock_set_groups(group)
|
||||||
mock_heos.sign_in = AsyncMock()
|
mock_heos.get_favorites.return_value = favorites
|
||||||
mock_heos.sign_out = AsyncMock()
|
mock_heos.get_input_sources.return_value = input_sources
|
||||||
mock_heos.get_players = AsyncMock(return_value=players)
|
mock_heos.get_playlists.return_value = playlists
|
||||||
mock_heos._players = players
|
mock_heos.load_players.return_value = change_data
|
||||||
mock_heos.get_favorites = AsyncMock(return_value=favorites)
|
mock_heos.player_get_quick_selects.return_value = quick_selects
|
||||||
mock_heos.get_input_sources = AsyncMock(return_value=input_sources)
|
return mock_heos
|
||||||
mock_heos.get_playlists = AsyncMock(return_value=playlists)
|
|
||||||
mock_heos.load_players = AsyncMock(return_value=change_data)
|
|
||||||
mock_heos._signed_in_username = "user@user.com"
|
|
||||||
mock_heos.get_groups = AsyncMock(return_value=group)
|
|
||||||
mock_heos._groups = group
|
|
||||||
mock_heos.set_group = AsyncMock(return_value=None)
|
|
||||||
new_mock = Mock(return_value=mock_heos)
|
|
||||||
mock_heos.new_mock = new_mock
|
|
||||||
with (
|
|
||||||
patch("homeassistant.components.heos.coordinator.Heos", new=new_mock),
|
|
||||||
patch("homeassistant.components.heos.config_flow.Heos", new=new_mock),
|
|
||||||
):
|
|
||||||
yield mock_heos
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="system")
|
@pytest.fixture(name="system")
|
||||||
def system_info_fixture() -> dict[str, str]:
|
def system_info_fixture() -> HeosSystem:
|
||||||
"""Create a system info fixture."""
|
"""Create a system info fixture."""
|
||||||
return HeosSystem(
|
main_host = HeosHost(
|
||||||
"user@user.com",
|
|
||||||
"127.0.0.1",
|
|
||||||
hosts=[
|
|
||||||
HeosHost(
|
|
||||||
"Test Player",
|
"Test Player",
|
||||||
"HEOS Drive HS2",
|
"HEOS Drive HS2",
|
||||||
"123456",
|
"123456",
|
||||||
"1.0.0",
|
"1.0.0",
|
||||||
"127.0.0.1",
|
"127.0.0.1",
|
||||||
NetworkType.WIRED,
|
NetworkType.WIRED,
|
||||||
),
|
)
|
||||||
|
return HeosSystem(
|
||||||
|
"user@user.com",
|
||||||
|
main_host,
|
||||||
|
hosts=[
|
||||||
|
main_host,
|
||||||
HeosHost(
|
HeosHost(
|
||||||
"Test Player 2",
|
"Test Player 2",
|
||||||
"Speaker",
|
"Speaker",
|
||||||
@ -128,7 +129,7 @@ def system_info_fixture() -> dict[str, str]:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(name="players")
|
@pytest.fixture(name="players")
|
||||||
def players_fixture(quick_selects: dict[int, str]) -> dict[int, HeosPlayer]:
|
def players_fixture() -> dict[int, HeosPlayer]:
|
||||||
"""Create two mock HeosPlayers."""
|
"""Create two mock HeosPlayers."""
|
||||||
players = {}
|
players = {}
|
||||||
for i in (1, 2):
|
for i in (1, 2):
|
||||||
@ -148,7 +149,6 @@ def players_fixture(quick_selects: dict[int, str]) -> dict[int, HeosPlayer]:
|
|||||||
shuffle=False,
|
shuffle=False,
|
||||||
repeat=RepeatType.OFF,
|
repeat=RepeatType.OFF,
|
||||||
volume=25,
|
volume=25,
|
||||||
heos=None,
|
|
||||||
)
|
)
|
||||||
player.now_playing_media = HeosNowPlayingMedia(
|
player.now_playing_media = HeosNowPlayingMedia(
|
||||||
type=MediaType.STATION,
|
type=MediaType.STATION,
|
||||||
@ -162,24 +162,6 @@ def players_fixture(quick_selects: dict[int, str]) -> dict[int, HeosPlayer]:
|
|||||||
queue_id=1,
|
queue_id=1,
|
||||||
source_id=10,
|
source_id=10,
|
||||||
)
|
)
|
||||||
player.add_to_queue = AsyncMock()
|
|
||||||
player.clear_queue = AsyncMock()
|
|
||||||
player.get_quick_selects = AsyncMock(return_value=quick_selects)
|
|
||||||
player.mute = AsyncMock()
|
|
||||||
player.pause = AsyncMock()
|
|
||||||
player.play = AsyncMock()
|
|
||||||
player.play_media = AsyncMock()
|
|
||||||
player.play_next = AsyncMock()
|
|
||||||
player.play_previous = AsyncMock()
|
|
||||||
player.play_preset_station = AsyncMock()
|
|
||||||
player.play_quick_select = AsyncMock()
|
|
||||||
player.play_url = AsyncMock()
|
|
||||||
player.set_mute = AsyncMock()
|
|
||||||
player.set_play_mode = AsyncMock()
|
|
||||||
player.set_quick_select = AsyncMock()
|
|
||||||
player.set_volume = AsyncMock()
|
|
||||||
player.stop = AsyncMock()
|
|
||||||
player.unmute = AsyncMock()
|
|
||||||
players[player.player_id] = player
|
players[player.player_id] = player
|
||||||
return players
|
return players
|
||||||
|
|
||||||
|
@ -98,8 +98,15 @@
|
|||||||
'Speaker - Line In 1',
|
'Speaker - Line In 1',
|
||||||
]),
|
]),
|
||||||
'system': dict({
|
'system': dict({
|
||||||
'connected_to_preferred_host': False,
|
'connected_to_preferred_host': True,
|
||||||
'host': '127.0.0.1',
|
'host': dict({
|
||||||
|
'ip_address': '127.0.0.1',
|
||||||
|
'model': 'HEOS Drive HS2',
|
||||||
|
'name': 'Test Player',
|
||||||
|
'network': 'wired',
|
||||||
|
'serial': '**REDACTED**',
|
||||||
|
'version': '1.0.0',
|
||||||
|
}),
|
||||||
'hosts': list([
|
'hosts': list([
|
||||||
dict({
|
dict({
|
||||||
'ip_address': '127.0.0.1',
|
'ip_address': '127.0.0.1',
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
"""Tests for the Heos config flow module."""
|
"""Tests for the Heos config flow module."""
|
||||||
|
|
||||||
from pyheos import CommandAuthenticationError, CommandFailedError, Heos, HeosError
|
from typing import Any
|
||||||
|
|
||||||
|
from pyheos import CommandAuthenticationError, CommandFailedError, HeosError
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.heos.const import DOMAIN
|
from homeassistant.components.heos.const import DOMAIN
|
||||||
@ -10,6 +12,8 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
from homeassistant.helpers.service_info.ssdp import SsdpServiceInfo
|
from homeassistant.helpers.service_info.ssdp import SsdpServiceInfo
|
||||||
|
|
||||||
|
from . import MockHeos
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +42,7 @@ async def test_no_host_shows_form(hass: HomeAssistant) -> None:
|
|||||||
|
|
||||||
|
|
||||||
async def test_cannot_connect_shows_error_form(
|
async def test_cannot_connect_shows_error_form(
|
||||||
hass: HomeAssistant, controller: Heos
|
hass: HomeAssistant, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test form is shown with error when cannot connect."""
|
"""Test form is shown with error when cannot connect."""
|
||||||
controller.connect.side_effect = HeosError()
|
controller.connect.side_effect = HeosError()
|
||||||
@ -47,13 +51,15 @@ async def test_cannot_connect_shows_error_form(
|
|||||||
)
|
)
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
assert result["step_id"] == "user"
|
assert result["step_id"] == "user"
|
||||||
assert result["errors"][CONF_HOST] == "cannot_connect"
|
errors = result["errors"]
|
||||||
|
assert errors is not None
|
||||||
|
assert errors[CONF_HOST] == "cannot_connect"
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 1
|
||||||
assert controller.disconnect.call_count == 1
|
assert controller.disconnect.call_count == 1
|
||||||
|
|
||||||
|
|
||||||
async def test_create_entry_when_host_valid(
|
async def test_create_entry_when_host_valid(
|
||||||
hass: HomeAssistant, controller: Heos
|
hass: HomeAssistant, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test result type is create entry when host is valid."""
|
"""Test result type is create entry when host is valid."""
|
||||||
data = {CONF_HOST: "127.0.0.1"}
|
data = {CONF_HOST: "127.0.0.1"}
|
||||||
@ -70,7 +76,7 @@ async def test_create_entry_when_host_valid(
|
|||||||
|
|
||||||
|
|
||||||
async def test_create_entry_when_friendly_name_valid(
|
async def test_create_entry_when_friendly_name_valid(
|
||||||
hass: HomeAssistant, controller: Heos
|
hass: HomeAssistant, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test result type is create entry when friendly name is valid."""
|
"""Test result type is create entry when friendly name is valid."""
|
||||||
hass.data[DOMAIN] = {"Office (127.0.0.1)": "127.0.0.1"}
|
hass.data[DOMAIN] = {"Office (127.0.0.1)": "127.0.0.1"}
|
||||||
@ -131,7 +137,7 @@ async def test_discovery_flow_aborts_already_setup(
|
|||||||
|
|
||||||
|
|
||||||
async def test_reconfigure_validates_and_updates_config(
|
async def test_reconfigure_validates_and_updates_config(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test reconfigure validates host and successfully updates."""
|
"""Test reconfigure validates host and successfully updates."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -139,9 +145,9 @@ async def test_reconfigure_validates_and_updates_config(
|
|||||||
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
assert config_entry.data[CONF_HOST] == "127.0.0.1"
|
||||||
|
|
||||||
# Test reconfigure initially shows form with current host value.
|
# Test reconfigure initially shows form with current host value.
|
||||||
host = next(
|
schema = result["data_schema"]
|
||||||
key.default() for key in result["data_schema"].schema if key == CONF_HOST
|
assert schema is not None
|
||||||
)
|
host = next(key.default() for key in schema.schema if key == CONF_HOST)
|
||||||
assert host == "127.0.0.1"
|
assert host == "127.0.0.1"
|
||||||
assert result["errors"] == {}
|
assert result["errors"] == {}
|
||||||
assert result["step_id"] == "reconfigure"
|
assert result["step_id"] == "reconfigure"
|
||||||
@ -161,7 +167,7 @@ async def test_reconfigure_validates_and_updates_config(
|
|||||||
|
|
||||||
|
|
||||||
async def test_reconfigure_cannot_connect_recovers(
|
async def test_reconfigure_cannot_connect_recovers(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test reconfigure cannot connect and recovers."""
|
"""Test reconfigure cannot connect and recovers."""
|
||||||
controller.connect.side_effect = HeosError()
|
controller.connect.side_effect = HeosError()
|
||||||
@ -176,11 +182,13 @@ async def test_reconfigure_cannot_connect_recovers(
|
|||||||
|
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 1
|
||||||
assert controller.disconnect.call_count == 1
|
assert controller.disconnect.call_count == 1
|
||||||
host = next(
|
schema = result["data_schema"]
|
||||||
key.default() for key in result["data_schema"].schema if key == CONF_HOST
|
assert schema is not None
|
||||||
)
|
host = next(key.default() for key in schema.schema if key == CONF_HOST)
|
||||||
assert host == "127.0.0.2"
|
assert host == "127.0.0.2"
|
||||||
assert result["errors"][CONF_HOST] == "cannot_connect"
|
errors = result["errors"]
|
||||||
|
assert errors is not None
|
||||||
|
assert errors[CONF_HOST] == "cannot_connect"
|
||||||
assert result["step_id"] == "reconfigure"
|
assert result["step_id"] == "reconfigure"
|
||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
|
||||||
@ -214,7 +222,7 @@ async def test_reconfigure_cannot_connect_recovers(
|
|||||||
async def test_options_flow_signs_in(
|
async def test_options_flow_signs_in(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
error: HeosError,
|
error: HeosError,
|
||||||
expected_error_key: str,
|
expected_error_key: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -255,7 +263,7 @@ async def test_options_flow_signs_in(
|
|||||||
|
|
||||||
|
|
||||||
async def test_options_flow_signs_out(
|
async def test_options_flow_signs_out(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> 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)
|
||||||
@ -268,7 +276,7 @@ async def test_options_flow_signs_out(
|
|||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
|
||||||
# Fail to sign-out, show error
|
# Fail to sign-out, show error
|
||||||
user_input = {}
|
user_input: dict[str, Any] = {}
|
||||||
controller.sign_out.side_effect = HeosError()
|
controller.sign_out.side_effect = HeosError()
|
||||||
result = await hass.config_entries.options.async_configure(
|
result = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"], user_input
|
result["flow_id"], user_input
|
||||||
@ -301,7 +309,7 @@ async def test_options_flow_signs_out(
|
|||||||
async def test_options_flow_missing_one_param_recovers(
|
async def test_options_flow_missing_one_param_recovers(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
user_input: dict[str, str],
|
user_input: dict[str, str],
|
||||||
expected_errors: dict[str, str],
|
expected_errors: dict[str, str],
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -350,7 +358,7 @@ async def test_options_flow_missing_one_param_recovers(
|
|||||||
async def test_reauth_signs_in_aborts(
|
async def test_reauth_signs_in_aborts(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
error: HeosError,
|
error: HeosError,
|
||||||
expected_error_key: str,
|
expected_error_key: str,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -391,7 +399,7 @@ async def test_reauth_signs_in_aborts(
|
|||||||
|
|
||||||
|
|
||||||
async def test_reauth_signs_out(
|
async def test_reauth_signs_out(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> 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)
|
||||||
@ -404,7 +412,7 @@ async def test_reauth_signs_out(
|
|||||||
assert result["type"] is FlowResultType.FORM
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
|
||||||
# Fail to sign-out, show error
|
# Fail to sign-out, show error
|
||||||
user_input = {}
|
user_input: dict[str, Any] = {}
|
||||||
controller.sign_out.side_effect = HeosError()
|
controller.sign_out.side_effect = HeosError()
|
||||||
result = await hass.config_entries.flow.async_configure(
|
result = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"], user_input
|
result["flow_id"], user_input
|
||||||
@ -439,7 +447,7 @@ async def test_reauth_signs_out(
|
|||||||
async def test_reauth_flow_missing_one_param_recovers(
|
async def test_reauth_flow_missing_one_param_recovers(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
user_input: dict[str, str],
|
user_input: dict[str, str],
|
||||||
expected_errors: dict[str, str],
|
expected_errors: dict[str, str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -2,15 +2,17 @@
|
|||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
from pyheos import Heos, HeosSystem
|
from pyheos import HeosSystem
|
||||||
import pytest
|
import pytest
|
||||||
from syrupy import SnapshotAssertion
|
from syrupy.assertion import SnapshotAssertion
|
||||||
from syrupy.filters import props
|
from syrupy.filters import props
|
||||||
|
|
||||||
from homeassistant.components.heos.const import DOMAIN
|
from homeassistant.components.heos.const import DOMAIN
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
|
from . import MockHeos
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
from tests.components.diagnostics import (
|
from tests.components.diagnostics import (
|
||||||
get_diagnostics_for_config_entry,
|
get_diagnostics_for_config_entry,
|
||||||
@ -23,7 +25,7 @@ async def test_config_entry_diagnostics(
|
|||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
hass_client: ClientSessionGenerator,
|
hass_client: ClientSessionGenerator,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
system: HeosSystem,
|
system: HeosSystem,
|
||||||
snapshot: SnapshotAssertion,
|
snapshot: SnapshotAssertion,
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -77,7 +79,7 @@ async def test_device_diagnostics(
|
|||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
device_registry = dr.async_get(hass)
|
device_registry = dr.async_get(hass)
|
||||||
device = device_registry.async_get_device({(DOMAIN, "1")})
|
device = device_registry.async_get_device({(DOMAIN, "1")})
|
||||||
|
assert device is not None
|
||||||
diagnostics = await get_diagnostics_for_device(
|
diagnostics = await get_diagnostics_for_device(
|
||||||
hass, hass_client, config_entry, device
|
hass, hass_client, config_entry, device
|
||||||
)
|
)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
"""Tests for the init module."""
|
"""Tests for the init module."""
|
||||||
|
|
||||||
from typing import cast
|
from typing import cast
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
from pyheos import Heos, HeosError, HeosOptions, SignalHeosEvent, SignalType
|
from pyheos import HeosError, HeosOptions, SignalHeosEvent, SignalType
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.heos.const import DOMAIN
|
from homeassistant.components.heos.const import DOMAIN
|
||||||
@ -11,13 +12,15 @@ from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers import device_registry as dr
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
|
from . import MockHeos
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_loads_platforms(
|
async def test_async_setup_entry_loads_platforms(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test load connects to heos, retrieves players, and loads platforms."""
|
"""Test load connects to heos, retrieves players, and loads platforms."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -32,7 +35,10 @@ async def test_async_setup_entry_loads_platforms(
|
|||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_with_options_loads_platforms(
|
async def test_async_setup_entry_with_options_loads_platforms(
|
||||||
hass: HomeAssistant, config_entry_options: MockConfigEntry, controller: Heos
|
hass: HomeAssistant,
|
||||||
|
config_entry_options: MockConfigEntry,
|
||||||
|
controller: MockHeos,
|
||||||
|
new_mock: Mock,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test load connects to heos with options, retrieves players, and loads platforms."""
|
"""Test load connects to heos with options, retrieves players, and loads platforms."""
|
||||||
config_entry_options.add_to_hass(hass)
|
config_entry_options.add_to_hass(hass)
|
||||||
@ -40,8 +46,9 @@ async def test_async_setup_entry_with_options_loads_platforms(
|
|||||||
|
|
||||||
# Assert options passed and methods called
|
# Assert options passed and methods called
|
||||||
assert config_entry_options.state is ConfigEntryState.LOADED
|
assert config_entry_options.state is ConfigEntryState.LOADED
|
||||||
options = cast(HeosOptions, controller.new_mock.call_args[0][0])
|
options = cast(HeosOptions, new_mock.call_args[0][0])
|
||||||
assert options.host == config_entry_options.data[CONF_HOST]
|
assert options.host == config_entry_options.data[CONF_HOST]
|
||||||
|
assert options.credentials is not None
|
||||||
assert options.credentials.username == config_entry_options.options[CONF_USERNAME]
|
assert options.credentials.username == config_entry_options.options[CONF_USERNAME]
|
||||||
assert options.credentials.password == config_entry_options.options[CONF_PASSWORD]
|
assert options.credentials.password == config_entry_options.options[CONF_PASSWORD]
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 1
|
||||||
@ -54,14 +61,14 @@ async def test_async_setup_entry_with_options_loads_platforms(
|
|||||||
async def test_async_setup_entry_auth_failure_starts_reauth(
|
async def test_async_setup_entry_auth_failure_starts_reauth(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry_options: MockConfigEntry,
|
config_entry_options: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test load with auth failure starts reauth, loads platforms."""
|
"""Test load with auth failure starts reauth, loads platforms."""
|
||||||
config_entry_options.add_to_hass(hass)
|
config_entry_options.add_to_hass(hass)
|
||||||
|
|
||||||
# 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.mock_set_signed_in_username(None)
|
||||||
await controller.dispatcher.wait_send(
|
await controller.dispatcher.wait_send(
|
||||||
SignalType.HEOS_EVENT, SignalHeosEvent.USER_CREDENTIALS_INVALID
|
SignalType.HEOS_EVENT, SignalHeosEvent.USER_CREDENTIALS_INVALID
|
||||||
)
|
)
|
||||||
@ -76,19 +83,19 @@ async def test_async_setup_entry_auth_failure_starts_reauth(
|
|||||||
controller.disconnect.assert_not_called()
|
controller.disconnect.assert_not_called()
|
||||||
assert config_entry_options.state is ConfigEntryState.LOADED
|
assert config_entry_options.state is ConfigEntryState.LOADED
|
||||||
assert any(
|
assert any(
|
||||||
config_entry_options.async_get_active_flows(hass, sources=[SOURCE_REAUTH])
|
config_entry_options.async_get_active_flows(hass, sources={SOURCE_REAUTH})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_not_signed_in_loads_platforms(
|
async def test_async_setup_entry_not_signed_in_loads_platforms(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: MockConfigEntry,
|
config_entry: MockConfigEntry,
|
||||||
controller: Heos,
|
controller: MockHeos,
|
||||||
caplog: pytest.LogCaptureFixture,
|
caplog: pytest.LogCaptureFixture,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test setup does not retrieve favorites when not logged in."""
|
"""Test setup does not retrieve favorites when not logged in."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
controller._signed_in_username = None
|
controller.mock_set_signed_in_username(None)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
assert controller.connect.call_count == 1
|
assert controller.connect.call_count == 1
|
||||||
assert controller.get_players.call_count == 1
|
assert controller.get_players.call_count == 1
|
||||||
@ -102,7 +109,7 @@ async def test_async_setup_entry_not_signed_in_loads_platforms(
|
|||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_connect_failure(
|
async def test_async_setup_entry_connect_failure(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Connection failure raises ConfigEntryNotReady."""
|
"""Connection failure raises ConfigEntryNotReady."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -114,7 +121,7 @@ async def test_async_setup_entry_connect_failure(
|
|||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_player_failure(
|
async def test_async_setup_entry_player_failure(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Failure to retrieve players raises ConfigEntryNotReady."""
|
"""Failure to retrieve players raises ConfigEntryNotReady."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -126,7 +133,7 @@ async def test_async_setup_entry_player_failure(
|
|||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_favorites_failure(
|
async def test_async_setup_entry_favorites_failure(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Failure to retrieve favorites loads."""
|
"""Failure to retrieve favorites loads."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -136,7 +143,7 @@ async def test_async_setup_entry_favorites_failure(
|
|||||||
|
|
||||||
|
|
||||||
async def test_async_setup_entry_inputs_failure(
|
async def test_async_setup_entry_inputs_failure(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Failure to retrieve inputs loads."""
|
"""Failure to retrieve inputs loads."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -146,7 +153,7 @@ async def test_async_setup_entry_inputs_failure(
|
|||||||
|
|
||||||
|
|
||||||
async def test_unload_entry(
|
async def test_unload_entry(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test entries are unloaded correctly."""
|
"""Test entries are unloaded correctly."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -164,12 +171,14 @@ async def test_device_info(
|
|||||||
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)
|
||||||
device = device_registry.async_get_device({(DOMAIN, "1")})
|
device = device_registry.async_get_device({(DOMAIN, "1")})
|
||||||
|
assert device is not None
|
||||||
assert device.manufacturer == "HEOS"
|
assert device.manufacturer == "HEOS"
|
||||||
assert device.model == "Drive HS2"
|
assert device.model == "Drive HS2"
|
||||||
assert device.name == "Test Player"
|
assert device.name == "Test Player"
|
||||||
assert device.serial_number == "123456"
|
assert device.serial_number == "123456"
|
||||||
assert device.sw_version == "1.0.0"
|
assert device.sw_version == "1.0.0"
|
||||||
device = device_registry.async_get_device({(DOMAIN, "2")})
|
device = device_registry.async_get_device({(DOMAIN, "2")})
|
||||||
|
assert device is not None
|
||||||
assert device.manufacturer == "HEOS"
|
assert device.manufacturer == "HEOS"
|
||||||
assert device.model == "Speaker"
|
assert device.model == "Speaker"
|
||||||
|
|
||||||
@ -183,12 +192,14 @@ async def test_device_id_migration(
|
|||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
# Create a device with a legacy identifier
|
# Create a device with a legacy identifier
|
||||||
device_registry.async_get_or_create(
|
device_registry.async_get_or_create(
|
||||||
config_entry_id=config_entry.entry_id, identifiers={(DOMAIN, 1)}
|
config_entry_id=config_entry.entry_id,
|
||||||
|
identifiers={(DOMAIN, 1)}, # type: ignore[arg-type]
|
||||||
)
|
)
|
||||||
device_registry.async_get_or_create(
|
device_registry.async_get_or_create(
|
||||||
config_entry_id=config_entry.entry_id, identifiers={("Other", 1)}
|
config_entry_id=config_entry.entry_id,
|
||||||
|
identifiers={("Other", 1)}, # type: ignore[arg-type]
|
||||||
)
|
)
|
||||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
assert device_registry.async_get_device({("Other", 1)}) is not None
|
assert device_registry.async_get_device({("Other", 1)}) is not None # type: ignore[arg-type]
|
||||||
assert device_registry.async_get_device({(DOMAIN, 1)}) is None
|
assert device_registry.async_get_device({(DOMAIN, 1)}) is None # type: ignore[arg-type]
|
||||||
assert device_registry.async_get_device({(DOMAIN, "1")}) is not None
|
assert device_registry.async_get_device({(DOMAIN, "1")}) is not None
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
"""Tests for the services module."""
|
"""Tests for the services module."""
|
||||||
|
|
||||||
from pyheos import CommandAuthenticationError, Heos, HeosError
|
from pyheos import CommandAuthenticationError, HeosError
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components.heos.const import (
|
from homeassistant.components.heos.const import (
|
||||||
@ -13,11 +13,13 @@ from homeassistant.components.heos.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 . import MockHeos
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
async def test_sign_in(
|
async def test_sign_in(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the sign-in service."""
|
"""Test the sign-in service."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -34,7 +36,7 @@ async def test_sign_in(
|
|||||||
|
|
||||||
|
|
||||||
async def test_sign_in_failed(
|
async def test_sign_in_failed(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test sign-in service logs error when not connected."""
|
"""Test sign-in service logs error when not connected."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -56,7 +58,7 @@ async def test_sign_in_failed(
|
|||||||
|
|
||||||
|
|
||||||
async def test_sign_in_unknown_error(
|
async def test_sign_in_unknown_error(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test sign-in service logs error for failure."""
|
"""Test sign-in service logs error for failure."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -93,7 +95,7 @@ async def test_sign_in_not_loaded_raises(
|
|||||||
|
|
||||||
|
|
||||||
async def test_sign_out(
|
async def test_sign_out(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the sign-out service."""
|
"""Test the sign-out service."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
@ -117,7 +119,7 @@ async def test_sign_out_not_loaded_raises(
|
|||||||
|
|
||||||
|
|
||||||
async def test_sign_out_unknown_error(
|
async def test_sign_out_unknown_error(
|
||||||
hass: HomeAssistant, config_entry: MockConfigEntry, controller: Heos
|
hass: HomeAssistant, config_entry: MockConfigEntry, controller: MockHeos
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Test the sign-out service."""
|
"""Test the sign-out service."""
|
||||||
config_entry.add_to_hass(hass)
|
config_entry.add_to_hass(hass)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user