mirror of
https://github.com/home-assistant/core.git
synced 2025-12-23 20:39:01 +00:00
Add config flow for Hue (#12830)
* Add config flow for Hue * Upgrade to aiohue 0.2 * Fix tests * Add tests * Add aiohue to test requirements * Bump aiohue dependency * Lint * Lint * Fix aiohttp mock * Lint * Fix tests
This commit is contained in:
@@ -4,13 +4,17 @@ import logging
|
||||
import unittest
|
||||
from unittest.mock import call, MagicMock, patch
|
||||
|
||||
import aiohue
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components import configurator, hue
|
||||
from homeassistant.const import CONF_FILENAME, CONF_HOST
|
||||
from homeassistant.setup import setup_component, async_setup_component
|
||||
|
||||
from tests.common import (
|
||||
assert_setup_component, get_test_home_assistant, get_test_config_dir,
|
||||
MockDependency
|
||||
MockDependency, MockConfigEntry, mock_coro
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@@ -212,7 +216,8 @@ class TestHueBridge(unittest.TestCase):
|
||||
mock_bridge = mock_phue.Bridge
|
||||
mock_bridge.side_effect = ConnectionRefusedError()
|
||||
|
||||
bridge = hue.HueBridge('localhost', self.hass, hue.PHUE_CONFIG_FILE)
|
||||
bridge = hue.HueBridge(
|
||||
'localhost', self.hass, hue.PHUE_CONFIG_FILE, None)
|
||||
bridge.setup()
|
||||
self.assertFalse(bridge.configured)
|
||||
self.assertTrue(bridge.config_request_id is None)
|
||||
@@ -228,7 +233,8 @@ class TestHueBridge(unittest.TestCase):
|
||||
mock_phue.PhueRegistrationException = Exception
|
||||
mock_bridge.side_effect = mock_phue.PhueRegistrationException(1, 2)
|
||||
|
||||
bridge = hue.HueBridge('localhost', self.hass, hue.PHUE_CONFIG_FILE)
|
||||
bridge = hue.HueBridge(
|
||||
'localhost', self.hass, hue.PHUE_CONFIG_FILE, None)
|
||||
bridge.setup()
|
||||
self.assertFalse(bridge.configured)
|
||||
self.assertFalse(bridge.config_request_id is None)
|
||||
@@ -250,7 +256,8 @@ class TestHueBridge(unittest.TestCase):
|
||||
None,
|
||||
]
|
||||
|
||||
bridge = hue.HueBridge('localhost', self.hass, hue.PHUE_CONFIG_FILE)
|
||||
bridge = hue.HueBridge(
|
||||
'localhost', self.hass, hue.PHUE_CONFIG_FILE, None)
|
||||
bridge.setup()
|
||||
self.assertFalse(bridge.configured)
|
||||
self.assertFalse(bridge.config_request_id is None)
|
||||
@@ -291,7 +298,8 @@ class TestHueBridge(unittest.TestCase):
|
||||
ConnectionRefusedError(),
|
||||
]
|
||||
|
||||
bridge = hue.HueBridge('localhost', self.hass, hue.PHUE_CONFIG_FILE)
|
||||
bridge = hue.HueBridge(
|
||||
'localhost', self.hass, hue.PHUE_CONFIG_FILE, None)
|
||||
bridge.setup()
|
||||
self.assertFalse(bridge.configured)
|
||||
self.assertFalse(bridge.config_request_id is None)
|
||||
@@ -332,7 +340,8 @@ class TestHueBridge(unittest.TestCase):
|
||||
mock_phue.PhueRegistrationException(1, 2),
|
||||
]
|
||||
|
||||
bridge = hue.HueBridge('localhost', self.hass, hue.PHUE_CONFIG_FILE)
|
||||
bridge = hue.HueBridge(
|
||||
'localhost', self.hass, hue.PHUE_CONFIG_FILE, None)
|
||||
bridge.setup()
|
||||
self.assertFalse(bridge.configured)
|
||||
self.assertFalse(bridge.config_request_id is None)
|
||||
@@ -364,7 +373,7 @@ class TestHueBridge(unittest.TestCase):
|
||||
"""Test the hue_activate_scene service."""
|
||||
with patch('homeassistant.helpers.discovery.load_platform'):
|
||||
bridge = hue.HueBridge('localhost', self.hass,
|
||||
hue.PHUE_CONFIG_FILE)
|
||||
hue.PHUE_CONFIG_FILE, None)
|
||||
bridge.setup()
|
||||
|
||||
# No args
|
||||
@@ -393,15 +402,187 @@ class TestHueBridge(unittest.TestCase):
|
||||
bridge.bridge.run_scene.assert_called_once_with('group', 'scene')
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_setup_no_host(hass, requests_mock):
|
||||
async def test_setup_no_host(hass, requests_mock):
|
||||
"""No host specified in any way."""
|
||||
requests_mock.get(hue.API_NUPNP, json=[])
|
||||
with MockDependency('phue') as mock_phue:
|
||||
result = yield from async_setup_component(
|
||||
result = await async_setup_component(
|
||||
hass, hue.DOMAIN, {hue.DOMAIN: {}})
|
||||
assert result
|
||||
|
||||
mock_phue.Bridge.assert_not_called()
|
||||
|
||||
assert hass.data[hue.DOMAIN] == {}
|
||||
|
||||
|
||||
async def test_flow_works(hass, aioclient_mock):
|
||||
"""Test config flow ."""
|
||||
aioclient_mock.get(hue.API_NUPNP, json=[
|
||||
{'internalipaddress': '1.2.3.4', 'id': 'bla'}
|
||||
])
|
||||
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
await flow.async_step_init()
|
||||
|
||||
with patch('aiohue.Bridge') as mock_bridge:
|
||||
def mock_constructor(host, websession):
|
||||
mock_bridge.host = host
|
||||
return mock_bridge
|
||||
|
||||
mock_bridge.side_effect = mock_constructor
|
||||
mock_bridge.username = 'username-abc'
|
||||
mock_bridge.config.name = 'Mock Bridge'
|
||||
mock_bridge.config.bridgeid = 'bridge-id-1234'
|
||||
mock_bridge.create_user.return_value = mock_coro()
|
||||
mock_bridge.initialize.return_value = mock_coro()
|
||||
|
||||
result = await flow.async_step_link(user_input={})
|
||||
|
||||
assert mock_bridge.host == '1.2.3.4'
|
||||
assert len(mock_bridge.create_user.mock_calls) == 1
|
||||
assert len(mock_bridge.initialize.mock_calls) == 1
|
||||
|
||||
assert result['type'] == 'create_entry'
|
||||
assert result['title'] == 'Mock Bridge'
|
||||
assert result['data'] == {
|
||||
'host': '1.2.3.4',
|
||||
'bridge_id': 'bridge-id-1234',
|
||||
'username': 'username-abc'
|
||||
}
|
||||
|
||||
|
||||
async def test_flow_no_discovered_bridges(hass, aioclient_mock):
|
||||
"""Test config flow discovers no bridges."""
|
||||
aioclient_mock.get(hue.API_NUPNP, json=[])
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_init()
|
||||
assert result['type'] == 'abort'
|
||||
|
||||
|
||||
async def test_flow_all_discovered_bridges_exist(hass, aioclient_mock):
|
||||
"""Test config flow discovers only already configured bridges."""
|
||||
aioclient_mock.get(hue.API_NUPNP, json=[
|
||||
{'internalipaddress': '1.2.3.4', 'id': 'bla'}
|
||||
])
|
||||
MockConfigEntry(domain='hue', data={
|
||||
'host': '1.2.3.4'
|
||||
}).add_to_hass(hass)
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_init()
|
||||
assert result['type'] == 'abort'
|
||||
|
||||
|
||||
async def test_flow_one_bridge_discovered(hass, aioclient_mock):
|
||||
"""Test config flow discovers one bridge."""
|
||||
aioclient_mock.get(hue.API_NUPNP, json=[
|
||||
{'internalipaddress': '1.2.3.4', 'id': 'bla'}
|
||||
])
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_init()
|
||||
assert result['type'] == 'form'
|
||||
assert result['step_id'] == 'link'
|
||||
|
||||
|
||||
async def test_flow_two_bridges_discovered(hass, aioclient_mock):
|
||||
"""Test config flow discovers two bridges."""
|
||||
aioclient_mock.get(hue.API_NUPNP, json=[
|
||||
{'internalipaddress': '1.2.3.4', 'id': 'bla'},
|
||||
{'internalipaddress': '5.6.7.8', 'id': 'beer'}
|
||||
])
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_init()
|
||||
assert result['type'] == 'form'
|
||||
assert result['step_id'] == 'init'
|
||||
|
||||
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_discovered_one_new(hass, aioclient_mock):
|
||||
"""Test config flow discovers two bridges."""
|
||||
aioclient_mock.get(hue.API_NUPNP, json=[
|
||||
{'internalipaddress': '1.2.3.4', 'id': 'bla'},
|
||||
{'internalipaddress': '5.6.7.8', 'id': 'beer'}
|
||||
])
|
||||
MockConfigEntry(domain='hue', data={
|
||||
'host': '1.2.3.4'
|
||||
}).add_to_hass(hass)
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
result = await flow.async_step_init()
|
||||
assert result['type'] == 'form'
|
||||
assert result['step_id'] == 'link'
|
||||
assert flow.host == '5.6.7.8'
|
||||
|
||||
|
||||
async def test_flow_timeout_discovery(hass):
|
||||
"""Test config flow ."""
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
with patch('aiohue.discovery.discover_nupnp',
|
||||
side_effect=asyncio.TimeoutError):
|
||||
result = await flow.async_step_init()
|
||||
|
||||
assert result['type'] == 'abort'
|
||||
|
||||
|
||||
async def test_flow_link_timeout(hass):
|
||||
"""Test config flow ."""
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
with patch('aiohue.Bridge.create_user',
|
||||
side_effect=asyncio.TimeoutError):
|
||||
result = await flow.async_step_link({})
|
||||
|
||||
assert result['type'] == 'form'
|
||||
assert result['step_id'] == 'link'
|
||||
assert result['errors'] == {
|
||||
'base': 'Failed to register, please try again.'
|
||||
}
|
||||
|
||||
|
||||
async def test_flow_link_button_not_pressed(hass):
|
||||
"""Test config flow ."""
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
with patch('aiohue.Bridge.create_user',
|
||||
side_effect=aiohue.LinkButtonNotPressed):
|
||||
result = await flow.async_step_link({})
|
||||
|
||||
assert result['type'] == 'form'
|
||||
assert result['step_id'] == 'link'
|
||||
assert result['errors'] == {
|
||||
'base': 'Failed to register, please try again.'
|
||||
}
|
||||
|
||||
|
||||
async def test_flow_link_unknown_host(hass):
|
||||
"""Test config flow ."""
|
||||
flow = hue.HueFlowHandler()
|
||||
flow.hass = hass
|
||||
|
||||
with patch('aiohue.Bridge.create_user',
|
||||
side_effect=aiohue.RequestError):
|
||||
result = await flow.async_step_link({})
|
||||
|
||||
assert result['type'] == 'form'
|
||||
assert result['step_id'] == 'link'
|
||||
assert result['errors'] == {
|
||||
'base': 'Failed to register, please try again.'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user