More async tests (#4223)

* Annotate test callbacks to be async

* Convert device_sun_light_trigger to be async
This commit is contained in:
Paulus Schoutsen 2016-11-05 16:36:20 -07:00 committed by GitHub
parent 22c3d014aa
commit 62785c2431
21 changed files with 110 additions and 21 deletions

View file

@ -9,6 +9,7 @@ from datetime import timedelta
import voluptuous as vol
from homeassistant.core import callback
import homeassistant.util.dt as dt_util
from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from homeassistant.helpers.event import track_point_in_time
@ -79,21 +80,22 @@ def setup(hass, config):
return None
return next_setting - LIGHT_TRANSITION_TIME * len(light_ids)
def turn_light_on_before_sunset(light_id):
def async_turn_on_before_sunset(light_id):
"""Helper function to turn on lights.
Speed is slow if there are devices home and the light is not on yet.
"""
if not device_tracker.is_on(hass) or light.is_on(hass, light_id):
return
light.turn_on(hass, light_id,
transition=LIGHT_TRANSITION_TIME.seconds,
profile=light_profile)
light.async_turn_on(hass, light_id,
transition=LIGHT_TRANSITION_TIME.seconds,
profile=light_profile)
# Track every time sun rises so we can schedule a time-based
# pre-sun set event
@track_state_change(sun.ENTITY_ID, sun.STATE_BELOW_HORIZON,
sun.STATE_ABOVE_HORIZON)
@callback
def schedule_lights_at_sun_set(hass, entity, old_state, new_state):
"""The moment sun sets we want to have all the lights on.
@ -104,16 +106,21 @@ def setup(hass, config):
if not start_point:
return
def turn_on(light_id):
def async_turn_on_factory(light_id):
"""Lambda can keep track of function parameters.
No local parameters. If we put the lambda directly in the below
statement only the last light will be turned on.
"""
return lambda now: turn_light_on_before_sunset(light_id)
@callback
def async_turn_on_light(now):
"""Turn on specific light."""
async_turn_on_before_sunset(light_id)
return async_turn_on_light
for index, light_id in enumerate(light_ids):
track_point_in_time(hass, turn_on(light_id),
track_point_in_time(hass, async_turn_on_factory(light_id),
start_point + index * LIGHT_TRANSITION_TIME)
# If the sun is already above horizon schedule the time-based pre-sun set
@ -122,6 +129,7 @@ def setup(hass, config):
schedule_lights_at_sun_set(hass, None, None, None)
@track_state_change(device_entity_ids, STATE_NOT_HOME, STATE_HOME)
@callback
def check_light_on_dev_state_change(hass, entity, old_state, new_state):
"""Handle tracked device state changes."""
# pylint: disable=unused-variable
@ -136,7 +144,7 @@ def setup(hass, config):
# Do we need lights?
if light_needed:
logger.info("Home coming event for %s. Turning lights on", entity)
light.turn_on(hass, light_ids, profile=light_profile)
light.async_turn_on(hass, light_ids, profile=light_profile)
# Are we in the time span were we would turn on the lights
# if someone would be home?
@ -149,7 +157,7 @@ def setup(hass, config):
# when the fading in started and turn it on if so
for index, light_id in enumerate(light_ids):
if now > start_point + index * LIGHT_TRANSITION_TIME:
light.turn_on(hass, light_id)
light.async_turn_on(hass, light_id)
else:
# If this light didn't happen to be turned on yet so
@ -158,6 +166,7 @@ def setup(hass, config):
if not disable_turn_off:
@track_state_change(device_group, STATE_HOME, STATE_NOT_HOME)
@callback
def turn_off_lights_when_all_leave(hass, entity, old_state, new_state):
"""Handle device group state change."""
# pylint: disable=unused-variable
@ -166,6 +175,6 @@ def setup(hass, config):
logger.info(
"Everyone has left but there are lights on. Turning them off")
light.turn_off(hass, light_ids)
light.async_turn_off(hass, light_ids)
return True

View file

@ -10,6 +10,7 @@ import csv
import voluptuous as vol
from homeassistant.core import callback
from homeassistant.components import group
from homeassistant.config import load_yaml_config_file
from homeassistant.const import (
@ -20,6 +21,7 @@ from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.config_validation import PLATFORM_SCHEMA # noqa
import homeassistant.helpers.config_validation as cv
import homeassistant.util.color as color_util
from homeassistant.util.async import run_callback_threadsafe
DOMAIN = "light"
@ -128,6 +130,18 @@ def turn_on(hass, entity_id=None, transition=None, brightness=None,
rgb_color=None, xy_color=None, color_temp=None, white_value=None,
profile=None, flash=None, effect=None, color_name=None):
"""Turn all or specified light on."""
run_callback_threadsafe(
hass.loop, async_turn_on, hass, entity_id, transition, brightness,
rgb_color, xy_color, color_temp, white_value,
profile, flash, effect, color_name).result()
@callback
def async_turn_on(hass, entity_id=None, transition=None, brightness=None,
rgb_color=None, xy_color=None, color_temp=None,
white_value=None, profile=None, flash=None, effect=None,
color_name=None):
"""Turn all or specified light on."""
data = {
key: value for key, value in [
(ATTR_ENTITY_ID, entity_id),
@ -144,10 +158,17 @@ def turn_on(hass, entity_id=None, transition=None, brightness=None,
] if value is not None
}
hass.services.call(DOMAIN, SERVICE_TURN_ON, data)
hass.async_add_job(hass.services.async_call, DOMAIN, SERVICE_TURN_ON, data)
def turn_off(hass, entity_id=None, transition=None):
"""Turn all or specified light off."""
run_callback_threadsafe(
hass.loop, async_turn_off, hass, entity_id, transition).result()
@callback
def async_turn_off(hass, entity_id=None, transition=None):
"""Turn all or specified light off."""
data = {
key: value for key, value in [
@ -156,7 +177,8 @@ def turn_off(hass, entity_id=None, transition=None):
] if value is not None
}
hass.services.call(DOMAIN, SERVICE_TURN_OFF, data)
hass.async_add_job(hass.services.async_call, DOMAIN, SERVICE_TURN_OFF,
data)
def toggle(hass, entity_id=None, transition=None):

View file

@ -49,14 +49,20 @@ def is_on(hass, entity_id=None):
def next_setting(hass, entity_id=None):
"""Local datetime object of the next sun setting."""
"""Local datetime object of the next sun setting.
Async friendly.
"""
utc_next = next_setting_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_setting_utc(hass, entity_id=None):
"""UTC datetime object of the next sun setting."""
"""UTC datetime object of the next sun setting.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)
@ -71,14 +77,20 @@ def next_setting_utc(hass, entity_id=None):
def next_rising(hass, entity_id=None):
"""Local datetime object of the next sun rising."""
"""Local datetime object of the next sun rising.
Async friendly.
"""
utc_next = next_rising_utc(hass, entity_id)
return dt_util.as_local(utc_next) if utc_next else None
def next_rising_utc(hass, entity_id=None):
"""UTC datetime object of the next sun rising."""
"""UTC datetime object of the next sun rising.
Async friendly.
"""
entity_id = entity_id or ENTITY_ID
state = hass.states.get(ENTITY_ID)

View file

@ -129,8 +129,12 @@ def mock_service(hass, domain, service):
"""
calls = []
@ha.callback
def mock_service(call):
calls.append(call)
# pylint: disable=unnecessary-lambda
hass.services.register(domain, service, lambda call: calls.append(call))
hass.services.register(domain, service, mock_service)
return calls

View file

@ -1,6 +1,7 @@
"""The tests for the Event automation."""
import unittest
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation
@ -16,6 +17,7 @@ class TestAutomationEvent(unittest.TestCase):
self.hass.config.components.append('group')
self.calls = []
@callback
def record_call(service):
"""Helper for recording the call."""
self.calls.append(service)

View file

@ -2,6 +2,7 @@
import unittest
from unittest.mock import patch
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation
from homeassistant.const import ATTR_ENTITY_ID
@ -22,6 +23,7 @@ class TestAutomation(unittest.TestCase):
self.hass.config.components.append('group')
self.calls = []
@callback
def record_call(service):
"""Record call."""
self.calls.append(service)

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT automation."""
import unittest
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation
from tests.common import (
@ -17,6 +18,7 @@ class TestAutomationMQTT(unittest.TestCase):
mock_mqtt_component(self.hass)
self.calls = []
@callback
def record_call(service):
self.calls.append(service)

View file

@ -1,6 +1,7 @@
"""The tests for numeric state automation."""
import unittest
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation
@ -16,6 +17,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.config.components.append('group')
self.calls = []
@callback
def record_call(service):
"""Helper to record calls."""
self.calls.append(service)

View file

@ -3,6 +3,7 @@ import unittest
from datetime import timedelta
from unittest.mock import patch
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.util.dt as dt_util
import homeassistant.components.automation as automation
@ -21,6 +22,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.states.set('test.entity', 'hello')
self.calls = []
@callback
def record_call(service):
self.calls.append(service)

View file

@ -3,6 +3,7 @@ from datetime import datetime
import unittest
from unittest.mock import patch
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
from homeassistant.components import sun
import homeassistant.components.automation as automation
@ -22,6 +23,7 @@ class TestAutomationSun(unittest.TestCase):
self.calls = []
@callback
def record_call(service):
self.calls.append(service)

View file

@ -1,6 +1,7 @@
"""The tests for the Template automation."""
import unittest
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation
@ -17,6 +18,7 @@ class TestAutomationTemplate(unittest.TestCase):
self.hass.states.set('test.entity', 'hello')
self.calls = []
@callback
def record_call(service):
"""helper for recording calls."""
self.calls.append(service)

View file

@ -3,6 +3,7 @@ from datetime import timedelta
import unittest
from unittest.mock import patch
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.util.dt as dt_util
import homeassistant.components.automation as automation
@ -20,6 +21,7 @@ class TestAutomationTime(unittest.TestCase):
self.hass.config.components.append('group')
self.calls = []
@callback
def record_call(service):
self.calls.append(service)

View file

@ -1,6 +1,7 @@
"""The tests for the location automation."""
import unittest
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
from homeassistant.components import automation, zone
@ -25,6 +26,7 @@ class TestAutomationZone(unittest.TestCase):
self.calls = []
@callback
def record_call(service):
self.calls.append(service)

View file

@ -3,7 +3,7 @@ import datetime
import unittest
from unittest import mock
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT,
@ -216,6 +216,7 @@ class TestClimateGenericThermostat(unittest.TestCase):
self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF)
self.calls = []
@callback
def log_call(call):
"""Log service calls."""
self.calls.append(call)
@ -306,6 +307,7 @@ class TestClimateGenericThermostatACMode(unittest.TestCase):
self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF)
self.calls = []
@callback
def log_call(call):
"""Log service calls."""
self.calls.append(call)
@ -397,6 +399,7 @@ class TestClimateGenericThermostatACModeMinCycle(unittest.TestCase):
self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF)
self.calls = []
@callback
def log_call(call):
"""Log service calls."""
self.calls.append(call)
@ -487,6 +490,7 @@ class TestClimateGenericThermostatMinCycle(unittest.TestCase):
self.hass.states.set(ENT_SWITCH, STATE_ON if is_on else STATE_OFF)
self.calls = []
@callback
def log_call(call):
"""Log service calls."""
self.calls.append(call)

View file

@ -1,7 +1,7 @@
"""The tests for the Template switch platform."""
from homeassistant.core import callback
import homeassistant.bootstrap as bootstrap
import homeassistant.components as core
from homeassistant.const import (
STATE_ON,
STATE_OFF)
@ -21,6 +21,7 @@ class TestTemplateSwitch:
self.hass = get_test_home_assistant()
self.calls = []
@callback
def record_call(service):
"""Track function calls.."""
self.calls.append(service)

View file

@ -6,6 +6,7 @@ import unittest
import requests
from homeassistant.core import callback
from homeassistant import bootstrap, const
from homeassistant.components import alexa, http
@ -47,7 +48,11 @@ def setUpModule():
{http.DOMAIN: {http.CONF_API_PASSWORD: API_PASSWORD,
http.CONF_SERVER_PORT: SERVER_PORT}})
hass.services.register("test", "alexa", lambda call: calls.append(call))
@callback
def mock_service(call):
calls.append(call)
hass.services.register("test", "alexa", mock_service)
bootstrap.setup_component(hass, alexa.DOMAIN, {
# Key is here to verify we allow other keys in config too

View file

@ -288,6 +288,7 @@ class TestAPI(unittest.TestCase):
"""Test if the API allows us to call a service."""
test_value = []
@ha.callback
def listener(service_call):
"""Helper method that will verify that our service got called."""
test_value.append(1)
@ -307,6 +308,7 @@ class TestAPI(unittest.TestCase):
"""Test if the API allows us to call a service."""
test_value = []
@ha.callback
def listener(service_call):
"""Helper method that will verify that our service got called.

View file

@ -3,6 +3,7 @@
import unittest
from unittest.mock import patch
from homeassistant.core import callback
from homeassistant.bootstrap import setup_component
import homeassistant.components as core_components
from homeassistant.components import conversation
@ -38,6 +39,7 @@ class TestConversation(unittest.TestCase):
"""Setup and perform good turn on requests."""
calls = []
@callback
def record_call(service):
calls.append(service)
@ -56,6 +58,7 @@ class TestConversation(unittest.TestCase):
"""Setup and perform good turn off requests."""
calls = []
@callback
def record_call(service):
calls.append(service)

View file

@ -130,6 +130,7 @@ class TestScriptComponent(unittest.TestCase):
"""Test different ways of passing in variables."""
calls = []
@callback
def record_call(service):
"""Add recorded event to set."""
calls.append(service)

View file

@ -508,7 +508,12 @@ class TestServiceRegistry(unittest.TestCase):
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self.services = self.hass.services
self.services.register("Test_Domain", "TEST_SERVICE", lambda x: None)
@ha.callback
def mock_service(call):
pass
self.services.register("Test_Domain", "TEST_SERVICE", mock_service)
# pylint: disable=invalid-name
def tearDown(self):
@ -535,6 +540,7 @@ class TestServiceRegistry(unittest.TestCase):
"""Test call with blocking."""
calls = []
@ha.callback
def service_handler(call):
"""Service handler."""
calls.append(call)

View file

@ -116,6 +116,7 @@ class TestRemoteMethods(unittest.TestCase):
"""Test Python API fire_event."""
test_value = []
@ha.callback
def listener(event):
"""Helper method that will verify our event got called."""
test_value.append(1)
@ -200,6 +201,7 @@ class TestRemoteMethods(unittest.TestCase):
"""Test Python API services.call."""
test_value = []
@ha.callback
def listener(service_call):
"""Helper method that will verify that our service got called."""
test_value.append(1)