diff --git a/homeassistant/components/litterrobot/__init__.py b/homeassistant/components/litterrobot/__init__.py index c7eda2f118b..daf71fe8a6e 100644 --- a/homeassistant/components/litterrobot/__init__.py +++ b/homeassistant/components/litterrobot/__init__.py @@ -6,6 +6,7 @@ from pylitterbot import FeederRobot, LitterRobot, LitterRobot3, LitterRobot4, Ro from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceEntry from .const import DOMAIN from .hub import LitterRobotHub @@ -58,3 +59,17 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data[DOMAIN].pop(entry.entry_id) return unload_ok + + +async def async_remove_config_entry_device( + hass: HomeAssistant, config_entry: ConfigEntry, device_entry: DeviceEntry +) -> bool: + """Remove a config entry from a device.""" + hub: LitterRobotHub = hass.data[DOMAIN][config_entry.entry_id] + return not any( + identifier + for identifier in device_entry.identifiers + if identifier[0] == DOMAIN + for robot in hub.account.robots + if robot.serial == identifier[1] + ) diff --git a/tests/components/litterrobot/common.py b/tests/components/litterrobot/common.py index f5b4e32a1e1..5bf6fb7cce6 100644 --- a/tests/components/litterrobot/common.py +++ b/tests/components/litterrobot/common.py @@ -142,3 +142,17 @@ FEEDER_ROBOT_DATA = { } VACUUM_ENTITY_ID = "vacuum.test_litter_box" + + +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"] diff --git a/tests/components/litterrobot/test_init.py b/tests/components/litterrobot/test_init.py index 8d340f40515..170d6313029 100644 --- a/tests/components/litterrobot/test_init.py +++ b/tests/components/litterrobot/test_init.py @@ -1,5 +1,5 @@ """Test Litter-Robot setup process.""" -from unittest.mock import patch +from unittest.mock import MagicMock, patch from pylitterbot.exceptions import LitterRobotException, LitterRobotLoginException import pytest @@ -13,14 +13,18 @@ from homeassistant.components.vacuum import ( from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ATTR_ENTITY_ID from homeassistant.core import HomeAssistant +from homeassistant.helpers import device_registry as dr, entity_registry as er +from homeassistant.helpers.entity_registry import EntityRegistry +from homeassistant.setup import async_setup_component -from .common import CONFIG, VACUUM_ENTITY_ID +from .common import CONFIG, VACUUM_ENTITY_ID, remove_device from .conftest import setup_integration from tests.common import MockConfigEntry +from tests.typing import WebSocketGenerator -async def test_unload_entry(hass: HomeAssistant, mock_account) -> None: +async def test_unload_entry(hass: HomeAssistant, mock_account: MagicMock) -> None: """Test being able to unload an entry.""" entry = await setup_integration(hass, mock_account, VACUUM_DOMAIN) @@ -49,7 +53,9 @@ async def test_unload_entry(hass: HomeAssistant, mock_account) -> None: ), ) async def test_entry_not_setup( - hass: HomeAssistant, side_effect, expected_state + hass: HomeAssistant, + side_effect: LitterRobotException, + expected_state: ConfigEntryState, ) -> None: """Test being able to handle config entry not setup.""" entry = MockConfigEntry( @@ -64,3 +70,35 @@ async def test_entry_not_setup( ): await hass.config_entries.async_setup(entry.entry_id) assert entry.state is expected_state + + +async def test_device_remove_devices( + hass: HomeAssistant, hass_ws_client: WebSocketGenerator, mock_account: MagicMock +) -> None: + """Test we can only remove a device that no longer exists.""" + assert await async_setup_component(hass, "config", {}) + config_entry = await setup_integration(hass, mock_account, VACUUM_DOMAIN) + + registry: EntityRegistry = er.async_get(hass) + entity = registry.entities[VACUUM_ENTITY_ID] + assert entity.unique_id == "LR3C012345-litter_box" + + 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, config_entry.entry_id + ) + is False + ) + + dead_device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + identifiers={(litterrobot.DOMAIN, "test-serial", "remove-serial")}, + ) + assert ( + await remove_device( + await hass_ws_client(hass), dead_device_entry.id, config_entry.entry_id + ) + is True + )