From 39f67afa64621e9a783212ba3d15a11e0efe24da Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 21 Jun 2024 10:36:52 +0200 Subject: [PATCH] Make UniFi services handle unloaded config entry (#120028) --- homeassistant/components/unifi/services.py | 15 +++++--- tests/components/unifi/test_services.py | 41 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/unifi/services.py b/homeassistant/components/unifi/services.py index 5dcc0e9719c984..ce726a0f5d025d 100644 --- a/homeassistant/components/unifi/services.py +++ b/homeassistant/components/unifi/services.py @@ -6,6 +6,7 @@ from aiounifi.models.client import ClientReconnectRequest, ClientRemoveRequest import voluptuous as vol +from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ATTR_DEVICE_ID from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.helpers import device_registry as dr @@ -66,9 +67,9 @@ async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) - if mac == "": return - for entry in hass.config_entries.async_entries(UNIFI_DOMAIN): - if ( - (hub := entry.runtime_data) + for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN): + if config_entry.state is not ConfigEntryState.LOADED or ( + (hub := config_entry.runtime_data) and not hub.available or (client := hub.api.clients.get(mac)) is None or client.is_wired @@ -85,8 +86,12 @@ async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) -> - Total time between first seen and last seen is less than 15 minutes. - Neither IP, hostname nor name is configured. """ - for entry in hass.config_entries.async_entries(UNIFI_DOMAIN): - if (hub := entry.runtime_data) and not hub.available: + for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN): + if ( + config_entry.state is not ConfigEntryState.LOADED + or (hub := config_entry.runtime_data) + and not hub.available + ): continue clients_to_remove = [] diff --git a/tests/components/unifi/test_services.py b/tests/components/unifi/test_services.py index 8cd029b1cf5ca3..c4ccdc8b902d76 100644 --- a/tests/components/unifi/test_services.py +++ b/tests/components/unifi/test_services.py @@ -281,3 +281,44 @@ async def test_remove_clients_no_call_on_empty_list( await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True) assert aioclient_mock.call_count == 0 + + +@pytest.mark.parametrize( + "clients_all_payload", + [ + [ + { + "first_seen": 100, + "last_seen": 500, + "mac": "00:00:00:00:00:01", + } + ] + ], +) +async def test_services_handle_unloaded_config_entry( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + device_registry: dr.DeviceRegistry, + config_entry_setup: ConfigEntry, + clients_all_payload, +) -> None: + """Verify no call is made if config entry is unloaded.""" + await hass.config_entries.async_unload(config_entry_setup.entry_id) + await hass.async_block_till_done() + + aioclient_mock.clear_requests() + + await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True) + assert aioclient_mock.call_count == 0 + + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry_setup.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, clients_all_payload[0]["mac"])}, + ) + await hass.services.async_call( + UNIFI_DOMAIN, + SERVICE_RECONNECT_CLIENT, + service_data={ATTR_DEVICE_ID: device_entry.id}, + blocking=True, + ) + assert aioclient_mock.call_count == 0