mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
Validate config entry when adding or updating entity registry entry (#135067)
This commit is contained in:
parent
028a0d4eec
commit
235fda55fe
@ -648,6 +648,7 @@ def _validate_item(
|
||||
domain: str,
|
||||
platform: str,
|
||||
*,
|
||||
config_entry_id: str | None | UndefinedType = None,
|
||||
device_id: str | None | UndefinedType = None,
|
||||
disabled_by: RegistryEntryDisabler | None | UndefinedType = None,
|
||||
entity_category: EntityCategory | None | UndefinedType = None,
|
||||
@ -672,6 +673,11 @@ def _validate_item(
|
||||
unique_id,
|
||||
report_issue,
|
||||
)
|
||||
if config_entry_id and config_entry_id is not UNDEFINED:
|
||||
if not hass.config_entries.async_get_entry(config_entry_id):
|
||||
raise ValueError(
|
||||
f"Can't link entity to unknown config entry {config_entry_id}"
|
||||
)
|
||||
if device_id and device_id is not UNDEFINED:
|
||||
device_registry = dr.async_get(hass)
|
||||
if not device_registry.async_get(device_id):
|
||||
@ -864,6 +870,7 @@ class EntityRegistry(BaseRegistry):
|
||||
self.hass,
|
||||
domain,
|
||||
platform,
|
||||
config_entry_id=config_entry_id,
|
||||
device_id=device_id,
|
||||
disabled_by=disabled_by,
|
||||
entity_category=entity_category,
|
||||
@ -1096,6 +1103,7 @@ class EntityRegistry(BaseRegistry):
|
||||
self.hass,
|
||||
old.domain,
|
||||
old.platform,
|
||||
config_entry_id=config_entry_id,
|
||||
device_id=device_id,
|
||||
disabled_by=disabled_by,
|
||||
entity_category=entity_category,
|
||||
|
@ -82,6 +82,7 @@ def _setup_entry(hass: HomeAssistant, config, sensors, unique_id=None):
|
||||
options={CONF_CONSIDER_HOME: 60},
|
||||
unique_id=unique_id,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
# init variable
|
||||
obj_prefix = slugify(HOST)
|
||||
@ -131,8 +132,6 @@ async def _test_sensors(
|
||||
disabled_by=None,
|
||||
)
|
||||
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
# initial devices setup
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
@ -751,6 +751,7 @@ async def test_unique_id_migration(
|
||||
old_unique_id,
|
||||
) -> None:
|
||||
"""Test that old unique id format is migrated to the new format that supports multiple accounts."""
|
||||
config_entry.add_to_hass(hass)
|
||||
# Create an entity using the old unique id format
|
||||
entity_registry.async_get_or_create(
|
||||
DOMAIN,
|
||||
@ -805,6 +806,7 @@ async def test_invalid_unique_id_cleanup(
|
||||
mock_calendars_yaml,
|
||||
) -> None:
|
||||
"""Test that old unique id format that is not actually unique is removed."""
|
||||
config_entry.add_to_hass(hass)
|
||||
# Create an entity using the old unique id format
|
||||
entity_registry.async_get_or_create(
|
||||
DOMAIN,
|
||||
|
@ -1200,6 +1200,7 @@ async def test_unique_id(
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test unique id convert to string."""
|
||||
config_entry.add_to_hass(hass)
|
||||
entity_registry.async_get_or_create(
|
||||
Platform.CLIMATE,
|
||||
DOMAIN,
|
||||
|
@ -166,6 +166,7 @@ async def test_group_entity_migration_with_v1_id(
|
||||
) -> None:
|
||||
"""Test if entity schema for grouped_lights migrates from v1 to v2."""
|
||||
config_entry = mock_bridge_v2.config_entry = mock_config_entry_v2
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
# create (deviceless) entity with V1 schema in registry
|
||||
# using the legacy style group id as unique id
|
||||
@ -201,6 +202,7 @@ async def test_group_entity_migration_with_v2_group_id(
|
||||
) -> None:
|
||||
"""Test if entity schema for grouped_lights migrates from v1 to v2."""
|
||||
config_entry = mock_bridge_v2.config_entry = mock_config_entry_v2
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
# create (deviceless) entity with V1 schema in registry
|
||||
# using the V2 group id as unique id
|
||||
|
@ -368,6 +368,7 @@ async def test_migrate_entry(
|
||||
version=1,
|
||||
minor_version=1,
|
||||
)
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
# Add entries with int unique_id
|
||||
entity_registry.async_get_or_create(
|
||||
@ -387,7 +388,6 @@ async def test_migrate_entry(
|
||||
assert entry.version == 1
|
||||
assert entry.minor_version == 1
|
||||
|
||||
entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -444,6 +444,7 @@ async def test_no_listen_start(
|
||||
version=1,
|
||||
data={"username": "foo", "token": {}},
|
||||
)
|
||||
mock_entry.add_to_hass(hass)
|
||||
# Create a binary sensor entity so it is not ignored by the deprecation check
|
||||
# and the listener will start
|
||||
entity_registry.async_get_or_create(
|
||||
@ -457,7 +458,6 @@ async def test_no_listen_start(
|
||||
|
||||
mock_ring_event_listener_class.return_value.started = False
|
||||
|
||||
mock_entry.add_to_hass(hass)
|
||||
await hass.config_entries.async_setup(mock_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
@ -46,6 +46,7 @@ async def test_entity_id_migration(
|
||||
) -> None:
|
||||
"""Test the migration of unique IDs on config entry setup."""
|
||||
config_entry = mock_config_entry(unique_id="binary_sensor_test_diffuser_v1")
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
# Pre-create old style unique IDs
|
||||
charging = entity_registry.async_get_or_create(
|
||||
|
@ -100,6 +100,7 @@ async def test_entity_entry_migration(
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test successful migration of entry data."""
|
||||
mock_config_entry.add_to_hass(hass)
|
||||
entity = entity_registry.async_get_or_create(
|
||||
suggested_object_id="advice",
|
||||
disabled_by=None,
|
||||
|
@ -374,6 +374,7 @@ async def test_change_device_source(
|
||||
|
||||
# Configure source entity 3 (without a device)
|
||||
source_config_entry_3 = MockConfigEntry()
|
||||
source_config_entry_3.add_to_hass(hass)
|
||||
source_entity_3 = entity_registry.async_get_or_create(
|
||||
"sensor",
|
||||
"test",
|
||||
|
@ -869,6 +869,7 @@ async def test_setup_entry(
|
||||
|
||||
platform = MockPlatform(async_setup_entry=async_setup_entry)
|
||||
config_entry = MockConfigEntry(entry_id="super-mock-id")
|
||||
config_entry.add_to_hass(hass)
|
||||
entity_platform = MockEntityPlatform(
|
||||
hass, platform_name=config_entry.domain, platform=platform
|
||||
)
|
||||
@ -1886,6 +1887,7 @@ async def test_setup_entry_with_entities_that_block_forever(
|
||||
|
||||
platform = MockPlatform(async_setup_entry=async_setup_entry)
|
||||
config_entry = MockConfigEntry(entry_id="super-mock-id")
|
||||
config_entry.add_to_hass(hass)
|
||||
platform = MockEntityPlatform(
|
||||
hass, platform_name=config_entry.domain, platform=platform
|
||||
)
|
||||
@ -1934,6 +1936,7 @@ async def test_cancellation_is_not_blocked(
|
||||
|
||||
platform = MockPlatform(async_setup_entry=async_setup_entry)
|
||||
config_entry = MockConfigEntry(entry_id="super-mock-id")
|
||||
config_entry.add_to_hass(hass)
|
||||
platform = MockEntityPlatform(
|
||||
hass, platform_name=config_entry.domain, platform=platform
|
||||
)
|
||||
|
@ -616,11 +616,13 @@ async def test_updating_config_entry_id(
|
||||
"""Test that we update config entry id in registry."""
|
||||
update_events = async_capture_events(hass, er.EVENT_ENTITY_REGISTRY_UPDATED)
|
||||
mock_config_1 = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config_1.add_to_hass(hass)
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config_1
|
||||
)
|
||||
|
||||
mock_config_2 = MockConfigEntry(domain="light", entry_id="mock-id-2")
|
||||
mock_config_2.add_to_hass(hass)
|
||||
entry2 = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config_2
|
||||
)
|
||||
@ -647,6 +649,7 @@ async def test_removing_config_entry_id(
|
||||
"""Test that we update config entry id in registry."""
|
||||
update_events = async_capture_events(hass, er.EVENT_ENTITY_REGISTRY_UPDATED)
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config.add_to_hass(hass)
|
||||
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
@ -670,11 +673,14 @@ async def test_removing_config_entry_id(
|
||||
|
||||
|
||||
async def test_deleted_entity_removing_config_entry_id(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test that we update config entry id in registry on deleted entity."""
|
||||
mock_config1 = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config2 = MockConfigEntry(domain="light", entry_id="mock-id-2")
|
||||
mock_config1.add_to_hass(hass)
|
||||
mock_config2.add_to_hass(hass)
|
||||
|
||||
entry1 = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config1
|
||||
@ -979,9 +985,12 @@ async def test_migration_1_11(
|
||||
}
|
||||
|
||||
|
||||
async def test_update_entity_unique_id(entity_registry: er.EntityRegistry) -> None:
|
||||
async def test_update_entity_unique_id(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test entity's unique_id is updated."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config.add_to_hass(hass)
|
||||
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
@ -1007,10 +1016,12 @@ async def test_update_entity_unique_id(entity_registry: er.EntityRegistry) -> No
|
||||
|
||||
|
||||
async def test_update_entity_unique_id_conflict(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test migration raises when unique_id already in use."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config.add_to_hass(hass)
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
@ -1099,9 +1110,12 @@ async def test_update_entity_entity_id_entity_id(
|
||||
assert entity_registry.async_get(state_entity_id) is None
|
||||
|
||||
|
||||
async def test_update_entity(entity_registry: er.EntityRegistry) -> None:
|
||||
async def test_update_entity(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test updating entity."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config.add_to_hass(hass)
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
@ -1126,9 +1140,12 @@ async def test_update_entity(entity_registry: er.EntityRegistry) -> None:
|
||||
entry = updated_entry
|
||||
|
||||
|
||||
async def test_update_entity_options(entity_registry: er.EntityRegistry) -> None:
|
||||
async def test_update_entity_options(
|
||||
hass: HomeAssistant, entity_registry: er.EntityRegistry
|
||||
) -> None:
|
||||
"""Test updating entity."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
mock_config.add_to_hass(hass)
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
@ -1181,6 +1198,7 @@ async def test_disabled_by(entity_registry: er.EntityRegistry) -> None:
|
||||
|
||||
|
||||
async def test_disabled_by_config_entry_pref(
|
||||
hass: HomeAssistant,
|
||||
entity_registry: er.EntityRegistry,
|
||||
) -> None:
|
||||
"""Test config entry preference setting disabled_by."""
|
||||
@ -1189,6 +1207,7 @@ async def test_disabled_by_config_entry_pref(
|
||||
entry_id="mock-id-1",
|
||||
pref_disable_new_entities=True,
|
||||
)
|
||||
mock_config.add_to_hass(hass)
|
||||
entry = entity_registry.async_get_or_create(
|
||||
"light", "hue", "AAAA", config_entry=mock_config
|
||||
)
|
||||
@ -1761,6 +1780,25 @@ def test_entity_registry_items() -> None:
|
||||
assert entities.get_entry(entry2.id) is None
|
||||
|
||||
|
||||
async def test_config_entry_does_not_exist(entity_registry: er.EntityRegistry) -> None:
|
||||
"""Test adding an entity linked to an unknown config entry."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain="light",
|
||||
entry_id="mock-id-1",
|
||||
pref_disable_new_entities=True,
|
||||
)
|
||||
with pytest.raises(ValueError):
|
||||
entity_registry.async_get_or_create(
|
||||
"light", "hue", "1234", config_entry=mock_config
|
||||
)
|
||||
|
||||
entity_id = entity_registry.async_get_or_create("light", "hue", "1234").entity_id
|
||||
with pytest.raises(ValueError):
|
||||
entity_registry.async_update_entity(
|
||||
entity_id, config_entry_id=mock_config.entry_id
|
||||
)
|
||||
|
||||
|
||||
async def test_device_does_not_exist(entity_registry: er.EntityRegistry) -> None:
|
||||
"""Test adding an entity linked to an unknown device."""
|
||||
with pytest.raises(ValueError):
|
||||
@ -1848,6 +1886,7 @@ def test_migrate_entity_to_new_platform(
|
||||
) -> None:
|
||||
"""Test migrate_entity_to_new_platform."""
|
||||
orig_config_entry = MockConfigEntry(domain="light")
|
||||
orig_config_entry.add_to_hass(hass)
|
||||
orig_unique_id = "5678"
|
||||
|
||||
orig_entry = entity_registry.async_get_or_create(
|
||||
@ -1870,6 +1909,7 @@ def test_migrate_entity_to_new_platform(
|
||||
)
|
||||
|
||||
new_config_entry = MockConfigEntry(domain="light")
|
||||
new_config_entry.add_to_hass(hass)
|
||||
new_unique_id = "1234"
|
||||
|
||||
assert entity_registry.async_update_entity_platform(
|
||||
@ -1924,6 +1964,7 @@ async def test_restore_entity(
|
||||
"""Make sure entity registry id is stable and entity_id is reused if possible."""
|
||||
update_events = async_capture_events(hass, er.EVENT_ENTITY_REGISTRY_UPDATED)
|
||||
config_entry = MockConfigEntry(domain="light")
|
||||
config_entry.add_to_hass(hass)
|
||||
entry1 = entity_registry.async_get_or_create(
|
||||
"light", "hue", "1234", config_entry=config_entry
|
||||
)
|
||||
@ -2018,6 +2059,8 @@ async def test_async_migrate_entry_delete_self(
|
||||
"""Test async_migrate_entry."""
|
||||
config_entry1 = MockConfigEntry(domain="test1")
|
||||
config_entry2 = MockConfigEntry(domain="test2")
|
||||
config_entry1.add_to_hass(hass)
|
||||
config_entry2.add_to_hass(hass)
|
||||
entry1 = entity_registry.async_get_or_create(
|
||||
"light", "hue", "1234", config_entry=config_entry1, original_name="Entry 1"
|
||||
)
|
||||
@ -2053,6 +2096,8 @@ async def test_async_migrate_entry_delete_other(
|
||||
"""Test async_migrate_entry."""
|
||||
config_entry1 = MockConfigEntry(domain="test1")
|
||||
config_entry2 = MockConfigEntry(domain="test2")
|
||||
config_entry1.add_to_hass(hass)
|
||||
config_entry2.add_to_hass(hass)
|
||||
entry1 = entity_registry.async_get_or_create(
|
||||
"light", "hue", "1234", config_entry=config_entry1, original_name="Entry 1"
|
||||
)
|
||||
|
@ -2126,6 +2126,7 @@ async def test_state_translated(
|
||||
hass.states.async_set("domain.is_unknown", "unknown", attributes={})
|
||||
|
||||
config_entry = MockConfigEntry(domain="light")
|
||||
config_entry.add_to_hass(hass)
|
||||
entity_registry.async_get_or_create(
|
||||
"light",
|
||||
"hue",
|
||||
|
Loading…
x
Reference in New Issue
Block a user