mirror of
https://github.com/home-assistant/core.git
synced 2025-04-26 02:07:54 +00:00
Add ability to replace connections in DeviceRegistry (#118555)
* Add ability to replace connections in DeviceRegistry * Add more tests * Improve coverage * Apply suggestion Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io> --------- Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
parent
d823e56659
commit
b459559c8b
@ -798,6 +798,7 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
|
|||||||
model: str | None | UndefinedType = UNDEFINED,
|
model: str | None | UndefinedType = UNDEFINED,
|
||||||
name_by_user: str | None | UndefinedType = UNDEFINED,
|
name_by_user: str | None | UndefinedType = UNDEFINED,
|
||||||
name: str | None | UndefinedType = UNDEFINED,
|
name: str | None | UndefinedType = UNDEFINED,
|
||||||
|
new_connections: set[tuple[str, str]] | UndefinedType = UNDEFINED,
|
||||||
new_identifiers: set[tuple[str, str]] | UndefinedType = UNDEFINED,
|
new_identifiers: set[tuple[str, str]] | UndefinedType = UNDEFINED,
|
||||||
remove_config_entry_id: str | UndefinedType = UNDEFINED,
|
remove_config_entry_id: str | UndefinedType = UNDEFINED,
|
||||||
serial_number: str | None | UndefinedType = UNDEFINED,
|
serial_number: str | None | UndefinedType = UNDEFINED,
|
||||||
@ -813,6 +814,9 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
|
|||||||
|
|
||||||
config_entries = old.config_entries
|
config_entries = old.config_entries
|
||||||
|
|
||||||
|
if merge_connections is not UNDEFINED and new_connections is not UNDEFINED:
|
||||||
|
raise HomeAssistantError("Cannot define both merge_connections and new_connections")
|
||||||
|
|
||||||
if merge_identifiers is not UNDEFINED and new_identifiers is not UNDEFINED:
|
if merge_identifiers is not UNDEFINED and new_identifiers is not UNDEFINED:
|
||||||
raise HomeAssistantError
|
raise HomeAssistantError
|
||||||
|
|
||||||
@ -873,6 +877,10 @@ class DeviceRegistry(BaseRegistry[dict[str, list[dict[str, Any]]]]):
|
|||||||
new_values[attr_name] = old_value | setvalue
|
new_values[attr_name] = old_value | setvalue
|
||||||
old_values[attr_name] = old_value
|
old_values[attr_name] = old_value
|
||||||
|
|
||||||
|
if new_connections is not UNDEFINED:
|
||||||
|
new_values["connections"] = _normalize_connections(new_connections)
|
||||||
|
old_values["connections"] = old.connections
|
||||||
|
|
||||||
if new_identifiers is not UNDEFINED:
|
if new_identifiers is not UNDEFINED:
|
||||||
new_values["identifiers"] = new_identifiers
|
new_values["identifiers"] = new_identifiers
|
||||||
old_values["identifiers"] = old.identifiers
|
old_values["identifiers"] = old.identifiers
|
||||||
|
@ -1257,6 +1257,7 @@ async def test_update(
|
|||||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
identifiers={("hue", "456"), ("bla", "123")},
|
identifiers={("hue", "456"), ("bla", "123")},
|
||||||
)
|
)
|
||||||
|
new_connections = {(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA")}
|
||||||
new_identifiers = {("hue", "654"), ("bla", "321")}
|
new_identifiers = {("hue", "654"), ("bla", "321")}
|
||||||
assert not entry.area_id
|
assert not entry.area_id
|
||||||
assert not entry.labels
|
assert not entry.labels
|
||||||
@ -1275,6 +1276,7 @@ async def test_update(
|
|||||||
model="Test Model",
|
model="Test Model",
|
||||||
name_by_user="Test Friendly Name",
|
name_by_user="Test Friendly Name",
|
||||||
name="name",
|
name="name",
|
||||||
|
new_connections=new_connections,
|
||||||
new_identifiers=new_identifiers,
|
new_identifiers=new_identifiers,
|
||||||
serial_number="serial_no",
|
serial_number="serial_no",
|
||||||
suggested_area="suggested_area",
|
suggested_area="suggested_area",
|
||||||
@ -1288,7 +1290,7 @@ async def test_update(
|
|||||||
area_id="12345A",
|
area_id="12345A",
|
||||||
config_entries={mock_config_entry.entry_id},
|
config_entries={mock_config_entry.entry_id},
|
||||||
configuration_url="https://example.com/config",
|
configuration_url="https://example.com/config",
|
||||||
connections={("mac", "12:34:56:ab:cd:ef")},
|
connections={("mac", "65:43:21:fe:dc:ba")},
|
||||||
disabled_by=dr.DeviceEntryDisabler.USER,
|
disabled_by=dr.DeviceEntryDisabler.USER,
|
||||||
entry_type=dr.DeviceEntryType.SERVICE,
|
entry_type=dr.DeviceEntryType.SERVICE,
|
||||||
hw_version="hw_version",
|
hw_version="hw_version",
|
||||||
@ -1319,6 +1321,12 @@ async def test_update(
|
|||||||
device_registry.async_get_device(
|
device_registry.async_get_device(
|
||||||
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}
|
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}
|
||||||
)
|
)
|
||||||
|
is None
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
device_registry.async_get_device(
|
||||||
|
connections={(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA")}
|
||||||
|
)
|
||||||
== updated_entry
|
== updated_entry
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1336,6 +1344,7 @@ async def test_update(
|
|||||||
"device_id": entry.id,
|
"device_id": entry.id,
|
||||||
"changes": {
|
"changes": {
|
||||||
"area_id": None,
|
"area_id": None,
|
||||||
|
"connections": {("mac", "12:34:56:ab:cd:ef")},
|
||||||
"configuration_url": None,
|
"configuration_url": None,
|
||||||
"disabled_by": None,
|
"disabled_by": None,
|
||||||
"entry_type": None,
|
"entry_type": None,
|
||||||
@ -1352,6 +1361,105 @@ async def test_update(
|
|||||||
"via_device_id": None,
|
"via_device_id": None,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
device_registry.async_update_device(
|
||||||
|
entry.id,
|
||||||
|
merge_connections=new_connections,
|
||||||
|
new_connections=new_connections,
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
device_registry.async_update_device(
|
||||||
|
entry.id,
|
||||||
|
merge_identifiers=new_identifiers,
|
||||||
|
new_identifiers=new_identifiers,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("initial_connections", "new_connections", "updated_connections"),
|
||||||
|
[
|
||||||
|
( # No connection -> single connection
|
||||||
|
None,
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "12:34:56:ab:cd:ef")},
|
||||||
|
),
|
||||||
|
( # No connection -> double connection
|
||||||
|
None,
|
||||||
|
{
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA"),
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "65:43:21:fe:dc:ba"),
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "12:34:56:ab:cd:ef"),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
( # single connection -> no connection
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA")},
|
||||||
|
set(),
|
||||||
|
set(),
|
||||||
|
),
|
||||||
|
( # single connection -> single connection
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA")},
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "12:34:56:ab:cd:ef")},
|
||||||
|
),
|
||||||
|
( # single connection -> double connection
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA")},
|
||||||
|
{
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA"),
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "65:43:21:fe:dc:ba"),
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "12:34:56:ab:cd:ef"),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
( # Double connection -> None
|
||||||
|
{
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF"),
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA"),
|
||||||
|
},
|
||||||
|
set(),
|
||||||
|
set(),
|
||||||
|
),
|
||||||
|
( # Double connection -> single connection
|
||||||
|
{
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA"),
|
||||||
|
(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF"),
|
||||||
|
},
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "65:43:21:FE:DC:BA")},
|
||||||
|
{(dr.CONNECTION_NETWORK_MAC, "65:43:21:fe:dc:ba")},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_update_connection(
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
initial_connections: set[tuple[str, str]] | None,
|
||||||
|
new_connections: set[tuple[str, str]] | None,
|
||||||
|
updated_connections: set[tuple[str, str]] | None,
|
||||||
|
) -> None:
|
||||||
|
"""Verify that we can update some attributes of a device."""
|
||||||
|
entry = device_registry.async_get_or_create(
|
||||||
|
config_entry_id=mock_config_entry.entry_id,
|
||||||
|
connections=initial_connections,
|
||||||
|
identifiers={("hue", "456"), ("bla", "123")},
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch.object(device_registry, "async_schedule_save") as mock_save:
|
||||||
|
updated_entry = device_registry.async_update_device(
|
||||||
|
entry.id,
|
||||||
|
new_connections=new_connections,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert mock_save.call_count == 1
|
||||||
|
assert updated_entry != entry
|
||||||
|
assert updated_entry.connections == updated_connections
|
||||||
|
assert (
|
||||||
|
device_registry.async_get_device(identifiers={("bla", "123")}) == updated_entry
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_update_remove_config_entries(
|
async def test_update_remove_config_entries(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user