Fix fetch options error for Home connect (#139392)
* Handle errors when obtaining options definitions * Don't fetch program options if the program key is unknown * Test to ensure that available program endpoint is not called on unknown programpull/139859/head
parent
585b950a46
commit
fa6d7d5e3c
|
@ -440,13 +440,27 @@ class HomeConnectCoordinator(
|
|||
self, ha_id: str, program_key: ProgramKey
|
||||
) -> dict[OptionKey, ProgramDefinitionOption]:
|
||||
"""Get options with constraints for appliance."""
|
||||
if program_key is ProgramKey.UNKNOWN:
|
||||
return {}
|
||||
try:
|
||||
return {
|
||||
option.key: option
|
||||
for option in (
|
||||
await self.client.get_available_program(ha_id, program_key=program_key)
|
||||
await self.client.get_available_program(
|
||||
ha_id, program_key=program_key
|
||||
)
|
||||
).options
|
||||
or []
|
||||
}
|
||||
except HomeConnectError as error:
|
||||
_LOGGER.debug(
|
||||
"Error fetching options for %s: %s",
|
||||
ha_id,
|
||||
error
|
||||
if isinstance(error, HomeConnectApiError)
|
||||
else type(error).__name__,
|
||||
)
|
||||
return {}
|
||||
|
||||
async def update_options(
|
||||
self, ha_id: str, event_key: EventKey, program_key: ProgramKey
|
||||
|
@ -456,7 +470,6 @@ class HomeConnectCoordinator(
|
|||
events = self.data[ha_id].events
|
||||
options_to_notify = options.copy()
|
||||
options.clear()
|
||||
if program_key is not ProgramKey.UNKNOWN:
|
||||
options.update(await self.get_options_definitions(ha_id, program_key))
|
||||
|
||||
for option in options.values():
|
||||
|
|
|
@ -75,21 +75,35 @@ async def test_coordinator_update_failing_get_appliances(
|
|||
assert config_entry.state == ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
async def test_coordinator_update_failing_get_settings_status(
|
||||
@pytest.mark.parametrize(
|
||||
"mock_method",
|
||||
[
|
||||
"get_settings",
|
||||
"get_status",
|
||||
"get_all_programs",
|
||||
"get_available_commands",
|
||||
"get_available_program",
|
||||
],
|
||||
)
|
||||
async def test_coordinator_update_failing(
|
||||
mock_method: str,
|
||||
config_entry: MockConfigEntry,
|
||||
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||
setup_credentials: None,
|
||||
client_with_exception: MagicMock,
|
||||
client: MagicMock,
|
||||
) -> None:
|
||||
"""Test that although is not possible to get settings and status, the config entry is loaded.
|
||||
|
||||
This is for cases where some appliances are reachable and some are not in the same configuration entry.
|
||||
"""
|
||||
# Get home appliances does pass at client_with_exception.get_home_appliances mock, so no need to mock it again
|
||||
setattr(client, mock_method, AsyncMock(side_effect=HomeConnectError()))
|
||||
|
||||
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||
await integration_setup(client_with_exception)
|
||||
await integration_setup(client)
|
||||
assert config_entry.state == ConfigEntryState.LOADED
|
||||
|
||||
getattr(client, mock_method).assert_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("appliance_ha_id", ["Dishwasher"], indirect=True)
|
||||
@pytest.mark.parametrize(
|
||||
|
|
|
@ -23,6 +23,7 @@ from aiohomeconnect.model.error import (
|
|||
SelectedProgramNotSetError,
|
||||
)
|
||||
from aiohomeconnect.model.program import (
|
||||
EnumerateProgram,
|
||||
ProgramDefinitionConstraints,
|
||||
ProgramDefinitionOption,
|
||||
)
|
||||
|
@ -234,6 +235,78 @@ async def test_program_options_retrieval(
|
|||
assert hass.states.is_state(entity_id, STATE_UNKNOWN)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("array_of_programs_program_arg", "event_key"),
|
||||
[
|
||||
(
|
||||
"active",
|
||||
EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM,
|
||||
),
|
||||
(
|
||||
"selected",
|
||||
EventKey.BSH_COMMON_ROOT_SELECTED_PROGRAM,
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_no_options_retrieval_on_unknown_program(
|
||||
array_of_programs_program_arg: str,
|
||||
event_key: EventKey,
|
||||
appliance_ha_id: str,
|
||||
hass: HomeAssistant,
|
||||
config_entry: MockConfigEntry,
|
||||
integration_setup: Callable[[MagicMock], Awaitable[bool]],
|
||||
setup_credentials: None,
|
||||
client: MagicMock,
|
||||
) -> None:
|
||||
"""Test that no options are retrieved when the program is unknown."""
|
||||
|
||||
async def get_all_programs_with_options_mock(ha_id: str) -> ArrayOfPrograms:
|
||||
return ArrayOfPrograms(
|
||||
**(
|
||||
{
|
||||
"programs": [
|
||||
EnumerateProgram(ProgramKey.UNKNOWN, "unknown program")
|
||||
],
|
||||
array_of_programs_program_arg: Program(
|
||||
ProgramKey.UNKNOWN, options=[]
|
||||
),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
client.get_all_programs = AsyncMock(side_effect=get_all_programs_with_options_mock)
|
||||
|
||||
assert config_entry.state == ConfigEntryState.NOT_LOADED
|
||||
assert await integration_setup(client)
|
||||
assert config_entry.state == ConfigEntryState.LOADED
|
||||
|
||||
assert client.get_available_program.call_count == 0
|
||||
|
||||
await client.add_events(
|
||||
[
|
||||
EventMessage(
|
||||
appliance_ha_id,
|
||||
EventType.NOTIFY,
|
||||
data=ArrayOfEvents(
|
||||
[
|
||||
Event(
|
||||
key=event_key,
|
||||
raw_key=event_key.value,
|
||||
timestamp=0,
|
||||
level="",
|
||||
handling="",
|
||||
value=ProgramKey.UNKNOWN,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
]
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert client.get_available_program.call_count == 0
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"event_key",
|
||||
[
|
||||
|
|
Loading…
Reference in New Issue