From 9c57be215fffebefcc2d3247720992fc1557dec8 Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Tue, 17 Feb 2026 10:03:57 +0100 Subject: [PATCH] Add 100% coverage to helpers for Fritz (#162999) --- homeassistant/components/fritz/coordinator.py | 6 ++-- homeassistant/components/fritz/helpers.py | 2 +- tests/components/fritz/test_init.py | 32 ++++++++++++++++++- tests/components/fritz/test_switch.py | 23 +++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/fritz/coordinator.py b/homeassistant/components/fritz/coordinator.py index 7ee5d07247e..1383a57b706 100644 --- a/homeassistant/components/fritz/coordinator.py +++ b/homeassistant/components/fritz/coordinator.py @@ -51,7 +51,7 @@ from .const import ( SCAN_INTERVAL, MeshRoles, ) -from .helpers import _ha_is_stopping +from .helpers import ha_is_stopping from .models import ( ConnectionInfo, Device, @@ -552,7 +552,7 @@ class FritzBoxTools(DataUpdateCoordinator[UpdateCoordinatorDataType]): """Scan for new network devices.""" if self.hass.is_stopping: - _ha_is_stopping("scan devices") + ha_is_stopping("scan devices") return _LOGGER.debug("Checking devices for FRITZ!Box device %s", self.host) @@ -727,7 +727,7 @@ class AvmWrapper(FritzBoxTools): """Return service details.""" if self.hass.is_stopping: - _ha_is_stopping(f"{service_name}/{action_name}") + ha_is_stopping(f"{service_name}/{action_name}") return {} if f"{service_name}{service_suffix}" not in self.connection.services: diff --git a/homeassistant/components/fritz/helpers.py b/homeassistant/components/fritz/helpers.py index af75b97e59a..47f2e462cd8 100644 --- a/homeassistant/components/fritz/helpers.py +++ b/homeassistant/components/fritz/helpers.py @@ -34,6 +34,6 @@ def device_filter_out_from_trackers( return bool(reason) -def _ha_is_stopping(activity: str) -> None: +def ha_is_stopping(activity: str) -> None: """Inform that HA is stopping.""" _LOGGER.warning("Cannot execute %s: HomeAssistant is shutting down", activity) diff --git a/tests/components/fritz/test_init.py b/tests/components/fritz/test_init.py index 09550c40485..5b2dad5dfdc 100644 --- a/tests/components/fritz/test_init.py +++ b/tests/components/fritz/test_init.py @@ -1,9 +1,12 @@ """Tests for Fritz!Tools.""" +import re from unittest.mock import patch +from freezegun.api import FrozenDateTimeFactory import pytest +from homeassistant import core from homeassistant.components.device_tracker import ( CONF_CONSIDER_HOME, DEFAULT_CONSIDER_HOME, @@ -12,13 +15,14 @@ from homeassistant.components.fritz.const import ( DOMAIN, FRITZ_AUTH_EXCEPTIONS, FRITZ_EXCEPTIONS, + SCAN_INTERVAL, ) from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from .const import MOCK_USER_DATA -from tests.common import MockConfigEntry +from tests.common import MockConfigEntry, async_fire_time_changed async def test_setup(hass: HomeAssistant, fc_class_mock, fh_class_mock) -> None: @@ -127,3 +131,29 @@ async def test_upnp_missing( "Config entry 'Mock Title' for fritz integration could not authenticate: Missing UPnP configuration" in caplog.text ) + + +async def test_execute_action_while_shutdown( + hass: HomeAssistant, + freezer: FrozenDateTimeFactory, + caplog: pytest.LogCaptureFixture, + fc_class_mock, + fh_class_mock, +) -> None: + """Test Fritz!Tools actions executed during shutdown of HomeAssistant.""" + + entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA) + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + assert entry.state is ConfigEntryState.LOADED + + hass.set_state(core.CoreState.stopping) + freezer.tick(SCAN_INTERVAL) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert re.search( + r"Cannot execute (.+): HomeAssistant is shutting down", caplog.text + ) diff --git a/tests/components/fritz/test_switch.py b/tests/components/fritz/test_switch.py index f8cf719fb0b..045369099a5 100644 --- a/tests/components/fritz/test_switch.py +++ b/tests/components/fritz/test_switch.py @@ -351,6 +351,29 @@ async def test_switch_device_no_wan_access( assert state.state == STATE_UNAVAILABLE +async def test_switch_device_no_ip_address( + hass: HomeAssistant, + fc_class_mock, + fh_class_mock, +) -> None: + """Test Fritz!Tools switches when device has no IP address.""" + + entity_id = "switch.printer_internet_access" + + entry = MockConfigEntry(domain=DOMAIN, data=MOCK_USER_DATA) + entry.add_to_hass(hass) + + attributes = deepcopy(MOCK_HOST_ATTRIBUTES_DATA) + attributes[0]["IPAddress"] = "" + + fh_class_mock.get_hosts_attributes = MagicMock(return_value=attributes) + + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done(wait_background_tasks=True) + + assert hass.states.get(entity_id) is None + + @pytest.mark.parametrize( ("entity_id", "wrapper_method", "state_value"), [