Use unique_id for config_entries of HomematicIP Cloud (#31133)

* use hapid as unique_id for config_entry of HomematicIP Cloud

* Add qualita_scale to manifest

* Update config_flow

* use core interface for config_flow tests

* refactor to fail earlier

* use asynctest

* rewrite tests

* rewrite tests

* fix test

* add assert
This commit is contained in:
SukramJ 2020-01-26 14:54:33 +01:00 committed by Martin Hjelmare
parent 3f03848a07
commit 1b3c4ed4b3
15 changed files with 254 additions and 250 deletions

View File

@ -17,7 +17,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.config_validation import comp_entity_ids
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
from .config_flow import configured_haps
from .const import (
CONF_ACCESSPOINT,
CONF_AUTHTOKEN,
@ -130,7 +129,10 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
accesspoints = config.get(DOMAIN, [])
for conf in accesspoints:
if conf[CONF_ACCESSPOINT] not in configured_haps(hass):
if conf[CONF_ACCESSPOINT] not in set(
entry.data[HMIPC_HAPID]
for entry in hass.config_entries.async_entries(DOMAIN)
):
hass.async_add_job(
hass.config_entries.flow.async_init(
DOMAIN,
@ -274,7 +276,7 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
anonymize = service.data[ATTR_ANONYMIZE]
for hap in hass.data[DOMAIN].values():
hap_sgtin = hap.config_entry.title
hap_sgtin = hap.config_entry.unique_id
if anonymize:
hap_sgtin = hap_sgtin[-4:]
@ -331,9 +333,17 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
"""Set up an access point from a config entry."""
# 0.104 introduced config entry unique id, this makes upgrading possible
if entry.unique_id is None:
new_data = dict(entry.data)
hass.config_entries.async_update_entry(
entry, unique_id=new_data[HMIPC_HAPID], data=new_data
)
hap = HomematicipHAP(hass, entry)
hapid = entry.data[HMIPC_HAPID].replace("-", "").upper()
hass.data[DOMAIN][hapid] = hap
hass.data[DOMAIN][entry.unique_id] = hap
if not await hap.async_setup():
return False
@ -356,5 +366,5 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
hap = hass.data[DOMAIN].pop(entry.data[HMIPC_HAPID])
hap = hass.data[DOMAIN].pop(entry.unique_id)
return await hap.async_reset()

View File

@ -18,7 +18,7 @@ from homeassistant.const import (
)
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID
from . import DOMAIN as HMIPC_DOMAIN
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -30,7 +30,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP alrm control panel from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
async_add_entities([HomematicipAlarmControlPanel(hap)])

View File

@ -41,7 +41,7 @@ from homeassistant.components.binary_sensor import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -79,7 +79,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP Cloud binary sensor from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = []
for device in hap.home.devices:
if isinstance(device, AsyncAccelerationSensor):

View File

@ -27,7 +27,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
from .hap import HomematicipHAP
HEATING_PROFILES = {"PROFILE_1": 0, "PROFILE_2": 1, "PROFILE_3": 2}
@ -47,7 +47,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP climate from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = []
for device in hap.home.groups:
if isinstance(device, AsyncHeatingGroup):

View File

@ -1,11 +1,9 @@
"""Config flow to configure the HomematicIP Cloud component."""
from typing import Any, Dict, Set
from typing import Any, Dict
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.core import callback
from homeassistant.helpers.typing import HomeAssistantType
from .const import (
_LOGGER,
@ -18,15 +16,6 @@ from .const import (
from .hap import HomematicipAuth
@callback
def configured_haps(hass: HomeAssistantType) -> Set[str]:
"""Return a set of the configured access points."""
return set(
entry.data[HMIPC_HAPID]
for entry in hass.config_entries.async_entries(HMIPC_DOMAIN)
)
@config_entries.HANDLERS.register(HMIPC_DOMAIN)
class HomematicipCloudFlowHandler(config_entries.ConfigFlow):
"""Config flow for the HomematicIP Cloud component."""
@ -48,8 +37,9 @@ class HomematicipCloudFlowHandler(config_entries.ConfigFlow):
if user_input is not None:
user_input[HMIPC_HAPID] = user_input[HMIPC_HAPID].replace("-", "").upper()
if user_input[HMIPC_HAPID] in configured_haps(self.hass):
return self.async_abort(reason="already_configured")
await self.async_set_unique_id(user_input[HMIPC_HAPID])
self._abort_if_unique_id_configured()
self.auth = HomematicipAuth(self.hass, user_input)
connected = await self.auth.async_setup()
@ -93,16 +83,14 @@ class HomematicipCloudFlowHandler(config_entries.ConfigFlow):
async def async_step_import(self, import_info) -> Dict[str, Any]:
"""Import a new access point as a config entry."""
hapid = import_info[HMIPC_HAPID]
hapid = import_info[HMIPC_HAPID].replace("-", "").upper()
authtoken = import_info[HMIPC_AUTHTOKEN]
name = import_info[HMIPC_NAME]
hapid = hapid.replace("-", "").upper()
if hapid in configured_haps(self.hass):
return self.async_abort(reason="already_configured")
await self.async_set_unique_id(hapid)
self._abort_if_unique_id_configured()
_LOGGER.info("Imported authentication for %s", hapid)
return self.async_create_entry(
title=hapid,
data={HMIPC_AUTHTOKEN: authtoken, HMIPC_HAPID: hapid, HMIPC_NAME: name},

View File

@ -17,7 +17,7 @@ from homeassistant.components.cover import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
_LOGGER = logging.getLogger(__name__)
@ -31,7 +31,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP cover from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = []
for device in hap.home.devices:
if isinstance(device, AsyncFullFlushBlind):

View File

@ -95,8 +95,7 @@ class HomematicipHAP:
raise ConfigEntryNotReady
_LOGGER.info(
"Connected to HomematicIP with HAP %s",
self.config_entry.data.get(HMIPC_HAPID),
"Connected to HomematicIP with HAP %s", self.config_entry.unique_id
)
for component in COMPONENTS:
@ -193,7 +192,7 @@ class HomematicipHAP:
_LOGGER.error(
"Error connecting to HomematicIP with HAP %s. "
"Retrying in %d seconds",
self.config_entry.data.get(HMIPC_HAPID),
self.config_entry.unique_id,
retry_delay,
)

View File

@ -25,7 +25,7 @@ from homeassistant.components.light import (
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -38,7 +38,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP Cloud lights from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = []
for device in hap.home.devices:
if isinstance(device, AsyncBrandSwitchMeasuring):

View File

@ -5,5 +5,6 @@
"documentation": "https://www.home-assistant.io/integrations/homematicip_cloud",
"requirements": ["homematicip==0.10.15"],
"dependencies": [],
"codeowners": ["@SukramJ"]
"codeowners": ["@SukramJ"],
"quality_scale": "platinum"
}

View File

@ -34,7 +34,7 @@ from homeassistant.const import (
)
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
from .device import ATTR_IS_GROUP, ATTR_MODEL_TYPE
from .hap import HomematicipHAP
@ -60,7 +60,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP Cloud sensors from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = [HomematicipAccesspointStatus(hap)]
for device in hap.home.devices:
if isinstance(device, (AsyncHeatingThermostat, AsyncHeatingThermostatCompact)):

View File

@ -19,7 +19,7 @@ from homeassistant.components.switch import SwitchDevice
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
from .device import ATTR_GROUP_MEMBER_UNREACHABLE
from .hap import HomematicipHAP
@ -30,7 +30,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP switch from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = []
for device in hap.home.devices:
if isinstance(device, AsyncBrandSwitchMeasuring):

View File

@ -13,7 +13,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import TEMP_CELSIUS
from homeassistant.helpers.typing import HomeAssistantType
from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice
from . import DOMAIN as HMIPC_DOMAIN, HomematicipGenericDevice
from .hap import HomematicipHAP
_LOGGER = logging.getLogger(__name__)
@ -41,7 +41,7 @@ async def async_setup_entry(
hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities
) -> None:
"""Set up the HomematicIP weather sensor from a config entry."""
hap = hass.data[HMIPC_DOMAIN][config_entry.data[HMIPC_HAPID]]
hap = hass.data[HMIPC_DOMAIN][config_entry.unique_id]
entities = []
for device in hap.home.devices:
if isinstance(device, AsyncWeatherSensorPro):

View File

@ -49,6 +49,7 @@ def hmip_config_entry_fixture() -> config_entries.ConfigEntry:
version=1,
domain=HMIPC_DOMAIN,
title=HAPID,
unique_id=HAPID,
data=entry_data,
source="import",
connection_class=config_entries.CONN_CLASS_CLOUD_PUSH,

View File

@ -1,34 +1,58 @@
"""Tests for HomematicIP Cloud config flow."""
from unittest.mock import patch
from asynctest import patch
from homeassistant.components.homematicip_cloud import config_flow, const, hap as hmipc
from homeassistant.components.homematicip_cloud import const
from tests.common import MockConfigEntry, mock_coro
from tests.common import MockConfigEntry
async def test_flow_works(hass):
"""Test config flow works."""
"""Test config flow."""
config = {
const.HMIPC_HAPID: "ABC123",
const.HMIPC_PIN: "123",
const.HMIPC_NAME: "hmip",
}
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
hap = hmipc.HomematicipAuth(hass, config)
with patch.object(hap, "get_auth", return_value=mock_coro()), patch.object(
hmipc.HomematicipAuth, "async_checkbutton", return_value=mock_coro(True)
), patch.object(
hmipc.HomematicipAuth, "async_setup", return_value=mock_coro(True)
), patch.object(
hmipc.HomematicipAuth, "async_register", return_value=mock_coro(True)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=False,
):
hap.authtoken = "ABC"
result = await flow.async_step_init(user_input=config)
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "user"}, data=config
)
assert hap.authtoken == "ABC"
assert result["type"] == "create_entry"
assert result["type"] == "form"
assert result["step_id"] == "link"
assert result["errors"] == {"base": "press_the_button"}
flow = next(
(
flow
for flow in hass.config_entries.flow.async_progress()
if flow["flow_id"] == result["flow_id"]
)
)
assert flow["context"]["unique_id"] == "ABC123"
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_setup",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_register",
return_value=True,
):
result = await hass.config_entries.flow.async_configure(
result["flow_id"], user_input={}
)
assert result["type"] == "create_entry"
assert result["title"] == "ABC123"
assert result["data"] == {"hapid": "ABC123", "authtoken": True, "name": "hmip"}
assert result["result"].unique_id == "ABC123"
async def test_flow_init_connection_error(hass):
@ -38,14 +62,17 @@ async def test_flow_init_connection_error(hass):
const.HMIPC_PIN: "123",
const.HMIPC_NAME: "hmip",
}
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
with patch.object(
hmipc.HomematicipAuth, "async_setup", return_value=mock_coro(False)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_setup",
return_value=False,
):
result = await flow.async_step_init(user_input=config)
assert result["type"] == "form"
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "user"}, data=config
)
assert result["type"] == "form"
assert result["step_id"] == "init"
async def test_flow_link_connection_error(hass):
@ -55,18 +82,23 @@ async def test_flow_link_connection_error(hass):
const.HMIPC_PIN: "123",
const.HMIPC_NAME: "hmip",
}
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
with patch.object(
hmipc.HomematicipAuth, "async_setup", return_value=mock_coro(True)
), patch.object(
hmipc.HomematicipAuth, "async_checkbutton", return_value=mock_coro(True)
), patch.object(
hmipc.HomematicipAuth, "async_register", return_value=mock_coro(False)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_setup",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_register",
return_value=False,
):
result = await flow.async_step_init(user_input=config)
assert result["type"] == "abort"
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "user"}, data=config
)
assert result["type"] == "abort"
assert result["reason"] == "connection_aborted"
async def test_flow_link_press_button(hass):
@ -76,92 +108,104 @@ async def test_flow_link_press_button(hass):
const.HMIPC_PIN: "123",
const.HMIPC_NAME: "hmip",
}
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
with patch.object(
hmipc.HomematicipAuth, "async_setup", return_value=mock_coro(True)
), patch.object(
hmipc.HomematicipAuth, "async_checkbutton", return_value=mock_coro(False)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=False,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_setup",
return_value=True,
):
result = await flow.async_step_init(user_input=config)
assert result["type"] == "form"
assert result["errors"] == {"base": "press_the_button"}
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "user"}, data=config
)
assert result["type"] == "form"
assert result["step_id"] == "link"
assert result["errors"] == {"base": "press_the_button"}
async def test_init_flow_show_form(hass):
"""Test config flow shows up with a form."""
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
result = await flow.async_step_init(user_input=None)
assert result["type"] == "form"
async def test_init_flow_user_show_form(hass):
"""Test config flow shows up with a form."""
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
result = await flow.async_step_user(user_input=None)
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "user"}
)
assert result["type"] == "form"
assert result["step_id"] == "init"
async def test_init_already_configured(hass):
"""Test accesspoint is already configured."""
MockConfigEntry(
domain=const.DOMAIN, data={const.HMIPC_HAPID: "ABC123"}
).add_to_hass(hass)
MockConfigEntry(domain=const.DOMAIN, unique_id="ABC123").add_to_hass(hass)
config = {
const.HMIPC_HAPID: "ABC123",
const.HMIPC_PIN: "123",
const.HMIPC_NAME: "hmip",
}
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=True,
):
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "user"}, data=config
)
result = await flow.async_step_init(user_input=config)
assert result["type"] == "abort"
assert result["reason"] == "already_configured"
async def test_import_config(hass):
"""Test importing a host with an existing config file."""
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
config = {
const.HMIPC_HAPID: "ABC123",
const.HMIPC_AUTHTOKEN: "123",
const.HMIPC_NAME: "hmip",
}
result = await flow.async_step_import(
{
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_NAME: "hmip",
}
)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_setup",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_register",
return_value=True,
):
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "import"}, data=config
)
assert result["type"] == "create_entry"
assert result["title"] == "ABC123"
assert result["data"] == {
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_NAME: "hmip",
}
assert result["data"] == {"authtoken": "123", "hapid": "ABC123", "name": "hmip"}
assert result["result"].unique_id == "ABC123"
async def test_import_existing_config(hass):
"""Test abort of an existing accesspoint from config."""
flow = config_flow.HomematicipCloudFlowHandler()
flow.hass = hass
MockConfigEntry(domain=const.DOMAIN, unique_id="ABC123").add_to_hass(hass)
config = {
const.HMIPC_HAPID: "ABC123",
const.HMIPC_AUTHTOKEN: "123",
const.HMIPC_NAME: "hmip",
}
MockConfigEntry(
domain=const.DOMAIN, data={hmipc.HMIPC_HAPID: "ABC123"}
).add_to_hass(hass)
result = await flow.async_step_import(
{
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_NAME: "hmip",
}
)
with patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_checkbutton",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_setup",
return_value=True,
), patch(
"homeassistant.components.homematicip_cloud.hap.HomematicipAuth.async_register",
return_value=True,
):
result = await hass.config_entries.flow.async_init(
const.DOMAIN, context={"source": "import"}, data=config
)
assert result["type"] == "abort"
assert result["reason"] == "already_configured"

View File

@ -1,154 +1,115 @@
"""Test HomematicIP Cloud setup process."""
from unittest.mock import patch
from asynctest import CoroutineMock, patch
from homeassistant.components import homematicip_cloud as hmipc
from homeassistant.setup import async_setup_component
from tests.common import Mock, MockConfigEntry, mock_coro
from tests.common import Mock, MockConfigEntry
async def test_config_with_accesspoint_passed_to_config_entry(hass):
"""Test that config for a accesspoint are loaded via config entry."""
with patch.object(hass, "config_entries") as mock_config_entries, patch.object(
hmipc, "configured_haps", return_value=[]
):
assert (
await async_setup_component(
hass,
hmipc.DOMAIN,
{
hmipc.DOMAIN: {
hmipc.CONF_ACCESSPOINT: "ABC123",
hmipc.CONF_AUTHTOKEN: "123",
hmipc.CONF_NAME: "name",
}
},
)
is True
)
# Flow started for the access point
assert len(mock_config_entries.flow.mock_calls) >= 2
entry_config = {
hmipc.CONF_ACCESSPOINT: "ABC123",
hmipc.CONF_AUTHTOKEN: "123",
hmipc.CONF_NAME: "name",
}
# no config_entry exists
assert len(hass.config_entries.async_entries(hmipc.DOMAIN)) == 0
# no acccesspoint exists
assert not hass.data.get(hmipc.DOMAIN)
assert (
await async_setup_component(hass, hmipc.DOMAIN, {hmipc.DOMAIN: entry_config})
is True
)
# config_entry created for access point
config_entries = hass.config_entries.async_entries(hmipc.DOMAIN)
assert len(config_entries) == 1
assert config_entries[0].data == {
"authtoken": "123",
"hapid": "ABC123",
"name": "name",
}
# defined access_point created for config_entry
assert isinstance(hass.data[hmipc.DOMAIN]["ABC123"], hmipc.HomematicipHAP)
async def test_config_already_registered_not_passed_to_config_entry(hass):
"""Test that an already registered accesspoint does not get imported."""
with patch.object(hass, "config_entries") as mock_config_entries, patch.object(
hmipc, "configured_haps", return_value=["ABC123"]
):
assert (
await async_setup_component(
hass,
hmipc.DOMAIN,
{
hmipc.DOMAIN: {
hmipc.CONF_ACCESSPOINT: "ABC123",
hmipc.CONF_AUTHTOKEN: "123",
hmipc.CONF_NAME: "name",
}
},
)
is True
)
# No flow started
assert not mock_config_entries.flow.mock_calls
async def test_setup_entry_successful(hass):
"""Test setup entry is successful."""
entry = MockConfigEntry(
domain=hmipc.DOMAIN,
data={
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_NAME: "hmip",
},
)
entry.add_to_hass(hass)
with patch.object(hmipc, "HomematicipHAP") as mock_hap:
instance = mock_hap.return_value
instance.async_setup.return_value = mock_coro(True)
instance.home.id = "1"
instance.home.modelType = "mock-type"
instance.home.name = "mock-name"
instance.home.currentAPVersion = "mock-ap-version"
assert (
await async_setup_component(
hass,
hmipc.DOMAIN,
{
hmipc.DOMAIN: {
hmipc.CONF_ACCESSPOINT: "ABC123",
hmipc.CONF_AUTHTOKEN: "123",
hmipc.CONF_NAME: "hmip",
}
},
)
is True
)
assert len(mock_hap.mock_calls) >= 2
async def test_setup_defined_accesspoint(hass):
"""Test we initiate config entry for the accesspoint."""
with patch.object(hass, "config_entries") as mock_config_entries, patch.object(
hmipc, "configured_haps", return_value=[]
):
mock_config_entries.flow.async_init.return_value = mock_coro()
assert (
await async_setup_component(
hass,
hmipc.DOMAIN,
{
hmipc.DOMAIN: {
hmipc.CONF_ACCESSPOINT: "ABC123",
hmipc.CONF_AUTHTOKEN: "123",
hmipc.CONF_NAME: "hmip",
}
},
)
is True
)
assert len(mock_config_entries.flow.mock_calls) == 1
assert mock_config_entries.flow.mock_calls[0][2]["data"] == {
hmipc.HMIPC_HAPID: "ABC123",
mock_config = {
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_NAME: "hmip",
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_NAME: "name",
}
MockConfigEntry(domain=hmipc.DOMAIN, data=mock_config).add_to_hass(hass)
# one config_entry exists
config_entries = hass.config_entries.async_entries(hmipc.DOMAIN)
assert len(config_entries) == 1
assert config_entries[0].data == {
"authtoken": "123",
"hapid": "ABC123",
"name": "name",
}
# config_enty has no unique_id
assert not config_entries[0].unique_id
entry_config = {
hmipc.CONF_ACCESSPOINT: "ABC123",
hmipc.CONF_AUTHTOKEN: "123",
hmipc.CONF_NAME: "name",
}
assert (
await async_setup_component(hass, hmipc.DOMAIN, {hmipc.DOMAIN: entry_config})
is True
)
# no new config_entry created / still one config_entry
config_entries = hass.config_entries.async_entries(hmipc.DOMAIN)
assert len(config_entries) == 1
assert config_entries[0].data == {
"authtoken": "123",
"hapid": "ABC123",
"name": "name",
}
# config_enty updated with unique_id
assert config_entries[0].unique_id == "ABC123"
async def test_unload_entry(hass):
"""Test being able to unload an entry."""
entry = MockConfigEntry(
domain=hmipc.DOMAIN,
data={
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_NAME: "hmip",
},
)
entry.add_to_hass(hass)
mock_config = {
hmipc.HMIPC_AUTHTOKEN: "123",
hmipc.HMIPC_HAPID: "ABC123",
hmipc.HMIPC_NAME: "name",
}
MockConfigEntry(domain=hmipc.DOMAIN, data=mock_config).add_to_hass(hass)
with patch.object(hmipc, "HomematicipHAP") as mock_hap:
instance = mock_hap.return_value
instance.async_setup.return_value = mock_coro(True)
instance.async_setup = CoroutineMock(return_value=True)
instance.home.id = "1"
instance.home.modelType = "mock-type"
instance.home.name = "mock-name"
instance.home.currentAPVersion = "mock-ap-version"
instance.async_reset = CoroutineMock(return_value=True)
assert await async_setup_component(hass, hmipc.DOMAIN, {}) is True
assert len(mock_hap.return_value.mock_calls) >= 1
assert mock_hap.return_value.mock_calls[0][0] == "async_setup"
mock_hap.return_value.async_reset.return_value = mock_coro(True)
assert await hmipc.async_unload_entry(hass, entry)
assert len(mock_hap.return_value.async_reset.mock_calls) == 1
assert hass.data[hmipc.DOMAIN]["ABC123"]
config_entries = hass.config_entries.async_entries(hmipc.DOMAIN)
assert len(config_entries) == 1
await hass.config_entries.async_unload(config_entries[0].entry_id)
# entry is unloaded
assert hass.data[hmipc.DOMAIN] == {}