working on unit testing

This commit is contained in:
Brian Cribbs
2017-05-17 16:20:25 -04:00
parent 7693083be7
commit c2fa266aa9
2 changed files with 213 additions and 129 deletions

View File

@@ -62,6 +62,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
level_action = device_config[LEVEL_ACTION] level_action = device_config[LEVEL_ACTION]
level_template = device_config[LEVEL_TEMPLATE] level_template = device_config[LEVEL_TEMPLATE]
entity_ids = [] entity_ids = []
if state_template is not None: if state_template is not None:
entity_ids = (device_config.get(ATTR_ENTITY_ID) or entity_ids = (device_config.get(ATTR_ENTITY_ID) or
state_template.extract_entities()) state_template.extract_entities())
@@ -98,6 +99,7 @@ class LightTemplate(Light):
self._off_script = Script(hass, off_action) self._off_script = Script(hass, off_action)
self._level_script = Script(hass, level_action) self._level_script = Script(hass, level_action)
self._level_template = level_template self._level_template = level_template
self._state = False self._state = False
self._brightness = 0 self._brightness = 0
self._entities = entity_ids self._entities = entity_ids
@@ -107,29 +109,6 @@ class LightTemplate(Light):
if self._level_template is not None: if self._level_template is not None:
self._level_template.hass = self.hass self._level_template.hass = self.hass
@asyncio.coroutine
def async_added_to_hass(self):
"""Register callbacks."""
state = yield from async_get_last_state(self.hass, self.entity_id)
if state:
self._state = state.state == STATE_ON
@callback
def template_light_state_listener(entity, old_state, new_state):
"""Handle target device state changes."""
self.hass.async_add_job(self.async_update_ha_state(True))
@callback
def template_light_startup(event):
"""Update template on startup."""
async_track_state_change(
self.hass, self._entities, template_light_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_light_startup)
@property @property
def brightness(self): def brightness(self):
"""Return the brightness of the light.""" """Return the brightness of the light."""
@@ -145,29 +124,56 @@ class LightTemplate(Light):
return 0 return 0
@property
def is_on(self):
"""Return true if device is on."""
return self._state
@asyncio.coroutine
def async_added_to_hass(self):
"""Register callbacks."""
state = yield from async_get_last_state(self.hass, self.entity_id)
_LOGGER.error("Previous state thawed " + str(state))
if state:
self._state = state.state == STATE_ON
@callback
def template_light_state_listener(entity, old_state, new_state):
"""Handle target device state changes."""
_LOGGER.error("state listener callback")
self.hass.async_add_job(self.async_update_ha_state(True))
@callback
def template_light_startup(event):
"""Update template on startup."""
_LOGGER.error("startup callback")
async_track_state_change(
self.hass, self._entities, template_light_state_listener)
self.hass.async_add_job(self.async_update_ha_state(True))
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, template_light_startup)
@asyncio.coroutine @asyncio.coroutine
def async_turn_on(self, **kwargs): def async_turn_on(self, **kwargs):
"""Turn the light on.""" """Turn the light on."""
_LOGGER.error(str(kwargs))
_LOGGER.error(str(self._level_script))
if ATTR_BRIGHTNESS in kwargs and self._level_script: if ATTR_BRIGHTNESS in kwargs and self._level_script:
self.hass.async_add_job(self._level_script.async_run( self.hass.async_add_job(self._level_script.async_run(
{"brightness": kwargs[ATTR_BRIGHTNESS]})) {"brightness": kwargs[ATTR_BRIGHTNESS]}))
self._brightness = kwargs[ATTR_BRIGHTNESS]
else: else:
self.hass.async_add_job(self._on_script.async_run()) self.hass.async_add_job(self._on_script.async_run())
self._state = True self._state = True
self.schedule_update_ha_state(True)
@asyncio.coroutine @asyncio.coroutine
def async_turn_off(self, **kwargs): def async_turn_off(self, **kwargs):
"""Turn the light off.""" """Turn the light off."""
self.hass.async_add_job(self._off_script.async_run()) self.hass.async_add_job(self._off_script.async_run())
self._state = False self._state = False
self.schedule_update_ha_state()
@property
def is_on(self):
"""Return true if device is on."""
return self._state
@asyncio.coroutine @asyncio.coroutine
def async_update(self): def async_update(self):
@@ -191,3 +197,4 @@ class LightTemplate(Light):
except TemplateError as ex: except TemplateError as ex:
_LOGGER.error(ex) _LOGGER.error(ex)
self._state = None self._state = None

View File

@@ -1,15 +1,18 @@
"""The tests for the Template light platform.""" """The tests for the Template light platform."""
import logging
import asyncio import asyncio
from homeassistant.core import callback, State, CoreState from homeassistant.core import callback, State, CoreState
from homeassistant import setup from homeassistant import setup
import homeassistant.components as core import homeassistant.components as core
from homeassistant.components.light import (
ATTR_BRIGHTNESS, ATTR_TRANSITION)
from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE from homeassistant.helpers.restore_state import DATA_RESTORE_CACHE
from tests.common import ( from tests.common import (
get_test_home_assistant, assert_setup_component, mock_component) get_test_home_assistant, assert_setup_component, mock_component)
_LOGGER = logging.getLogger(__name__)
class TestTemplateLight: class TestTemplateLight:
"""Test the Template light.""" """Test the Template light."""
@@ -151,7 +154,7 @@ class TestTemplateLight:
def test_template_syntax_error(self): def test_template_syntax_error(self):
"""Test templating syntax error.""" """Test templating syntax error."""
with assert_setup_component(1): with assert_setup_component(0):
assert setup.setup_component(self.hass, 'light', { assert setup.setup_component(self.hass, 'light', {
'light': { 'light': {
'platform': 'template', 'platform': 'template',
@@ -186,21 +189,27 @@ class TestTemplateLight:
def test_invalid_name_does_not_create(self): def test_invalid_name_does_not_create(self):
"""Test invalid name.""" """Test invalid name."""
with assert_setup_component(0): with assert_setup_component(0):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test INVALID switch': { 'bad name here': {
'value_template': 'value_template': "{{ 1== 1}}",
"{{ rubbish }",
'turn_on': { 'turn_on': {
'service': 'switch.turn_on', 'service': 'light.turn_on',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'turn_off': { 'turn_off': {
'service': 'switch.turn_off', 'service': 'light.turn_off',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'set_level': {
'service': 'light.turn_on',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
@@ -211,14 +220,14 @@ class TestTemplateLight:
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_invalid_switch_does_not_create(self): def test_invalid_light_does_not_create(self):
"""Test invalid switch.""" """Test invalid light."""
with assert_setup_component(0): with assert_setup_component(0):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'switches': {
'test_template_switch': 'Invalid' 'test_template_light': 'Invalid'
} }
} }
}) })
@@ -228,11 +237,11 @@ class TestTemplateLight:
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_no_switches_does_not_create(self): def test_no_lights_does_not_create(self):
"""Test if there are no switches no creation.""" """Test if there are no lights no creation."""
with assert_setup_component(0): with assert_setup_component(0):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template' 'platform': 'template'
} }
}) })
@@ -242,24 +251,29 @@ class TestTemplateLight:
assert self.hass.states.all() == [] assert self.hass.states.all() == []
def test_missing_template_does_not_create(self): def test_missing_template_does_create(self):
"""Test missing template.""" """Test missing template."""
with assert_setup_component(0): with assert_setup_component(1):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test_template_switch': { 'light_one': {
'not_value_template':
"{{ states.switch.test_state.state }}",
'turn_on': { 'turn_on': {
'service': 'switch.turn_on', 'service': 'light.turn_on',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'turn_off': { 'turn_off': {
'service': 'switch.turn_off', 'service': 'light.turn_off',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'set_level': {
'service': 'light.turn_on',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
@@ -268,26 +282,28 @@ class TestTemplateLight:
self.hass.start() self.hass.start()
self.hass.block_till_done() self.hass.block_till_done()
assert self.hass.states.all() == [] assert self.hass.states.all() != []
def test_missing_on_does_not_create(self): def test_missing_on_does_not_create(self):
"""Test missing on.""" """Test missing on."""
with assert_setup_component(0): with assert_setup_component(0):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test_template_switch': { 'bad name here': {
'value_template': 'value_template': "{{ 1== 1}}",
"{{ states.switch.test_state.state }}",
'not_on': {
'service': 'switch.turn_on',
'entity_id': 'switch.test_state'
},
'turn_off': { 'turn_off': {
'service': 'switch.turn_off', 'service': 'light.turn_off',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'set_level': {
'service': 'light.turn_on',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
@@ -301,21 +317,23 @@ class TestTemplateLight:
def test_missing_off_does_not_create(self): def test_missing_off_does_not_create(self):
"""Test missing off.""" """Test missing off."""
with assert_setup_component(0): with assert_setup_component(0):
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test_template_switch': { 'bad name here': {
'value_template': 'value_template': "{{ 1== 1}}",
"{{ states.switch.test_state.state }}",
'turn_on': { 'turn_on': {
'service': 'switch.turn_on', 'service': 'light.turn_on',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
},
'not_off': {
'service': 'switch.turn_off',
'entity_id': 'switch.test_state'
}, },
'set_level': {
'service': 'light.turn_on',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
@@ -328,20 +346,26 @@ class TestTemplateLight:
def test_on_action(self): def test_on_action(self):
"""Test on action.""" """Test on action."""
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test_template_switch': { 'test_template_light': {
'value_template': 'value_template': "{{states.light.test_state.state}}",
"{{ states.switch.test_state.state }}",
'turn_on': { 'turn_on': {
'service': 'test.automation' 'service': 'test.automation',
}, },
'turn_off': { 'turn_off': {
'service': 'switch.turn_off', 'service': 'light.turn_off',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'set_level': {
'service': 'light.turn_on',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
@@ -350,34 +374,39 @@ class TestTemplateLight:
self.hass.start() self.hass.start()
self.hass.block_till_done() self.hass.block_till_done()
self.hass.states.set('switch.test_state', STATE_OFF) self.hass.states.set('light.test_state', STATE_OFF)
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.test_template_switch') state = self.hass.states.get('light.test_template_light')
assert state.state == STATE_OFF assert state.state == STATE_OFF
core.switch.turn_on(self.hass, 'switch.test_template_switch') core.light.turn_on(self.hass, 'light.test_template_light')
self.hass.block_till_done() self.hass.block_till_done()
assert len(self.calls) == 1 assert len(self.calls) == 1
def test_off_action(self): def test_off_action(self):
"""Test off action.""" """Test off action."""
assert setup.setup_component(self.hass, 'switch', { assert setup.setup_component(self.hass, 'light', {
'switch': { 'light': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test_template_switch': { 'test_template_light': {
'value_template': 'value_template': "{{states.light.test_state.state}}",
"{{ states.switch.test_state.state }}",
'turn_on': { 'turn_on': {
'service': 'switch.turn_on', 'service': 'light.turn_on',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'turn_off': { 'turn_off': {
'service': 'test.automation' 'service': 'test.automation',
}, },
'set_level': {
'service': 'light.turn_on',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
@@ -386,54 +415,102 @@ class TestTemplateLight:
self.hass.start() self.hass.start()
self.hass.block_till_done() self.hass.block_till_done()
self.hass.states.set('switch.test_state', STATE_ON) self.hass.states.set('light.test_state', STATE_ON)
self.hass.block_till_done() self.hass.block_till_done()
state = self.hass.states.get('switch.test_template_switch') state = self.hass.states.get('light.test_template_light')
assert state.state == STATE_ON assert state.state == STATE_ON
core.switch.turn_off(self.hass, 'switch.test_template_switch') core.light.turn_off(self.hass, 'light.test_template_light')
self.hass.block_till_done() self.hass.block_till_done()
assert len(self.calls) == 1 assert len(self.calls) == 1
def test_level_action_no_template(self):
"""Test setting brightness"""
assert setup.setup_component(self.hass, 'light', {
'light': {
'platform': 'template',
'lights': {
'test_template_light': {
'turn_on': {
'service': 'light.turn_on',
'entity_id': 'light.test_state'
},
'turn_off': {
'service': 'light.turn_off',
'entity_id': 'light.test_state'
},
'set_level': {
'service': 'test.automation',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
},
'level_template': '{{states.light.test_state.attributes.brightness}}'
}
}
}
})
self.hass.start()
self.hass.block_till_done()
state = self.hass.states.get('light.test_template_light')
assert state.attributes.get('brightness') == None
core.light.turn_on(
self.hass, 'light.test_template_light', **{ATTR_BRIGHTNESS: 124})
self.hass.block_till_done()
state = self.hass.states.get('light.test_template_light')
assert len(self.calls) == 1
assert self.calls[0].data['brightness'] == '124'
# need to add assertions about optimistic state
# assert state.attributes.get('brightness') == 124
@asyncio.coroutine @asyncio.coroutine
def test_restore_state(hass): def test_restore_state(hass):
"""Ensure states are restored on startup.""" """Ensure states are restored on startup."""
hass.data[DATA_RESTORE_CACHE] = { hass.data[DATA_RESTORE_CACHE] = {
'switch.test_template_switch': 'light.test_template_light':
State('switch.test_template_switch', 'on'), State('light.test_template_light', 'on'),
} }
hass.state = CoreState.starting hass.state = CoreState.starting
mock_component(hass, 'recorder') mock_component(hass, 'recorder')
yield from setup.async_setup_component(hass, 'light', {
yield from setup.async_setup_component(hass, 'switch', { 'light': {
'switch': {
'platform': 'template', 'platform': 'template',
'switches': { 'lights': {
'test_template_switch': { 'test_template_light': {
'value_template': 'value_template':
"{{ states.switch.test_state.state }}", "{{states.light.test_state.state}}",
'turn_on': { 'turn_on': {
'service': 'switch.turn_on', 'service': 'test.automation',
'entity_id': 'switch.test_state'
}, },
'turn_off': { 'turn_off': {
'service': 'switch.turn_off', 'service': 'light.turn_off',
'entity_id': 'switch.test_state' 'entity_id': 'light.test_state'
}, },
'set_level': {
'service': 'test.automation',
'data_template': {
'entity_id': 'light.test_state',
'brightness': '{{brightness}}'
}
}
} }
} }
} }
}) })
state = hass.states.get('switch.test_template_switch') state = hass.states.get('light.test_template_light')
assert state.state == 'on' assert state.state == 'on'
yield from hass.async_start() yield from hass.async_start()
yield from hass.async_block_till_done() yield from hass.async_block_till_done()
state = hass.states.get('switch.test_template_switch') state = hass.states.get('light.test_template_light')
assert state.state == 'unavailable' assert state.state == 'off'