Add system options to config entries (#25926)
* Add system options to config entries * For feedback * Follow most of balloobs comments * Fix balloobs comments * Improvements * Fix second round of Balloobs comments * Fix third round * Add system options to mock config entry * Fix integration tests * Fix the last failing tests * Fix disabled string * Fix failing disabled_by tests * New tests * Config entry WS API tests * Fix commentspull/26035/head
parent
fc716a45c9
commit
a2589f56e1
|
@ -1,6 +1,9 @@
|
|||
"""Http views to control the config manager."""
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.auth.permissions.const import CAT_CONFIG_ENTRIES
|
||||
from homeassistant.components import websocket_api
|
||||
from homeassistant.components.http import HomeAssistantView
|
||||
from homeassistant.exceptions import Unauthorized
|
||||
from homeassistant.helpers.data_entry_flow import (
|
||||
|
@ -17,12 +20,17 @@ async def async_setup(hass):
|
|||
hass.http.register_view(ConfigManagerFlowIndexView(hass.config_entries.flow))
|
||||
hass.http.register_view(ConfigManagerFlowResourceView(hass.config_entries.flow))
|
||||
hass.http.register_view(ConfigManagerAvailableFlowView)
|
||||
|
||||
hass.http.register_view(
|
||||
OptionManagerFlowIndexView(hass.config_entries.options.flow)
|
||||
)
|
||||
hass.http.register_view(
|
||||
OptionManagerFlowResourceView(hass.config_entries.options.flow)
|
||||
)
|
||||
|
||||
hass.components.websocket_api.async_register_command(system_options_list)
|
||||
hass.components.websocket_api.async_register_command(system_options_update)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
@ -231,3 +239,40 @@ class OptionManagerFlowResourceView(FlowManagerResourceView):
|
|||
|
||||
# pylint: disable=no-value-for-parameter
|
||||
return await super().post(request, flow_id)
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
@websocket_api.async_response
|
||||
@websocket_api.websocket_command(
|
||||
{"type": "config_entries/system_options/list", "entry_id": str}
|
||||
)
|
||||
async def system_options_list(hass, connection, msg):
|
||||
"""List all system options for a config entry."""
|
||||
entry_id = msg["entry_id"]
|
||||
entry = hass.config_entries.async_get_entry(entry_id)
|
||||
|
||||
if entry:
|
||||
connection.send_result(msg["id"], entry.system_options.as_dict())
|
||||
|
||||
|
||||
@websocket_api.require_admin
|
||||
@websocket_api.async_response
|
||||
@websocket_api.websocket_command(
|
||||
{
|
||||
"type": "config_entries/system_options/update",
|
||||
"entry_id": str,
|
||||
vol.Optional("disable_new_entities"): bool,
|
||||
}
|
||||
)
|
||||
async def system_options_update(hass, connection, msg):
|
||||
"""Update config entry system options."""
|
||||
changes = dict(msg)
|
||||
changes.pop("id")
|
||||
changes.pop("type")
|
||||
entry_id = changes.pop("entry_id")
|
||||
entry = hass.config_entries.async_get_entry(entry_id)
|
||||
|
||||
if entry and changes:
|
||||
entry.system_options.update(**changes)
|
||||
|
||||
connection.send_result(msg["id"], entry.system_options.as_dict())
|
||||
|
|
|
@ -127,7 +127,7 @@ async def async_migrate_entry(hass, entry):
|
|||
DOMAIN,
|
||||
unique_id,
|
||||
suggested_object_id=new_id,
|
||||
config_entry_id=e_entry.config_entry_id,
|
||||
config_entry=entry,
|
||||
device_id=e_entry.device_id,
|
||||
)
|
||||
entry.version = 3
|
||||
|
|
|
@ -12,13 +12,14 @@ from typing import (
|
|||
)
|
||||
import weakref
|
||||
|
||||
import attr
|
||||
|
||||
from homeassistant import data_entry_flow, loader
|
||||
from homeassistant.core import callback, HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ConfigEntryNotReady
|
||||
from homeassistant.setup import async_setup_component, async_process_deps_reqs
|
||||
from homeassistant.util.decorator import Registry
|
||||
|
||||
|
||||
# mypy: allow-untyped-defs
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -88,6 +89,7 @@ class ConfigEntry:
|
|||
"title",
|
||||
"data",
|
||||
"options",
|
||||
"system_options",
|
||||
"source",
|
||||
"connection_class",
|
||||
"state",
|
||||
|
@ -104,6 +106,7 @@ class ConfigEntry:
|
|||
data: dict,
|
||||
source: str,
|
||||
connection_class: str,
|
||||
system_options: dict,
|
||||
options: Optional[dict] = None,
|
||||
entry_id: Optional[str] = None,
|
||||
state: str = ENTRY_STATE_NOT_LOADED,
|
||||
|
@ -127,6 +130,9 @@ class ConfigEntry:
|
|||
# Entry options
|
||||
self.options = options or {}
|
||||
|
||||
# Entry system options
|
||||
self.system_options = SystemOptions(**system_options)
|
||||
|
||||
# Source of the configuration (user, discovery, cloud)
|
||||
self.source = source
|
||||
|
||||
|
@ -355,6 +361,7 @@ class ConfigEntry:
|
|||
"title": self.title,
|
||||
"data": self.data,
|
||||
"options": self.options,
|
||||
"system_options": self.system_options.as_dict(),
|
||||
"source": self.source,
|
||||
"connection_class": self.connection_class,
|
||||
}
|
||||
|
@ -457,6 +464,8 @@ class ConfigEntries:
|
|||
connection_class=entry.get("connection_class", CONN_CLASS_UNKNOWN),
|
||||
# New in 0.89
|
||||
options=entry.get("options"),
|
||||
# New in 0.98
|
||||
system_options=entry.get("system_options", {}),
|
||||
)
|
||||
for entry in config["entries"]
|
||||
]
|
||||
|
@ -580,6 +589,7 @@ class ConfigEntries:
|
|||
title=result["title"],
|
||||
data=result["data"],
|
||||
options={},
|
||||
system_options={},
|
||||
source=flow.context["source"],
|
||||
connection_class=flow.CONNECTION_CLASS,
|
||||
)
|
||||
|
@ -722,3 +732,18 @@ class OptionsFlow(data_entry_flow.FlowHandler):
|
|||
"""Base class for config option flows."""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@attr.s(slots=True)
|
||||
class SystemOptions:
|
||||
"""Config entry system options."""
|
||||
|
||||
disable_new_entities = attr.ib(type=bool, default=False)
|
||||
|
||||
def update(self, *, disable_new_entities):
|
||||
"""Update properties."""
|
||||
self.disable_new_entities = disable_new_entities
|
||||
|
||||
def as_dict(self):
|
||||
"""Return dictionary version of this config entrys system options."""
|
||||
return {"disable_new_entities": self.disable_new_entities}
|
||||
|
|
|
@ -343,7 +343,7 @@ class EntityPlatform:
|
|||
self.platform_name,
|
||||
entity.unique_id,
|
||||
suggested_object_id=suggested_object_id,
|
||||
config_entry_id=config_entry_id,
|
||||
config_entry=self.config_entry,
|
||||
device_id=device_id,
|
||||
known_object_ids=self.entities.keys(),
|
||||
disabled_by=disabled_by,
|
||||
|
|
|
@ -33,6 +33,7 @@ EVENT_ENTITY_REGISTRY_UPDATED = "entity_registry_updated"
|
|||
SAVE_DELAY = 10
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_UNDEF = object()
|
||||
DISABLED_CONFIG_ENTRY = "config_entry"
|
||||
DISABLED_HASS = "hass"
|
||||
DISABLED_USER = "user"
|
||||
DISABLED_INTEGRATION = "integration"
|
||||
|
@ -55,7 +56,13 @@ class RegistryEntry:
|
|||
type=str,
|
||||
default=None,
|
||||
validator=attr.validators.in_(
|
||||
(DISABLED_HASS, DISABLED_USER, DISABLED_INTEGRATION, None)
|
||||
(
|
||||
DISABLED_HASS,
|
||||
DISABLED_USER,
|
||||
DISABLED_INTEGRATION,
|
||||
DISABLED_CONFIG_ENTRY,
|
||||
None,
|
||||
)
|
||||
),
|
||||
) # type: Optional[str]
|
||||
domain = attr.ib(type=str, init=False, repr=False)
|
||||
|
@ -132,13 +139,18 @@ class EntityRegistry:
|
|||
unique_id,
|
||||
*,
|
||||
suggested_object_id=None,
|
||||
config_entry_id=None,
|
||||
config_entry=None,
|
||||
device_id=None,
|
||||
known_object_ids=None,
|
||||
disabled_by=None,
|
||||
):
|
||||
"""Get entity. Create if it doesn't exist."""
|
||||
config_entry_id = None
|
||||
if config_entry:
|
||||
config_entry_id = config_entry.entry_id
|
||||
|
||||
entity_id = self.async_get_entity_id(domain, platform, unique_id)
|
||||
|
||||
if entity_id:
|
||||
return self._async_update_entity(
|
||||
entity_id,
|
||||
|
@ -159,6 +171,13 @@ class EntityRegistry:
|
|||
known_object_ids,
|
||||
)
|
||||
|
||||
if (
|
||||
disabled_by is None
|
||||
and config_entry
|
||||
and config_entry.system_options.disable_new_entities
|
||||
):
|
||||
disabled_by = DISABLED_INTEGRATION
|
||||
|
||||
entity = RegistryEntry(
|
||||
entity_id=entity_id,
|
||||
config_entry_id=config_entry_id,
|
||||
|
|
|
@ -665,6 +665,7 @@ class MockConfigEntry(config_entries.ConfigEntry):
|
|||
title="Mock Title",
|
||||
state=None,
|
||||
options={},
|
||||
system_options={},
|
||||
connection_class=config_entries.CONN_CLASS_UNKNOWN,
|
||||
):
|
||||
"""Initialize a mock config entry."""
|
||||
|
@ -672,6 +673,7 @@ class MockConfigEntry(config_entries.ConfigEntry):
|
|||
"entry_id": entry_id or uuid.uuid4().hex,
|
||||
"domain": domain,
|
||||
"data": data or {},
|
||||
"system_options": system_options,
|
||||
"options": options,
|
||||
"version": version,
|
||||
"title": title,
|
||||
|
|
|
@ -57,6 +57,7 @@ async def setup_device(hass):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
device = axis.AxisNetworkDevice(hass, config_entry)
|
||||
|
|
|
@ -41,6 +41,7 @@ async def setup_device(hass):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
device = axis.AxisNetworkDevice(hass, config_entry)
|
||||
|
|
|
@ -59,6 +59,7 @@ async def setup_device(hass):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
device = axis.AxisNetworkDevice(hass, config_entry)
|
||||
|
|
|
@ -584,3 +584,47 @@ async def test_two_step_options_flow(hass, client):
|
|||
"description": None,
|
||||
"description_placeholders": None,
|
||||
}
|
||||
|
||||
|
||||
async def test_list_system_options(hass, hass_ws_client):
|
||||
"""Test that we can list an entries system options."""
|
||||
assert await async_setup_component(hass, "config", {})
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
entry = MockConfigEntry(domain="demo")
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 5,
|
||||
"type": "config_entries/system_options/list",
|
||||
"entry_id": entry.entry_id,
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
||||
assert response["success"]
|
||||
assert response["result"] == {"disable_new_entities": False}
|
||||
|
||||
|
||||
async def test_update_system_options(hass, hass_ws_client):
|
||||
"""Test that we can update system options."""
|
||||
assert await async_setup_component(hass, "config", {})
|
||||
ws_client = await hass_ws_client(hass)
|
||||
|
||||
entry = MockConfigEntry(domain="demo")
|
||||
entry.add_to_hass(hass)
|
||||
|
||||
await ws_client.send_json(
|
||||
{
|
||||
"id": 5,
|
||||
"type": "config_entries/system_options/update",
|
||||
"entry_id": entry.entry_id,
|
||||
"disable_new_entities": True,
|
||||
}
|
||||
)
|
||||
response = await ws_client.receive_json()
|
||||
|
||||
assert response["success"]
|
||||
assert response["result"]["disable_new_entities"]
|
||||
assert entry.system_options.disable_new_entities
|
||||
|
|
|
@ -59,7 +59,8 @@ async def setup_gateway(hass, data, allow_clip_sensor=True):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
ENTRY_OPTIONS,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(loop, session, **config_entry.data)
|
||||
|
|
|
@ -71,7 +71,8 @@ async def setup_gateway(hass, data, allow_clip_sensor=True):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
ENTRY_OPTIONS,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(hass.loop, session, **config_entry.data)
|
||||
|
|
|
@ -63,6 +63,7 @@ async def setup_gateway(hass, data):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(loop, session, **config_entry.data)
|
||||
|
|
|
@ -90,7 +90,8 @@ async def setup_gateway(hass, data, allow_deconz_groups=True):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
ENTRY_OPTIONS,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(loop, session, **config_entry.data)
|
||||
|
|
|
@ -46,6 +46,7 @@ async def setup_gateway(hass, data):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(loop, session, **config_entry.data)
|
||||
|
|
|
@ -103,7 +103,8 @@ async def setup_gateway(hass, data, allow_clip_sensor=True):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
ENTRY_OPTIONS,
|
||||
system_options={},
|
||||
options=ENTRY_OPTIONS,
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(loop, session, **config_entry.data)
|
||||
|
|
|
@ -67,6 +67,7 @@ async def setup_gateway(hass, data):
|
|||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
gateway = deconz.DeconzGateway(hass, config_entry)
|
||||
gateway.api = DeconzSession(loop, session, **config_entry.data)
|
||||
|
|
|
@ -97,6 +97,7 @@ async def test_storage_is_removed_on_config_entry_removal(hass, utcnow):
|
|||
pairing_data,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
|
||||
assert hkid in hass.data[ENTITY_MAP].storage_data
|
||||
|
|
|
@ -221,6 +221,7 @@ async def setup_bridge(hass, mock_bridge):
|
|||
{"host": "mock-host"},
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_POLL,
|
||||
system_options={},
|
||||
)
|
||||
await hass.config_entries.async_forward_entry_setup(config_entry, "light")
|
||||
# To flush out the service call to update the group
|
||||
|
|
|
@ -306,6 +306,7 @@ async def setup_bridge(hass, mock_bridge, hostname=None):
|
|||
{"host": hostname},
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_POLL,
|
||||
system_options={},
|
||||
)
|
||||
await hass.config_entries.async_forward_entry_setup(config_entry, "binary_sensor")
|
||||
await hass.config_entries.async_forward_entry_setup(config_entry, "sensor")
|
||||
|
|
|
@ -142,7 +142,7 @@ async def test_config_flow_entry_migrate(hass):
|
|||
"media_player",
|
||||
"ps4",
|
||||
MOCK_UNIQUE_ID,
|
||||
config_entry_id=MOCK_ENTRY_ID,
|
||||
config_entry=mock_entry,
|
||||
device_id=MOCK_DEVICE_ID,
|
||||
)
|
||||
assert len(mock_e_registry.entities) == 1
|
||||
|
|
|
@ -335,7 +335,7 @@ async def test_device_info_is_assummed(hass):
|
|||
mock_unique_id = ps4.format_unique_id(MOCK_CREDS, MOCK_HOST_ID)
|
||||
mock_e_registry = mock_registry(hass)
|
||||
mock_e_registry.async_get_or_create(
|
||||
"media_player", DOMAIN, mock_unique_id, config_entry_id=MOCK_ENTRY_ID
|
||||
"media_player", DOMAIN, mock_unique_id, config_entry=MOCK_CONFIG
|
||||
)
|
||||
mock_entity_id = mock_e_registry.async_get_entity_id(
|
||||
"media_player", DOMAIN, mock_unique_id
|
||||
|
|
|
@ -56,6 +56,7 @@ async def setup_platform(hass, platform: str, *, devices=None, scenes=None):
|
|||
{CONF_INSTALLED_APP_ID: str(uuid4())},
|
||||
SOURCE_USER,
|
||||
CONN_CLASS_CLOUD_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
broker = DeviceBroker(
|
||||
hass, config_entry, Mock(), Mock(), devices or [], scenes or []
|
||||
|
|
|
@ -145,6 +145,7 @@ async def setup_controller(hass, mock_controller):
|
|||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_POLL,
|
||||
entry_id=1,
|
||||
system_options={},
|
||||
)
|
||||
mock_controller.config_entry = config_entry
|
||||
|
||||
|
@ -235,20 +236,31 @@ async def test_restoring_client(hass, mock_controller):
|
|||
mock_controller.mock_client_all_responses.append([CLIENT_1])
|
||||
mock_controller.unifi_config = {unifi.CONF_BLOCK_CLIENT: True}
|
||||
|
||||
config_entry = config_entries.ConfigEntry(
|
||||
1,
|
||||
unifi.DOMAIN,
|
||||
"Mock Title",
|
||||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_POLL,
|
||||
entry_id=1,
|
||||
system_options={},
|
||||
)
|
||||
|
||||
registry = await entity_registry.async_get_registry(hass)
|
||||
registry.async_get_or_create(
|
||||
device_tracker.DOMAIN,
|
||||
unifi_dt.UNIFI_DOMAIN,
|
||||
"{}-mock-site".format(CLIENT_1["mac"]),
|
||||
suggested_object_id=CLIENT_1["hostname"],
|
||||
config_entry_id=1,
|
||||
config_entry=config_entry,
|
||||
)
|
||||
registry.async_get_or_create(
|
||||
device_tracker.DOMAIN,
|
||||
unifi_dt.UNIFI_DOMAIN,
|
||||
"{}-mock-site".format(CLIENT_2["mac"]),
|
||||
suggested_object_id=CLIENT_2["hostname"],
|
||||
config_entry_id=1,
|
||||
config_entry=config_entry,
|
||||
)
|
||||
|
||||
await setup_controller(hass, mock_controller)
|
||||
|
|
|
@ -262,6 +262,7 @@ async def setup_controller(hass, mock_controller):
|
|||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_POLL,
|
||||
entry_id=1,
|
||||
system_options={},
|
||||
)
|
||||
mock_controller.config_entry = config_entry
|
||||
|
||||
|
@ -468,20 +469,31 @@ async def test_restoring_client(hass, mock_controller):
|
|||
mock_controller.mock_client_all_responses.append([CLIENT_1])
|
||||
mock_controller.unifi_config = {unifi.CONF_BLOCK_CLIENT: ["random mac"]}
|
||||
|
||||
config_entry = config_entries.ConfigEntry(
|
||||
1,
|
||||
unifi.DOMAIN,
|
||||
"Mock Title",
|
||||
ENTRY_CONFIG,
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_POLL,
|
||||
entry_id=1,
|
||||
system_options={},
|
||||
)
|
||||
|
||||
registry = await entity_registry.async_get_registry(hass)
|
||||
registry.async_get_or_create(
|
||||
switch.DOMAIN,
|
||||
unifi.DOMAIN,
|
||||
"poe-{}".format(CLIENT_1["mac"]),
|
||||
suggested_object_id=CLIENT_1["hostname"],
|
||||
config_entry_id=1,
|
||||
config_entry=config_entry,
|
||||
)
|
||||
registry.async_get_or_create(
|
||||
switch.DOMAIN,
|
||||
unifi.DOMAIN,
|
||||
"poe-{}".format(CLIENT_2["mac"]),
|
||||
suggested_object_id=CLIENT_2["hostname"],
|
||||
config_entry_id=1,
|
||||
config_entry=config_entry,
|
||||
)
|
||||
|
||||
await setup_controller(hass, mock_controller)
|
||||
|
|
|
@ -14,7 +14,13 @@ from homeassistant.components.zha.core.store import async_get_registry
|
|||
def config_entry_fixture(hass):
|
||||
"""Fixture representing a config entry."""
|
||||
config_entry = config_entries.ConfigEntry(
|
||||
1, DOMAIN, "Mock Title", {}, "test", config_entries.CONN_CLASS_LOCAL_PUSH
|
||||
1,
|
||||
DOMAIN,
|
||||
"Mock Title",
|
||||
{},
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
return config_entry
|
||||
|
||||
|
|
|
@ -287,6 +287,7 @@ async def setup_ozw(hass, mock_openzwave):
|
|||
{"usb_path": "mock-path", "network_key": "mock-key"},
|
||||
"test",
|
||||
config_entries.CONN_CLASS_LOCAL_PUSH,
|
||||
system_options={},
|
||||
)
|
||||
await hass.config_entries.async_forward_entry_setup(config_entry, "lock")
|
||||
await hass.async_block_till_done()
|
||||
|
|
|
@ -8,7 +8,7 @@ import pytest
|
|||
from homeassistant.core import valid_entity_id, callback
|
||||
from homeassistant.helpers import entity_registry
|
||||
|
||||
from tests.common import mock_registry, flush_store
|
||||
from tests.common import MockConfigEntry, mock_registry, flush_store
|
||||
|
||||
|
||||
YAML__OPEN_PATH = "homeassistant.util.yaml.loader.open"
|
||||
|
@ -88,9 +88,11 @@ def test_create_triggers_save(hass, registry):
|
|||
|
||||
async def test_loading_saving_data(hass, registry):
|
||||
"""Test that we load/save data correctly."""
|
||||
mock_config = MockConfigEntry(domain="light")
|
||||
|
||||
orig_entry1 = registry.async_get_or_create("light", "hue", "1234")
|
||||
orig_entry2 = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id"
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
|
||||
assert len(registry.entities) == 2
|
||||
|
@ -104,7 +106,7 @@ async def test_loading_saving_data(hass, registry):
|
|||
assert list(registry.entities) == list(registry2.entities)
|
||||
new_entry1 = registry.async_get_or_create("light", "hue", "1234")
|
||||
new_entry2 = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id"
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
|
||||
assert orig_entry1 == new_entry1
|
||||
|
@ -198,11 +200,14 @@ def test_async_get_entity_id(registry):
|
|||
|
||||
async def test_updating_config_entry_id(hass, registry, update_events):
|
||||
"""Test that we update config entry id in registry."""
|
||||
mock_config_1 = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
entry = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id-1"
|
||||
"light", "hue", "5678", config_entry=mock_config_1
|
||||
)
|
||||
|
||||
mock_config_2 = MockConfigEntry(domain="light", entry_id="mock-id-2")
|
||||
entry2 = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id-2"
|
||||
"light", "hue", "5678", config_entry=mock_config_2
|
||||
)
|
||||
assert entry.entity_id == entry2.entity_id
|
||||
assert entry2.config_entry_id == "mock-id-2"
|
||||
|
@ -218,8 +223,10 @@ async def test_updating_config_entry_id(hass, registry, update_events):
|
|||
|
||||
async def test_removing_config_entry_id(hass, registry, update_events):
|
||||
"""Test that we update config entry id in registry."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
|
||||
entry = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id-1"
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
assert entry.config_entry_id == "mock-id-1"
|
||||
registry.async_clear_config_entry("mock-id-1")
|
||||
|
@ -237,6 +244,8 @@ async def test_removing_config_entry_id(hass, registry, update_events):
|
|||
|
||||
async def test_migration(hass):
|
||||
"""Test migration from old data to new."""
|
||||
mock_config = MockConfigEntry(domain="test-platform", entry_id="test-config-id")
|
||||
|
||||
old_conf = {
|
||||
"light.kitchen": {
|
||||
"config_entry_id": "test-config-id",
|
||||
|
@ -256,7 +265,7 @@ async def test_migration(hass):
|
|||
domain="light",
|
||||
platform="test-platform",
|
||||
unique_id="test-unique",
|
||||
config_entry_id="test-config-id",
|
||||
config_entry=mock_config,
|
||||
)
|
||||
assert entry.name == "Test Name"
|
||||
assert entry.disabled_by == "hass"
|
||||
|
@ -326,8 +335,10 @@ async def test_loading_race_condition(hass):
|
|||
|
||||
async def test_update_entity_unique_id(registry):
|
||||
"""Test entity's unique_id is updated."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
|
||||
entry = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id-1"
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
new_unique_id = "1234"
|
||||
with patch.object(registry, "async_schedule_save") as mock_schedule_save:
|
||||
|
@ -341,11 +352,12 @@ async def test_update_entity_unique_id(registry):
|
|||
|
||||
async def test_update_entity_unique_id_conflict(registry):
|
||||
"""Test migration raises when unique_id already in use."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
entry = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id-1"
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
entry2 = registry.async_get_or_create(
|
||||
"light", "hue", "1234", config_entry_id="mock-id-1"
|
||||
"light", "hue", "1234", config_entry=mock_config
|
||||
)
|
||||
with patch.object(
|
||||
registry, "async_schedule_save"
|
||||
|
@ -356,8 +368,9 @@ async def test_update_entity_unique_id_conflict(registry):
|
|||
|
||||
async def test_update_entity(registry):
|
||||
"""Test updating entity."""
|
||||
mock_config = MockConfigEntry(domain="light", entry_id="mock-id-1")
|
||||
entry = registry.async_get_or_create(
|
||||
"light", "hue", "5678", config_entry_id="mock-id-1"
|
||||
"light", "hue", "5678", config_entry=mock_config
|
||||
)
|
||||
|
||||
for attr_name, new_value in (
|
||||
|
@ -386,3 +399,21 @@ async def test_disabled_by(registry):
|
|||
|
||||
entry2 = registry.async_get_or_create("light", "hue", "1234")
|
||||
assert entry2.disabled_by is None
|
||||
|
||||
|
||||
async def test_disabled_by_system_options(registry):
|
||||
"""Test system options setting disabled_by."""
|
||||
mock_config = MockConfigEntry(
|
||||
domain="light",
|
||||
entry_id="mock-id-1",
|
||||
system_options={"disable_new_entities": True},
|
||||
)
|
||||
entry = registry.async_get_or_create(
|
||||
"light", "hue", "AAAA", config_entry=mock_config
|
||||
)
|
||||
assert entry.disabled_by == "integration"
|
||||
|
||||
entry2 = registry.async_get_or_create(
|
||||
"light", "hue", "BBBB", config_entry=mock_config, disabled_by="user"
|
||||
)
|
||||
assert entry2.disabled_by == "user"
|
||||
|
|
|
@ -596,6 +596,22 @@ async def test_updating_entry_data(manager):
|
|||
assert entry.data == {"second": True}
|
||||
|
||||
|
||||
async def test_updating_entry_system_options(manager):
|
||||
"""Test that we can update an entry data."""
|
||||
entry = MockConfigEntry(
|
||||
domain="test",
|
||||
data={"first": True},
|
||||
state=config_entries.ENTRY_STATE_SETUP_ERROR,
|
||||
system_options={"disable_new_entities": True},
|
||||
)
|
||||
entry.add_to_manager(manager)
|
||||
|
||||
assert entry.system_options.disable_new_entities
|
||||
|
||||
entry.system_options.update(disable_new_entities=False)
|
||||
assert not entry.system_options.disable_new_entities
|
||||
|
||||
|
||||
async def test_update_entry_options_and_trigger_listener(hass, manager):
|
||||
"""Test that we can update entry options and trigger listener."""
|
||||
entry = MockConfigEntry(domain="test", options={"first": True})
|
||||
|
|
Loading…
Reference in New Issue