Improve Home Connect appliances test fixture (#139787)

Improve Home Connect appliances fixture
This commit is contained in:
Martin Hjelmare
2025-03-05 00:45:58 +01:00
committed by GitHub
parent 50ba93042b
commit c671862d3f
4 changed files with 267 additions and 225 deletions

View File

@@ -11,6 +11,7 @@ from aiohomeconnect.client import Client as HomeConnectClient
from aiohomeconnect.model import (
ArrayOfCommands,
ArrayOfEvents,
ArrayOfHomeAppliances,
ArrayOfOptions,
ArrayOfPrograms,
ArrayOfSettings,
@@ -39,15 +40,9 @@ from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component
from . import (
MOCK_APPLIANCES,
MOCK_AVAILABLE_COMMANDS,
MOCK_PROGRAMS,
MOCK_SETTINGS,
MOCK_STATUS,
)
from . import MOCK_AVAILABLE_COMMANDS, MOCK_PROGRAMS, MOCK_SETTINGS, MOCK_STATUS
from tests.common import MockConfigEntry
from tests.common import MockConfigEntry, load_fixture
CLIENT_ID = "1234"
CLIENT_SECRET = "5678"
@@ -148,14 +143,6 @@ async def mock_integration_setup(
return run
def _get_specific_appliance_side_effect(ha_id: str) -> HomeAppliance:
"""Get specific appliance side effect."""
for appliance in copy.deepcopy(MOCK_APPLIANCES).homeappliances:
if appliance.ha_id == ha_id:
return appliance
raise HomeConnectApiError("error.key", "error description")
def _get_set_program_side_effect(
event_queue: asyncio.Queue[list[EventMessage]], event_key: EventKey
):
@@ -271,68 +258,12 @@ def _get_set_program_options_side_effect(
return set_program_options_side_effect
async def _get_all_programs_side_effect(ha_id: str) -> ArrayOfPrograms:
"""Get all programs."""
appliance_type = next(
appliance
for appliance in MOCK_APPLIANCES.homeappliances
if appliance.ha_id == ha_id
).type
if appliance_type not in MOCK_PROGRAMS:
raise HomeConnectApiError("error.key", "error description")
return ArrayOfPrograms(
[
EnumerateProgram.from_dict(program)
for program in MOCK_PROGRAMS[appliance_type]["data"]["programs"]
],
Program.from_dict(MOCK_PROGRAMS[appliance_type]["data"]["programs"][0]),
Program.from_dict(MOCK_PROGRAMS[appliance_type]["data"]["programs"][0]),
)
async def _get_settings_side_effect(ha_id: str) -> ArrayOfSettings:
"""Get settings."""
return ArrayOfSettings.from_dict(
MOCK_SETTINGS.get(
next(
appliance
for appliance in MOCK_APPLIANCES.homeappliances
if appliance.ha_id == ha_id
).type,
{},
).get("data", {"settings": []})
)
async def _get_setting_side_effect(ha_id: str, setting_key: SettingKey):
"""Get setting."""
for appliance in MOCK_APPLIANCES.homeappliances:
if appliance.ha_id == ha_id:
settings = MOCK_SETTINGS.get(
next(
appliance
for appliance in MOCK_APPLIANCES.homeappliances
if appliance.ha_id == ha_id
).type,
{},
).get("data", {"settings": []})
for setting_dict in cast(list[dict], settings["settings"]):
if setting_dict["key"] == setting_key:
return GetSetting.from_dict(setting_dict)
raise HomeConnectApiError("error.key", "error description")
async def _get_available_commands_side_effect(ha_id: str) -> ArrayOfCommands:
"""Get available commands."""
for appliance in MOCK_APPLIANCES.homeappliances:
if appliance.ha_id == ha_id and appliance.type in MOCK_AVAILABLE_COMMANDS:
return ArrayOfCommands.from_dict(MOCK_AVAILABLE_COMMANDS[appliance.type])
raise HomeConnectApiError("error.key", "error description")
@pytest.fixture(name="client")
def mock_client(request: pytest.FixtureRequest) -> MagicMock:
def mock_client(
appliances: list[HomeAppliance],
appliance: HomeAppliance | None,
request: pytest.FixtureRequest,
) -> MagicMock:
"""Fixture to mock Client from HomeConnect."""
mock = MagicMock(
@@ -369,17 +300,78 @@ def mock_client(request: pytest.FixtureRequest) -> MagicMock:
]
)
appliances = [appliance] if appliance else appliances
async def stream_all_events() -> AsyncGenerator[EventMessage]:
"""Mock stream_all_events."""
while True:
for event in await event_queue.get():
yield event
mock.get_home_appliances = AsyncMock(return_value=copy.deepcopy(MOCK_APPLIANCES))
mock.get_home_appliances = AsyncMock(return_value=ArrayOfHomeAppliances(appliances))
def _get_specific_appliance_side_effect(ha_id: str) -> HomeAppliance:
"""Get specific appliance side effect."""
for appliance_ in appliances:
if appliance_.ha_id == ha_id:
return appliance_
raise HomeConnectApiError("error.key", "error description")
mock.get_specific_appliance = AsyncMock(
side_effect=_get_specific_appliance_side_effect
)
mock.stream_all_events = stream_all_events
async def _get_all_programs_side_effect(ha_id: str) -> ArrayOfPrograms:
"""Get all programs."""
appliance_type = next(
appliance for appliance in appliances if appliance.ha_id == ha_id
).type
if appliance_type not in MOCK_PROGRAMS:
raise HomeConnectApiError("error.key", "error description")
return ArrayOfPrograms(
[
EnumerateProgram.from_dict(program)
for program in MOCK_PROGRAMS[appliance_type]["data"]["programs"]
],
Program.from_dict(MOCK_PROGRAMS[appliance_type]["data"]["programs"][0]),
Program.from_dict(MOCK_PROGRAMS[appliance_type]["data"]["programs"][0]),
)
async def _get_settings_side_effect(ha_id: str) -> ArrayOfSettings:
"""Get settings."""
return ArrayOfSettings.from_dict(
MOCK_SETTINGS.get(
next(
appliance for appliance in appliances if appliance.ha_id == ha_id
).type,
{},
).get("data", {"settings": []})
)
async def _get_setting_side_effect(ha_id: str, setting_key: SettingKey):
"""Get setting."""
for appliance_ in appliances:
if appliance_.ha_id == ha_id:
settings = MOCK_SETTINGS.get(
appliance_.type,
{},
).get("data", {"settings": []})
for setting_dict in cast(list[dict], settings["settings"]):
if setting_dict["key"] == setting_key:
return GetSetting.from_dict(setting_dict)
raise HomeConnectApiError("error.key", "error description")
async def _get_available_commands_side_effect(ha_id: str) -> ArrayOfCommands:
"""Get available commands."""
for appliance_ in appliances:
if appliance_.ha_id == ha_id and appliance_.type in MOCK_AVAILABLE_COMMANDS:
return ArrayOfCommands.from_dict(
MOCK_AVAILABLE_COMMANDS[appliance_.type]
)
raise HomeConnectApiError("error.key", "error description")
mock.start_program = AsyncMock(
side_effect=_get_set_program_side_effect(
event_queue, EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM
@@ -431,7 +423,11 @@ def mock_client(request: pytest.FixtureRequest) -> MagicMock:
@pytest.fixture(name="client_with_exception")
def mock_client_with_exception(request: pytest.FixtureRequest) -> MagicMock:
def mock_client_with_exception(
appliances: list[HomeAppliance],
appliance: HomeAppliance | None,
request: pytest.FixtureRequest,
) -> MagicMock:
"""Fixture to mock Client from HomeConnect that raise exceptions."""
mock = MagicMock(
autospec=HomeConnectClient,
@@ -449,7 +445,8 @@ def mock_client_with_exception(request: pytest.FixtureRequest) -> MagicMock:
for event in await event_queue.get():
yield event
mock.get_home_appliances = AsyncMock(return_value=copy.deepcopy(MOCK_APPLIANCES))
appliances = [appliance] if appliance else appliances
mock.get_home_appliances = AsyncMock(return_value=ArrayOfHomeAppliances(appliances))
mock.stream_all_events = stream_all_events
mock.start_program = AsyncMock(side_effect=exception)
@@ -477,12 +474,52 @@ def mock_client_with_exception(request: pytest.FixtureRequest) -> MagicMock:
@pytest.fixture(name="appliance_ha_id")
def mock_appliance_ha_id(request: pytest.FixtureRequest) -> str:
"""Fixture to mock Appliance."""
app = "Washer"
def mock_appliance_ha_id(
appliances: list[HomeAppliance], request: pytest.FixtureRequest
) -> str:
"""Fixture to get the ha_id of an appliance."""
appliance_type = "Washer"
if hasattr(request, "param") and request.param:
app = request.param
for appliance in MOCK_APPLIANCES.homeappliances:
if appliance.type == app:
appliance_type = request.param
for appliance in appliances:
if appliance.type == appliance_type:
return appliance.ha_id
raise ValueError(f"Appliance {app} not found")
raise ValueError(f"Appliance {appliance_type} not found")
@pytest.fixture(name="appliances")
def mock_appliances(
appliances_data: str, request: pytest.FixtureRequest
) -> list[HomeAppliance]:
"""Fixture to mock the returned appliances."""
appliances = ArrayOfHomeAppliances.from_json(appliances_data).homeappliances
appliance_types = {appliance.type for appliance in appliances}
if hasattr(request, "param") and request.param:
appliance_types = request.param
return [appliance for appliance in appliances if appliance.type in appliance_types]
@pytest.fixture(name="appliance")
def mock_appliance(
appliances_data: str, request: pytest.FixtureRequest
) -> HomeAppliance | None:
"""Fixture to mock a single specific appliance to return."""
appliance_type = None
if hasattr(request, "param") and request.param:
appliance_type = request.param
return next(
(
appliance
for appliance in ArrayOfHomeAppliances.from_json(
appliances_data
).homeappliances
if appliance.type == appliance_type
),
None,
)
@pytest.fixture(name="appliances_data")
def appliances_data_fixture() -> str:
"""Fixture to return a the string for an array of appliances."""
return load_fixture("appliances.json", integration=DOMAIN)