From 99c76fc2117bc3da45f6bc17b895205883fcf4ba Mon Sep 17 00:00:00 2001 From: Ronald van der Meer Date: Fri, 11 Sep 2026 09:12:39 +0200 Subject: [PATCH] Consolidate Duco capability recovery tests (#181916) --- tests/components/duco/test_init.py | 65 +++++++++++++--------------- tests/components/duco/test_sensor.py | 44 ++++++------------- 2 files changed, 45 insertions(+), 64 deletions(-) diff --git a/tests/components/duco/test_init.py b/tests/components/duco/test_init.py index 4ff7b1f65913..20c9b68a8467 100644 --- a/tests/components/duco/test_init.py +++ b/tests/components/duco/test_init.py @@ -265,16 +265,41 @@ async def test_setup_entry_retries_on_bypass_temperature_failure( assert mock_config_entry.error_reason_translation_placeholders is None -async def test_empty_bypass_temperature_targets_are_retried( +@pytest.mark.parametrize( + ("initial_zone_ids", "initial_missing_entity_ids"), + [ + pytest.param( + frozenset(), + ( + "number.living_bypass_target_1", + "number.living_bypass_target_2", + ), + id="empty", + ), + pytest.param( + frozenset({2}), + ("number.living_bypass_target_1",), + id="zone_1_missing", + ), + ], +) +async def test_bypass_temperature_targets_are_retried( hass: HomeAssistant, freezer: FrozenDateTimeFactory, mock_bypass_supply_temperature_targets: dict[int, BypassSupplyTemperatureTarget], mock_config_entry: MockConfigEntry, mock_duco_client: AsyncMock, + initial_zone_ids: frozenset[int], + initial_missing_entity_ids: tuple[str, ...], ) -> None: - """Test empty bypass targets are retried and can later create entities.""" + """Test missing bypass targets are retried and create number entities.""" + initial_targets = { + zone_id: target + for zone_id, target in mock_bypass_supply_temperature_targets.items() + if zone_id in initial_zone_ids + } mock_duco_client.async_get_bypass_supply_temperature_targets.side_effect = [ - {}, + initial_targets, mock_bypass_supply_temperature_targets.copy(), ] mock_config_entry.add_to_hass(hass) @@ -283,45 +308,17 @@ async def test_empty_bypass_temperature_targets_are_retried( await hass.async_block_till_done() assert mock_config_entry.state is ConfigEntryState.LOADED - assert hass.states.get("number.living_bypass_target_1") is None - assert hass.states.get("number.living_bypass_target_2") is None + for entity_id in initial_missing_entity_ids: + assert hass.states.get(entity_id) is None mock_duco_client.async_get_bypass_supply_temperature_targets.assert_awaited_once_with() await async_fire_coordinator_update(hass, freezer) assert mock_duco_client.async_get_bypass_supply_temperature_targets.await_count == 2 - assert hass.states.get("number.living_bypass_target_1") is not None - assert hass.states.get("number.living_bypass_target_2") is not None - - -async def test_missing_bypass_temperature_targets_are_retried( - hass: HomeAssistant, - freezer: FrozenDateTimeFactory, - mock_bypass_supply_temperature_targets: dict[int, BypassSupplyTemperatureTarget], - mock_config_entry: MockConfigEntry, - mock_duco_client: AsyncMock, -) -> None: - """Test missing bypass targets are retried and can later create entities.""" - targets_without_zone_1 = { - k: v for k, v in mock_bypass_supply_temperature_targets.items() if k != 1 - } - mock_duco_client.async_get_bypass_supply_temperature_targets.side_effect = [ - targets_without_zone_1, - mock_bypass_supply_temperature_targets.copy(), - ] - mock_config_entry.add_to_hass(hass) - - await hass.config_entries.async_setup(mock_config_entry.entry_id) - await hass.async_block_till_done() - - assert mock_config_entry.state is ConfigEntryState.LOADED - assert hass.states.get("number.living_bypass_target_1") is None - - await async_fire_coordinator_update(hass, freezer) - state = hass.states.get("number.living_bypass_target_1") assert state is not None assert state.state == "20.0" + assert hass.states.get("number.living_bypass_target_2") is not None async def test_setup_entry_ignores_node_name_config_failures( diff --git a/tests/components/duco/test_sensor.py b/tests/components/duco/test_sensor.py index e6e9f7683067..b342e93a2ffd 100644 --- a/tests/components/duco/test_sensor.py +++ b/tests/components/duco/test_sensor.py @@ -259,19 +259,27 @@ async def test_lan_info_failures_keep_node_entities_available( assert state.state == "-60" -async def test_time_filter_remaining_missing_is_retried( +@pytest.mark.parametrize( + "initial_time_filter_remain", + [ + pytest.param(None, id="missing"), + pytest.param(DucoError("heat recovery info error"), id="transient_failure"), + ], +) +async def test_time_filter_remaining_is_retried( hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_duco_client: AsyncMock, mock_sensor_nodes: list[Node], freezer: FrozenDateTimeFactory, + initial_time_filter_remain: DucoError | None, ) -> None: - """Test a missing filter timer does not create the sensor but is retried.""" + """Test unavailable filter timer data is retried and can create the sensor.""" mock_duco_client.async_get_nodes.return_value = mock_sensor_nodes - - mock_duco_client.async_get_time_filter_remaining = AsyncMock( - side_effect=[None, 180] - ) + mock_duco_client.async_get_time_filter_remaining.side_effect = [ + initial_time_filter_remain, + 180, + ] await setup_platform_integration(hass, mock_config_entry, [Platform.SENSOR]) @@ -334,30 +342,6 @@ async def test_partial_ventilation_temperatures_only_expose_available_sensor_val assert hass.states.get("sensor.living_exhaust_air_temperature") is None -async def test_time_filter_remaining_transient_failure_recovers_sensor_creation( - hass: HomeAssistant, - mock_config_entry: MockConfigEntry, - mock_duco_client: AsyncMock, - mock_sensor_nodes: list[Node], - freezer: FrozenDateTimeFactory, -) -> None: - """Test the filter timer sensor is added once a transient startup failure recovers.""" - mock_duco_client.async_get_nodes.return_value = mock_sensor_nodes - mock_duco_client.async_get_time_filter_remaining = AsyncMock( - side_effect=[DucoError("heat recovery info error"), 180] - ) - - await setup_platform_integration(hass, mock_config_entry, [Platform.SENSOR]) - - assert hass.states.get(FILTER_REMAINING_ENTITY_ID) is None - - await async_fire_coordinator_update(hass, freezer) - - state = hass.states.get(FILTER_REMAINING_ENTITY_ID) - assert state is not None - assert state.state == "180" - - @pytest.mark.parametrize( ( "node_id",