From 0a4f3ec1ec83f882c4fe7abea624b9d6db4b2007 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 3 Jan 2020 11:50:53 +0100 Subject: [PATCH] Use config entry unique id for deCONZ (#30122) * Use config entry unique id * Clean up * Backwards compatiblity note * Fix some of Balloobs comments * Bump dependency to v66 * Black somehow missed config flow tests... * Move set unique ID til after possibility to update existing entry --- homeassistant/components/deconz/__init__.py | 25 ++- .../components/deconz/config_flow.py | 67 ++++----- homeassistant/components/deconz/const.py | 1 - .../components/deconz/device_trigger.py | 6 +- homeassistant/components/deconz/gateway.py | 13 +- homeassistant/components/deconz/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/deconz/test_config_flow.py | 90 +++++------ tests/components/deconz/test_gateway.py | 7 +- tests/components/deconz/test_init.py | 142 ++++++------------ tests/components/deconz/test_services.py | 5 +- 12 files changed, 136 insertions(+), 226 deletions(-) diff --git a/homeassistant/components/deconz/__init__.py b/homeassistant/components/deconz/__init__.py index 0ea91d10b19..096bc6c2904 100644 --- a/homeassistant/components/deconz/__init__.py +++ b/homeassistant/components/deconz/__init__.py @@ -4,8 +4,8 @@ import voluptuous as vol from homeassistant.const import EVENT_HOMEASSISTANT_STOP from .config_flow import get_master_gateway -from .const import CONF_BRIDGEID, CONF_MASTER_GATEWAY, CONF_UUID, DOMAIN -from .gateway import DeconzGateway, get_gateway_from_config_entry +from .const import CONF_MASTER_GATEWAY, DOMAIN +from .gateway import DeconzGateway from .services import async_setup_services, async_unload_services CONFIG_SCHEMA = vol.Schema( @@ -35,13 +35,16 @@ async def async_setup_entry(hass, config_entry): if not await gateway.async_setup(): return False - hass.data[DOMAIN][gateway.bridgeid] = gateway + # 0.104 introduced config entry unique id, this makes upgrading possible + if config_entry.unique_id is None: + hass.config_entries.async_update_entry( + config_entry, unique_id=gateway.api.config.bridgeid + ) + + hass.data[DOMAIN][config_entry.unique_id] = gateway await gateway.async_update_device_registry() - if CONF_UUID not in config_entry.data: - await async_add_uuid_to_config_entry(hass, config_entry) - await async_setup_services(hass) hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gateway.shutdown) @@ -51,7 +54,7 @@ async def async_setup_entry(hass, config_entry): async def async_unload_entry(hass, config_entry): """Unload deCONZ config entry.""" - gateway = hass.data[DOMAIN].pop(config_entry.data[CONF_BRIDGEID]) + gateway = hass.data[DOMAIN].pop(config_entry.unique_id) if not hass.data[DOMAIN]: await async_unload_services(hass) @@ -74,11 +77,3 @@ async def async_update_master_gateway(hass, config_entry): options = {**config_entry.options, CONF_MASTER_GATEWAY: master} hass.config_entries.async_update_entry(config_entry, options=options) - - -async def async_add_uuid_to_config_entry(hass, config_entry): - """Add UUID to config entry to help discovery identify entries.""" - gateway = get_gateway_from_config_entry(hass, config_entry) - config = {**config_entry.data, CONF_UUID: gateway.api.config.uuid} - - hass.config_entries.async_update_entry(config_entry, data=config) diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index c84192456d1..0cec6add28c 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -4,7 +4,12 @@ from urllib.parse import urlparse import async_timeout from pydeconz.errors import RequestError, ResponseError -from pydeconz.utils import async_discovery, async_get_api_key, async_get_gateway_config +from pydeconz.utils import ( + async_discovery, + async_get_api_key, + async_get_bridge_id, + normalize_bridge_id, +) import voluptuous as vol from homeassistant import config_entries @@ -14,11 +19,9 @@ from homeassistant.core import callback from homeassistant.helpers import aiohttp_client from .const import ( - _LOGGER, CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, CONF_BRIDGEID, - CONF_UUID, DEFAULT_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_DECONZ_GROUPS, DEFAULT_PORT, @@ -29,15 +32,6 @@ DECONZ_MANUFACTURERURL = "http://www.dresden-elektronik.de" CONF_SERIAL = "serial" -@callback -def configured_gateways(hass): - """Return a set of all configured gateways.""" - return { - entry.data[CONF_BRIDGEID]: entry - for entry in hass.config_entries.async_entries(DOMAIN) - } - - @callback def get_master_gateway(hass): """Return the gateway which is marked as master.""" @@ -62,6 +56,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): def __init__(self): """Initialize the deCONZ config flow.""" + self.bridge_id = None self.bridges = [] self.deconz_config = {} @@ -79,7 +74,11 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): if user_input is not None: for bridge in self.bridges: if bridge[CONF_HOST] == user_input[CONF_HOST]: - self.deconz_config = bridge + self.bridge_id = bridge[CONF_BRIDGEID] + self.deconz_config = { + CONF_HOST: bridge[CONF_HOST], + CONF_PORT: bridge[CONF_PORT], + } return await self.async_step_link() self.deconz_config = user_input @@ -95,8 +94,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): self.bridges = [] if len(self.bridges) == 1: - self.deconz_config = self.bridges[0] - return await self.async_step_link() + return await self.async_step_user(self.bridges[0]) if len(self.bridges) > 1: hosts = [] @@ -141,23 +139,21 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): async def _create_entry(self): """Create entry for gateway.""" - if CONF_BRIDGEID not in self.deconz_config: + if not self.bridge_id: session = aiohttp_client.async_get_clientsession(self.hass) try: with async_timeout.timeout(10): - gateway_config = await async_get_gateway_config( + self.bridge_id = await async_get_bridge_id( session, **self.deconz_config ) - self.deconz_config[CONF_BRIDGEID] = gateway_config.bridgeid - self.deconz_config[CONF_UUID] = gateway_config.uuid + await self.async_set_unique_id(self.bridge_id) + self._abort_if_unique_id_configured() except asyncio.TimeoutError: return self.async_abort(reason="no_bridges") - return self.async_create_entry( - title="deCONZ-" + self.deconz_config[CONF_BRIDGEID], data=self.deconz_config - ) + return self.async_create_entry(title=self.bridge_id, data=self.deconz_config) def _update_entry(self, entry, host, port, api_key=None): """Update existing entry.""" @@ -182,27 +178,17 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): if discovery_info[ssdp.ATTR_UPNP_MANUFACTURER_URL] != DECONZ_MANUFACTURERURL: return self.async_abort(reason="not_deconz_bridge") - uuid = discovery_info[ssdp.ATTR_UPNP_UDN].replace("uuid:", "") - - _LOGGER.debug("deCONZ gateway discovered (%s)", uuid) - + self.bridge_id = normalize_bridge_id(discovery_info[ssdp.ATTR_UPNP_SERIAL]) parsed_url = urlparse(discovery_info[ssdp.ATTR_SSDP_LOCATION]) for entry in self.hass.config_entries.async_entries(DOMAIN): - if uuid == entry.data.get(CONF_UUID): + if self.bridge_id == entry.unique_id: if entry.source == "hassio": return self.async_abort(reason="already_configured") return self._update_entry(entry, parsed_url.hostname, parsed_url.port) - bridgeid = discovery_info[ssdp.ATTR_UPNP_SERIAL] - if any( - bridgeid == flow["context"][CONF_BRIDGEID] - for flow in self._async_in_progress() - ): - return self.async_abort(reason="already_in_progress") - + await self.async_set_unique_id(self.bridge_id) # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 - self.context[CONF_BRIDGEID] = bridgeid self.context["title_placeholders"] = {"host": parsed_url.hostname} self.deconz_config = { @@ -217,18 +203,18 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): This flow is triggered by the discovery component. """ - bridgeid = user_input[CONF_SERIAL] - gateway_entries = configured_gateways(self.hass) + self.bridge_id = normalize_bridge_id(user_input[CONF_SERIAL]) + gateway = self.hass.data.get(DOMAIN, {}).get(self.bridge_id) - if bridgeid in gateway_entries: - entry = gateway_entries[bridgeid] + if gateway: return self._update_entry( - entry, + gateway.config_entry, user_input[CONF_HOST], user_input[CONF_PORT], user_input[CONF_API_KEY], ) + await self.async_set_unique_id(self.bridge_id) self._hassio_discovery = user_input return await self.async_step_hassio_confirm() @@ -239,7 +225,6 @@ class DeconzFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): self.deconz_config = { CONF_HOST: self._hassio_discovery[CONF_HOST], CONF_PORT: self._hassio_discovery[CONF_PORT], - CONF_BRIDGEID: self._hassio_discovery[CONF_SERIAL], CONF_API_KEY: self._hassio_discovery[CONF_API_KEY], } diff --git a/homeassistant/components/deconz/const.py b/homeassistant/components/deconz/const.py index a663f99bf73..47975750de9 100644 --- a/homeassistant/components/deconz/const.py +++ b/homeassistant/components/deconz/const.py @@ -6,7 +6,6 @@ _LOGGER = logging.getLogger(__package__) DOMAIN = "deconz" CONF_BRIDGEID = "bridgeid" -CONF_UUID = "uuid" DEFAULT_PORT = 80 DEFAULT_ALLOW_CLIP_SENSOR = False diff --git a/homeassistant/components/deconz/device_trigger.py b/homeassistant/components/deconz/device_trigger.py index 9c8a41453aa..9bdfa70b7de 100644 --- a/homeassistant/components/deconz/device_trigger.py +++ b/homeassistant/components/deconz/device_trigger.py @@ -15,9 +15,7 @@ from homeassistant.const import ( ) from . import DOMAIN -from .config_flow import configured_gateways from .deconz_event import CONF_DECONZ_EVENT, CONF_UNIQUE_ID -from .gateway import get_gateway_from_config_entry CONF_SUBTYPE = "subtype" @@ -287,10 +285,8 @@ TRIGGER_SCHEMA = TRIGGER_BASE_SCHEMA.extend( def _get_deconz_event_from_device_id(hass, device_id): """Resolve deconz event from device id.""" - deconz_config_entries = configured_gateways(hass) - for config_entry in deconz_config_entries.values(): + for gateway in hass.data.get(DOMAIN): - gateway = get_gateway_from_config_entry(hass, config_entry) for deconz_event in gateway.events: if device_id == deconz_event.device_id: diff --git a/homeassistant/components/deconz/gateway.py b/homeassistant/components/deconz/gateway.py index 083af2dca6f..04452cc313c 100644 --- a/homeassistant/components/deconz/gateway.py +++ b/homeassistant/components/deconz/gateway.py @@ -22,7 +22,6 @@ from .const import ( _LOGGER, CONF_ALLOW_CLIP_SENSOR, CONF_ALLOW_DECONZ_GROUPS, - CONF_BRIDGEID, CONF_MASTER_GATEWAY, DEFAULT_ALLOW_CLIP_SENSOR, DEFAULT_ALLOW_DECONZ_GROUPS, @@ -36,7 +35,7 @@ from .errors import AuthenticationRequired, CannotConnect @callback def get_gateway_from_config_entry(hass, config_entry): """Return gateway with a matching bridge id.""" - return hass.data[DOMAIN][config_entry.data[CONF_BRIDGEID]] + return hass.data[DOMAIN][config_entry.unique_id] class DeconzGateway: @@ -56,7 +55,7 @@ class DeconzGateway: @property def bridgeid(self) -> str: """Return the unique identifier of the gateway.""" - return self.config_entry.data[CONF_BRIDGEID] + return self.config_entry.unique_id @property def master(self) -> bool: @@ -92,11 +91,9 @@ class DeconzGateway: async def async_setup(self) -> bool: """Set up a deCONZ gateway.""" - hass = self.hass - try: self.api = await get_gateway( - hass, + self.hass, self.config_entry.data, self.async_add_device_callback, self.async_connection_status_callback, @@ -110,8 +107,8 @@ class DeconzGateway: return False for component in SUPPORTED_PLATFORMS: - hass.async_create_task( - hass.config_entries.async_forward_entry_setup( + self.hass.async_create_task( + self.hass.config_entries.async_forward_entry_setup( self.config_entry, component ) ) diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index 30b00600331..402244fbc13 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/deconz", "requirements": [ - "pydeconz==65" + "pydeconz==66" ], "ssdp": [ { diff --git a/requirements_all.txt b/requirements_all.txt index 8c85b023b02..a6cba26235b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1187,7 +1187,7 @@ pydaikin==1.6.1 pydanfossair==0.1.0 # homeassistant.components.deconz -pydeconz==65 +pydeconz==66 # homeassistant.components.delijn pydelijn==0.5.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index fb0a7d76513..93eedd2ccff 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -410,7 +410,7 @@ pycoolmasternet==0.0.4 pydaikin==1.6.1 # homeassistant.components.deconz -pydeconz==65 +pydeconz==66 # homeassistant.components.zwave pydispatcher==2.0.5 diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index da8b0a8a7f4..f8fe42d10d8 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -1,11 +1,20 @@ """Tests for deCONZ config flow.""" import asyncio -from unittest.mock import Mock, patch +from copy import deepcopy +from asynctest import Mock, patch import pydeconz from homeassistant.components import ssdp from homeassistant.components.deconz import config_flow +from homeassistant.components.deconz.const import CONF_BRIDGEID + +from .test_gateway import ( + BRIDGEID, + DECONZ_WEB_REQUEST, + ENTRY_CONFIG, + setup_deconz_integration, +) from tests.common import MockConfigEntry @@ -14,7 +23,7 @@ async def test_flow_works(hass, aioclient_mock): """Test that config flow works.""" aioclient_mock.get( pydeconz.utils.URL_DISCOVER, - json=[{"id": "id", "internalipaddress": "1.2.3.4", "internalport": 80}], + json=[{"id": BRIDGEID, "internalipaddress": "1.2.3.4", "internalport": 80}], headers={"content-type": "application/json"}, ) aioclient_mock.post( @@ -35,9 +44,8 @@ async def test_flow_works(hass, aioclient_mock): ) assert result["type"] == "create_entry" - assert result["title"] == "deCONZ-id" + assert result["title"] == BRIDGEID assert result["data"] == { - config_flow.CONF_BRIDGEID: "id", config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80, config_flow.CONF_API_KEY: "1234567890ABCDEF", @@ -117,12 +125,12 @@ async def test_user_step_two_bridges_selection(hass, aioclient_mock): flow.hass = hass flow.bridges = [ { - config_flow.CONF_BRIDGEID: "id1", + CONF_BRIDGEID: "id1", config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80, }, { - config_flow.CONF_BRIDGEID: "id2", + CONF_BRIDGEID: "id2", config_flow.CONF_HOST: "5.6.7.8", config_flow.CONF_PORT: 80, }, @@ -241,25 +249,22 @@ async def test_bridge_discovery_update_existing_entry(hass): """Test if a discovered bridge has already been configured.""" entry = MockConfigEntry( domain=config_flow.DOMAIN, - data={ - config_flow.CONF_HOST: "1.2.3.4", - config_flow.CONF_BRIDGEID: "123ABC", - config_flow.CONF_UUID: "456DEF", - }, + source="user", + data={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80}, + unique_id=BRIDGEID, ) entry.add_to_hass(hass) gateway = Mock() gateway.config_entry = entry - hass.data[config_flow.DOMAIN] = {"123ABC": gateway} + hass.data[config_flow.DOMAIN] = {BRIDGEID: gateway} result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, data={ ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/", ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL, - ssdp.ATTR_UPNP_SERIAL: "123ABC", - ssdp.ATTR_UPNP_UDN: "uuid:456DEF", + ssdp.ATTR_UPNP_SERIAL: BRIDGEID, }, context={"source": "ssdp"}, ) @@ -277,8 +282,8 @@ async def test_bridge_discovery_dont_update_existing_hassio_entry(hass): data={ config_flow.CONF_HOST: "core-deconz", config_flow.CONF_BRIDGEID: "123ABC", - config_flow.CONF_UUID: "456DEF", }, + unique_id="123ABC", ) entry.add_to_hass(hass) @@ -292,7 +297,6 @@ async def test_bridge_discovery_dont_update_existing_hassio_entry(hass): ssdp.ATTR_SSDP_LOCATION: "http://mock-deconz/", ssdp.ATTR_UPNP_MANUFACTURER_URL: config_flow.DECONZ_MANUFACTURERURL, ssdp.ATTR_UPNP_SERIAL: "123ABC", - ssdp.ATTR_UPNP_UDN: "uuid:456DEF", }, context={"source": "ssdp"}, ) @@ -306,11 +310,12 @@ async def test_create_entry(hass, aioclient_mock): """Test that _create_entry work and that bridgeid can be requested.""" aioclient_mock.get( "http://1.2.3.4:80/api/1234567890ABCDEF/config", - json={"bridgeid": "123ABC", "uuid": "456DEF"}, + json={"bridgeid": BRIDGEID, "uuid": "456DEF"}, headers={"content-type": "application/json"}, ) flow = config_flow.DeconzFlowHandler() + flow.context = {} flow.hass = hass flow.deconz_config = { config_flow.CONF_HOST: "1.2.3.4", @@ -321,13 +326,11 @@ async def test_create_entry(hass, aioclient_mock): result = await flow._create_entry() assert result["type"] == "create_entry" - assert result["title"] == "deCONZ-123ABC" + assert result["title"] == BRIDGEID assert result["data"] == { - config_flow.CONF_BRIDGEID: "123ABC", config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_PORT: 80, config_flow.CONF_API_KEY: "1234567890ABCDEF", - config_flow.CONF_UUID: "456DEF", } @@ -342,7 +345,7 @@ async def test_create_entry_timeout(hass, aioclient_mock): } with patch( - "homeassistant.components.deconz.config_flow.async_get_gateway_config", + "homeassistant.components.deconz.config_flow.async_get_bridge_id", side_effect=asyncio.TimeoutError, ): result = await flow._create_entry() @@ -353,54 +356,44 @@ async def test_create_entry_timeout(hass, aioclient_mock): async def test_hassio_update_instance(hass): """Test we can update an existing config entry.""" - entry = MockConfigEntry( - domain=config_flow.DOMAIN, - data={ - config_flow.CONF_BRIDGEID: "id", - config_flow.CONF_HOST: "1.2.3.4", - config_flow.CONF_PORT: 40850, - config_flow.CONF_API_KEY: "secret", - }, + data = deepcopy(DECONZ_WEB_REQUEST) + entry_config = deepcopy(ENTRY_CONFIG) + gateway = await setup_deconz_integration( + hass, entry_config, options={}, get_state_response=data ) - entry.add_to_hass(hass) result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, data={ - config_flow.CONF_HOST: "mock-deconz", + config_flow.CONF_HOST: "2.3.4.5", config_flow.CONF_PORT: 8080, config_flow.CONF_API_KEY: "updated", - config_flow.CONF_SERIAL: "id", + config_flow.CONF_SERIAL: BRIDGEID, }, context={"source": "hassio"}, ) assert result["type"] == "abort" assert result["reason"] == "updated_instance" - assert entry.data[config_flow.CONF_HOST] == "mock-deconz" - assert entry.data[config_flow.CONF_PORT] == 8080 - assert entry.data[config_flow.CONF_API_KEY] == "updated" + assert gateway.config_entry.data[config_flow.CONF_HOST] == "2.3.4.5" + assert gateway.config_entry.data[config_flow.CONF_PORT] == 8080 + assert gateway.config_entry.data[config_flow.CONF_API_KEY] == "updated" async def test_hassio_dont_update_instance(hass): """Test we can update an existing config entry.""" - entry = MockConfigEntry( - domain=config_flow.DOMAIN, - data={ - config_flow.CONF_BRIDGEID: "id", - config_flow.CONF_HOST: "1.2.3.4", - config_flow.CONF_PORT: 8080, - config_flow.CONF_API_KEY: "secret", - }, + data = deepcopy(DECONZ_WEB_REQUEST) + await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data ) - entry.add_to_hass(hass) + result = await hass.config_entries.flow.async_init( config_flow.DOMAIN, data={ config_flow.CONF_HOST: "1.2.3.4", - config_flow.CONF_PORT: 8080, - config_flow.CONF_API_KEY: "secret", - config_flow.CONF_SERIAL: "id", + config_flow.CONF_PORT: 80, + config_flow.CONF_API_KEY: "ABCDEF", + config_flow.CONF_SERIAL: BRIDGEID, }, context={"source": "hassio"}, ) @@ -417,7 +410,7 @@ async def test_hassio_confirm(hass): "addon": "Mock Addon", config_flow.CONF_HOST: "mock-deconz", config_flow.CONF_PORT: 80, - config_flow.CONF_SERIAL: "id", + config_flow.CONF_SERIAL: BRIDGEID, config_flow.CONF_API_KEY: "1234567890ABCDEF", }, context={"source": "hassio"}, @@ -434,7 +427,6 @@ async def test_hassio_confirm(hass): assert result["result"].data == { config_flow.CONF_HOST: "mock-deconz", config_flow.CONF_PORT: 80, - config_flow.CONF_BRIDGEID: "id", config_flow.CONF_API_KEY: "1234567890ABCDEF", } diff --git a/tests/components/deconz/test_gateway.py b/tests/components/deconz/test_gateway.py index 288868f1bec..656b610f4a2 100644 --- a/tests/components/deconz/test_gateway.py +++ b/tests/components/deconz/test_gateway.py @@ -10,14 +10,12 @@ from homeassistant.components import deconz, ssdp from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.dispatcher import async_dispatcher_connect -BRIDGEID = "0123456789" +BRIDGEID = "01234E56789A" ENTRY_CONFIG = { deconz.config_flow.CONF_API_KEY: "ABCDEF", - deconz.config_flow.CONF_BRIDGEID: BRIDGEID, deconz.config_flow.CONF_HOST: "1.2.3.4", deconz.config_flow.CONF_PORT: 80, - deconz.config_flow.CONF_UUID: "456DEF", } DECONZ_CONFIG = { @@ -60,7 +58,8 @@ async def setup_deconz_integration(hass, config, options, get_state_response): hass.config_entries._entries.append(config_entry) - return hass.data[deconz.DOMAIN].get(config[deconz.CONF_BRIDGEID]) + bridgeid = get_state_response["config"]["bridgeid"] + return hass.data[deconz.DOMAIN].get(bridgeid) async def test_gateway_setup(hass): diff --git a/tests/components/deconz/test_init.py b/tests/components/deconz/test_init.py index 3c6e02ab41c..806fd7ed4aa 100644 --- a/tests/components/deconz/test_init.py +++ b/tests/components/deconz/test_init.py @@ -1,13 +1,14 @@ """Test deCONZ component setup process.""" import asyncio +from copy import deepcopy -from asynctest import Mock, patch +from asynctest import patch import pytest from homeassistant.components import deconz from homeassistant.exceptions import ConfigEntryNotReady -from tests.common import MockConfigEntry +from .test_gateway import DECONZ_WEB_REQUEST, ENTRY_CONFIG, setup_deconz_integration ENTRY1_HOST = "1.2.3.4" ENTRY1_PORT = 80 @@ -34,138 +35,83 @@ async def setup_entry(hass, entry): async def test_setup_entry_fails(hass): """Test setup entry fails if deCONZ is not available.""" - entry = Mock() - entry.data = { - deconz.config_flow.CONF_HOST: ENTRY1_HOST, - deconz.config_flow.CONF_PORT: ENTRY1_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, - } + data = deepcopy(DECONZ_WEB_REQUEST) with patch("pydeconz.DeconzSession.initialize", side_effect=Exception): - await deconz.async_setup_entry(hass, entry) + await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data + ) + assert not hass.data[deconz.DOMAIN] async def test_setup_entry_no_available_bridge(hass): """Test setup entry fails if deCONZ is not available.""" - entry = Mock() - entry.data = { - deconz.config_flow.CONF_HOST: ENTRY1_HOST, - deconz.config_flow.CONF_PORT: ENTRY1_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, - } + data = deepcopy(DECONZ_WEB_REQUEST) with patch( "pydeconz.DeconzSession.initialize", side_effect=asyncio.TimeoutError ), pytest.raises(ConfigEntryNotReady): - await deconz.async_setup_entry(hass, entry) + await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data + ) async def test_setup_entry_successful(hass): """Test setup entry is successful.""" - entry = MockConfigEntry( - domain=deconz.DOMAIN, - data={ - deconz.config_flow.CONF_HOST: ENTRY1_HOST, - deconz.config_flow.CONF_PORT: ENTRY1_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, - deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, - deconz.CONF_UUID: ENTRY1_UUID, - }, + data = deepcopy(DECONZ_WEB_REQUEST) + gateway = await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data ) - entry.add_to_hass(hass) - await setup_entry(hass, entry) - - assert ENTRY1_BRIDGEID in hass.data[deconz.DOMAIN] - assert hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].master + assert hass.data[deconz.DOMAIN] + assert gateway.bridgeid in hass.data[deconz.DOMAIN] + assert hass.data[deconz.DOMAIN][gateway.bridgeid].master async def test_setup_entry_multiple_gateways(hass): """Test setup entry is successful with multiple gateways.""" - entry = MockConfigEntry( - domain=deconz.DOMAIN, - data={ - deconz.config_flow.CONF_HOST: ENTRY1_HOST, - deconz.config_flow.CONF_PORT: ENTRY1_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, - deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, - deconz.CONF_UUID: ENTRY1_UUID, - }, + data = deepcopy(DECONZ_WEB_REQUEST) + gateway = await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data ) - entry.add_to_hass(hass) - entry2 = MockConfigEntry( - domain=deconz.DOMAIN, - data={ - deconz.config_flow.CONF_HOST: ENTRY2_HOST, - deconz.config_flow.CONF_PORT: ENTRY2_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY2_API_KEY, - deconz.CONF_BRIDGEID: ENTRY2_BRIDGEID, - deconz.CONF_UUID: ENTRY2_UUID, - }, + data2 = deepcopy(DECONZ_WEB_REQUEST) + data2["config"]["bridgeid"] = "01234E56789B" + gateway2 = await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data2 ) - entry2.add_to_hass(hass) - await setup_entry(hass, entry) - await setup_entry(hass, entry2) - - assert ENTRY1_BRIDGEID in hass.data[deconz.DOMAIN] - assert hass.data[deconz.DOMAIN][ENTRY1_BRIDGEID].master - assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN] - assert not hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master + assert len(hass.data[deconz.DOMAIN]) == 2 + assert hass.data[deconz.DOMAIN][gateway.bridgeid].master + assert not hass.data[deconz.DOMAIN][gateway2.bridgeid].master async def test_unload_entry(hass): """Test being able to unload an entry.""" - entry = MockConfigEntry( - domain=deconz.DOMAIN, - data={ - deconz.config_flow.CONF_HOST: ENTRY1_HOST, - deconz.config_flow.CONF_PORT: ENTRY1_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, - deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, - deconz.CONF_UUID: ENTRY1_UUID, - }, + data = deepcopy(DECONZ_WEB_REQUEST) + gateway = await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data ) - entry.add_to_hass(hass) - - await setup_entry(hass, entry) - - with patch.object(deconz.DeconzGateway, "async_reset", return_value=True): - assert await deconz.async_unload_entry(hass, entry) + assert hass.data[deconz.DOMAIN] + assert await deconz.async_unload_entry(hass, gateway.config_entry) assert not hass.data[deconz.DOMAIN] async def test_unload_entry_multiple_gateways(hass): """Test being able to unload an entry and master gateway gets moved.""" - entry = MockConfigEntry( - domain=deconz.DOMAIN, - data={ - deconz.config_flow.CONF_HOST: ENTRY1_HOST, - deconz.config_flow.CONF_PORT: ENTRY1_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY1_API_KEY, - deconz.CONF_BRIDGEID: ENTRY1_BRIDGEID, - deconz.CONF_UUID: ENTRY1_UUID, - }, + data = deepcopy(DECONZ_WEB_REQUEST) + gateway = await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data ) - entry.add_to_hass(hass) - entry2 = MockConfigEntry( - domain=deconz.DOMAIN, - data={ - deconz.config_flow.CONF_HOST: ENTRY2_HOST, - deconz.config_flow.CONF_PORT: ENTRY2_PORT, - deconz.config_flow.CONF_API_KEY: ENTRY2_API_KEY, - deconz.CONF_BRIDGEID: ENTRY2_BRIDGEID, - deconz.CONF_UUID: ENTRY2_UUID, - }, + data2 = deepcopy(DECONZ_WEB_REQUEST) + data2["config"]["bridgeid"] = "01234E56789B" + gateway2 = await setup_deconz_integration( + hass, ENTRY_CONFIG, options={}, get_state_response=data2 ) - entry2.add_to_hass(hass) - await setup_entry(hass, entry) - await setup_entry(hass, entry2) + assert len(hass.data[deconz.DOMAIN]) == 2 - with patch.object(deconz.DeconzGateway, "async_reset", return_value=True): - assert await deconz.async_unload_entry(hass, entry) + assert await deconz.async_unload_entry(hass, gateway.config_entry) - assert ENTRY2_BRIDGEID in hass.data[deconz.DOMAIN] - assert hass.data[deconz.DOMAIN][ENTRY2_BRIDGEID].master + assert len(hass.data[deconz.DOMAIN]) == 1 + assert hass.data[deconz.DOMAIN][gateway2.bridgeid].master diff --git a/tests/components/deconz/test_services.py b/tests/components/deconz/test_services.py index fad5444aa00..32065c60f83 100644 --- a/tests/components/deconz/test_services.py +++ b/tests/components/deconz/test_services.py @@ -6,6 +6,7 @@ import pytest import voluptuous as vol from homeassistant.components import deconz +from homeassistant.components.deconz.const import CONF_BRIDGEID from .test_gateway import ( BRIDGEID, @@ -99,7 +100,7 @@ async def test_configure_service_with_field(hass): data = { deconz.services.SERVICE_FIELD: "/light/2", - deconz.CONF_BRIDGEID: BRIDGEID, + CONF_BRIDGEID: BRIDGEID, deconz.services.SERVICE_DATA: {"on": True, "attr1": 10, "attr2": 20}, } @@ -203,7 +204,7 @@ async def test_service_refresh_devices(hass): hass, ENTRY_CONFIG, options={}, get_state_response=data ) - data = {deconz.CONF_BRIDGEID: BRIDGEID} + data = {CONF_BRIDGEID: BRIDGEID} with patch( "pydeconz.DeconzSession.request",