Add tests, fix styling
parent
980ecdaacb
commit
cdbcc844cf
|
@ -1,7 +1,18 @@
|
||||||
|
"""
|
||||||
|
homeassistant.components.configurator
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A component to allow pieces of code to request configuration from the user.
|
||||||
|
|
||||||
|
Initiate a request by calling the `request_config` method with a callback.
|
||||||
|
This will return a request id that has to be used for future calls.
|
||||||
|
A callback has to be provided to `request_config` which will be called when
|
||||||
|
the user has submitted configuration information.
|
||||||
|
"""
|
||||||
import logging
|
import logging
|
||||||
|
import threading
|
||||||
|
|
||||||
from homeassistant.helpers import generate_entity_id
|
from homeassistant.helpers import generate_entity_id
|
||||||
from homeassistant.const import EVENT_TIME_CHANGED
|
|
||||||
|
|
||||||
DOMAIN = "configurator"
|
DOMAIN = "configurator"
|
||||||
DEPENDENCIES = []
|
DEPENDENCIES = []
|
||||||
|
@ -19,30 +30,50 @@ ATTR_SUBMIT_CAPTION = "submit_caption"
|
||||||
ATTR_FIELDS = "fields"
|
ATTR_FIELDS = "fields"
|
||||||
ATTR_ERRORS = "errors"
|
ATTR_ERRORS = "errors"
|
||||||
|
|
||||||
|
_REQUESTS = {}
|
||||||
_INSTANCES = {}
|
_INSTANCES = {}
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
def request_config(
|
def request_config(
|
||||||
hass, name, callback, description=None, description_image=None,
|
hass, name, callback, description=None, description_image=None,
|
||||||
submit_caption=None, fields=None):
|
submit_caption=None, fields=None):
|
||||||
""" Create a new request for config.
|
""" Create a new request for config.
|
||||||
Will return an ID to be used for sequent calls. """
|
Will return an ID to be used for sequent calls. """
|
||||||
|
|
||||||
return _get_instance(hass).request_config(
|
instance = _get_instance(hass)
|
||||||
|
|
||||||
|
request_id = instance.request_config(
|
||||||
name, callback,
|
name, callback,
|
||||||
description, description_image, submit_caption, fields)
|
description, description_image, submit_caption, fields)
|
||||||
|
|
||||||
|
_REQUESTS[request_id] = instance
|
||||||
|
|
||||||
def notify_errors(hass, request_id, error):
|
return request_id
|
||||||
_get_instance(hass).notify_errors(request_id, error)
|
|
||||||
|
|
||||||
|
|
||||||
def request_done(hass, request_id):
|
def notify_errors(request_id, error):
|
||||||
_get_instance(hass).request_done(request_id)
|
""" Add errors to a config request. """
|
||||||
|
try:
|
||||||
|
_REQUESTS[request_id].notify_errors(request_id, error)
|
||||||
|
except KeyError:
|
||||||
|
# If request_id does not exist
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def request_done(request_id):
|
||||||
|
""" Mark a config request as done. """
|
||||||
|
try:
|
||||||
|
_REQUESTS.pop(request_id).request_done(request_id)
|
||||||
|
except KeyError:
|
||||||
|
# If request_id does not exist
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
|
""" Set up Configurator. """
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,7 +82,6 @@ def _get_instance(hass):
|
||||||
try:
|
try:
|
||||||
return _INSTANCES[hass]
|
return _INSTANCES[hass]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print("Creating instance")
|
|
||||||
_INSTANCES[hass] = Configurator(hass)
|
_INSTANCES[hass] = Configurator(hass)
|
||||||
|
|
||||||
if DOMAIN not in hass.components:
|
if DOMAIN not in hass.components:
|
||||||
|
@ -61,6 +91,10 @@ def _get_instance(hass):
|
||||||
|
|
||||||
|
|
||||||
class Configurator(object):
|
class Configurator(object):
|
||||||
|
"""
|
||||||
|
Class to keep track of current configuration requests.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, hass):
|
def __init__(self, hass):
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
self._cur_id = 0
|
self._cur_id = 0
|
||||||
|
@ -68,6 +102,7 @@ class Configurator(object):
|
||||||
hass.services.register(
|
hass.services.register(
|
||||||
DOMAIN, SERVICE_CONFIGURE, self.handle_service_call)
|
DOMAIN, SERVICE_CONFIGURE, self.handle_service_call)
|
||||||
|
|
||||||
|
# pylint: disable=too-many-arguments
|
||||||
def request_config(
|
def request_config(
|
||||||
self, name, callback,
|
self, name, callback,
|
||||||
description, description_image, submit_caption, fields):
|
description, description_image, submit_caption, fields):
|
||||||
|
@ -120,25 +155,26 @@ class Configurator(object):
|
||||||
|
|
||||||
entity_id = self._requests.pop(request_id)[0]
|
entity_id = self._requests.pop(request_id)[0]
|
||||||
|
|
||||||
# If we remove the state right away, it will not be passed down
|
|
||||||
# with the service request (limitation current design).
|
|
||||||
# Instead we will set it to configured right away and remove it soon.
|
|
||||||
def deferred_remove(event):
|
|
||||||
self.hass.states.remove(entity_id)
|
|
||||||
|
|
||||||
self.hass.bus.listen_once(EVENT_TIME_CHANGED, deferred_remove)
|
|
||||||
|
|
||||||
self.hass.states.set(entity_id, STATE_CONFIGURED)
|
self.hass.states.set(entity_id, STATE_CONFIGURED)
|
||||||
|
|
||||||
|
# If we remove the state right away, it will not be included with
|
||||||
|
# the result fo the service call (limitation current design).
|
||||||
|
# Instead we will set it to configured to give as feedback but delete
|
||||||
|
# it shortly after so that it is deleted when the client updates.
|
||||||
|
threading.Timer(
|
||||||
|
.001, lambda: self.hass.states.remove(entity_id)).start()
|
||||||
|
|
||||||
def handle_service_call(self, call):
|
def handle_service_call(self, call):
|
||||||
|
""" Handle a configure service call. """
|
||||||
request_id = call.data.get(ATTR_CONFIGURE_ID)
|
request_id = call.data.get(ATTR_CONFIGURE_ID)
|
||||||
|
|
||||||
if not self._validate_request_id(request_id):
|
if not self._validate_request_id(request_id):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# pylint: disable=unused-variable
|
||||||
entity_id, fields, callback = self._requests[request_id]
|
entity_id, fields, callback = self._requests[request_id]
|
||||||
|
|
||||||
# TODO field validation?
|
# field validation goes here?
|
||||||
|
|
||||||
callback(call.data.get(ATTR_FIELDS, {}))
|
callback(call.data.get(ATTR_FIELDS, {}))
|
||||||
|
|
||||||
|
@ -148,8 +184,5 @@ class Configurator(object):
|
||||||
return "{}-{}".format(id(self), self._cur_id)
|
return "{}-{}".format(id(self), self._cur_id)
|
||||||
|
|
||||||
def _validate_request_id(self, request_id):
|
def _validate_request_id(self, request_id):
|
||||||
if request_id not in self._requests:
|
""" Validate that the request belongs to this instance. """
|
||||||
_LOGGER.error("Invalid configure id received: %s", request_id)
|
return request_id in self._requests
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
|
@ -174,6 +174,7 @@ def setup(hass, config):
|
||||||
|
|
||||||
configurator_ids = []
|
configurator_ids = []
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
def hue_configuration_callback(data):
|
def hue_configuration_callback(data):
|
||||||
""" Fake callback, mark config as done. """
|
""" Fake callback, mark config as done. """
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
@ -181,12 +182,12 @@ def setup(hass, config):
|
||||||
# First time it is called, pretend it failed.
|
# First time it is called, pretend it failed.
|
||||||
if len(configurator_ids) == 1:
|
if len(configurator_ids) == 1:
|
||||||
configurator.notify_errors(
|
configurator.notify_errors(
|
||||||
hass, configurator_ids[0],
|
configurator_ids[0],
|
||||||
"Failed to register, please try again.")
|
"Failed to register, please try again.")
|
||||||
|
|
||||||
configurator_ids.append(0)
|
configurator_ids.append(0)
|
||||||
else:
|
else:
|
||||||
configurator.request_done(hass, configurator_ids[0])
|
configurator.request_done(configurator_ids[0])
|
||||||
|
|
||||||
request_id = configurator.request_config(
|
request_id = configurator.request_config(
|
||||||
hass, "Philips Hue", hue_configuration_callback,
|
hass, "Philips Hue", hue_configuration_callback,
|
||||||
|
|
|
@ -137,6 +137,14 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
// local methods
|
// local methods
|
||||||
|
removeState: function(entityId) {
|
||||||
|
var state = this.getState(entityId);
|
||||||
|
|
||||||
|
if (state !== null) {
|
||||||
|
this.states.splice(this.states.indexOf(state), 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
getState: function(entityId) {
|
getState: function(entityId) {
|
||||||
var found = this.states.filter(function(state) {
|
var found = this.states.filter(function(state) {
|
||||||
return state.entity_id == entityId;
|
return state.entity_id == entityId;
|
||||||
|
@ -158,6 +166,11 @@
|
||||||
return states;
|
return states;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getEntityIDs: function() {
|
||||||
|
return this.states.map(
|
||||||
|
function(state) { return state.entity_id; });
|
||||||
|
},
|
||||||
|
|
||||||
hasService: function(domain, service) {
|
hasService: function(domain, service) {
|
||||||
var found = this.services.filter(function(serv) {
|
var found = this.services.filter(function(serv) {
|
||||||
return serv.domain == domain && serv.services.indexOf(service) !== -1;
|
return serv.domain == domain && serv.services.indexOf(service) !== -1;
|
||||||
|
@ -179,8 +192,8 @@
|
||||||
this.stateUpdateTimeout = setTimeout(this.fetchStates.bind(this), 60000);
|
this.stateUpdateTimeout = setTimeout(this.fetchStates.bind(this), 60000);
|
||||||
},
|
},
|
||||||
|
|
||||||
_sortStates: function(states) {
|
_sortStates: function() {
|
||||||
states.sort(function(one, two) {
|
this.states.sort(function(one, two) {
|
||||||
if (one.entity_id > two.entity_id) {
|
if (one.entity_id > two.entity_id) {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (one.entity_id < two.entity_id) {
|
} else if (one.entity_id < two.entity_id) {
|
||||||
|
@ -191,32 +204,62 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pushes a new state to the state machine.
|
||||||
|
* Will resort the states after a push and fire states-updated event.
|
||||||
|
*/
|
||||||
_pushNewState: function(new_state) {
|
_pushNewState: function(new_state) {
|
||||||
var state;
|
if (this.__pushNewState(new_state)) {
|
||||||
var stateFound = false;
|
this._sortStates();
|
||||||
|
|
||||||
for(var i = 0; i < this.states.length; i++) {
|
|
||||||
if(this.states[i].entity_id == new_state.entity_id) {
|
|
||||||
state = this.states[i];
|
|
||||||
state.attributes = new_state.attributes;
|
|
||||||
state.last_changed = new_state.last_changed;
|
|
||||||
state.state = new_state.state;
|
|
||||||
|
|
||||||
stateFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!stateFound) {
|
|
||||||
this.states.push(new State(new_state, this));
|
|
||||||
this._sortStates(this.states);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fire('states-updated');
|
this.fire('states-updated');
|
||||||
},
|
},
|
||||||
|
|
||||||
_pushNewStates: function(new_states) {
|
/**
|
||||||
new_states.forEach(this._pushNewState.bind(this));
|
* Creates or updates a state. Returns if a new state was added.
|
||||||
|
*/
|
||||||
|
__pushNewState: function(new_state) {
|
||||||
|
var curState = this.getState(new_state.entity_id);
|
||||||
|
|
||||||
|
if (curState === null) {
|
||||||
|
this.states.push(new State(new_state, this));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
curState.attributes = new_state.attributes;
|
||||||
|
curState.last_changed = new_state.last_changed;
|
||||||
|
curState.state = new_state.state;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_pushNewStates: function(newStates, removeNonPresent) {
|
||||||
|
removeNonPresent = !!removeNonPresent;
|
||||||
|
var currentEntityIds = removeNonPresent ? this.getEntityIDs() : [];
|
||||||
|
|
||||||
|
var hasNew = newStates.reduce(function(hasNew, newState) {
|
||||||
|
var isNewState = this.__pushNewState(newState);
|
||||||
|
|
||||||
|
if (isNewState) {
|
||||||
|
return true;
|
||||||
|
} else if(removeNonPresent) {
|
||||||
|
currentEntityIds.splice(currentEntityIds.indexOf(newState.entity_id), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hasNew;
|
||||||
|
}.bind(this), false);
|
||||||
|
|
||||||
|
currentEntityIds.forEach(function(entityId) {
|
||||||
|
this.removeState(entityId);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
if (hasNew) {
|
||||||
|
this._sortStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fire('states-updated');
|
||||||
},
|
},
|
||||||
|
|
||||||
// call api methods
|
// call api methods
|
||||||
|
@ -236,9 +279,7 @@
|
||||||
|
|
||||||
fetchStates: function(onSuccess, onError) {
|
fetchStates: function(onSuccess, onError) {
|
||||||
var successStatesUpdate = function(newStates) {
|
var successStatesUpdate = function(newStates) {
|
||||||
this._pushNewStates(newStates);
|
this._pushNewStates(newStates, true);
|
||||||
|
|
||||||
this.fire('states-updated');
|
|
||||||
|
|
||||||
this._laterFetchStates();
|
this._laterFetchStates();
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class='error' hidden?="{{!stateObj.attributes.errors}}">
|
<p class='error' hidden?="{{!stateObj.attributes.errors}}">
|
||||||
Errors: {{stateObj.attributes.errors}}
|
{{stateObj.attributes.errors}}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p hidden?="{{!stateObj.attributes.description_image}}">
|
<p hidden?="{{!stateObj.attributes.description_image}}">
|
||||||
|
|
|
@ -26,7 +26,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||||
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Gets the Hue lights. """
|
""" Gets the Hue lights. """
|
||||||
try:
|
try:
|
||||||
import phue
|
# pylint: disable=unused-variable
|
||||||
|
import phue # noqa
|
||||||
except ImportError:
|
except ImportError:
|
||||||
_LOGGER.exception("Error while importing dependency phue.")
|
_LOGGER.exception("Error while importing dependency phue.")
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
|
|
||||||
|
|
||||||
def setup_bridge(host, hass, add_devices_callback):
|
def setup_bridge(host, hass, add_devices_callback):
|
||||||
|
""" Setup a phue bridge based on host parameter. """
|
||||||
import phue
|
import phue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -68,7 +70,7 @@ def setup_bridge(host, hass, add_devices_callback):
|
||||||
|
|
||||||
configurator = get_component('configurator')
|
configurator = get_component('configurator')
|
||||||
|
|
||||||
configurator.request_done(hass, request_id)
|
configurator.request_done(request_id)
|
||||||
|
|
||||||
lights = {}
|
lights = {}
|
||||||
|
|
||||||
|
@ -108,13 +110,14 @@ def request_configuration(host, hass, add_devices_callback):
|
||||||
""" Request configuration steps from the user. """
|
""" Request configuration steps from the user. """
|
||||||
configurator = get_component('configurator')
|
configurator = get_component('configurator')
|
||||||
|
|
||||||
# If this method called while we are configuring, means we got an error
|
# We got an error if this method is called while we are configuring
|
||||||
if host in _CONFIGURING:
|
if host in _CONFIGURING:
|
||||||
configurator.notify_errors(
|
configurator.notify_errors(
|
||||||
hass, _CONFIGURING[host], "Failed to register, please try again.")
|
_CONFIGURING[host], "Failed to register, please try again.")
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# pylint: disable=unused-argument
|
||||||
def hue_configuration_callback(data):
|
def hue_configuration_callback(data):
|
||||||
""" Actions to do when our configuration callback is called. """
|
""" Actions to do when our configuration callback is called. """
|
||||||
setup_bridge(host, hass, add_devices_callback)
|
setup_bridge(host, hass, add_devices_callback)
|
||||||
|
|
|
@ -13,6 +13,7 @@ from homeassistant.util import ensure_unique_string, slugify
|
||||||
|
|
||||||
|
|
||||||
def generate_entity_id(entity_id_format, name, current_ids=None, hass=None):
|
def generate_entity_id(entity_id_format, name, current_ids=None, hass=None):
|
||||||
|
""" Generate a unique entity ID based on given entity IDs or used ids. """
|
||||||
if current_ids is None:
|
if current_ids is None:
|
||||||
if hass is None:
|
if hass is None:
|
||||||
raise RuntimeError("Missing required parameter currentids or hass")
|
raise RuntimeError("Missing required parameter currentids or hass")
|
||||||
|
|
|
@ -24,6 +24,11 @@ def init(empty=False):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_lights(hass, config):
|
def setup_platform(hass, config, add_devices_callback, discovery_info=None):
|
||||||
""" Returns mock devices. """
|
""" Returns mock devices. """
|
||||||
|
add_devices_callback(DEVICES)
|
||||||
|
|
||||||
|
|
||||||
|
def get_lights():
|
||||||
|
""" Helper method to get current light objects. """
|
||||||
return DEVICES
|
return DEVICES
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
"""
|
||||||
|
tests.test_component_configurator
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Tests Configurator component.
|
||||||
|
"""
|
||||||
|
# pylint: disable=too-many-public-methods,protected-access
|
||||||
|
import unittest
|
||||||
|
import time
|
||||||
|
|
||||||
|
import homeassistant as ha
|
||||||
|
import homeassistant.components.configurator as configurator
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfigurator(unittest.TestCase):
|
||||||
|
""" Test the chromecast module. """
|
||||||
|
|
||||||
|
def setUp(self): # pylint: disable=invalid-name
|
||||||
|
self.hass = ha.HomeAssistant()
|
||||||
|
|
||||||
|
def tearDown(self): # pylint: disable=invalid-name
|
||||||
|
""" Stop down stuff we started. """
|
||||||
|
self.hass.stop()
|
||||||
|
|
||||||
|
def test_request_least_info(self):
|
||||||
|
""" Test request config with least amount of data. """
|
||||||
|
|
||||||
|
request_id = configurator.request_config(
|
||||||
|
self.hass, "Test Request", lambda _: None)
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
1, len(self.hass.services.services.get(configurator.DOMAIN, [])),
|
||||||
|
"No new service registered")
|
||||||
|
|
||||||
|
states = self.hass.states.all()
|
||||||
|
|
||||||
|
self.assertEqual(1, len(states), "Expected a new state registered")
|
||||||
|
|
||||||
|
state = states[0]
|
||||||
|
|
||||||
|
self.assertEqual(configurator.STATE_CONFIGURE, state.state)
|
||||||
|
self.assertEqual(
|
||||||
|
request_id, state.attributes.get(configurator.ATTR_CONFIGURE_ID))
|
||||||
|
|
||||||
|
def test_request_all_info(self):
|
||||||
|
""" Test request config with all possible info. """
|
||||||
|
|
||||||
|
values = [
|
||||||
|
"config_description", "config image url",
|
||||||
|
"config submit caption", []]
|
||||||
|
|
||||||
|
keys = [
|
||||||
|
configurator.ATTR_DESCRIPTION, configurator.ATTR_DESCRIPTION_IMAGE,
|
||||||
|
configurator.ATTR_SUBMIT_CAPTION, configurator.ATTR_FIELDS]
|
||||||
|
|
||||||
|
exp_attr = dict(zip(keys, values))
|
||||||
|
|
||||||
|
exp_attr[configurator.ATTR_CONFIGURE_ID] = configurator.request_config(
|
||||||
|
self.hass, "Test Request", lambda _: None,
|
||||||
|
*values)
|
||||||
|
|
||||||
|
states = self.hass.states.all()
|
||||||
|
|
||||||
|
self.assertEqual(1, len(states))
|
||||||
|
|
||||||
|
state = states[0]
|
||||||
|
|
||||||
|
self.assertEqual(configurator.STATE_CONFIGURE, state.state)
|
||||||
|
self.assertEqual(exp_attr, state.attributes)
|
||||||
|
|
||||||
|
def test_callback_called_on_configure(self):
|
||||||
|
""" Test if our callback gets called when configure service called. """
|
||||||
|
calls = []
|
||||||
|
|
||||||
|
request_id = configurator.request_config(
|
||||||
|
self.hass, "Test Request", lambda _: calls.append(1))
|
||||||
|
|
||||||
|
self.hass.services.call(
|
||||||
|
configurator.DOMAIN, configurator.SERVICE_CONFIGURE,
|
||||||
|
{configurator.ATTR_CONFIGURE_ID: request_id})
|
||||||
|
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
|
||||||
|
self.assertEqual(1, len(calls), "Callback not called")
|
||||||
|
|
||||||
|
def test_state_change_on_notify_errors(self):
|
||||||
|
""" Test state change on notify errors. """
|
||||||
|
request_id = configurator.request_config(
|
||||||
|
self.hass, "Test Request", lambda _: None)
|
||||||
|
|
||||||
|
error = "Oh no bad bad bad"
|
||||||
|
|
||||||
|
configurator.notify_errors(request_id, error)
|
||||||
|
|
||||||
|
state = self.hass.states.all()[0]
|
||||||
|
|
||||||
|
self.assertEqual(error, state.attributes.get(configurator.ATTR_ERRORS))
|
||||||
|
|
||||||
|
def test_notify_errors_fail_silently_on_bad_request_id(self):
|
||||||
|
""" Test if notify errors fails silently with a bad request id. """
|
||||||
|
configurator.notify_errors(2015, "Try this error")
|
||||||
|
|
||||||
|
def test_request_done_works(self):
|
||||||
|
""" Test if calling request done works. """
|
||||||
|
request_id = configurator.request_config(
|
||||||
|
self.hass, "Test Request", lambda _: None)
|
||||||
|
|
||||||
|
configurator.request_done(request_id)
|
||||||
|
|
||||||
|
self.assertEqual(1, len(self.hass.states.all()))
|
||||||
|
|
||||||
|
time.sleep(.02)
|
||||||
|
|
||||||
|
self.assertEqual(0, len(self.hass.states.all()))
|
||||||
|
|
||||||
|
def test_request_done_fail_silently_on_bad_request_id(self):
|
||||||
|
""" Test that request_done fails silently with a bad request id. """
|
||||||
|
configurator.request_done(2016)
|
|
@ -8,7 +8,6 @@ Tests switch component.
|
||||||
import unittest
|
import unittest
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import homeassistant as ha
|
|
||||||
import homeassistant.loader as loader
|
import homeassistant.loader as loader
|
||||||
import homeassistant.util as util
|
import homeassistant.util as util
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
@ -104,7 +103,7 @@ class TestLight(unittest.TestCase):
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
light.setup(self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}))
|
light.setup(self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}))
|
||||||
|
|
||||||
dev1, dev2, dev3 = platform.get_lights(None, None)
|
dev1, dev2, dev3 = platform.get_lights()
|
||||||
|
|
||||||
# Test init
|
# Test init
|
||||||
self.assertTrue(light.is_on(self.hass, dev1.entity_id))
|
self.assertTrue(light.is_on(self.hass, dev1.entity_id))
|
||||||
|
@ -214,7 +213,7 @@ class TestLight(unittest.TestCase):
|
||||||
light.ATTR_XY_COLOR: [prof_x, prof_y]},
|
light.ATTR_XY_COLOR: [prof_x, prof_y]},
|
||||||
data)
|
data)
|
||||||
|
|
||||||
def test_light_profiles(self):
|
def test_broken_light_profiles(self):
|
||||||
""" Test light profiles. """
|
""" Test light profiles. """
|
||||||
platform = loader.get_component('light.test')
|
platform = loader.get_component('light.test')
|
||||||
platform.init()
|
platform.init()
|
||||||
|
@ -230,8 +229,12 @@ class TestLight(unittest.TestCase):
|
||||||
self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
|
self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
|
||||||
))
|
))
|
||||||
|
|
||||||
# Clean up broken file
|
def test_light_profiles(self):
|
||||||
os.remove(user_light_file)
|
""" Test light profiles. """
|
||||||
|
platform = loader.get_component('light.test')
|
||||||
|
platform.init()
|
||||||
|
|
||||||
|
user_light_file = self.hass.get_config_path(light.LIGHT_PROFILES_FILE)
|
||||||
|
|
||||||
with open(user_light_file, 'w') as user_file:
|
with open(user_light_file, 'w') as user_file:
|
||||||
user_file.write('id,x,y,brightness\n')
|
user_file.write('id,x,y,brightness\n')
|
||||||
|
@ -241,7 +244,7 @@ class TestLight(unittest.TestCase):
|
||||||
self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
|
self.hass, {light.DOMAIN: {CONF_TYPE: 'test'}}
|
||||||
))
|
))
|
||||||
|
|
||||||
dev1, dev2, dev3 = platform.get_lights(None, None)
|
dev1, dev2, dev3 = platform.get_lights()
|
||||||
|
|
||||||
light.turn_on(self.hass, dev1.entity_id, profile='test')
|
light.turn_on(self.hass, dev1.entity_id, profile='test')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue