1
0
mirror of https://github.com/home-assistant/core.git synced 2025-12-24 21:06:19 +00:00

Try to fix crashes after Hue refactoring (#11270)

* Try to fix crashes after Hue refactoring

Refs #11183

* Fix usage of dispatcher_send via helper.

* Address review feedback.
This commit is contained in:
Andrea Campi
2018-01-10 07:05:04 +00:00
committed by Martin Hjelmare
parent 3cba09c6f6
commit 4dda842b16
3 changed files with 202 additions and 130 deletions

View File

@@ -12,6 +12,8 @@ from tests.common import get_test_home_assistant, MockDependency
_LOGGER = logging.getLogger(__name__)
HUE_LIGHT_NS = 'homeassistant.components.light.hue.'
class TestSetup(unittest.TestCase):
"""Test the Hue light platform."""
@@ -29,11 +31,10 @@ class TestSetup(unittest.TestCase):
def setup_mocks_for_update_lights(self):
"""Set up all mocks for update_lights tests."""
self.mock_bridge = MagicMock()
self.mock_bridge.bridge_id = 'bridge-id'
self.mock_bridge.allow_hue_groups = False
self.mock_api = MagicMock()
self.mock_bridge.get_api.return_value = self.mock_api
self.mock_lights = []
self.mock_groups = []
self.mock_add_devices = MagicMock()
def setup_mocks_for_process_lights(self):
@@ -56,6 +57,7 @@ class TestSetup(unittest.TestCase):
def create_mock_bridge(self, host, allow_hue_groups=True):
"""Return a mock HueBridge with reasonable defaults."""
mock_bridge = MagicMock()
mock_bridge.bridge_id = 'bridge-id'
mock_bridge.host = host
mock_bridge.allow_hue_groups = allow_hue_groups
mock_bridge.lights = {}
@@ -72,6 +74,14 @@ class TestSetup(unittest.TestCase):
return mock_bridge_lights
def build_mock_light(self, bridge, light_id, name):
"""Return a mock HueLight."""
light = MagicMock()
light.bridge = bridge
light.light_id = light_id
light.name = name
return light
def test_setup_platform_no_discovery_info(self):
"""Test setup_platform without discovery info."""
self.hass.data[hue.DOMAIN] = {}
@@ -96,8 +106,8 @@ class TestSetup(unittest.TestCase):
self.hass.data[hue.DOMAIN] = {'10.0.0.1': mock_bridge}
mock_add_devices = MagicMock()
with patch('homeassistant.components.light.hue.' +
'unthrottled_update_lights') as mock_update_lights:
with patch(HUE_LIGHT_NS + 'unthrottled_update_lights') \
as mock_update_lights:
hue_light.setup_platform(
self.hass, {}, mock_add_devices,
{'bridge_id': '10.0.0.1'})
@@ -114,8 +124,8 @@ class TestSetup(unittest.TestCase):
}
mock_add_devices = MagicMock()
with patch('homeassistant.components.light.hue.' +
'unthrottled_update_lights') as mock_update_lights:
with patch(HUE_LIGHT_NS + 'unthrottled_update_lights') \
as mock_update_lights:
hue_light.setup_platform(
self.hass, {}, mock_add_devices,
{'bridge_id': '10.0.0.1'})
@@ -133,83 +143,105 @@ class TestSetup(unittest.TestCase):
"""Test the update_lights function when no lights are found."""
self.setup_mocks_for_update_lights()
with patch('homeassistant.components.light.hue.process_lights',
return_value=[]) as mock_process_lights:
with patch('homeassistant.components.light.hue.process_groups',
return_value=self.mock_groups) \
with patch(HUE_LIGHT_NS + 'process_lights', return_value=[]) \
as mock_process_lights:
with patch(HUE_LIGHT_NS + 'process_groups', return_value=[]) \
as mock_process_groups:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
with patch.object(self.hass.helpers.dispatcher,
'dispatcher_send') as dispatcher_send:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_not_called()
self.mock_add_devices.assert_not_called()
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_not_called()
self.mock_add_devices.assert_not_called()
dispatcher_send.assert_not_called()
@MockDependency('phue')
def test_update_lights_with_some_lights(self, mock_phue):
"""Test the update_lights function with some lights."""
self.setup_mocks_for_update_lights()
self.mock_lights = ['some', 'light']
mock_lights = [
self.build_mock_light(self.mock_bridge, 42, 'some'),
self.build_mock_light(self.mock_bridge, 84, 'light'),
]
with patch('homeassistant.components.light.hue.process_lights',
return_value=self.mock_lights) as mock_process_lights:
with patch('homeassistant.components.light.hue.process_groups',
return_value=self.mock_groups) \
with patch(HUE_LIGHT_NS + 'process_lights',
return_value=mock_lights) as mock_process_lights:
with patch(HUE_LIGHT_NS + 'process_groups', return_value=[]) \
as mock_process_groups:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
with patch.object(self.hass.helpers.dispatcher,
'dispatcher_send') as dispatcher_send:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_not_called()
self.mock_add_devices.assert_called_once_with(
self.mock_lights)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_not_called()
self.mock_add_devices.assert_called_once_with(
mock_lights)
dispatcher_send.assert_not_called()
@MockDependency('phue')
def test_update_lights_no_groups(self, mock_phue):
"""Test the update_lights function when no groups are found."""
self.setup_mocks_for_update_lights()
self.mock_bridge.allow_hue_groups = True
self.mock_lights = ['some', 'light']
mock_lights = [
self.build_mock_light(self.mock_bridge, 42, 'some'),
self.build_mock_light(self.mock_bridge, 84, 'light'),
]
with patch('homeassistant.components.light.hue.process_lights',
return_value=self.mock_lights) as mock_process_lights:
with patch('homeassistant.components.light.hue.process_groups',
return_value=self.mock_groups) \
with patch(HUE_LIGHT_NS + 'process_lights',
return_value=mock_lights) as mock_process_lights:
with patch(HUE_LIGHT_NS + 'process_groups', return_value=[]) \
as mock_process_groups:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
with patch.object(self.hass.helpers.dispatcher,
'dispatcher_send') as dispatcher_send:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
self.mock_add_devices.assert_called_once_with(
self.mock_lights)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
self.mock_add_devices.assert_called_once_with(
mock_lights)
dispatcher_send.assert_not_called()
@MockDependency('phue')
def test_update_lights_with_lights_and_groups(self, mock_phue):
"""Test the update_lights function with both lights and groups."""
self.setup_mocks_for_update_lights()
self.mock_bridge.allow_hue_groups = True
self.mock_lights = ['some', 'light']
self.mock_groups = ['and', 'groups']
mock_lights = [
self.build_mock_light(self.mock_bridge, 42, 'some'),
self.build_mock_light(self.mock_bridge, 84, 'light'),
]
mock_groups = [
self.build_mock_light(self.mock_bridge, 15, 'and'),
self.build_mock_light(self.mock_bridge, 72, 'groups'),
]
with patch('homeassistant.components.light.hue.process_lights',
return_value=self.mock_lights) as mock_process_lights:
with patch('homeassistant.components.light.hue.process_groups',
return_value=self.mock_groups) \
as mock_process_groups:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
with patch(HUE_LIGHT_NS + 'process_lights',
return_value=mock_lights) as mock_process_lights:
with patch(HUE_LIGHT_NS + 'process_groups',
return_value=mock_groups) as mock_process_groups:
with patch.object(self.hass.helpers.dispatcher,
'dispatcher_send') as dispatcher_send:
hue_light.unthrottled_update_lights(
self.hass, self.mock_bridge, self.mock_add_devices)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
self.mock_add_devices.assert_called_once_with(
self.mock_lights)
mock_process_lights.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
mock_process_groups.assert_called_once_with(
self.hass, self.mock_api, self.mock_bridge, mock.ANY)
# note that mock_lights has been modified in place and
# now contains both lights and groups
self.mock_add_devices.assert_called_once_with(
mock_lights)
dispatcher_send.assert_not_called()
@MockDependency('phue')
def test_update_lights_with_two_bridges(self, mock_phue):
@@ -288,36 +320,42 @@ class TestSetup(unittest.TestCase):
"""Test the process_lights function when bridge returns no lights."""
self.setup_mocks_for_process_lights()
ret = hue_light.process_lights(
self.hass, self.mock_api, self.mock_bridge, None)
with patch.object(self.hass.helpers.dispatcher, 'dispatcher_send') \
as mock_dispatcher_send:
ret = hue_light.process_lights(
self.hass, self.mock_api, self.mock_bridge, None)
self.assertEquals([], ret)
self.assertEquals(self.mock_bridge.lights, {})
self.assertEquals([], ret)
mock_dispatcher_send.assert_not_called()
self.assertEquals(self.mock_bridge.lights, {})
@patch('homeassistant.components.light.hue.HueLight')
@patch(HUE_LIGHT_NS + 'HueLight')
def test_process_lights_some_lights(self, mock_hue_light):
"""Test the process_lights function with multiple groups."""
self.setup_mocks_for_process_lights()
self.mock_api.get.return_value = {
1: {'state': 'on'}, 2: {'state': 'off'}}
ret = hue_light.process_lights(
self.hass, self.mock_api, self.mock_bridge, None)
with patch.object(self.hass.helpers.dispatcher, 'dispatcher_send') \
as mock_dispatcher_send:
ret = hue_light.process_lights(
self.hass, self.mock_api, self.mock_bridge, None)
self.assertEquals(len(ret), 2)
mock_hue_light.assert_has_calls([
call(
1, {'state': 'on'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue),
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue),
])
self.assertEquals(len(self.mock_bridge.lights), 2)
self.assertEquals(len(ret), 2)
mock_hue_light.assert_has_calls([
call(
1, {'state': 'on'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue),
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue),
])
mock_dispatcher_send.assert_not_called()
self.assertEquals(len(self.mock_bridge.lights), 2)
@patch('homeassistant.components.light.hue.HueLight')
@patch(HUE_LIGHT_NS + 'HueLight')
def test_process_lights_new_light(self, mock_hue_light):
"""
Test the process_lights function with new groups.
@@ -327,21 +365,24 @@ class TestSetup(unittest.TestCase):
self.setup_mocks_for_process_lights()
self.mock_api.get.return_value = {
1: {'state': 'on'}, 2: {'state': 'off'}}
self.mock_bridge.lights = {1: MagicMock()}
self.mock_bridge.lights = {
1: self.build_mock_light(self.mock_bridge, 1, 'foo')}
ret = hue_light.process_lights(
self.hass, self.mock_api, self.mock_bridge, None)
with patch.object(self.hass.helpers.dispatcher, 'dispatcher_send') \
as mock_dispatcher_send:
ret = hue_light.process_lights(
self.hass, self.mock_api, self.mock_bridge, None)
self.assertEquals(len(ret), 1)
mock_hue_light.assert_has_calls([
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue),
])
self.assertEquals(len(self.mock_bridge.lights), 2)
self.mock_bridge.lights[1]\
.schedule_update_ha_state.assert_called_once_with()
self.assertEquals(len(ret), 1)
mock_hue_light.assert_has_calls([
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue),
])
mock_dispatcher_send.assert_called_once_with(
'hue_light_callback_bridge-id_1')
self.assertEquals(len(self.mock_bridge.lights), 2)
def test_process_groups_api_error(self):
"""Test the process_groups function when the bridge errors out."""
@@ -359,36 +400,42 @@ class TestSetup(unittest.TestCase):
self.setup_mocks_for_process_groups()
self.mock_bridge.get_group.return_value = {'name': 'Group 0'}
ret = hue_light.process_groups(
self.hass, self.mock_api, self.mock_bridge, None)
with patch.object(self.hass.helpers.dispatcher, 'dispatcher_send') \
as mock_dispatcher_send:
ret = hue_light.process_groups(
self.hass, self.mock_api, self.mock_bridge, None)
self.assertEquals([], ret)
self.assertEquals(self.mock_bridge.lightgroups, {})
self.assertEquals([], ret)
mock_dispatcher_send.assert_not_called()
self.assertEquals(self.mock_bridge.lightgroups, {})
@patch('homeassistant.components.light.hue.HueLight')
@patch(HUE_LIGHT_NS + 'HueLight')
def test_process_groups_some_groups(self, mock_hue_light):
"""Test the process_groups function with multiple groups."""
self.setup_mocks_for_process_groups()
self.mock_api.get.return_value = {
1: {'state': 'on'}, 2: {'state': 'off'}}
ret = hue_light.process_groups(
self.hass, self.mock_api, self.mock_bridge, None)
with patch.object(self.hass.helpers.dispatcher, 'dispatcher_send') \
as mock_dispatcher_send:
ret = hue_light.process_groups(
self.hass, self.mock_api, self.mock_bridge, None)
self.assertEquals(len(ret), 2)
mock_hue_light.assert_has_calls([
call(
1, {'state': 'on'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue, True),
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue, True),
])
self.assertEquals(len(self.mock_bridge.lightgroups), 2)
self.assertEquals(len(ret), 2)
mock_hue_light.assert_has_calls([
call(
1, {'state': 'on'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue, True),
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue, True),
])
mock_dispatcher_send.assert_not_called()
self.assertEquals(len(self.mock_bridge.lightgroups), 2)
@patch('homeassistant.components.light.hue.HueLight')
@patch(HUE_LIGHT_NS + 'HueLight')
def test_process_groups_new_group(self, mock_hue_light):
"""
Test the process_groups function with new groups.
@@ -398,21 +445,24 @@ class TestSetup(unittest.TestCase):
self.setup_mocks_for_process_groups()
self.mock_api.get.return_value = {
1: {'state': 'on'}, 2: {'state': 'off'}}
self.mock_bridge.lightgroups = {1: MagicMock()}
self.mock_bridge.lightgroups = {
1: self.build_mock_light(self.mock_bridge, 1, 'foo')}
ret = hue_light.process_groups(
self.hass, self.mock_api, self.mock_bridge, None)
with patch.object(self.hass.helpers.dispatcher, 'dispatcher_send') \
as mock_dispatcher_send:
ret = hue_light.process_groups(
self.hass, self.mock_api, self.mock_bridge, None)
self.assertEquals(len(ret), 1)
mock_hue_light.assert_has_calls([
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue, True),
])
self.assertEquals(len(self.mock_bridge.lightgroups), 2)
self.mock_bridge.lightgroups[1]\
.schedule_update_ha_state.assert_called_once_with()
self.assertEquals(len(ret), 1)
mock_hue_light.assert_has_calls([
call(
2, {'state': 'off'}, self.mock_bridge, mock.ANY,
self.mock_bridge.allow_unreachable,
self.mock_bridge.allow_in_emulated_hue, True),
])
mock_dispatcher_send.assert_called_once_with(
'hue_light_callback_bridge-id_1')
self.assertEquals(len(self.mock_bridge.lightgroups), 2)
class TestHueLight(unittest.TestCase):
@@ -440,6 +490,10 @@ class TestHueLight(unittest.TestCase):
def buildLight(
self, light_id=None, info=None, update_lights=None, is_group=None):
"""Helper to build a HueLight object with minimal fuss."""
if 'state' not in info:
on_key = 'any_on' if is_group is not None else 'on'
info['state'] = {on_key: False}
return hue_light.HueLight(
light_id if light_id is not None else self.light_id,
info if info is not None else self.mock_info,