Support deCONZ library with exception handling (#21952)

pull/22360/head
Robert Svensson 2019-03-24 19:27:32 +01:00 committed by GitHub
parent 89f8203163
commit 8d1cf553de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 190 additions and 65 deletions

View File

@ -12,7 +12,7 @@ from .config_flow import configured_hosts
from .const import DEFAULT_PORT, DOMAIN, _LOGGER from .const import DEFAULT_PORT, DOMAIN, _LOGGER
from .gateway import DeconzGateway from .gateway import DeconzGateway
REQUIREMENTS = ['pydeconz==52'] REQUIREMENTS = ['pydeconz==53']
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
@ -124,8 +124,7 @@ async def async_setup_entry(hass, config_entry):
scenes = set(gateway.api.scenes.keys()) scenes = set(gateway.api.scenes.keys())
sensors = set(gateway.api.sensors.keys()) sensors = set(gateway.api.sensors.keys())
if not await gateway.api.async_load_parameters(): await gateway.api.async_load_parameters()
return
gateway.async_add_device_callback( gateway.async_add_device_callback(
'group', [group 'group', [group

View File

@ -1,4 +1,6 @@
"""Config flow to configure deCONZ component.""" """Config flow to configure deCONZ component."""
import asyncio
import async_timeout
import voluptuous as vol import voluptuous as vol
from homeassistant import config_entries from homeassistant import config_entries
@ -32,15 +34,12 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
self.deconz_config = {} self.deconz_config = {}
async def async_step_user(self, user_input=None): async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
return await self.async_step_init(user_input)
async def async_step_init(self, user_input=None):
"""Handle a deCONZ config flow start. """Handle a deCONZ config flow start.
Only allows one instance to be set up. Only allows one instance to be set up.
If only one bridge is found go to link step. If only one bridge is found go to link step.
If more than one bridge is found let user choose bridge to link. If more than one bridge is found let user choose bridge to link.
If no bridge is found allow user to manually input configuration.
""" """
from pydeconz.utils import async_discovery from pydeconz.utils import async_discovery
@ -52,11 +51,18 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
if bridge[CONF_HOST] == user_input[CONF_HOST]: if bridge[CONF_HOST] == user_input[CONF_HOST]:
self.deconz_config = bridge self.deconz_config = bridge
return await self.async_step_link() return await self.async_step_link()
self.deconz_config = user_input self.deconz_config = user_input
return await self.async_step_link() return await self.async_step_link()
session = aiohttp_client.async_get_clientsession(self.hass) session = aiohttp_client.async_get_clientsession(self.hass)
self.bridges = await async_discovery(session)
try:
with async_timeout.timeout(10):
self.bridges = await async_discovery(session)
except asyncio.TimeoutError:
self.bridges = []
if len(self.bridges) == 1: if len(self.bridges) == 1:
self.deconz_config = self.bridges[0] self.deconz_config = self.bridges[0]
@ -64,8 +70,10 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
if len(self.bridges) > 1: if len(self.bridges) > 1:
hosts = [] hosts = []
for bridge in self.bridges: for bridge in self.bridges:
hosts.append(bridge[CONF_HOST]) hosts.append(bridge[CONF_HOST])
return self.async_show_form( return self.async_show_form(
step_id='init', step_id='init',
data_schema=vol.Schema({ data_schema=vol.Schema({
@ -74,7 +82,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
) )
return self.async_show_form( return self.async_show_form(
step_id='user', step_id='init',
data_schema=vol.Schema({ data_schema=vol.Schema({
vol.Required(CONF_HOST): str, vol.Required(CONF_HOST): str,
vol.Required(CONF_PORT, default=DEFAULT_PORT): int, vol.Required(CONF_PORT, default=DEFAULT_PORT): int,
@ -83,18 +91,27 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
async def async_step_link(self, user_input=None): async def async_step_link(self, user_input=None):
"""Attempt to link with the deCONZ bridge.""" """Attempt to link with the deCONZ bridge."""
from pydeconz.errors import ResponseError, RequestError
from pydeconz.utils import async_get_api_key from pydeconz.utils import async_get_api_key
errors = {} errors = {}
if user_input is not None: if user_input is not None:
if configured_hosts(self.hass): if configured_hosts(self.hass):
return self.async_abort(reason='one_instance_only') return self.async_abort(reason='one_instance_only')
session = aiohttp_client.async_get_clientsession(self.hass) session = aiohttp_client.async_get_clientsession(self.hass)
api_key = await async_get_api_key(session, **self.deconz_config)
if api_key: try:
with async_timeout.timeout(10):
api_key = await async_get_api_key(
session, **self.deconz_config)
except (ResponseError, RequestError, asyncio.TimeoutError):
errors['base'] = 'no_key'
else:
self.deconz_config[CONF_API_KEY] = api_key self.deconz_config[CONF_API_KEY] = api_key
return await self.async_step_options() return await self.async_step_options()
errors['base'] = 'no_key'
return self.async_show_form( return self.async_show_form(
step_id='link', step_id='link',
@ -117,8 +134,14 @@ class DeconzFlowHandler(config_entries.ConfigFlow):
if CONF_BRIDGEID not in self.deconz_config: if CONF_BRIDGEID not in self.deconz_config:
session = aiohttp_client.async_get_clientsession(self.hass) session = aiohttp_client.async_get_clientsession(self.hass)
self.deconz_config[CONF_BRIDGEID] = await async_get_bridgeid( try:
session, **self.deconz_config) with async_timeout.timeout(10):
self.deconz_config[CONF_BRIDGEID] = \
await async_get_bridgeid(
session, **self.deconz_config)
except asyncio.TimeoutError:
return self.async_abort(reason='no_bridges')
return self.async_create_entry( return self.async_create_entry(
title='deCONZ-' + self.deconz_config[CONF_BRIDGEID], title='deCONZ-' + self.deconz_config[CONF_BRIDGEID],

View File

@ -0,0 +1,18 @@
"""Errors for the deCONZ component."""
from homeassistant.exceptions import HomeAssistantError
class DeconzException(HomeAssistantError):
"""Base class for deCONZ exceptions."""
class AlreadyConfigured(DeconzException):
"""Gateway is already configured."""
class AuthenticationRequired(DeconzException):
"""Unknown error occurred."""
class CannotConnect(DeconzException):
"""Unable to connect to the gateway."""

View File

@ -1,6 +1,9 @@
"""Representation of a deCONZ gateway.""" """Representation of a deCONZ gateway."""
import asyncio
import async_timeout
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.const import CONF_EVENT, CONF_ID from homeassistant.const import CONF_EVENT, CONF_HOST, CONF_ID
from homeassistant.core import EventOrigin, callback from homeassistant.core import EventOrigin, callback
from homeassistant.helpers import aiohttp_client from homeassistant.helpers import aiohttp_client
from homeassistant.helpers.dispatcher import ( from homeassistant.helpers.dispatcher import (
@ -10,6 +13,7 @@ from homeassistant.util import slugify
from .const import ( from .const import (
_LOGGER, DECONZ_REACHABLE, CONF_ALLOW_CLIP_SENSOR, NEW_DEVICE, NEW_SENSOR, _LOGGER, DECONZ_REACHABLE, CONF_ALLOW_CLIP_SENSOR, NEW_DEVICE, NEW_SENSOR,
SUPPORTED_PLATFORMS) SUPPORTED_PLATFORMS)
from .errors import AuthenticationRequired, CannotConnect
class DeconzGateway: class DeconzGateway:
@ -26,18 +30,23 @@ class DeconzGateway:
self.events = [] self.events = []
self.listeners = [] self.listeners = []
async def async_setup(self, tries=0): async def async_setup(self):
"""Set up a deCONZ gateway.""" """Set up a deCONZ gateway."""
hass = self.hass hass = self.hass
self.api = await get_gateway( try:
hass, self.config_entry.data, self.async_add_device_callback, self.api = await get_gateway(
self.async_connection_status_callback hass, self.config_entry.data, self.async_add_device_callback,
) self.async_connection_status_callback
)
if not self.api: except CannotConnect:
raise ConfigEntryNotReady raise ConfigEntryNotReady
except Exception: # pylint: disable=broad-except
_LOGGER.error('Error connecting with deCONZ gateway.')
return False
for component in SUPPORTED_PLATFORMS: for component in SUPPORTED_PLATFORMS:
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup( hass.config_entries.async_forward_entry_setup(
@ -113,17 +122,26 @@ class DeconzGateway:
async def get_gateway(hass, config, async_add_device_callback, async def get_gateway(hass, config, async_add_device_callback,
async_connection_status_callback): async_connection_status_callback):
"""Create a gateway object and verify configuration.""" """Create a gateway object and verify configuration."""
from pydeconz import DeconzSession from pydeconz import DeconzSession, errors
session = aiohttp_client.async_get_clientsession(hass) session = aiohttp_client.async_get_clientsession(hass)
deconz = DeconzSession(hass.loop, session, **config, deconz = DeconzSession(hass.loop, session, **config,
async_add_device=async_add_device_callback, async_add_device=async_add_device_callback,
connection_status=async_connection_status_callback) connection_status=async_connection_status_callback)
result = await deconz.async_load_parameters() try:
with async_timeout.timeout(10):
if result: await deconz.async_load_parameters()
return deconz return deconz
return result
except errors.Unauthorized:
_LOGGER.warning("Invalid key for deCONZ at %s.", config[CONF_HOST])
raise AuthenticationRequired
except (asyncio.TimeoutError, errors.RequestError):
_LOGGER.error(
"Error connecting to deCONZ gateway at %s", config[CONF_HOST])
raise CannotConnect
class DeconzEvent: class DeconzEvent:

View File

@ -1001,7 +1001,7 @@ pydaikin==1.1.0
pydanfossair==0.0.7 pydanfossair==0.0.7
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==52 pydeconz==53
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5

View File

@ -200,7 +200,7 @@ pyHS100==0.3.4
pyblackbird==0.5 pyblackbird==0.5
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==52 pydeconz==53
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5

View File

@ -46,11 +46,14 @@ async def setup_gateway(hass, data, allow_clip_sensor=True):
"""Load the deCONZ sensor platform.""" """Load the deCONZ sensor platform."""
from pydeconz import DeconzSession from pydeconz import DeconzSession
session = Mock(put=asynctest.CoroutineMock( response = Mock(
return_value=Mock(status=200, status=200, json=asynctest.CoroutineMock(),
json=asynctest.CoroutineMock(), text=asynctest.CoroutineMock())
text=asynctest.CoroutineMock(), response.content_type = 'application/json'
)
session = Mock(
put=asynctest.CoroutineMock(
return_value=response
) )
) )

View File

@ -1,7 +1,8 @@
"""Tests for deCONZ config flow.""" """Tests for deCONZ config flow."""
import pytest from unittest.mock import patch
import asyncio
import voluptuous as vol
from homeassistant.components.deconz import config_flow from homeassistant.components.deconz import config_flow
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
@ -12,15 +13,17 @@ async def test_flow_works(hass, aioclient_mock):
"""Test that config flow works.""" """Test that config flow works."""
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[ aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[
{'id': 'id', 'internalipaddress': '1.2.3.4', 'internalport': 80} {'id': 'id', 'internalipaddress': '1.2.3.4', 'internalport': 80}
]) ], headers={'content-type': 'application/json'})
aioclient_mock.post('http://1.2.3.4:80/api', json=[ aioclient_mock.post('http://1.2.3.4:80/api', json=[
{"success": {"username": "1234567890ABCDEF"}} {"success": {"username": "1234567890ABCDEF"}}
]) ], headers={'content-type': 'application/json'})
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
await flow.async_step_user() await flow.async_step_user()
await flow.async_step_link(user_input={}) await flow.async_step_link(user_input={})
result = await flow.async_step_options( result = await flow.async_step_options(
user_input={'allow_clip_sensor': True, 'allow_deconz_groups': True}) user_input={'allow_clip_sensor': True, 'allow_deconz_groups': True})
@ -41,35 +44,53 @@ async def test_flow_already_registered_bridge(hass):
MockConfigEntry(domain='deconz', data={ MockConfigEntry(domain='deconz', data={
'host': '1.2.3.4' 'host': '1.2.3.4'
}).add_to_hass(hass) }).add_to_hass(hass)
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
result = await flow.async_step_init() result = await flow.async_step_user()
assert result['type'] == 'abort' assert result['type'] == 'abort'
async def test_flow_bridge_discovery_fails(hass, aioclient_mock):
"""Test config flow works when discovery fails."""
flow = config_flow.DeconzFlowHandler()
flow.hass = hass
with patch('pydeconz.utils.async_discovery',
side_effect=asyncio.TimeoutError):
result = await flow.async_step_user()
assert result['type'] == 'form'
assert result['step_id'] == 'init'
async def test_flow_no_discovered_bridges(hass, aioclient_mock): async def test_flow_no_discovered_bridges(hass, aioclient_mock):
"""Test config flow discovers no bridges.""" """Test config flow discovers no bridges."""
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[]) aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[],
headers={'content-type': 'application/json'})
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
result = await flow.async_step_init() result = await flow.async_step_user()
assert result['type'] == 'form' assert result['type'] == 'form'
assert result['step_id'] == 'user' assert result['step_id'] == 'init'
async def test_flow_one_bridge_discovered(hass, aioclient_mock): async def test_flow_one_bridge_discovered(hass, aioclient_mock):
"""Test config flow discovers one bridge.""" """Test config flow discovers one bridge."""
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[ aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[
{'id': 'id', 'internalipaddress': '1.2.3.4', 'internalport': 80} {'id': 'id', 'internalipaddress': '1.2.3.4', 'internalport': 80}
]) ], headers={'content-type': 'application/json'})
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
result = await flow.async_step_init() result = await flow.async_step_user()
assert result['type'] == 'form' assert result['type'] == 'form'
assert result['step_id'] == 'link' assert result['step_id'] == 'link'
assert flow.deconz_config['host'] == '1.2.3.4'
async def test_flow_two_bridges_discovered(hass, aioclient_mock): async def test_flow_two_bridges_discovered(hass, aioclient_mock):
@ -77,19 +98,14 @@ async def test_flow_two_bridges_discovered(hass, aioclient_mock):
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[ aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[
{'id': 'id1', 'internalipaddress': '1.2.3.4', 'internalport': 80}, {'id': 'id1', 'internalipaddress': '1.2.3.4', 'internalport': 80},
{'id': 'id2', 'internalipaddress': '5.6.7.8', 'internalport': 80} {'id': 'id2', 'internalipaddress': '5.6.7.8', 'internalport': 80}
]) ], headers={'content-type': 'application/json'})
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
result = await flow.async_step_init() result = await flow.async_step_user()
assert result['type'] == 'form' assert result['data_schema']({'host': '1.2.3.4'})
assert result['step_id'] == 'init' assert result['data_schema']({'host': '5.6.7.8'})
with pytest.raises(vol.Invalid):
assert result['data_schema']({'host': '0.0.0.0'})
result['data_schema']({'host': '1.2.3.4'})
result['data_schema']({'host': '5.6.7.8'})
async def test_flow_two_bridges_selection(hass, aioclient_mock): async def test_flow_two_bridges_selection(hass, aioclient_mock):
@ -101,7 +117,7 @@ async def test_flow_two_bridges_selection(hass, aioclient_mock):
{'bridgeid': 'id2', 'host': '5.6.7.8', 'port': 80} {'bridgeid': 'id2', 'host': '5.6.7.8', 'port': 80}
] ]
result = await flow.async_step_init(user_input={'host': '1.2.3.4'}) result = await flow.async_step_user(user_input={'host': '1.2.3.4'})
assert result['type'] == 'form' assert result['type'] == 'form'
assert result['step_id'] == 'link' assert result['step_id'] == 'link'
assert flow.deconz_config['host'] == '1.2.3.4' assert flow.deconz_config['host'] == '1.2.3.4'
@ -110,25 +126,28 @@ async def test_flow_two_bridges_selection(hass, aioclient_mock):
async def test_flow_manual_configuration(hass, aioclient_mock): async def test_flow_manual_configuration(hass, aioclient_mock):
"""Test config flow with manual input.""" """Test config flow with manual input."""
aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[]) aioclient_mock.get(pydeconz.utils.URL_DISCOVER, json=[])
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
user_input = {'host': '1.2.3.4', 'port': 80} user_input = {'host': '1.2.3.4', 'port': 80}
result = await flow.async_step_init(user_input) result = await flow.async_step_user(user_input)
assert result['type'] == 'form' assert result['type'] == 'form'
assert result['step_id'] == 'link' assert result['step_id'] == 'link'
assert flow.deconz_config == user_input assert flow.deconz_config == user_input
async def test_link_no_api_key(hass, aioclient_mock): async def test_link_no_api_key(hass):
"""Test config flow should abort if no API key was possible to retrieve.""" """Test config flow should abort if no API key was possible to retrieve."""
aioclient_mock.post('http://1.2.3.4:80/api', json=[])
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
flow.deconz_config = {'host': '1.2.3.4', 'port': 80} flow.deconz_config = {'host': '1.2.3.4', 'port': 80}
result = await flow.async_step_link(user_input={}) with patch('pydeconz.utils.async_get_api_key',
side_effect=pydeconz.errors.ResponseError):
result = await flow.async_step_link(user_input={})
assert result['type'] == 'form' assert result['type'] == 'form'
assert result['step_id'] == 'link' assert result['step_id'] == 'link'
assert result['errors'] == {'base': 'no_key'} assert result['errors'] == {'base': 'no_key'}
@ -143,6 +162,7 @@ async def test_link_already_registered_bridge(hass):
MockConfigEntry(domain='deconz', data={ MockConfigEntry(domain='deconz', data={
'host': '1.2.3.4' 'host': '1.2.3.4'
}).add_to_hass(hass) }).add_to_hass(hass)
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
flow.deconz_config = {'host': '1.2.3.4', 'port': 80} flow.deconz_config = {'host': '1.2.3.4', 'port': 80}
@ -155,6 +175,7 @@ async def test_bridge_discovery(hass):
"""Test a bridge being discovered.""" """Test a bridge being discovered."""
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
result = await flow.async_step_discovery({ result = await flow.async_step_discovery({
'host': '1.2.3.4', 'host': '1.2.3.4',
'port': 80, 'port': 80,
@ -222,14 +243,18 @@ async def test_import_with_api_key(hass):
async def test_options(hass, aioclient_mock): async def test_options(hass, aioclient_mock):
"""Test that options work and that bridgeid can be requested.""" """Test that options work and that bridgeid can be requested."""
aioclient_mock.get('http://1.2.3.4:80/api/1234567890ABCDEF/config', aioclient_mock.get('http://1.2.3.4:80/api/1234567890ABCDEF/config',
json={"bridgeid": "id"}) json={"bridgeid": "id"},
headers={'content-type': 'application/json'})
flow = config_flow.DeconzFlowHandler() flow = config_flow.DeconzFlowHandler()
flow.hass = hass flow.hass = hass
flow.deconz_config = {'host': '1.2.3.4', flow.deconz_config = {'host': '1.2.3.4',
'port': 80, 'port': 80,
'api_key': '1234567890ABCDEF'} 'api_key': '1234567890ABCDEF'}
result = await flow.async_step_options( result = await flow.async_step_options(
user_input={'allow_clip_sensor': False, 'allow_deconz_groups': False}) user_input={'allow_clip_sensor': False, 'allow_deconz_groups': False})
assert result['type'] == 'create_entry' assert result['type'] == 'create_entry'
assert result['title'] == 'deCONZ-id' assert result['title'] == 'deCONZ-id'
assert result['data'] == { assert result['data'] == {

View File

@ -4,10 +4,13 @@ from unittest.mock import Mock, patch
import pytest import pytest
from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.components.deconz import gateway from homeassistant.components.deconz import errors, gateway
from tests.common import mock_coro from tests.common import mock_coro
import pydeconz
ENTRY_CONFIG = { ENTRY_CONFIG = {
"host": "1.2.3.4", "host": "1.2.3.4",
"port": 80, "port": 80,
@ -62,11 +65,25 @@ async def test_gateway_retry():
deconz_gateway = gateway.DeconzGateway(hass, entry) deconz_gateway = gateway.DeconzGateway(hass, entry)
with patch.object( with patch.object(
gateway, 'get_gateway', return_value=mock_coro(False) gateway, 'get_gateway', side_effect=errors.CannotConnect), \
), pytest.raises(ConfigEntryNotReady): pytest.raises(ConfigEntryNotReady):
await deconz_gateway.async_setup() await deconz_gateway.async_setup()
async def test_gateway_setup_fails():
"""Retry setup."""
hass = Mock()
entry = Mock()
entry.data = ENTRY_CONFIG
deconz_gateway = gateway.DeconzGateway(hass, entry)
with patch.object(gateway, 'get_gateway', side_effect=Exception):
result = await deconz_gateway.async_setup()
assert not result
async def test_connection_status(hass): async def test_connection_status(hass):
"""Make sure that connection status triggers a dispatcher send.""" """Make sure that connection status triggers a dispatcher send."""
entry = Mock() entry = Mock()
@ -170,10 +187,20 @@ async def test_get_gateway(hass):
assert await gateway.get_gateway(hass, ENTRY_CONFIG, Mock(), Mock()) assert await gateway.get_gateway(hass, ENTRY_CONFIG, Mock(), Mock())
async def test_get_gateway_fails(hass): async def test_get_gateway_fails_unauthorized(hass):
"""Failed call.""" """Failed call."""
with patch('pydeconz.DeconzSession.async_load_parameters', with patch('pydeconz.DeconzSession.async_load_parameters',
return_value=mock_coro(False)): side_effect=pydeconz.errors.Unauthorized), \
pytest.raises(errors.AuthenticationRequired):
assert await gateway.get_gateway(
hass, ENTRY_CONFIG, Mock(), Mock()) is False
async def test_get_gateway_fails_cannot_connect(hass):
"""Failed call."""
with patch('pydeconz.DeconzSession.async_load_parameters',
side_effect=pydeconz.errors.RequestError), \
pytest.raises(errors.CannotConnect):
assert await gateway.get_gateway( assert await gateway.get_gateway(
hass, ENTRY_CONFIG, Mock(), Mock()) is False hass, ENTRY_CONFIG, Mock(), Mock()) is False

View File

@ -1,6 +1,7 @@
"""Test deCONZ component setup process.""" """Test deCONZ component setup process."""
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
import asyncio
import pytest import pytest
import voluptuous as vol import voluptuous as vol
@ -76,13 +77,22 @@ async def test_setup_entry_already_registered_bridge(hass):
assert await deconz.async_setup_entry(hass, {}) is False assert await deconz.async_setup_entry(hass, {}) is False
async def test_setup_entry_fails(hass):
"""Test setup entry fails if deCONZ is not available."""
entry = Mock()
entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'}
with patch('pydeconz.DeconzSession.async_load_parameters',
side_effect=Exception):
await deconz.async_setup_entry(hass, entry)
async def test_setup_entry_no_available_bridge(hass): async def test_setup_entry_no_available_bridge(hass):
"""Test setup entry fails if deCONZ is not available.""" """Test setup entry fails if deCONZ is not available."""
entry = Mock() entry = Mock()
entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'} entry.data = {'host': '1.2.3.4', 'port': 80, 'api_key': '1234567890ABCDEF'}
with patch( with patch(
'pydeconz.DeconzSession.async_load_parameters', 'pydeconz.DeconzSession.async_load_parameters',
return_value=mock_coro(False) side_effect=asyncio.TimeoutError
), pytest.raises(ConfigEntryNotReady): ), pytest.raises(ConfigEntryNotReady):
await deconz.async_setup_entry(hass, entry) await deconz.async_setup_entry(hass, entry)
@ -185,6 +195,7 @@ async def test_service_refresh_devices(hass):
}) })
entry.add_to_hass(hass) entry.add_to_hass(hass)
mock_registry = Mock() mock_registry = Mock()
with patch.object(deconz, 'DeconzGateway') as mock_gateway, \ with patch.object(deconz, 'DeconzGateway') as mock_gateway, \
patch('homeassistant.helpers.device_registry.async_get_registry', patch('homeassistant.helpers.device_registry.async_get_registry',
return_value=mock_coro(mock_registry)): return_value=mock_coro(mock_registry)):
@ -196,6 +207,7 @@ async def test_service_refresh_devices(hass):
await hass.services.async_call( await hass.services.async_call(
'deconz', 'device_refresh', service_data={}) 'deconz', 'device_refresh', service_data={})
await hass.async_block_till_done() await hass.async_block_till_done()
with patch.object(hass.data[deconz.DOMAIN].api, 'async_load_parameters', with patch.object(hass.data[deconz.DOMAIN].api, 'async_load_parameters',
return_value=mock_coro(False)): return_value=mock_coro(False)):
await hass.services.async_call( await hass.services.async_call(