From fd2edf6c0ab2835726db8a687a300113de25fe1b Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 6 Oct 2023 13:33:28 +0200 Subject: [PATCH] Allow remove devices in Scrape (#101229) --- homeassistant/components/scrape/__init__.py | 17 +++++++- tests/components/scrape/test_init.py | 48 ++++++++++++++++++++- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/scrape/__init__.py b/homeassistant/components/scrape/__init__.py index bdfa3fd9c5a..e96260139da 100644 --- a/homeassistant/components/scrape/__init__.py +++ b/homeassistant/components/scrape/__init__.py @@ -18,8 +18,9 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant -from homeassistant.helpers import discovery +from homeassistant.helpers import discovery, entity_registry as er import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.device_registry import DeviceEntry from homeassistant.helpers.trigger_template_entity import ( CONF_AVAILABILITY, TEMPLATE_SENSOR_BASE_SCHEMA, @@ -120,3 +121,17 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None: """Handle options update.""" await hass.config_entries.async_reload(entry.entry_id) + + +async def async_remove_config_entry_device( + hass: HomeAssistant, entry: ConfigEntry, device: DeviceEntry +) -> bool: + """Remove Scrape config entry from a device.""" + entity_registry = er.async_get(hass) + for identifier in device.identifiers: + if identifier[0] == DOMAIN and entity_registry.async_get_entity_id( + SENSOR_DOMAIN, DOMAIN, identifier[1] + ): + return False + + return True diff --git a/tests/components/scrape/test_init.py b/tests/components/scrape/test_init.py index aa4be4cdef3..638e25a6e05 100644 --- a/tests/components/scrape/test_init.py +++ b/tests/components/scrape/test_init.py @@ -8,13 +8,14 @@ import pytest from homeassistant import config_entries from homeassistant.components.scrape.const import DEFAULT_SCAN_INTERVAL, DOMAIN from homeassistant.core import HomeAssistant -from homeassistant.helpers import entity_registry as er +from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util from . import MockRestData, return_integration_config from tests.common import MockConfigEntry, async_fire_time_changed +from tests.typing import WebSocketGenerator async def test_setup_config(hass: HomeAssistant) -> None: @@ -125,3 +126,48 @@ async def test_unload_entry(hass: HomeAssistant, loaded_entry: MockConfigEntry) assert await hass.config_entries.async_unload(loaded_entry.entry_id) await hass.async_block_till_done() assert loaded_entry.state is config_entries.ConfigEntryState.NOT_LOADED + + +async def remove_device(ws_client, device_id, config_entry_id): + """Remove config entry from a device.""" + await ws_client.send_json( + { + "id": 5, + "type": "config/device_registry/remove_config_entry", + "config_entry_id": config_entry_id, + "device_id": device_id, + } + ) + response = await ws_client.receive_json() + return response["success"] + + +async def test_device_remove_devices( + hass: HomeAssistant, + loaded_entry: MockConfigEntry, + hass_ws_client: WebSocketGenerator, +) -> None: + """Test we can only remove a device that no longer exists.""" + assert await async_setup_component(hass, "config", {}) + registry: er.EntityRegistry = er.async_get(hass) + entity = registry.entities["sensor.current_version"] + + device_registry = dr.async_get(hass) + device_entry = device_registry.async_get(entity.device_id) + assert ( + await remove_device( + await hass_ws_client(hass), device_entry.id, loaded_entry.entry_id + ) + is False + ) + + dead_device_entry = device_registry.async_get_or_create( + config_entry_id=loaded_entry.entry_id, + identifiers={(DOMAIN, "remove-device-id")}, + ) + assert ( + await remove_device( + await hass_ws_client(hass), dead_device_entry.id, loaded_entry.entry_id + ) + is True + )