From 0fbadc274a75aa73eb95e8a9b9eeb948d61ffc29 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Sat, 17 Feb 2024 14:06:53 +0100 Subject: [PATCH] Cleanups in device registry tests (#110786) --- .../components/config/test_device_registry.py | 54 ++- tests/helpers/test_device_registry.py | 341 ++++++++++-------- 2 files changed, 212 insertions(+), 183 deletions(-) diff --git a/tests/components/config/test_device_registry.py b/tests/components/config/test_device_registry.py index 5f0c423fc21..53746d2aa34 100644 --- a/tests/components/config/test_device_registry.py +++ b/tests/components/config/test_device_registry.py @@ -7,7 +7,7 @@ from homeassistant.helpers import device_registry as dr from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry, MockModule, mock_integration -from tests.typing import WebSocketGenerator +from tests.typing import MockHAClientWebSocket, WebSocketGenerator @pytest.fixture(autouse=True, name="stub_blueprint_populate") @@ -15,15 +15,19 @@ def stub_blueprint_populate_autouse(stub_blueprint_populate: None) -> None: """Stub copying the blueprints to the config folder.""" -@pytest.fixture -async def client(hass, hass_ws_client): +@pytest.fixture(name="client") +async def client_fixture( + hass: HomeAssistant, hass_ws_client: WebSocketGenerator +) -> MockHAClientWebSocket: """Fixture that can interact with the config manager API.""" device_registry.async_setup(hass) return await hass_ws_client(hass) async def test_list_devices( - hass: HomeAssistant, client, device_registry: dr.DeviceRegistry + hass: HomeAssistant, + client: MockHAClientWebSocket, + device_registry: dr.DeviceRegistry, ) -> None: """Test list entries.""" entry = MockConfigEntry(title=None) @@ -44,10 +48,10 @@ async def test_list_devices( entry_type=dr.DeviceEntryType.SERVICE, ) - await client.send_json({"id": 5, "type": "config/device_registry/list"}) + await client.send_json_auto_id({"type": "config/device_registry/list"}) msg = await client.receive_json() - dev1, dev2 = (entry.pop("id") for entry in msg["result"]) + dev1, _ = (entry.pop("id") for entry in msg["result"]) assert msg["result"] == [ { @@ -92,7 +96,7 @@ async def test_list_devices( device_registry.async_update_device(device2.id, name=Unserializable()) await hass.async_block_till_done() - await client.send_json({"id": 6, "type": "config/device_registry/list"}) + await client.send_json_auto_id({"type": "config/device_registry/list"}) msg = await client.receive_json() assert msg["result"] == [ @@ -134,10 +138,10 @@ async def test_list_devices( ) async def test_update_device( hass: HomeAssistant, - client, + client: MockHAClientWebSocket, device_registry: dr.DeviceRegistry, - payload_key, - payload_value, + payload_key: str, + payload_value: str | None | dr.DeviceEntryDisabler, ) -> None: """Test update entry.""" entry = MockConfigEntry(title=None) @@ -152,9 +156,8 @@ async def test_update_device( assert not getattr(device, payload_key) - await client.send_json( + await client.send_json_auto_id( { - "id": 1, "type": "config/device_registry/update", "device_id": device.id, payload_key: payload_value, @@ -231,9 +234,8 @@ async def test_remove_config_entry_from_device( # Try removing a config entry from the device, it should fail because # async_remove_config_entry_device returns False - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 5, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_1.entry_id, "device_id": device_entry.id, @@ -248,9 +250,8 @@ async def test_remove_config_entry_from_device( can_remove = True # Remove the 1st config entry - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 6, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_1.entry_id, "device_id": device_entry.id, @@ -267,9 +268,8 @@ async def test_remove_config_entry_from_device( } # Remove the 2nd config entry - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 7, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_2.entry_id, "device_id": device_entry.id, @@ -354,9 +354,8 @@ async def test_remove_config_entry_from_device_fails( assert device_entry.id != fake_device_id # Try removing a non existing config entry from the device - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 5, "type": "config/device_registry/remove_config_entry", "config_entry_id": fake_entry_id, "device_id": device_entry.id, @@ -369,9 +368,8 @@ async def test_remove_config_entry_from_device_fails( assert response["error"]["message"] == "Unknown config entry" # Try removing a config entry which does not support removal from the device - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 6, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_1.entry_id, "device_id": device_entry.id, @@ -386,9 +384,8 @@ async def test_remove_config_entry_from_device_fails( ) # Try removing a config entry from a device which does not exist - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 7, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_2.entry_id, "device_id": fake_device_id, @@ -401,9 +398,8 @@ async def test_remove_config_entry_from_device_fails( assert response["error"]["message"] == "Unknown device" # Try removing a config entry from a device which it's not connected to - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 8, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_2.entry_id, "device_id": device_entry.id, @@ -417,9 +413,8 @@ async def test_remove_config_entry_from_device_fails( entry_3.entry_id, } - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 9, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_2.entry_id, "device_id": device_entry.id, @@ -432,9 +427,8 @@ async def test_remove_config_entry_from_device_fails( assert response["error"]["message"] == "Config entry not in device" # Try removing a config entry which can't be loaded from a device - allowed - await ws_client.send_json( + await ws_client.send_json_auto_id( { - "id": 10, "type": "config/device_registry/remove_config_entry", "config_entry_id": entry_3.entry_id, "device_id": device_entry.id, diff --git a/tests/helpers/test_device_registry.py b/tests/helpers/test_device_registry.py index c82a7493fe1..e83dec3ae99 100644 --- a/tests/helpers/test_device_registry.py +++ b/tests/helpers/test_device_registry.py @@ -9,7 +9,7 @@ from yarl import URL from homeassistant import config_entries from homeassistant.const import EVENT_HOMEASSISTANT_STARTED -from homeassistant.core import CoreState, HomeAssistant, callback +from homeassistant.core import CoreState, HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import ( area_registry as ar, @@ -19,26 +19,13 @@ from homeassistant.helpers import ( from tests.common import ( MockConfigEntry, + async_capture_events, flush_store, help_test_all, import_and_test_deprecated_constant_enum, ) -@pytest.fixture -def update_events(hass): - """Capture update events.""" - events = [] - - @callback - def async_capture(event): - events.append(event.data) - - hass.bus.async_listen(dr.EVENT_DEVICE_REGISTRY_UPDATED, async_capture) - - return events - - @pytest.fixture def mock_config_entry(hass: HomeAssistant) -> MockConfigEntry: """Create a mock config entry and add it to hass.""" @@ -52,9 +39,9 @@ async def test_get_or_create_returns_same_entry( device_registry: dr.DeviceRegistry, area_registry: ar.AreaRegistry, mock_config_entry: MockConfigEntry, - update_events, ) -> None: """Make sure we do not duplicate entries.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) entry = device_registry.async_get_or_create( config_entry_id=mock_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, @@ -101,13 +88,14 @@ async def test_get_or_create_returns_same_entry( # Only 2 update events. The third entry did not generate any changes. assert len(update_events) == 2 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry.id - assert update_events[1]["changes"] == { - "connections": {("mac", "12:34:56:ab:cd:ef")} + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "update", + "device_id": entry.id, + "changes": {"connections": {("mac", "12:34:56:ab:cd:ef")}}, } @@ -656,9 +644,10 @@ async def test_migration_1_3_to_1_4( async def test_removing_config_entries( - hass: HomeAssistant, device_registry: dr.DeviceRegistry, update_events + hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Make sure we do not get duplicate entries.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) config_entry_1 = MockConfigEntry() config_entry_1.add_to_hass(hass) config_entry_2 = MockConfigEntry() @@ -703,29 +692,37 @@ async def test_removing_config_entries( await hass.async_block_till_done() assert len(update_events) == 5 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry2.id - assert update_events[1]["changes"] == {"config_entries": {config_entry_1.entry_id}} - assert update_events[2]["action"] == "create" - assert update_events[2]["device_id"] == entry3.id - assert "changes" not in update_events[2] - assert update_events[3]["action"] == "update" - assert update_events[3]["device_id"] == entry.id - assert update_events[3]["changes"] == { - "config_entries": {config_entry_1.entry_id, config_entry_2.entry_id} + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "update", + "device_id": entry.id, + "changes": {"config_entries": {config_entry_1.entry_id}}, + } + assert update_events[2].data == { + "action": "create", + "device_id": entry3.id, + } + assert update_events[3].data == { + "action": "update", + "device_id": entry.id, + "changes": { + "config_entries": {config_entry_1.entry_id, config_entry_2.entry_id} + }, + } + assert update_events[4].data == { + "action": "remove", + "device_id": entry3.id, } - assert update_events[4]["action"] == "remove" - assert update_events[4]["device_id"] == entry3.id - assert "changes" not in update_events[4] async def test_deleted_device_removing_config_entries( - hass: HomeAssistant, device_registry: dr.DeviceRegistry, update_events + hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Make sure we do not get duplicate entries.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) config_entry_1 = MockConfigEntry() config_entry_1.add_to_hass(hass) config_entry_2 = MockConfigEntry() @@ -767,21 +764,27 @@ async def test_deleted_device_removing_config_entries( await hass.async_block_till_done() assert len(update_events) == 5 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry2.id - assert update_events[1]["changes"] == {"config_entries": {config_entry_1.entry_id}} - assert update_events[2]["action"] == "create" - assert update_events[2]["device_id"] == entry3.id - assert "changes" not in update_events[2]["device_id"] - assert update_events[3]["action"] == "remove" - assert update_events[3]["device_id"] == entry.id - assert "changes" not in update_events[3] - assert update_events[4]["action"] == "remove" - assert update_events[4]["device_id"] == entry3.id - assert "changes" not in update_events[4] + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "update", + "device_id": entry2.id, + "changes": {"config_entries": {config_entry_1.entry_id}}, + } + assert update_events[2].data == { + "action": "create", + "device_id": entry3.id, + } + assert update_events[3].data == { + "action": "remove", + "device_id": entry.id, + } + assert update_events[4].data == { + "action": "remove", + "device_id": entry3.id, + } device_registry.async_clear_config_entry(config_entry_1.entry_id) assert len(device_registry.devices) == 0 @@ -1105,9 +1108,9 @@ async def test_update( hass: HomeAssistant, device_registry: dr.DeviceRegistry, mock_config_entry: MockConfigEntry, - update_events, ) -> None: """Verify that we can update some attributes of a device.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) entry = device_registry.async_get_or_create( config_entry_id=mock_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, @@ -1180,33 +1183,37 @@ async def test_update( await hass.async_block_till_done() assert len(update_events) == 2 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry.id - assert update_events[1]["changes"] == { - "area_id": None, - "configuration_url": None, - "disabled_by": None, - "entry_type": None, - "hw_version": None, - "identifiers": {("bla", "123"), ("hue", "456")}, - "manufacturer": None, - "model": None, - "name": None, - "name_by_user": None, - "serial_number": None, - "suggested_area": None, - "sw_version": None, - "via_device_id": None, + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "update", + "device_id": entry.id, + "changes": { + "area_id": None, + "configuration_url": None, + "disabled_by": None, + "entry_type": None, + "hw_version": None, + "identifiers": {("bla", "123"), ("hue", "456")}, + "manufacturer": None, + "model": None, + "name": None, + "name_by_user": None, + "serial_number": None, + "suggested_area": None, + "sw_version": None, + "via_device_id": None, + }, } async def test_update_remove_config_entries( - hass: HomeAssistant, device_registry: dr.DeviceRegistry, update_events + hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Make sure we do not get duplicate entries.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) config_entry_1 = MockConfigEntry() config_entry_1.add_to_hass(hass) config_entry_2 = MockConfigEntry() @@ -1256,23 +1263,30 @@ async def test_update_remove_config_entries( await hass.async_block_till_done() assert len(update_events) == 5 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry2.id - assert update_events[1]["changes"] == {"config_entries": {config_entry_1.entry_id}} - assert update_events[2]["action"] == "create" - assert update_events[2]["device_id"] == entry3.id - assert "changes" not in update_events[2] - assert update_events[3]["action"] == "update" - assert update_events[3]["device_id"] == entry.id - assert update_events[3]["changes"] == { - "config_entries": {config_entry_1.entry_id, config_entry_2.entry_id} + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "update", + "device_id": entry2.id, + "changes": {"config_entries": {config_entry_1.entry_id}}, + } + assert update_events[2].data == { + "action": "create", + "device_id": entry3.id, + } + assert update_events[3].data == { + "action": "update", + "device_id": entry.id, + "changes": { + "config_entries": {config_entry_1.entry_id, config_entry_2.entry_id} + }, + } + assert update_events[4].data == { + "action": "remove", + "device_id": entry3.id, } - assert update_events[4]["action"] == "remove" - assert update_events[4]["device_id"] == entry3.id - assert "changes" not in update_events[4] async def test_update_suggested_area( @@ -1280,9 +1294,9 @@ async def test_update_suggested_area( device_registry: dr.DeviceRegistry, area_registry: ar.AreaRegistry, mock_config_entry: MockConfigEntry, - update_events, ) -> None: """Verify that we can update the suggested area version of a device.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) entry = device_registry.async_get_or_create( config_entry_id=mock_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, @@ -1310,12 +1324,15 @@ async def test_update_suggested_area( await hass.async_block_till_done() assert len(update_events) == 2 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry.id - assert update_events[1]["changes"] == {"area_id": None, "suggested_area": None} + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "update", + "device_id": entry.id, + "changes": {"area_id": None, "suggested_area": None}, + } # Do not save or fire the event if the suggested # area does not result in a change of area @@ -1457,9 +1474,9 @@ async def test_restore_device( hass: HomeAssistant, device_registry: dr.DeviceRegistry, mock_config_entry: MockConfigEntry, - update_events, ) -> None: """Make sure device id is stable.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) entry = device_registry.async_get_or_create( config_entry_id=mock_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, @@ -1503,27 +1520,31 @@ async def test_restore_device( await hass.async_block_till_done() assert len(update_events) == 4 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "remove" - assert update_events[1]["device_id"] == entry.id - assert "changes" not in update_events[1] - assert update_events[2]["action"] == "create" - assert update_events[2]["device_id"] == entry2.id - assert "changes" not in update_events[2] - assert update_events[3]["action"] == "create" - assert update_events[3]["device_id"] == entry3.id - assert "changes" not in update_events[3] + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "remove", + "device_id": entry.id, + } + assert update_events[2].data == { + "action": "create", + "device_id": entry2.id, + } + assert update_events[3].data == { + "action": "create", + "device_id": entry3.id, + } async def test_restore_simple_device( hass: HomeAssistant, device_registry: dr.DeviceRegistry, mock_config_entry: MockConfigEntry, - update_events, ) -> None: """Make sure device id is stable.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) entry = device_registry.async_get_or_create( config_entry_id=mock_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, @@ -1557,24 +1578,29 @@ async def test_restore_simple_device( await hass.async_block_till_done() assert len(update_events) == 4 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "remove" - assert update_events[1]["device_id"] == entry.id - assert "changes" not in update_events[1] - assert update_events[2]["action"] == "create" - assert update_events[2]["device_id"] == entry2.id - assert "changes" not in update_events[2] - assert update_events[3]["action"] == "create" - assert update_events[3]["device_id"] == entry3.id - assert "changes" not in update_events[3] + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[1].data == { + "action": "remove", + "device_id": entry.id, + } + assert update_events[2].data == { + "action": "create", + "device_id": entry2.id, + } + assert update_events[3].data == { + "action": "create", + "device_id": entry3.id, + } async def test_restore_shared_device( - hass: HomeAssistant, device_registry: dr.DeviceRegistry, update_events + hass: HomeAssistant, device_registry: dr.DeviceRegistry ) -> None: """Make sure device id is stable for shared devices.""" + update_events = async_capture_events(hass, dr.EVENT_DEVICE_REGISTRY_UPDATED) config_entry_1 = MockConfigEntry() config_entry_1.add_to_hass(hass) config_entry_2 = MockConfigEntry() @@ -1660,32 +1686,41 @@ async def test_restore_shared_device( await hass.async_block_till_done() assert len(update_events) == 7 - assert update_events[0]["action"] == "create" - assert update_events[0]["device_id"] == entry.id - assert "changes" not in update_events[0] - assert update_events[1]["action"] == "update" - assert update_events[1]["device_id"] == entry.id - assert update_events[1]["changes"] == { - "config_entries": {config_entry_1.entry_id}, - "identifiers": {("entry_123", "0123")}, + assert update_events[0].data == { + "action": "create", + "device_id": entry.id, } - assert update_events[2]["action"] == "remove" - assert update_events[2]["device_id"] == entry.id - assert "changes" not in update_events[2] - assert update_events[3]["action"] == "create" - assert update_events[3]["device_id"] == entry.id - assert "changes" not in update_events[3] - assert update_events[4]["action"] == "remove" - assert update_events[4]["device_id"] == entry.id - assert "changes" not in update_events[4] - assert update_events[5]["action"] == "create" - assert update_events[5]["device_id"] == entry.id - assert "changes" not in update_events[5] - assert update_events[6]["action"] == "update" - assert update_events[6]["device_id"] == entry.id - assert update_events[6]["changes"] == { - "config_entries": {config_entry_2.entry_id}, - "identifiers": {("entry_234", "2345")}, + assert update_events[1].data == { + "action": "update", + "device_id": entry.id, + "changes": { + "config_entries": {config_entry_1.entry_id}, + "identifiers": {("entry_123", "0123")}, + }, + } + assert update_events[2].data == { + "action": "remove", + "device_id": entry.id, + } + assert update_events[3].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[4].data == { + "action": "remove", + "device_id": entry.id, + } + assert update_events[5].data == { + "action": "create", + "device_id": entry.id, + } + assert update_events[6].data == { + "action": "update", + "device_id": entry.id, + "changes": { + "config_entries": {config_entry_2.entry_id}, + "identifiers": {("entry_234", "2345")}, + }, }