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:
committed by
Martin Hjelmare
parent
3cba09c6f6
commit
4dda842b16
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user