Skip to content

Fix fetch options error for Home connect #139392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions homeassistant/components/home_connect/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -440,13 +440,27 @@ async def get_options_definitions(
self, ha_id: str, program_key: ProgramKey
) -> dict[OptionKey, ProgramDefinitionOption]:
"""Get options with constraints for appliance."""
return {
option.key: option
for option in (
await self.client.get_available_program(ha_id, program_key=program_key)
).options
or []
}
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
)
).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
Expand All @@ -456,8 +470,7 @@ async def update_options(
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))
options.update(await self.get_options_definitions(ha_id, program_key))

for option in options.values():
option_value = option.constraints.default if option.constraints else None
Expand Down
22 changes: 18 additions & 4 deletions tests/components/home_connect/test_coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
73 changes: 73 additions & 0 deletions tests/components/home_connect/test_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
SelectedProgramNotSetError,
)
from aiohomeconnect.model.program import (
EnumerateProgram,
ProgramDefinitionConstraints,
ProgramDefinitionOption,
)
Expand Down Expand Up @@ -234,6 +235,78 @@ async def get_all_programs_with_options_mock(ha_id: str) -> ArrayOfPrograms:
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",
[
Expand Down