Async bootstrap / component init (#3991)

* Async bootstrap

* Adress comments

* Fix tests

* More fixes

* Tests fixes
This commit is contained in:
Pascal Vizeli 2016-10-27 09:16:23 +02:00 committed by Paulus Schoutsen
parent d9999f36e8
commit d5368f6f78
54 changed files with 1431 additions and 1131 deletions

View File

@ -1,11 +1,10 @@
"""Provides methods to bootstrap a home assistant instance.""" """Provides methods to bootstrap a home assistant instance."""
import asyncio
import logging import logging
import logging.handlers import logging.handlers
import os import os
import sys import sys
from collections import defaultdict from collections import defaultdict
from threading import RLock
from types import ModuleType from types import ModuleType
from typing import Any, Optional, Dict from typing import Any, Optional, Dict
@ -19,6 +18,8 @@ import homeassistant.config as conf_util
import homeassistant.core as core import homeassistant.core as core
import homeassistant.loader as loader import homeassistant.loader as loader
import homeassistant.util.package as pkg_util import homeassistant.util.package as pkg_util
from homeassistant.util.async import (
run_coroutine_threadsafe, run_callback_threadsafe)
from homeassistant.util.yaml import clear_secret_cache from homeassistant.util.yaml import clear_secret_cache
from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -26,7 +27,6 @@ from homeassistant.helpers import (
event_decorators, service, config_per_platform, extract_domain_configs) event_decorators, service, config_per_platform, extract_domain_configs)
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
_SETUP_LOCK = RLock()
_CURRENT_SETUP = [] _CURRENT_SETUP = []
ATTR_COMPONENT = 'component' ATTR_COMPONENT = 'component'
@ -39,11 +39,23 @@ _PERSISTENT_VALIDATION = set()
def setup_component(hass: core.HomeAssistant, domain: str, def setup_component(hass: core.HomeAssistant, domain: str,
config: Optional[Dict]=None) -> bool: config: Optional[Dict]=None) -> bool:
"""Setup a component and all its dependencies.""" """Setup a component and all its dependencies."""
return run_coroutine_threadsafe(
async_setup_component(hass, domain, config), loop=hass.loop).result()
@asyncio.coroutine
def async_setup_component(hass: core.HomeAssistant, domain: str,
config: Optional[Dict]=None) -> bool:
"""Setup a component and all its dependencies.
This method need to run in a executor.
"""
if domain in hass.config.components: if domain in hass.config.components:
_LOGGER.debug('Component %s already set up.', domain) _LOGGER.debug('Component %s already set up.', domain)
return True return True
_ensure_loader_prepared(hass) if not loader.PREPARED:
yield from hass.loop.run_in_executor(None, loader.prepare, hass)
if config is None: if config is None:
config = defaultdict(dict) config = defaultdict(dict)
@ -55,7 +67,8 @@ def setup_component(hass: core.HomeAssistant, domain: str,
return False return False
for component in components: for component in components:
if not _setup_component(hass, component, config): res = yield from _async_setup_component(hass, component, config)
if not res:
_LOGGER.error('Component %s failed to setup', component) _LOGGER.error('Component %s failed to setup', component)
return False return False
@ -64,7 +77,11 @@ def setup_component(hass: core.HomeAssistant, domain: str,
def _handle_requirements(hass: core.HomeAssistant, component, def _handle_requirements(hass: core.HomeAssistant, component,
name: str) -> bool: name: str) -> bool:
"""Install the requirements for a component.""" """Install the requirements for a component.
Asyncio don't support file operation jet.
This method need to run in a executor.
"""
if hass.config.skip_pip or not hasattr(component, 'REQUIREMENTS'): if hass.config.skip_pip or not hasattr(component, 'REQUIREMENTS'):
return True return True
@ -77,65 +94,82 @@ def _handle_requirements(hass: core.HomeAssistant, component,
return True return True
def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool: @asyncio.coroutine
"""Setup a component for Home Assistant.""" def _async_setup_component(hass: core.HomeAssistant,
domain: str, config) -> bool:
"""Setup a component for Home Assistant.
This method is a coroutine.
"""
# pylint: disable=too-many-return-statements,too-many-branches # pylint: disable=too-many-return-statements,too-many-branches
# pylint: disable=too-many-statements # pylint: disable=too-many-statements
if domain in hass.config.components: if domain in hass.config.components:
return True return True
with _SETUP_LOCK: if domain in _CURRENT_SETUP:
# It might have been loaded while waiting for lock _LOGGER.error('Attempt made to setup %s during setup of %s',
if domain in hass.config.components: domain, domain)
return True return False
if domain in _CURRENT_SETUP: config = yield from async_prepare_setup_component(hass, config, domain)
_LOGGER.error('Attempt made to setup %s during setup of %s',
domain, domain) if config is None:
return False
component = loader.get_component(domain)
_CURRENT_SETUP.append(domain)
try:
if hasattr(component, 'async_setup'):
result = yield from component.async_setup(hass, config)
else:
result = yield from hass.loop.run_in_executor(
None, component.setup, hass, config)
if result is False:
_LOGGER.error('component %s failed to initialize', domain)
return False return False
elif result is not True:
config = prepare_setup_component(hass, config, domain) _LOGGER.error('component %s did not return boolean if setup '
'was successful. Disabling component.', domain)
if config is None: loader.set_component(domain, None)
return False return False
except Exception: # pylint: disable=broad-except
_LOGGER.exception('Error during setup of component %s', domain)
return False
finally:
_CURRENT_SETUP.remove(domain)
component = loader.get_component(domain) hass.config.components.append(component.DOMAIN)
_CURRENT_SETUP.append(domain)
try: # Assumption: if a component does not depend on groups
result = component.setup(hass, config) # it communicates with devices
if result is False: if 'group' not in getattr(component, 'DEPENDENCIES', []) and \
_LOGGER.error('component %s failed to initialize', domain) hass.pool.worker_count <= 10:
return False hass.pool.add_worker()
elif result is not True:
_LOGGER.error('component %s did not return boolean if setup '
'was successful. Disabling component.', domain)
loader.set_component(domain, None)
return False
except Exception: # pylint: disable=broad-except
_LOGGER.exception('Error during setup of component %s', domain)
return False
finally:
_CURRENT_SETUP.remove(domain)
hass.config.components.append(component.DOMAIN) hass.bus.async_fire(
EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN}
)
# Assumption: if a component does not depend on groups return True
# it communicates with devices
if 'group' not in getattr(component, 'DEPENDENCIES', []) and \
hass.pool.worker_count <= 10:
hass.pool.add_worker()
hass.bus.fire(
EVENT_COMPONENT_LOADED, {ATTR_COMPONENT: component.DOMAIN}
)
return True
def prepare_setup_component(hass: core.HomeAssistant, config: dict, def prepare_setup_component(hass: core.HomeAssistant, config: dict,
domain: str): domain: str):
"""Prepare setup of a component and return processed config.""" """Prepare setup of a component and return processed config."""
return run_coroutine_threadsafe(
async_prepare_setup_component(hass, config, domain), loop=hass.loop
).result()
@asyncio.coroutine
def async_prepare_setup_component(hass: core.HomeAssistant, config: dict,
domain: str):
"""Prepare setup of a component and return processed config.
This method is a coroutine.
"""
# pylint: disable=too-many-return-statements # pylint: disable=too-many-return-statements
component = loader.get_component(domain) component = loader.get_component(domain)
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', []) missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
@ -151,7 +185,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
try: try:
config = component.CONFIG_SCHEMA(config) config = component.CONFIG_SCHEMA(config)
except vol.Invalid as ex: except vol.Invalid as ex:
log_exception(ex, domain, config, hass) async_log_exception(ex, domain, config, hass)
return None return None
elif hasattr(component, 'PLATFORM_SCHEMA'): elif hasattr(component, 'PLATFORM_SCHEMA'):
@ -161,7 +195,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
try: try:
p_validated = component.PLATFORM_SCHEMA(p_config) p_validated = component.PLATFORM_SCHEMA(p_config)
except vol.Invalid as ex: except vol.Invalid as ex:
log_exception(ex, domain, config, hass) async_log_exception(ex, domain, config, hass)
continue continue
# Not all platform components follow same pattern for platforms # Not all platform components follow same pattern for platforms
@ -171,8 +205,8 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
platforms.append(p_validated) platforms.append(p_validated)
continue continue
platform = prepare_setup_platform(hass, config, domain, platform = yield from async_prepare_setup_platform(
p_name) hass, config, domain, p_name)
if platform is None: if platform is None:
continue continue
@ -180,10 +214,11 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
# Validate platform specific schema # Validate platform specific schema
if hasattr(platform, 'PLATFORM_SCHEMA'): if hasattr(platform, 'PLATFORM_SCHEMA'):
try: try:
# pylint: disable=no-member
p_validated = platform.PLATFORM_SCHEMA(p_validated) p_validated = platform.PLATFORM_SCHEMA(p_validated)
except vol.Invalid as ex: except vol.Invalid as ex:
log_exception(ex, '{}.{}'.format(domain, p_name), async_log_exception(ex, '{}.{}'.format(domain, p_name),
p_validated, hass) p_validated, hass)
continue continue
platforms.append(p_validated) platforms.append(p_validated)
@ -195,7 +230,9 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
if key not in filter_keys} if key not in filter_keys}
config[domain] = platforms config[domain] = platforms
if not _handle_requirements(hass, component, domain): res = yield from hass.loop.run_in_executor(
None, _handle_requirements, hass, component, domain)
if not res:
return None return None
return config return config
@ -204,7 +241,22 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
platform_name: str) -> Optional[ModuleType]: platform_name: str) -> Optional[ModuleType]:
"""Load a platform and makes sure dependencies are setup.""" """Load a platform and makes sure dependencies are setup."""
_ensure_loader_prepared(hass) return run_coroutine_threadsafe(
async_prepare_setup_platform(hass, config, domain, platform_name),
loop=hass.loop
).result()
@asyncio.coroutine
def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
platform_name: str) \
-> Optional[ModuleType]:
"""Load a platform and makes sure dependencies are setup.
This method is a coroutine.
"""
if not loader.PREPARED:
yield from hass.loop.run_in_executor(None, loader.prepare, hass)
platform_path = PLATFORM_FORMAT.format(domain, platform_name) platform_path = PLATFORM_FORMAT.format(domain, platform_name)
@ -218,7 +270,7 @@ def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
message = ('Unable to find the following platforms: ' + message = ('Unable to find the following platforms: ' +
', '.join(list(_PERSISTENT_PLATFORMS)) + ', '.join(list(_PERSISTENT_PLATFORMS)) +
'(please check your configuration)') '(please check your configuration)')
persistent_notification.create( persistent_notification.async_create(
hass, message, 'Invalid platforms', 'platform_errors') hass, message, 'Invalid platforms', 'platform_errors')
return None return None
@ -228,14 +280,17 @@ def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
# Load dependencies # Load dependencies
for component in getattr(platform, 'DEPENDENCIES', []): for component in getattr(platform, 'DEPENDENCIES', []):
if not setup_component(hass, component, config): res = yield from async_setup_component(hass, component, config)
if not res:
_LOGGER.error( _LOGGER.error(
'Unable to prepare setup for platform %s because ' 'Unable to prepare setup for platform %s because '
'dependency %s could not be initialized', platform_path, 'dependency %s could not be initialized', platform_path,
component) component)
return None return None
if not _handle_requirements(hass, platform, platform_path): res = yield from hass.loop.run_in_executor(
None, _handle_requirements, hass, platform, platform_path)
if not res:
return None return None
return platform return platform
@ -261,15 +316,50 @@ def from_config_dict(config: Dict[str, Any],
hass.config.config_dir = config_dir hass.config.config_dir = config_dir
mount_local_lib_path(config_dir) mount_local_lib_path(config_dir)
@asyncio.coroutine
def _async_init_from_config_dict(future):
try:
re_hass = yield from async_from_config_dict(
config, hass, config_dir, enable_log, verbose, skip_pip,
log_rotate_days)
future.set_result(re_hass)
# pylint: disable=broad-except
except Exception as exc:
future.set_exception(exc)
# run task
future = asyncio.Future()
asyncio.Task(_async_init_from_config_dict(future), loop=hass.loop)
hass.loop.run_until_complete(future)
return future.result()
@asyncio.coroutine
# pylint: disable=too-many-branches, too-many-statements, too-many-arguments
def async_from_config_dict(config: Dict[str, Any],
hass: core.HomeAssistant,
config_dir: Optional[str]=None,
enable_log: bool=True,
verbose: bool=False,
skip_pip: bool=False,
log_rotate_days: Any=None) \
-> Optional[core.HomeAssistant]:
"""Try to configure Home Assistant from a config dict.
Dynamically loads required components and its dependencies.
This method is a coroutine.
"""
core_config = config.get(core.DOMAIN, {}) core_config = config.get(core.DOMAIN, {})
try: try:
conf_util.process_ha_core_config(hass, core_config) yield from conf_util.async_process_ha_core_config(hass, core_config)
except vol.Invalid as ex: except vol.Invalid as ex:
log_exception(ex, 'homeassistant', core_config, hass) async_log_exception(ex, 'homeassistant', core_config, hass)
return None return None
conf_util.process_ha_config_upgrade(hass) yield from hass.loop.run_in_executor(
None, conf_util.process_ha_config_upgrade, hass)
if enable_log: if enable_log:
enable_logging(hass, verbose, log_rotate_days) enable_logging(hass, verbose, log_rotate_days)
@ -279,7 +369,8 @@ def from_config_dict(config: Dict[str, Any],
_LOGGER.warning('Skipping pip installation of required modules. ' _LOGGER.warning('Skipping pip installation of required modules. '
'This may cause issues.') 'This may cause issues.')
_ensure_loader_prepared(hass) if not loader.PREPARED:
yield from hass.loop.run_in_executor(None, loader.prepare, hass)
# Make a copy because we are mutating it. # Make a copy because we are mutating it.
# Convert it to defaultdict so components can always have config dict # Convert it to defaultdict so components can always have config dict
@ -291,29 +382,25 @@ def from_config_dict(config: Dict[str, Any],
components = set(key.split(' ')[0] for key in config.keys() components = set(key.split(' ')[0] for key in config.keys()
if key != core.DOMAIN) if key != core.DOMAIN)
# Setup in a thread to avoid blocking # setup components
def component_setup(): # pylint: disable=not-an-iterable
"""Set up a component.""" res = yield from core_components.async_setup(hass, config)
if not core_components.setup(hass, config): if not res:
_LOGGER.error('Home Assistant core failed to initialize. ' _LOGGER.error('Home Assistant core failed to initialize. '
'Further initialization aborted.') 'Further initialization aborted.')
return hass return hass
persistent_notification.setup(hass, config) yield from persistent_notification.async_setup(hass, config)
_LOGGER.info('Home Assistant core initialized') _LOGGER.info('Home Assistant core initialized')
# Give event decorators access to HASS # Give event decorators access to HASS
event_decorators.HASS = hass event_decorators.HASS = hass
service.HASS = hass service.HASS = hass
# Setup the components # Setup the components
for domain in loader.load_order_components(components): for domain in loader.load_order_components(components):
_setup_component(hass, domain, config) yield from _async_setup_component(hass, domain, config)
hass.loop.run_until_complete(
hass.loop.run_in_executor(None, component_setup)
)
return hass return hass
@ -331,27 +418,62 @@ def from_config_file(config_path: str,
if hass is None: if hass is None:
hass = core.HomeAssistant() hass = core.HomeAssistant()
@asyncio.coroutine
def _async_init_from_config_file(future):
try:
re_hass = yield from async_from_config_file(
config_path, hass, verbose, skip_pip, log_rotate_days)
future.set_result(re_hass)
# pylint: disable=broad-except
except Exception as exc:
future.set_exception(exc)
# run task
future = asyncio.Future()
asyncio.Task(_async_init_from_config_file(future), loop=hass.loop)
hass.loop.run_until_complete(future)
return future.result()
@asyncio.coroutine
def async_from_config_file(config_path: str,
hass: core.HomeAssistant,
verbose: bool=False,
skip_pip: bool=True,
log_rotate_days: Any=None):
"""Read the configuration file and try to start all the functionality.
Will add functionality to 'hass' parameter.
This method is a coroutine.
"""
# Set config dir to directory holding config file # Set config dir to directory holding config file
config_dir = os.path.abspath(os.path.dirname(config_path)) config_dir = os.path.abspath(os.path.dirname(config_path))
hass.config.config_dir = config_dir hass.config.config_dir = config_dir
mount_local_lib_path(config_dir) yield from hass.loop.run_in_executor(
None, mount_local_lib_path, config_dir)
enable_logging(hass, verbose, log_rotate_days) enable_logging(hass, verbose, log_rotate_days)
try: try:
config_dict = conf_util.load_yaml_config_file(config_path) config_dict = yield from hass.loop.run_in_executor(
None, conf_util.load_yaml_config_file, config_path)
except HomeAssistantError: except HomeAssistantError:
return None return None
finally: finally:
clear_secret_cache() clear_secret_cache()
return from_config_dict(config_dict, hass, enable_log=False, hass = yield from async_from_config_dict(
skip_pip=skip_pip) config_dict, hass, enable_log=False, skip_pip=skip_pip)
return hass
def enable_logging(hass: core.HomeAssistant, verbose: bool=False, def enable_logging(hass: core.HomeAssistant, verbose: bool=False,
log_rotate_days=None) -> None: log_rotate_days=None) -> None:
"""Setup the logging.""" """Setup the logging.
Async friendly.
"""
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)s) " fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)s) "
"[%(name)s] %(message)s%(reset)s") "[%(name)s] %(message)s%(reset)s")
@ -407,44 +529,50 @@ def enable_logging(hass: core.HomeAssistant, verbose: bool=False,
'Unable to setup error log %s (access denied)', err_log_path) 'Unable to setup error log %s (access denied)', err_log_path)
def _ensure_loader_prepared(hass: core.HomeAssistant) -> None: def log_exception(ex, domain, config, hass):
"""Ensure Home Assistant loader is prepared."""
if not loader.PREPARED:
loader.prepare(hass)
def log_exception(ex, domain, config, hass=None):
"""Generate log exception for config validation.""" """Generate log exception for config validation."""
run_callback_threadsafe(
hass.loop, async_log_exception, ex, domain, config, hass).result()
@core.callback
def async_log_exception(ex, domain, config, hass):
"""Generate log exception for config validation.
Need to run in a async loop.
"""
message = 'Invalid config for [{}]: '.format(domain) message = 'Invalid config for [{}]: '.format(domain)
if hass is not None: _PERSISTENT_VALIDATION.add(domain)
_PERSISTENT_VALIDATION.add(domain) message = ('The following platforms contain invalid configuration: ' +
message = ('The following platforms contain invalid configuration: ' + ', '.join(list(_PERSISTENT_VALIDATION)) +
', '.join(list(_PERSISTENT_VALIDATION)) + ' (please check your configuration). ')
' (please check your configuration)') persistent_notification.async_create(
persistent_notification.create( hass, message, 'Invalid config', 'invalid_config')
hass, message, 'Invalid config', 'invalid_config')
if 'extra keys not allowed' in ex.error_message: if 'extra keys not allowed' in ex.error_message:
message += '[{}] is an invalid option for [{}]. Check: {}->{}.'\ message += '[{}] is an invalid option for [{}]. Check: {}->{}.'\
.format(ex.path[-1], domain, domain, .format(ex.path[-1], domain, domain,
'->'.join('%s' % m for m in ex.path)) '->'.join(str(m) for m in ex.path))
else: else:
message += '{}.'.format(humanize_error(config, ex)) message += '{}.'.format(humanize_error(config, ex))
domain_config = config.get(domain, config) domain_config = config.get(domain, config)
message += " (See {}:{})".format( message += " (See {}:{}). ".format(
getattr(domain_config, '__config_file__', '?'), getattr(domain_config, '__config_file__', '?'),
getattr(domain_config, '__line__', '?')) getattr(domain_config, '__line__', '?'))
if domain != 'homeassistant': if domain != 'homeassistant':
message += (' Please check the docs at ' message += ('Please check the docs at '
'https://home-assistant.io/components/{}/'.format(domain)) 'https://home-assistant.io/components/{}/'.format(domain))
_LOGGER.error(message) _LOGGER.error(message)
def mount_local_lib_path(config_dir: str) -> str: def mount_local_lib_path(config_dir: str) -> str:
"""Add local library to Python Path.""" """Add local library to Python Path.
Async friendly.
"""
deps_dir = os.path.join(config_dir, 'deps') deps_dir = os.path.join(config_dir, 'deps')
if deps_dir not in sys.path: if deps_dir not in sys.path:
sys.path.insert(0, os.path.join(config_dir, 'deps')) sys.path.insert(0, os.path.join(config_dir, 'deps'))

View File

@ -7,6 +7,7 @@ Component design guidelines:
format "<DOMAIN>.<OBJECT_ID>". format "<DOMAIN>.<OBJECT_ID>".
- Each component should publish services only under its own domain. - Each component should publish services only under its own domain.
""" """
import asyncio
import itertools as it import itertools as it
import logging import logging
@ -79,8 +80,10 @@ def reload_core_config(hass):
hass.services.call(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG) hass.services.call(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG)
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""Setup general services related to Home Assistant.""" """Setup general services related to Home Assistant."""
@asyncio.coroutine
def handle_turn_service(service): def handle_turn_service(service):
"""Method to handle calls to homeassistant.turn_on/off.""" """Method to handle calls to homeassistant.turn_on/off."""
entity_ids = extract_entity_ids(hass, service) entity_ids = extract_entity_ids(hass, service)
@ -96,6 +99,8 @@ def setup(hass, config):
by_domain = it.groupby(sorted(entity_ids), by_domain = it.groupby(sorted(entity_ids),
lambda item: ha.split_entity_id(item)[0]) lambda item: ha.split_entity_id(item)[0])
tasks = []
for domain, ent_ids in by_domain: for domain, ent_ids in by_domain:
# We want to block for all calls and only return when all calls # We want to block for all calls and only return when all calls
# have been processed. If a service does not exist it causes a 10 # have been processed. If a service does not exist it causes a 10
@ -111,27 +116,34 @@ def setup(hass, config):
# ent_ids is a generator, convert it to a list. # ent_ids is a generator, convert it to a list.
data[ATTR_ENTITY_ID] = list(ent_ids) data[ATTR_ENTITY_ID] = list(ent_ids)
hass.services.call(domain, service.service, data, blocking) tasks.append(hass.services.async_call(
domain, service.service, data, blocking))
hass.services.register(ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service) yield from asyncio.gather(*tasks, loop=hass.loop)
hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service)
hass.services.register(ha.DOMAIN, SERVICE_TOGGLE, handle_turn_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_TURN_OFF, handle_turn_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service)
hass.services.async_register(
ha.DOMAIN, SERVICE_TOGGLE, handle_turn_service)
@asyncio.coroutine
def handle_reload_config(call): def handle_reload_config(call):
"""Service handler for reloading core config.""" """Service handler for reloading core config."""
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant import config as conf_util from homeassistant import config as conf_util
try: try:
path = conf_util.find_config_file(hass.config.config_dir) conf = yield from conf_util.async_hass_config_yaml(hass)
conf = conf_util.load_yaml_config_file(path)
except HomeAssistantError as err: except HomeAssistantError as err:
_LOGGER.error(err) _LOGGER.error(err)
return return
conf_util.process_ha_core_config(hass, conf.get(ha.DOMAIN) or {}) yield from conf_util.async_process_ha_core_config(
hass, conf.get(ha.DOMAIN) or {})
hass.services.register(ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, hass.services.async_register(
handle_reload_config) ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, handle_reload_config)
return True return True

View File

@ -11,7 +11,6 @@ import os
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
from homeassistant.bootstrap import prepare_setup_platform from homeassistant.bootstrap import prepare_setup_platform
from homeassistant import config as conf_util from homeassistant import config as conf_util
from homeassistant.const import ( from homeassistant.const import (
@ -25,7 +24,6 @@ from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.loader import get_platform from homeassistant.loader import get_platform
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util.async import run_coroutine_threadsafe
DOMAIN = 'automation' DOMAIN = 'automation'
ENTITY_ID_FORMAT = DOMAIN + '.{}' ENTITY_ID_FORMAT = DOMAIN + '.{}'
@ -144,42 +142,50 @@ def reload(hass):
hass.services.call(DOMAIN, SERVICE_RELOAD) hass.services.call(DOMAIN, SERVICE_RELOAD)
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""Setup the automation.""" """Setup the automation."""
component = EntityComponent(_LOGGER, DOMAIN, hass, component = EntityComponent(_LOGGER, DOMAIN, hass,
group_name=GROUP_NAME_ALL_AUTOMATIONS) group_name=GROUP_NAME_ALL_AUTOMATIONS)
success = run_coroutine_threadsafe( success = yield from _async_process_config(hass, config, component)
_async_process_config(hass, config, component), hass.loop).result()
if not success: if not success:
return False return False
descriptions = conf_util.load_yaml_config_file( descriptions = yield from hass.loop.run_in_executor(
os.path.join(os.path.dirname(__file__), 'services.yaml')) None, conf_util.load_yaml_config_file, os.path.join(
os.path.dirname(__file__), 'services.yaml')
)
@callback @asyncio.coroutine
def trigger_service_handler(service_call): def trigger_service_handler(service_call):
"""Handle automation triggers.""" """Handle automation triggers."""
tasks = []
for entity in component.async_extract_from_service(service_call): for entity in component.async_extract_from_service(service_call):
hass.loop.create_task(entity.async_trigger( tasks.append(entity.async_trigger(
service_call.data.get(ATTR_VARIABLES), True)) service_call.data.get(ATTR_VARIABLES), True))
yield from asyncio.gather(*tasks, loop=hass.loop)
@callback @asyncio.coroutine
def turn_onoff_service_handler(service_call): def turn_onoff_service_handler(service_call):
"""Handle automation turn on/off service calls.""" """Handle automation turn on/off service calls."""
tasks = []
method = 'async_{}'.format(service_call.service) method = 'async_{}'.format(service_call.service)
for entity in component.async_extract_from_service(service_call): for entity in component.async_extract_from_service(service_call):
hass.loop.create_task(getattr(entity, method)()) tasks.append(getattr(entity, method)())
yield from asyncio.gather(*tasks, loop=hass.loop)
@callback @asyncio.coroutine
def toggle_service_handler(service_call): def toggle_service_handler(service_call):
"""Handle automation toggle service calls.""" """Handle automation toggle service calls."""
tasks = []
for entity in component.async_extract_from_service(service_call): for entity in component.async_extract_from_service(service_call):
if entity.is_on: if entity.is_on:
hass.loop.create_task(entity.async_turn_off()) tasks.append(entity.async_turn_off())
else: else:
hass.loop.create_task(entity.async_turn_on()) tasks.append(entity.async_turn_on())
yield from asyncio.gather(*tasks, loop=hass.loop)
@asyncio.coroutine @asyncio.coroutine
def reload_service_handler(service_call): def reload_service_handler(service_call):
@ -187,24 +193,24 @@ def setup(hass, config):
conf = yield from component.async_prepare_reload() conf = yield from component.async_prepare_reload()
if conf is None: if conf is None:
return return
hass.loop.create_task(_async_process_config(hass, conf, component)) yield from _async_process_config(hass, conf, component)
hass.services.register(DOMAIN, SERVICE_TRIGGER, trigger_service_handler, hass.services.async_register(
descriptions.get(SERVICE_TRIGGER), DOMAIN, SERVICE_TRIGGER, trigger_service_handler,
schema=TRIGGER_SERVICE_SCHEMA) descriptions.get(SERVICE_TRIGGER), schema=TRIGGER_SERVICE_SCHEMA)
hass.services.register(DOMAIN, SERVICE_RELOAD, reload_service_handler, hass.services.async_register(
descriptions.get(SERVICE_RELOAD), DOMAIN, SERVICE_RELOAD, reload_service_handler,
schema=RELOAD_SERVICE_SCHEMA) descriptions.get(SERVICE_RELOAD), schema=RELOAD_SERVICE_SCHEMA)
hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service_handler, hass.services.async_register(
descriptions.get(SERVICE_TOGGLE), DOMAIN, SERVICE_TOGGLE, toggle_service_handler,
schema=SERVICE_SCHEMA) descriptions.get(SERVICE_TOGGLE), schema=SERVICE_SCHEMA)
for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF): for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF):
hass.services.register(DOMAIN, service, turn_onoff_service_handler, hass.services.async_register(
descriptions.get(service), DOMAIN, service, turn_onoff_service_handler,
schema=SERVICE_SCHEMA) descriptions.get(service), schema=SERVICE_SCHEMA)
return True return True

View File

@ -114,7 +114,7 @@ def setup(hass: HomeAssistantType, config: ConfigType):
try: try:
conf = config.get(DOMAIN, []) conf = config.get(DOMAIN, [])
except vol.Invalid as ex: except vol.Invalid as ex:
log_exception(ex, DOMAIN, config) log_exception(ex, DOMAIN, config, hass)
return False return False
else: else:
conf = conf[0] if len(conf) > 0 else {} conf = conf[0] if len(conf) > 0 else {}
@ -431,7 +431,7 @@ def load_config(path: str, hass: HomeAssistantType, consider_home: timedelta):
device = dev_schema(device) device = dev_schema(device)
device['dev_id'] = cv.slugify(dev_id) device['dev_id'] = cv.slugify(dev_id)
except vol.Invalid as exp: except vol.Invalid as exp:
log_exception(exp, dev_id, devices) log_exception(exp, dev_id, devices, hass)
else: else:
result.append(Device(hass, **device)) result.append(Device(hass, **device))
return result return result

View File

@ -144,15 +144,17 @@ def get_entity_ids(hass, entity_id, domain_filter=None):
if ent_id.startswith(domain_filter)] if ent_id.startswith(domain_filter)]
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""Setup all groups found definded in the configuration.""" """Setup all groups found definded in the configuration."""
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
run_coroutine_threadsafe( yield from _async_process_config(hass, config, component)
_async_process_config(hass, config, component), hass.loop).result()
descriptions = conf_util.load_yaml_config_file( descriptions = yield from hass.loop.run_in_executor(
os.path.join(os.path.dirname(__file__), 'services.yaml')) None, conf_util.load_yaml_config_file, os.path.join(
os.path.dirname(__file__), 'services.yaml')
)
@asyncio.coroutine @asyncio.coroutine
def reload_service_handler(service_call): def reload_service_handler(service_call):
@ -162,9 +164,9 @@ def setup(hass, config):
return return
hass.loop.create_task(_async_process_config(hass, conf, component)) hass.loop.create_task(_async_process_config(hass, conf, component))
hass.services.register(DOMAIN, SERVICE_RELOAD, reload_service_handler, hass.services.async_register(
descriptions[DOMAIN][SERVICE_RELOAD], DOMAIN, SERVICE_RELOAD, reload_service_handler,
schema=RELOAD_SERVICE_SCHEMA) descriptions[DOMAIN][SERVICE_RELOAD], schema=RELOAD_SERVICE_SCHEMA)
return True return True

View File

@ -10,12 +10,13 @@ import logging
import voluptuous as vol import voluptuous as vol
from homeassistant.core import callback
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.util import slugify from homeassistant.util import slugify
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.util.async import run_coroutine_threadsafe from homeassistant.util.async import run_callback_threadsafe
DOMAIN = 'persistent_notification' DOMAIN = 'persistent_notification'
ENTITY_ID_FORMAT = DOMAIN + '.{}' ENTITY_ID_FORMAT = DOMAIN + '.{}'
@ -38,12 +39,12 @@ _LOGGER = logging.getLogger(__name__)
def create(hass, message, title=None, notification_id=None): def create(hass, message, title=None, notification_id=None):
"""Generate a notification.""" """Generate a notification."""
run_coroutine_threadsafe( run_callback_threadsafe(
async_create(hass, message, title, notification_id), hass.loop hass.loop, async_create, hass, message, title, notification_id
).result() ).result()
@asyncio.coroutine @callback
def async_create(hass, message, title=None, notification_id=None): def async_create(hass, message, title=None, notification_id=None):
"""Generate a notification.""" """Generate a notification."""
data = { data = {
@ -54,11 +55,14 @@ def async_create(hass, message, title=None, notification_id=None):
] if value is not None ] if value is not None
} }
yield from hass.services.async_call(DOMAIN, SERVICE_CREATE, data) hass.loop.create_task(
hass.services.async_call(DOMAIN, SERVICE_CREATE, data))
def setup(hass, config): @asyncio.coroutine
def async_setup(hass, config):
"""Setup the persistent notification component.""" """Setup the persistent notification component."""
@callback
def create_service(call): def create_service(call):
"""Handle a create notification service call.""" """Handle a create notification service call."""
title = call.data.get(ATTR_TITLE) title = call.data.get(ATTR_TITLE)
@ -68,13 +72,13 @@ def setup(hass, config):
if notification_id is not None: if notification_id is not None:
entity_id = ENTITY_ID_FORMAT.format(slugify(notification_id)) entity_id = ENTITY_ID_FORMAT.format(slugify(notification_id))
else: else:
entity_id = generate_entity_id(ENTITY_ID_FORMAT, DEFAULT_OBJECT_ID, entity_id = async_generate_entity_id(
hass=hass) ENTITY_ID_FORMAT, DEFAULT_OBJECT_ID, hass=hass)
attr = {} attr = {}
if title is not None: if title is not None:
try: try:
title.hass = hass title.hass = hass
title = title.render() title = title.async_render()
except TemplateError as ex: except TemplateError as ex:
_LOGGER.error('Error rendering title %s: %s', title, ex) _LOGGER.error('Error rendering title %s: %s', title, ex)
title = title.template title = title.template
@ -83,17 +87,19 @@ def setup(hass, config):
try: try:
message.hass = hass message.hass = hass
message = message.render() message = message.async_render()
except TemplateError as ex: except TemplateError as ex:
_LOGGER.error('Error rendering message %s: %s', message, ex) _LOGGER.error('Error rendering message %s: %s', message, ex)
message = message.template message = message.template
hass.states.set(entity_id, message, attr) hass.states.async_set(entity_id, message, attr)
descriptions = load_yaml_config_file( descriptions = yield from hass.loop.run_in_executor(
os.path.join(os.path.dirname(__file__), 'services.yaml')) None, load_yaml_config_file, os.path.join(
hass.services.register(DOMAIN, SERVICE_CREATE, create_service, os.path.dirname(__file__), 'services.yaml')
descriptions[DOMAIN][SERVICE_CREATE], )
SCHEMA_SERVICE_CREATE) hass.services.async_register(DOMAIN, SERVICE_CREATE, create_service,
descriptions[DOMAIN][SERVICE_CREATE],
SCHEMA_SERVICE_CREATE)
return True return True

View File

@ -1,4 +1,5 @@
"""Module to help with parsing and generating configuration files.""" """Module to help with parsing and generating configuration files."""
import asyncio
import logging import logging
import os import os
import shutil import shutil
@ -180,6 +181,24 @@ def create_default_config(config_dir, detect_location=True):
return None return None
@asyncio.coroutine
def async_hass_config_yaml(hass):
"""Load YAML from hass config File.
This function allow component inside asyncio loop to reload his config by
self.
This method is a coroutine.
"""
def _load_hass_yaml_config():
path = find_config_file(hass.config.config_dir)
conf = load_yaml_config_file(path)
return conf
conf = yield from hass.loop.run_in_executor(None, _load_hass_yaml_config)
return conf
def find_config_file(config_dir): def find_config_file(config_dir):
"""Look in given directory for supported configuration files.""" """Look in given directory for supported configuration files."""
config_path = os.path.join(config_dir, YAML_CONFIG_FILE) config_path = os.path.join(config_dir, YAML_CONFIG_FILE)
@ -201,7 +220,11 @@ def load_yaml_config_file(config_path):
def process_ha_config_upgrade(hass): def process_ha_config_upgrade(hass):
"""Upgrade config if necessary.""" """Upgrade config if necessary.
Asyncio don't support file operation jet.
This method need to run in a executor.
"""
version_path = hass.config.path(VERSION_FILE) version_path = hass.config.path(VERSION_FILE)
try: try:
@ -225,8 +248,12 @@ def process_ha_config_upgrade(hass):
outp.write(__version__) outp.write(__version__)
def process_ha_core_config(hass, config): @asyncio.coroutine
"""Process the [homeassistant] section from the config.""" def async_process_ha_core_config(hass, config):
"""Process the [homeassistant] section from the config.
This method is a coroutine.
"""
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
config = CORE_CONFIG_SCHEMA(config) config = CORE_CONFIG_SCHEMA(config)
hac = hass.config hac = hass.config
@ -282,7 +309,8 @@ def process_ha_core_config(hass, config):
# If we miss some of the needed values, auto detect them # If we miss some of the needed values, auto detect them
if None in (hac.latitude, hac.longitude, hac.units, if None in (hac.latitude, hac.longitude, hac.units,
hac.time_zone): hac.time_zone):
info = loc_util.detect_location_info() info = yield from hass.loop.run_in_executor(
None, loc_util.detect_location_info)
if info is None: if info is None:
_LOGGER.error('Could not detect location information') _LOGGER.error('Could not detect location information')
@ -307,7 +335,8 @@ def process_ha_core_config(hass, config):
if hac.elevation is None and hac.latitude is not None and \ if hac.elevation is None and hac.latitude is not None and \
hac.longitude is not None: hac.longitude is not None:
elevation = loc_util.elevation(hac.latitude, hac.longitude) elevation = yield from hass.loop.run_in_executor(
None, loc_util.elevation, hac.latitude, hac.longitude)
hac.elevation = elevation hac.elevation = elevation
discovered.append(('elevation', elevation)) discovered.append(('elevation', elevation))

View File

@ -56,7 +56,10 @@ def async_generate_entity_id(entity_id_format: str, name: Optional[str],
def set_customize(customize: Dict[str, Any]) -> None: def set_customize(customize: Dict[str, Any]) -> None:
"""Overwrite all current customize settings.""" """Overwrite all current customize settings.
Async friendly.
"""
global _OVERWRITE global _OVERWRITE
_OVERWRITE = {key.lower(): val for key, val in customize.items()} _OVERWRITE = {key.lower(): val for key, val in customize.items()}

View File

@ -2,8 +2,8 @@
import asyncio import asyncio
from homeassistant import config as conf_util from homeassistant import config as conf_util
from homeassistant.bootstrap import (prepare_setup_platform, from homeassistant.bootstrap import (
prepare_setup_component) async_prepare_setup_platform, async_prepare_setup_component)
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, CONF_SCAN_INTERVAL, CONF_ENTITY_NAMESPACE, ATTR_ENTITY_ID, CONF_SCAN_INTERVAL, CONF_ENTITY_NAMESPACE,
DEVICE_DEFAULT_NAME) DEVICE_DEFAULT_NAME)
@ -118,10 +118,8 @@ class EntityComponent(object):
This method must be run in the event loop. This method must be run in the event loop.
""" """
platform = yield from self.hass.loop.run_in_executor( platform = yield from async_prepare_setup_platform(
None, prepare_setup_platform, self.hass, self.config, self.domain, self.hass, self.config, self.domain, platform_type)
platform_type
)
if platform is None: if platform is None:
return return
@ -238,20 +236,8 @@ class EntityComponent(object):
def prepare_reload(self): def prepare_reload(self):
"""Prepare reloading this entity component.""" """Prepare reloading this entity component."""
try: return run_coroutine_threadsafe(
path = conf_util.find_config_file(self.hass.config.config_dir) self.async_prepare_reload(), loop=self.hass.loop).result()
conf = conf_util.load_yaml_config_file(path)
except HomeAssistantError as err:
self.logger.error(err)
return None
conf = prepare_setup_component(self.hass, conf, self.domain)
if conf is None:
return None
self.reset()
return conf
@asyncio.coroutine @asyncio.coroutine
def async_prepare_reload(self): def async_prepare_reload(self):
@ -259,9 +245,20 @@ class EntityComponent(object):
This method must be run in the event loop. This method must be run in the event loop.
""" """
conf = yield from self.hass.loop.run_in_executor( try:
None, self.prepare_reload conf = yield from \
) conf_util.async_hass_config_yaml(self.hass)
except HomeAssistantError as err:
self.logger.error(err)
return None
conf = yield from async_prepare_setup_component(
self.hass, conf, self.domain)
if conf is None:
return None
yield from self.async_reset()
return conf return conf

View File

@ -40,7 +40,11 @@ _LOGGER = logging.getLogger(__name__)
def prepare(hass: 'HomeAssistant'): def prepare(hass: 'HomeAssistant'):
"""Prepare the loading of components.""" """Prepare the loading of components.
Asyncio don't support file operation jet.
This method need to run in a executor.
"""
global PREPARED # pylint: disable=global-statement global PREPARED # pylint: disable=global-statement
# Load the built-in components # Load the built-in components
@ -81,14 +85,20 @@ def prepare(hass: 'HomeAssistant'):
def set_component(comp_name: str, component: ModuleType) -> None: def set_component(comp_name: str, component: ModuleType) -> None:
"""Set a component in the cache.""" """Set a component in the cache.
Async friendly.
"""
_check_prepared() _check_prepared()
_COMPONENT_CACHE[comp_name] = component _COMPONENT_CACHE[comp_name] = component
def get_platform(domain: str, platform: str) -> Optional[ModuleType]: def get_platform(domain: str, platform: str) -> Optional[ModuleType]:
"""Try to load specified platform.""" """Try to load specified platform.
Async friendly.
"""
return get_component(PLATFORM_FORMAT.format(domain, platform)) return get_component(PLATFORM_FORMAT.format(domain, platform))
@ -97,6 +107,8 @@ def get_component(comp_name) -> Optional[ModuleType]:
Looks in config dir first, then built-in components. Looks in config dir first, then built-in components.
Only returns it if also found to be valid. Only returns it if also found to be valid.
Async friendly.
""" """
if comp_name in _COMPONENT_CACHE: if comp_name in _COMPONENT_CACHE:
return _COMPONENT_CACHE[comp_name] return _COMPONENT_CACHE[comp_name]
@ -166,6 +178,8 @@ def load_order_components(components: Sequence[str]) -> OrderedSet:
- Will ensure that all components that do not directly depend on - Will ensure that all components that do not directly depend on
the group component will be loaded before the group component. the group component will be loaded before the group component.
- returns an OrderedSet load order. - returns an OrderedSet load order.
Async friendly.
""" """
_check_prepared() _check_prepared()
@ -192,13 +206,18 @@ def load_order_component(comp_name: str) -> OrderedSet:
Raises HomeAssistantError if a circular dependency is detected. Raises HomeAssistantError if a circular dependency is detected.
Returns an empty list if component could not be loaded. Returns an empty list if component could not be loaded.
Async friendly.
""" """
return _load_order_component(comp_name, OrderedSet(), set()) return _load_order_component(comp_name, OrderedSet(), set())
def _load_order_component(comp_name: str, load_order: OrderedSet, def _load_order_component(comp_name: str, load_order: OrderedSet,
loading: Set) -> OrderedSet: loading: Set) -> OrderedSet:
"""Recursive function to get load order of components.""" """Recursive function to get load order of components.
Async friendly.
"""
component = get_component(comp_name) component = get_component(comp_name)
# If None it does not exist, error already thrown by get_component. # If None it does not exist, error already thrown by get_component.
@ -235,7 +254,10 @@ def _load_order_component(comp_name: str, load_order: OrderedSet,
def _check_prepared() -> None: def _check_prepared() -> None:
"""Issue a warning if loader.prepare() has never been called.""" """Issue a warning if loader.prepare() has never been called.
Async friendly.
"""
if not PREPARED: if not PREPARED:
_LOGGER.warning(( _LOGGER.warning((
"You did not call loader.prepare() yet. " "You did not call loader.prepare() yet. "

View File

@ -26,8 +26,8 @@ MOCKS = {
'load*': ("homeassistant.config.load_yaml", yaml.load_yaml), 'load*': ("homeassistant.config.load_yaml", yaml.load_yaml),
'get': ("homeassistant.loader.get_component", loader.get_component), 'get': ("homeassistant.loader.get_component", loader.get_component),
'secrets': ("homeassistant.util.yaml._secret_yaml", yaml._secret_yaml), 'secrets': ("homeassistant.util.yaml._secret_yaml", yaml._secret_yaml),
'except': ("homeassistant.bootstrap.log_exception", 'except': ("homeassistant.bootstrap.async_log_exception",
bootstrap.log_exception) bootstrap.async_log_exception)
} }
SILENCE = ( SILENCE = (
'homeassistant.bootstrap.clear_secret_cache', 'homeassistant.bootstrap.clear_secret_cache',
@ -185,9 +185,15 @@ def check(config_path):
# Test if platform/component and overwrite setup # Test if platform/component and overwrite setup
if '.' in comp_name: if '.' in comp_name:
module.setup_platform = mock_setup module.setup_platform = mock_setup
if hasattr(module, 'async_setup_platform'):
del module.async_setup_platform
else: else:
module.setup = mock_setup module.setup = mock_setup
if hasattr(module, 'async_setup'):
del module.async_setup
return module return module
def mock_secrets(ldr, node): # pylint: disable=unused-variable def mock_secrets(ldr, node): # pylint: disable=unused-variable

View File

@ -23,7 +23,10 @@ DATETIME_RE = re.compile(
def set_default_time_zone(time_zone: dt.tzinfo) -> None: def set_default_time_zone(time_zone: dt.tzinfo) -> None:
"""Set a default time zone to be used when none is specified.""" """Set a default time zone to be used when none is specified.
Async friendly.
"""
global DEFAULT_TIME_ZONE # pylint: disable=global-statement global DEFAULT_TIME_ZONE # pylint: disable=global-statement
# NOTE: Remove in the future in favour of typing # NOTE: Remove in the future in favour of typing
@ -33,7 +36,10 @@ def set_default_time_zone(time_zone: dt.tzinfo) -> None:
def get_time_zone(time_zone_str: str) -> Optional[dt.tzinfo]: def get_time_zone(time_zone_str: str) -> Optional[dt.tzinfo]:
"""Get time zone from string. Return None if unable to determine.""" """Get time zone from string. Return None if unable to determine.
Async friendly.
"""
try: try:
return pytz.timezone(time_zone_str) return pytz.timezone(time_zone_str)
except pytz.exceptions.UnknownTimeZoneError: except pytz.exceptions.UnknownTimeZoneError:

View File

@ -49,7 +49,10 @@ def load_yaml(fname: str) -> Union[List, Dict]:
def clear_secret_cache() -> None: def clear_secret_cache() -> None:
"""Clear the secret cache.""" """Clear the secret cache.
Async friendly.
"""
__SECRET_CACHE.clear() __SECRET_CACHE.clear()

View File

@ -10,7 +10,8 @@ import threading
from contextlib import contextmanager from contextlib import contextmanager
from homeassistant import core as ha, loader from homeassistant import core as ha, loader
from homeassistant.bootstrap import setup_component, prepare_setup_component from homeassistant.bootstrap import (
setup_component, async_prepare_setup_component)
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.util.unit_system import METRIC_SYSTEM from homeassistant.util.unit_system import METRIC_SYSTEM
import homeassistant.util.dt as date_util import homeassistant.util.dt as date_util
@ -234,6 +235,7 @@ class MockModule(object):
self.DOMAIN = domain self.DOMAIN = domain
self.DEPENDENCIES = dependencies or [] self.DEPENDENCIES = dependencies or []
self.REQUIREMENTS = requirements or [] self.REQUIREMENTS = requirements or []
self._setup = setup
if config_schema is not None: if config_schema is not None:
self.CONFIG_SCHEMA = config_schema self.CONFIG_SCHEMA = config_schema
@ -241,11 +243,11 @@ class MockModule(object):
if platform_schema is not None: if platform_schema is not None:
self.PLATFORM_SCHEMA = platform_schema self.PLATFORM_SCHEMA = platform_schema
# Setup a mock setup if none given. def setup(self, hass, config):
if setup is None: """Setup the component."""
self.setup = lambda hass, config: True if self._setup is not None:
else: return self._setup(hass, config)
self.setup = setup return True
class MockPlatform(object): class MockPlatform(object):
@ -366,16 +368,19 @@ def assert_setup_component(count, domain=None):
""" """
config = {} config = {}
@asyncio.coroutine
def mock_psc(hass, config_input, domain): def mock_psc(hass, config_input, domain):
"""Mock the prepare_setup_component to capture config.""" """Mock the prepare_setup_component to capture config."""
res = prepare_setup_component(hass, config_input, domain) res = yield from async_prepare_setup_component(
hass, config_input, domain)
config[domain] = None if res is None else res.get(domain) config[domain] = None if res is None else res.get(domain)
_LOGGER.debug('Configuration for %s, Validated: %s, Original %s', _LOGGER.debug('Configuration for %s, Validated: %s, Original %s',
domain, config[domain], config_input.get(domain)) domain, config[domain], config_input.get(domain))
return res return res
assert isinstance(config, dict) assert isinstance(config, dict)
with patch('homeassistant.bootstrap.prepare_setup_component', mock_psc): with patch('homeassistant.bootstrap.async_prepare_setup_component',
mock_psc):
yield config yield config
if domain is None: if domain is None:

View File

@ -1,7 +1,7 @@
"""The tests for the Event automation.""" """The tests for the Event automation."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -28,7 +28,7 @@ class TestAutomationEvent(unittest.TestCase):
def test_if_fires_on_event(self): def test_if_fires_on_event(self):
"""Test the firing of events.""" """Test the firing of events."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -53,7 +53,7 @@ class TestAutomationEvent(unittest.TestCase):
def test_if_fires_on_event_with_data(self): def test_if_fires_on_event_with_data(self):
"""Test the firing of events with data.""" """Test the firing of events with data."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -73,7 +73,7 @@ class TestAutomationEvent(unittest.TestCase):
def test_if_not_fires_if_event_data_not_matches(self): def test_if_not_fires_if_event_data_not_matches(self):
"""Test firing of event if no match.""" """Test firing of event if no match."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',

View File

@ -379,21 +379,22 @@ class TestAutomation(unittest.TestCase):
self.hass.block_till_done() self.hass.block_till_done()
assert automation.is_on(self.hass, entity_id) assert automation.is_on(self.hass, entity_id)
@patch('homeassistant.config.load_yaml_config_file', return_value={ @patch('homeassistant.config.load_yaml_config_file', autospec=True,
automation.DOMAIN: { return_value={
'alias': 'bye', automation.DOMAIN: {
'trigger': { 'alias': 'bye',
'platform': 'event', 'trigger': {
'event_type': 'test_event2', 'platform': 'event',
}, 'event_type': 'test_event2',
'action': { },
'service': 'test.automation', 'action': {
'data_template': { 'service': 'test.automation',
'event': '{{ trigger.event.event_type }}' 'data_template': {
'event': '{{ trigger.event.event_type }}'
}
}
} }
} })
}
})
def test_reload_config_service(self, mock_load_yaml): def test_reload_config_service(self, mock_load_yaml):
"""Test the reload config service.""" """Test the reload config service."""
assert setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
@ -443,9 +444,8 @@ class TestAutomation(unittest.TestCase):
assert len(self.calls) == 2 assert len(self.calls) == 2
assert self.calls[1].data.get('event') == 'test_event2' assert self.calls[1].data.get('event') == 'test_event2'
@patch('homeassistant.config.load_yaml_config_file', return_value={ @patch('homeassistant.config.load_yaml_config_file', autospec=True,
automation.DOMAIN: 'not valid', return_value={automation.DOMAIN: 'not valid'})
})
def test_reload_config_when_invalid_config(self, mock_load_yaml): def test_reload_config_when_invalid_config(self, mock_load_yaml):
"""Test the reload config service handling invalid config.""" """Test the reload config service handling invalid config."""
with assert_setup_component(1): with assert_setup_component(1):

View File

@ -1,7 +1,7 @@
"""The tests for the MQTT automation.""" """The tests for the MQTT automation."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
from tests.common import ( from tests.common import (
mock_mqtt_component, fire_mqtt_message, get_test_home_assistant) mock_mqtt_component, fire_mqtt_message, get_test_home_assistant)
@ -28,7 +28,7 @@ class TestAutomationMQTT(unittest.TestCase):
def test_if_fires_on_topic_match(self): def test_if_fires_on_topic_match(self):
"""Test if message is fired on topic match.""" """Test if message is fired on topic match."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'mqtt', 'platform': 'mqtt',
@ -58,7 +58,7 @@ class TestAutomationMQTT(unittest.TestCase):
def test_if_fires_on_topic_and_payload_match(self): def test_if_fires_on_topic_and_payload_match(self):
"""Test if message is fired on topic and payload match.""" """Test if message is fired on topic and payload match."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'mqtt', 'platform': 'mqtt',
@ -77,7 +77,7 @@ class TestAutomationMQTT(unittest.TestCase):
def test_if_not_fires_on_topic_but_no_payload_match(self): def test_if_not_fires_on_topic_but_no_payload_match(self):
"""Test if message is not fired on topic but no payload.""" """Test if message is not fired on topic but no payload."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'mqtt', 'platform': 'mqtt',

View File

@ -1,7 +1,7 @@
"""The tests for numeric state automation.""" """The tests for numeric state automation."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -28,7 +28,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_below(self): def test_if_fires_on_entity_change_below(self):
""""Test the firing with changed entity.""" """"Test the firing with changed entity."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -58,7 +58,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.states.set('test.entity', 11) self.hass.states.set('test.entity', 11)
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -81,7 +81,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.states.set('test.entity', 9) self.hass.states.set('test.entity', 9)
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -101,7 +101,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_above(self): def test_if_fires_on_entity_change_above(self):
""""Test the firing with changed entity.""" """"Test the firing with changed entity."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -124,7 +124,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.states.set('test.entity', 9) self.hass.states.set('test.entity', 9)
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -148,7 +148,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.states.set('test.entity', 11) self.hass.states.set('test.entity', 11)
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -168,7 +168,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_below_range(self): def test_if_fires_on_entity_change_below_range(self):
""""Test the firing with changed entity.""" """"Test the firing with changed entity."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -188,7 +188,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_below_above_range(self): def test_if_fires_on_entity_change_below_above_range(self):
""""Test the firing with changed entity.""" """"Test the firing with changed entity."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -211,7 +211,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.states.set('test.entity', 11) self.hass.states.set('test.entity', 11)
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -235,7 +235,7 @@ class TestAutomationNumericState(unittest.TestCase):
self.hass.states.set('test.entity', 11) self.hass.states.set('test.entity', 11)
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -256,7 +256,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_not_fires_if_entity_not_match(self): def test_if_not_fires_if_entity_not_match(self):
""""Test if not fired with non matching entity.""" """"Test if not fired with non matching entity."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -275,7 +275,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_entity_change_below_with_attribute(self): def test_if_fires_on_entity_change_below_with_attribute(self):
""""Test attributes change.""" """"Test attributes change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -294,7 +294,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_not_fires_on_entity_change_not_below_with_attribute(self): def test_if_not_fires_on_entity_change_not_below_with_attribute(self):
""""Test attributes.""" """"Test attributes."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -313,7 +313,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_fires_on_attribute_change_with_attribute_below(self): def test_if_fires_on_attribute_change_with_attribute_below(self):
""""Test attributes change.""" """"Test attributes change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -333,7 +333,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_not_fires_on_attribute_change_with_attribute_not_below(self): def test_if_not_fires_on_attribute_change_with_attribute_not_below(self):
""""Test attributes change.""" """"Test attributes change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -353,7 +353,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_not_fires_on_entity_change_with_attribute_below(self): def test_if_not_fires_on_entity_change_with_attribute_below(self):
""""Test attributes change.""" """"Test attributes change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -373,7 +373,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_if_not_fires_on_entity_change_with_not_attribute_below(self): def test_if_not_fires_on_entity_change_with_not_attribute_below(self):
""""Test attributes change.""" """"Test attributes change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -393,7 +393,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_fires_on_attr_change_with_attribute_below_and_multiple_attr(self): def test_fires_on_attr_change_with_attribute_below_and_multiple_attr(self):
""""Test attributes change.""" """"Test attributes change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -414,7 +414,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_template_list(self): def test_template_list(self):
""""Test template list.""" """"Test template list."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -436,7 +436,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_template_string(self): def test_template_string(self):
""""Test template string.""" """"Test template string."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -469,7 +469,7 @@ class TestAutomationNumericState(unittest.TestCase):
def test_not_fires_on_attr_change_with_attr_not_below_multiple_attr(self): def test_not_fires_on_attr_change_with_attr_not_below_multiple_attr(self):
""""Test if not fired changed attributes.""" """"Test if not fired changed attributes."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'numeric_state', 'platform': 'numeric_state',
@ -492,7 +492,7 @@ class TestAutomationNumericState(unittest.TestCase):
""""Test if action.""" """"Test if action."""
entity_id = 'domain.test_entity' entity_id = 'domain.test_entity'
test_state = 10 test_state = 10
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',

View File

@ -3,11 +3,12 @@ import unittest
from datetime import timedelta from datetime import timedelta
from unittest.mock import patch from unittest.mock import patch
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
from tests.common import fire_time_changed, get_test_home_assistant from tests.common import (
fire_time_changed, get_test_home_assistant, assert_setup_component)
class TestAutomationState(unittest.TestCase): class TestAutomationState(unittest.TestCase):
@ -34,7 +35,7 @@ class TestAutomationState(unittest.TestCase):
self.hass.states.set('test.entity', 'hello') self.hass.states.set('test.entity', 'hello')
self.hass.block_till_done() self.hass.block_till_done()
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -67,7 +68,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_from_filter(self): def test_if_fires_on_entity_change_with_from_filter(self):
"""Test for firing on entity change with filter.""" """Test for firing on entity change with filter."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -86,7 +87,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_to_filter(self): def test_if_fires_on_entity_change_with_to_filter(self):
"""Test for firing on entity change with no filter.""" """Test for firing on entity change with no filter."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -105,7 +106,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_state_filter(self): def test_if_fires_on_entity_change_with_state_filter(self):
"""Test for firing on entity change with state filter.""" """Test for firing on entity change with state filter."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -124,7 +125,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_both_filters(self): def test_if_fires_on_entity_change_with_both_filters(self):
"""Test for firing if both filters are a non match.""" """Test for firing if both filters are a non match."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -144,7 +145,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_not_fires_if_to_filter_not_match(self): def test_if_not_fires_if_to_filter_not_match(self):
"""Test for not firing if to filter is not a match.""" """Test for not firing if to filter is not a match."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -166,7 +167,7 @@ class TestAutomationState(unittest.TestCase):
"""Test for not firing if from filter is not a match.""" """Test for not firing if from filter is not a match."""
self.hass.states.set('test.entity', 'bye') self.hass.states.set('test.entity', 'bye')
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -186,7 +187,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_not_fires_if_entity_not_match(self): def test_if_not_fires_if_entity_not_match(self):
"""Test for not firing if entity is not matching.""" """Test for not firing if entity is not matching."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -206,7 +207,7 @@ class TestAutomationState(unittest.TestCase):
"""Test for to action.""" """Test for to action."""
entity_id = 'domain.test_entity' entity_id = 'domain.test_entity'
test_state = 'new_state' test_state = 'new_state'
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -237,68 +238,72 @@ class TestAutomationState(unittest.TestCase):
def test_if_fails_setup_if_to_boolean_value(self): def test_if_fails_setup_if_to_boolean_value(self):
"""Test for setup failure for boolean to.""" """Test for setup failure for boolean to."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'state', 'trigger': {
'entity_id': 'test.entity', 'platform': 'state',
'to': True, 'entity_id': 'test.entity',
}, 'to': True,
'action': { },
'service': 'homeassistant.turn_on', 'action': {
} 'service': 'homeassistant.turn_on',
}}) }
}})
def test_if_fails_setup_if_from_boolean_value(self): def test_if_fails_setup_if_from_boolean_value(self):
"""Test for setup failure for boolean from.""" """Test for setup failure for boolean from."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'state', 'trigger': {
'entity_id': 'test.entity', 'platform': 'state',
'from': True, 'entity_id': 'test.entity',
}, 'from': True,
'action': { },
'service': 'homeassistant.turn_on', 'action': {
} 'service': 'homeassistant.turn_on',
}}) }
}})
def test_if_fails_setup_bad_for(self): def test_if_fails_setup_bad_for(self):
"""Test for setup failure for bad for.""" """Test for setup failure for bad for."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'state', 'trigger': {
'entity_id': 'test.entity', 'platform': 'state',
'to': 'world', 'entity_id': 'test.entity',
'for': { 'to': 'world',
'invalid': 5 'for': {
'invalid': 5
},
}, },
}, 'action': {
'action': { 'service': 'homeassistant.turn_on',
'service': 'homeassistant.turn_on', }
} }})
}})
def test_if_fails_setup_for_without_to(self): def test_if_fails_setup_for_without_to(self):
"""Test for setup failures for missing to.""" """Test for setup failures for missing to."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'state', 'trigger': {
'entity_id': 'test.entity', 'platform': 'state',
'for': { 'entity_id': 'test.entity',
'seconds': 5 'for': {
'seconds': 5
},
}, },
}, 'action': {
'action': { 'service': 'homeassistant.turn_on',
'service': 'homeassistant.turn_on', }
} }})
}})
def test_if_not_fires_on_entity_change_with_for(self): def test_if_not_fires_on_entity_change_with_for(self):
"""Test for not firing on entity change with for.""" """Test for not firing on entity change with for."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -324,7 +329,7 @@ class TestAutomationState(unittest.TestCase):
def test_if_fires_on_entity_change_with_for(self): def test_if_fires_on_entity_change_with_for(self):
"""Test for firing on entity change with for.""" """Test for firing on entity change with for."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'state', 'platform': 'state',
@ -353,7 +358,7 @@ class TestAutomationState(unittest.TestCase):
with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow: with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow:
mock_utcnow.return_value = point1 mock_utcnow.return_value = point1
self.hass.states.set('test.entity', 'on') self.hass.states.set('test.entity', 'on')
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -384,32 +389,34 @@ class TestAutomationState(unittest.TestCase):
def test_if_fails_setup_for_without_time(self): def test_if_fails_setup_for_without_time(self):
"""Test for setup failure if no time is provided.""" """Test for setup failure if no time is provided."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'event', 'trigger': {
'event_type': 'bla' 'platform': 'event',
}, 'event_type': 'bla'
'condition': { },
'platform': 'state', 'condition': {
'entity_id': 'test.entity', 'platform': 'state',
'state': 'on', 'entity_id': 'test.entity',
'for': {}, 'state': 'on',
}, 'for': {},
'action': {'service': 'test.automation'}, },
}}) 'action': {'service': 'test.automation'},
}})
def test_if_fails_setup_for_without_entity(self): def test_if_fails_setup_for_without_entity(self):
"""Test for setup failure if no entity is provided.""" """Test for setup failure if no entity is provided."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': {'event_type': 'bla'}, automation.DOMAIN: {
'condition': { 'trigger': {'event_type': 'bla'},
'platform': 'state', 'condition': {
'state': 'on', 'platform': 'state',
'for': { 'state': 'on',
'seconds': 5 'for': {
'seconds': 5
},
}, },
}, 'action': {'service': 'test.automation'},
'action': {'service': 'test.automation'}, }})
}})

View File

@ -3,7 +3,7 @@ from datetime import datetime
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import sun from homeassistant.components import sun
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -42,7 +42,7 @@ class TestAutomationSun(unittest.TestCase):
with patch('homeassistant.util.dt.utcnow', with patch('homeassistant.util.dt.utcnow',
return_value=now): return_value=now):
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'sun', 'platform': 'sun',
@ -81,7 +81,7 @@ class TestAutomationSun(unittest.TestCase):
with patch('homeassistant.util.dt.utcnow', with patch('homeassistant.util.dt.utcnow',
return_value=now): return_value=now):
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'sun', 'platform': 'sun',
@ -108,7 +108,7 @@ class TestAutomationSun(unittest.TestCase):
with patch('homeassistant.util.dt.utcnow', with patch('homeassistant.util.dt.utcnow',
return_value=now): return_value=now):
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'sun', 'platform': 'sun',
@ -142,7 +142,7 @@ class TestAutomationSun(unittest.TestCase):
with patch('homeassistant.util.dt.utcnow', with patch('homeassistant.util.dt.utcnow',
return_value=now): return_value=now):
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'sun', 'platform': 'sun',
@ -165,7 +165,7 @@ class TestAutomationSun(unittest.TestCase):
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z', sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
}) })
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -201,7 +201,7 @@ class TestAutomationSun(unittest.TestCase):
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z', sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
}) })
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -237,7 +237,7 @@ class TestAutomationSun(unittest.TestCase):
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z', sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
}) })
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -274,7 +274,7 @@ class TestAutomationSun(unittest.TestCase):
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z', sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
}) })
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -312,7 +312,7 @@ class TestAutomationSun(unittest.TestCase):
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T15:00:00Z', sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T15:00:00Z',
}) })
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -358,7 +358,7 @@ class TestAutomationSun(unittest.TestCase):
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T17:30:00Z', sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T17:30:00Z',
}) })
_setup_component(self.hass, automation.DOMAIN, { setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',

View File

@ -1,10 +1,10 @@
"""The tests for the Template automation.""" """The tests for the Template automation."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant, assert_setup_component
class TestAutomationTemplate(unittest.TestCase): class TestAutomationTemplate(unittest.TestCase):
@ -29,7 +29,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_bool(self): def test_if_fires_on_change_bool(self):
"""Test for firing on boolean change.""" """Test for firing on boolean change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -54,7 +54,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_str(self): def test_if_fires_on_change_str(self):
"""Test for firing on change.""" """Test for firing on change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -72,7 +72,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_str_crazy(self): def test_if_fires_on_change_str_crazy(self):
"""Test for firing on change.""" """Test for firing on change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -90,7 +90,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_not_fires_on_change_bool(self): def test_if_not_fires_on_change_bool(self):
"""Test for not firing on boolean change.""" """Test for not firing on boolean change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -108,7 +108,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_not_fires_on_change_str(self): def test_if_not_fires_on_change_str(self):
"""Test for not firing on string change.""" """Test for not firing on string change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -126,7 +126,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_not_fires_on_change_str_crazy(self): def test_if_not_fires_on_change_str_crazy(self):
"""Test for not firing on string change.""" """Test for not firing on string change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -144,7 +144,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_no_change(self): def test_if_fires_on_no_change(self):
"""Test for firing on no change.""" """Test for firing on no change."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -165,7 +165,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_two_change(self): def test_if_fires_on_two_change(self):
"""Test for firing on two changes.""" """Test for firing on two changes."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -189,7 +189,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_with_template(self): def test_if_fires_on_change_with_template(self):
"""Test for firing on change with template.""" """Test for firing on change with template."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -207,7 +207,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_not_fires_on_change_with_template(self): def test_if_not_fires_on_change_with_template(self):
"""Test for not firing on change with template.""" """Test for not firing on change with template."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -228,7 +228,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_with_template_advanced(self): def test_if_fires_on_change_with_template_advanced(self):
"""Test for firing on change with template advanced.""" """Test for firing on change with template advanced."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -262,7 +262,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_no_change_with_template_advanced(self): def test_if_fires_on_no_change_with_template_advanced(self):
"""Test for firing on no change with template advanced.""" """Test for firing on no change with template advanced."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -290,7 +290,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_with_template_2(self): def test_if_fires_on_change_with_template_2(self):
"""Test for firing on change with template.""" """Test for firing on change with template."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',
@ -332,7 +332,7 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_action(self): def test_if_action(self):
"""Test for firing if action.""" """Test for firing if action."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -365,21 +365,22 @@ class TestAutomationTemplate(unittest.TestCase):
def test_if_fires_on_change_with_bad_template(self): def test_if_fires_on_change_with_bad_template(self):
"""Test for firing on change with bad template.""" """Test for firing on change with bad template."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'template', 'trigger': {
'value_template': '{{ ', 'platform': 'template',
}, 'value_template': '{{ ',
'action': { },
'service': 'test.automation' 'action': {
'service': 'test.automation'
}
} }
} })
})
def test_if_fires_on_change_with_bad_template_2(self): def test_if_fires_on_change_with_bad_template_2(self):
"""Test for firing on change with bad template.""" """Test for firing on change with bad template."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'template', 'platform': 'template',

View File

@ -3,11 +3,12 @@ from datetime import timedelta
import unittest import unittest
from unittest.mock import patch from unittest.mock import patch
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
import homeassistant.components.automation as automation import homeassistant.components.automation as automation
from tests.common import fire_time_changed, get_test_home_assistant from tests.common import (
fire_time_changed, get_test_home_assistant, assert_setup_component)
class TestAutomationTime(unittest.TestCase): class TestAutomationTime(unittest.TestCase):
@ -30,7 +31,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_when_hour_matches(self): def test_if_fires_when_hour_matches(self):
"""Test for firing if hour is matching.""" """Test for firing if hour is matching."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -55,7 +56,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_when_minute_matches(self): def test_if_fires_when_minute_matches(self):
"""Test for firing if minutes are matching.""" """Test for firing if minutes are matching."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -74,7 +75,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_when_second_matches(self): def test_if_fires_when_second_matches(self):
"""Test for firing if seconds are matching.""" """Test for firing if seconds are matching."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -93,7 +94,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_when_all_matches(self): def test_if_fires_when_all_matches(self):
"""Test for firing if everything matches.""" """Test for firing if everything matches."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -115,7 +116,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_periodic_seconds(self): def test_if_fires_periodic_seconds(self):
"""Test for firing periodically every second.""" """Test for firing periodically every second."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -135,7 +136,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_periodic_minutes(self): def test_if_fires_periodic_minutes(self):
"""Test for firing periodically every minute.""" """Test for firing periodically every minute."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -155,7 +156,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_periodic_hours(self): def test_if_fires_periodic_hours(self):
"""Test for firing periodically every hour.""" """Test for firing periodically every hour."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -175,7 +176,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_fires_using_after(self): def test_if_fires_using_after(self):
"""Test for firing after.""" """Test for firing after."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'time', 'platform': 'time',
@ -200,16 +201,17 @@ class TestAutomationTime(unittest.TestCase):
def test_if_not_working_if_no_values_in_conf_provided(self): def test_if_not_working_if_no_values_in_conf_provided(self):
"""Test for failure if no configuration.""" """Test for failure if no configuration."""
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'time', 'trigger': {
}, 'platform': 'time',
'action': { },
'service': 'test.automation' 'action': {
'service': 'test.automation'
}
} }
} })
})
fire_time_changed(self.hass, dt_util.utcnow().replace( fire_time_changed(self.hass, dt_util.utcnow().replace(
hour=5, minute=0, second=0)) hour=5, minute=0, second=0))
@ -222,18 +224,19 @@ class TestAutomationTime(unittest.TestCase):
This should break the before rule. This should break the before rule.
""" """
assert not _setup_component(self.hass, automation.DOMAIN, { with assert_setup_component(0):
automation.DOMAIN: { assert not setup_component(self.hass, automation.DOMAIN, {
'trigger': { automation.DOMAIN: {
'platform': 'time', 'trigger': {
'after': 3605, 'platform': 'time',
# Total seconds. Hour = 3600 second 'after': 3605,
}, # Total seconds. Hour = 3600 second
'action': { },
'service': 'test.automation' 'action': {
'service': 'test.automation'
}
} }
} })
})
fire_time_changed(self.hass, dt_util.utcnow().replace( fire_time_changed(self.hass, dt_util.utcnow().replace(
hour=1, minute=0, second=5)) hour=1, minute=0, second=5))
@ -243,7 +246,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_action_before(self): def test_if_action_before(self):
"""Test for if action before.""" """Test for if action before."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -278,7 +281,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_action_after(self): def test_if_action_after(self):
"""Test for if action after.""" """Test for if action after."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -313,7 +316,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_action_one_weekday(self): def test_if_action_one_weekday(self):
"""Test for if action with one weekday.""" """Test for if action with one weekday."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',
@ -349,7 +352,7 @@ class TestAutomationTime(unittest.TestCase):
def test_if_action_list_weekday(self): def test_if_action_list_weekday(self):
"""Test for action with a list of weekdays.""" """Test for action with a list of weekdays."""
assert _setup_component(self.hass, automation.DOMAIN, { assert setup_component(self.hass, automation.DOMAIN, {
automation.DOMAIN: { automation.DOMAIN: {
'trigger': { 'trigger': {
'platform': 'event', 'platform': 'event',

View File

@ -1,7 +1,7 @@
"""The tests for the MQTT binary sensor platform.""" """The tests for the MQTT binary sensor platform."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.binary_sensor as binary_sensor import homeassistant.components.binary_sensor as binary_sensor
from tests.common import mock_mqtt_component, fire_mqtt_message from tests.common import mock_mqtt_component, fire_mqtt_message
from homeassistant.const import (STATE_OFF, STATE_ON) from homeassistant.const import (STATE_OFF, STATE_ON)
@ -24,7 +24,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_setting_sensor_value_via_mqtt_message(self): def test_setting_sensor_value_via_mqtt_message(self):
"""Test the setting of the value via MQTT.""" """Test the setting of the value via MQTT."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, binary_sensor.DOMAIN, { assert setup_component(self.hass, binary_sensor.DOMAIN, {
binary_sensor.DOMAIN: { binary_sensor.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -50,7 +50,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_valid_sensor_class(self): def test_valid_sensor_class(self):
"""Test the setting of a valid sensor class.""" """Test the setting of a valid sensor class."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, binary_sensor.DOMAIN, { assert setup_component(self.hass, binary_sensor.DOMAIN, {
binary_sensor.DOMAIN: { binary_sensor.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -65,7 +65,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_invalid_sensor_class(self): def test_invalid_sensor_class(self):
"""Test the setting of an invalid sensor class.""" """Test the setting of an invalid sensor class."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, binary_sensor.DOMAIN, { assert setup_component(self.hass, binary_sensor.DOMAIN, {
binary_sensor.DOMAIN: { binary_sensor.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',

View File

@ -8,6 +8,8 @@ from nx584 import client as nx584_client
from homeassistant.components.binary_sensor import nx584 from homeassistant.components.binary_sensor import nx584
from homeassistant.bootstrap import setup_component from homeassistant.bootstrap import setup_component
from tests.common import get_test_home_assistant
class StopMe(Exception): class StopMe(Exception):
"""Stop helper.""" """Stop helper."""
@ -20,6 +22,7 @@ class TestNX584SensorSetup(unittest.TestCase):
def setUp(self): def setUp(self):
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
self._mock_client = mock.patch.object(nx584_client, 'Client') self._mock_client = mock.patch.object(nx584_client, 'Client')
self._mock_client.start() self._mock_client.start()
@ -35,6 +38,7 @@ class TestNX584SensorSetup(unittest.TestCase):
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
self.hass.stop()
self._mock_client.stop() self._mock_client.stop()
@mock.patch('homeassistant.components.binary_sensor.nx584.NX584Watcher') @mock.patch('homeassistant.components.binary_sensor.nx584.NX584Watcher')
@ -42,14 +46,13 @@ class TestNX584SensorSetup(unittest.TestCase):
def test_setup_defaults(self, mock_nx, mock_watcher): def test_setup_defaults(self, mock_nx, mock_watcher):
"""Test the setup with no configuration.""" """Test the setup with no configuration."""
add_devices = mock.MagicMock() add_devices = mock.MagicMock()
hass = mock.MagicMock()
config = { config = {
'host': nx584.DEFAULT_HOST, 'host': nx584.DEFAULT_HOST,
'port': nx584.DEFAULT_PORT, 'port': nx584.DEFAULT_PORT,
'exclude_zones': [], 'exclude_zones': [],
'zone_types': {}, 'zone_types': {},
} }
self.assertTrue(nx584.setup_platform(hass, config, add_devices)) self.assertTrue(nx584.setup_platform(self.hass, config, add_devices))
mock_nx.assert_has_calls( mock_nx.assert_has_calls(
[mock.call(zone, 'opening') for zone in self.fake_zones]) [mock.call(zone, 'opening') for zone in self.fake_zones])
self.assertTrue(add_devices.called) self.assertTrue(add_devices.called)
@ -69,8 +72,7 @@ class TestNX584SensorSetup(unittest.TestCase):
'zone_types': {3: 'motion'}, 'zone_types': {3: 'motion'},
} }
add_devices = mock.MagicMock() add_devices = mock.MagicMock()
hass = mock.MagicMock() self.assertTrue(nx584.setup_platform(self.hass, config, add_devices))
self.assertTrue(nx584.setup_platform(hass, config, add_devices))
mock_nx.assert_has_calls([ mock_nx.assert_has_calls([
mock.call(self.fake_zones[0], 'opening'), mock.call(self.fake_zones[0], 'opening'),
mock.call(self.fake_zones[2], 'motion'), mock.call(self.fake_zones[2], 'motion'),
@ -84,9 +86,8 @@ class TestNX584SensorSetup(unittest.TestCase):
def _test_assert_graceful_fail(self, config): def _test_assert_graceful_fail(self, config):
"""Test the failing.""" """Test the failing."""
hass = add_devices = mock.MagicMock() self.assertFalse(setup_component(
self.assertFalse(setup_component(hass, 'binary_sensor.nx584', config)) self.hass, 'binary_sensor.nx584', config))
self.assertFalse(add_devices.called)
def test_setup_bad_config(self): def test_setup_bad_config(self):
"""Test the setup with bad configuration.""" """Test the setup with bad configuration."""
@ -113,8 +114,8 @@ class TestNX584SensorSetup(unittest.TestCase):
def test_setup_no_zones(self): def test_setup_no_zones(self):
"""Test the setup with no zones.""" """Test the setup with no zones."""
nx584_client.Client.return_value.list_zones.return_value = [] nx584_client.Client.return_value.list_zones.return_value = []
hass = add_devices = mock.MagicMock() add_devices = mock.MagicMock()
self.assertTrue(nx584.setup_platform(hass, {}, add_devices)) self.assertTrue(nx584.setup_platform(self.hass, {}, add_devices))
self.assertFalse(add_devices.called) self.assertFalse(add_devices.called)

View File

@ -3,7 +3,7 @@ import unittest
import pytest import pytest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import rfxtrx as rfxtrx_core from homeassistant.components import rfxtrx as rfxtrx_core
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -28,7 +28,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_valid_config(self): def test_valid_config(self):
"""Test configuration.""" """Test configuration."""
self.assertTrue(_setup_component(self.hass, 'cover', { self.assertTrue(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -39,7 +39,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_invalid_config_capital_letters(self): def test_invalid_config_capital_letters(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'cover', { self.assertFalse(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -51,7 +51,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_invalid_config_extra_key(self): def test_invalid_config_extra_key(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'cover', { self.assertFalse(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'invalid_key': 'afda', 'invalid_key': 'afda',
@ -64,7 +64,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_invalid_config_capital_packetid(self): def test_invalid_config_capital_packetid(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'cover', { self.assertFalse(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -76,7 +76,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_invalid_config_missing_packetid(self): def test_invalid_config_missing_packetid(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'cover', { self.assertFalse(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -87,14 +87,14 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_default_config(self): def test_default_config(self):
"""Test with 0 cover.""" """Test with 0 cover."""
self.assertTrue(_setup_component(self.hass, 'cover', { self.assertTrue(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'devices': {}}})) 'devices': {}}}))
self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES))
def test_one_cover(self): def test_one_cover(self):
"""Test with 1 cover.""" """Test with 1 cover."""
self.assertTrue(_setup_component(self.hass, 'cover', { self.assertTrue(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'devices': 'devices':
{'0b1400cd0213c7f210010f51': { {'0b1400cd0213c7f210010f51': {
@ -117,7 +117,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_several_covers(self): def test_several_covers(self):
"""Test with 3 covers.""" """Test with 3 covers."""
self.assertTrue(_setup_component(self.hass, 'cover', { self.assertTrue(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'signal_repetitions': 3, 'signal_repetitions': 3,
'devices': 'devices':
@ -145,7 +145,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_discover_covers(self): def test_discover_covers(self):
"""Test with discovery of covers.""" """Test with discovery of covers."""
self.assertTrue(_setup_component(self.hass, 'cover', { self.assertTrue(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': {}}})) 'devices': {}}}))
@ -183,7 +183,7 @@ class TestCoverRfxtrx(unittest.TestCase):
def test_discover_cover_noautoadd(self): def test_discover_cover_noautoadd(self):
"""Test with discovery of cover when auto add is False.""" """Test with discovery of cover when auto add is False."""
self.assertTrue(_setup_component(self.hass, 'cover', { self.assertTrue(setup_component(self.hass, 'cover', {
'cover': {'platform': 'rfxtrx', 'cover': {'platform': 'rfxtrx',
'automatic_add': False, 'automatic_add': False,
'devices': {}}})) 'devices': {}}}))

View File

@ -4,7 +4,7 @@ from unittest.mock import patch
import logging import logging
import os import os
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import device_tracker from homeassistant.components import device_tracker
from homeassistant.const import CONF_PLATFORM from homeassistant.const import CONF_PLATFORM
@ -42,7 +42,7 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase):
dev_id = 'paulus' dev_id = 'paulus'
topic = '/location/paulus' topic = '/location/paulus'
self.hass.config.components = ['mqtt', 'zone'] self.hass.config.components = ['mqtt', 'zone']
assert _setup_component(self.hass, device_tracker.DOMAIN, { assert setup_component(self.hass, device_tracker.DOMAIN, {
device_tracker.DOMAIN: { device_tracker.DOMAIN: {
CONF_PLATFORM: 'mqtt', CONF_PLATFORM: 'mqtt',
'devices': {dev_id: topic} 'devices': {dev_id: topic}
@ -58,7 +58,7 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase):
location = 'work' location = 'work'
self.hass.config.components = ['mqtt', 'zone'] self.hass.config.components = ['mqtt', 'zone']
assert _setup_component(self.hass, device_tracker.DOMAIN, { assert setup_component(self.hass, device_tracker.DOMAIN, {
device_tracker.DOMAIN: { device_tracker.DOMAIN: {
CONF_PLATFORM: 'mqtt', CONF_PLATFORM: 'mqtt',
'devices': {dev_id: topic} 'devices': {dev_id: topic}

View File

@ -30,7 +30,7 @@ light:
import json import json
import unittest import unittest
from homeassistant.bootstrap import _setup_component, setup_component from homeassistant.bootstrap import setup_component
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE
import homeassistant.components.light as light import homeassistant.components.light as light
from tests.common import ( from tests.common import (
@ -67,7 +67,7 @@ class TestLightMQTTJSON(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
"""Test if there is no color and brightness if they aren't defined.""" """Test if there is no color and brightness if they aren't defined."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: { light.DOMAIN: {
'platform': 'mqtt_json', 'platform': 'mqtt_json',
'name': 'test', 'name': 'test',
@ -93,7 +93,7 @@ class TestLightMQTTJSON(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
"""Test the controlling of the state via topic.""" """Test the controlling of the state via topic."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: { light.DOMAIN: {
'platform': 'mqtt_json', 'platform': 'mqtt_json',
'name': 'test', 'name': 'test',
@ -153,7 +153,7 @@ class TestLightMQTTJSON(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
"""Test the sending of command in optimistic mode.""" """Test the sending of command in optimistic mode."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: { light.DOMAIN: {
'platform': 'mqtt_json', 'platform': 'mqtt_json',
'name': 'test', 'name': 'test',
@ -209,7 +209,7 @@ class TestLightMQTTJSON(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
"""Test for flash length being sent when included.""" """Test for flash length being sent when included."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: { light.DOMAIN: {
'platform': 'mqtt_json', 'platform': 'mqtt_json',
'name': 'test', 'name': 'test',
@ -251,7 +251,7 @@ class TestLightMQTTJSON(unittest.TestCase):
def test_transition(self): def test_transition(self):
"""Test for transition time being sent when included.""" """Test for transition time being sent when included."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: { light.DOMAIN: {
'platform': 'mqtt_json', 'platform': 'mqtt_json',
'name': 'test', 'name': 'test',
@ -293,7 +293,7 @@ class TestLightMQTTJSON(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
"""Test that invalid color/brightness values are ignored.""" """Test that invalid color/brightness values are ignored."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, light.DOMAIN, { assert setup_component(self.hass, light.DOMAIN, {
light.DOMAIN: { light.DOMAIN: {
'platform': 'mqtt_json', 'platform': 'mqtt_json',
'name': 'test', 'name': 'test',

View File

@ -3,7 +3,7 @@ import unittest
import pytest import pytest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import rfxtrx as rfxtrx_core from homeassistant.components import rfxtrx as rfxtrx_core
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -28,7 +28,7 @@ class TestLightRfxtrx(unittest.TestCase):
def test_valid_config(self): def test_valid_config(self):
"""Test configuration.""" """Test configuration."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -36,7 +36,7 @@ class TestLightRfxtrx(unittest.TestCase):
'name': 'Test', 'name': 'Test',
rfxtrx_core.ATTR_FIREEVENT: True}}}})) rfxtrx_core.ATTR_FIREEVENT: True}}}}))
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -47,7 +47,7 @@ class TestLightRfxtrx(unittest.TestCase):
def test_invalid_config(self): def test_invalid_config(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'light', { self.assertFalse(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'invalid_key': 'afda', 'invalid_key': 'afda',
@ -59,14 +59,14 @@ class TestLightRfxtrx(unittest.TestCase):
def test_default_config(self): def test_default_config(self):
"""Test with 0 switches.""" """Test with 0 switches."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'devices': {}}})) 'devices': {}}}))
self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES)) self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES))
def test_old_config(self): def test_old_config(self):
"""Test with 1 light.""" """Test with 1 light."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'devices': 'devices':
{'123efab1': { {'123efab1': {
@ -110,7 +110,7 @@ class TestLightRfxtrx(unittest.TestCase):
def test_one_light(self): def test_one_light(self):
"""Test with 1 light.""" """Test with 1 light."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'devices': 'devices':
{'0b1100cd0213c7f210010f51': { {'0b1100cd0213c7f210010f51': {
@ -179,7 +179,7 @@ class TestLightRfxtrx(unittest.TestCase):
def test_several_lights(self): def test_several_lights(self):
"""Test with 3 lights.""" """Test with 3 lights."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'signal_repetitions': 3, 'signal_repetitions': 3,
'devices': 'devices':
@ -212,7 +212,7 @@ class TestLightRfxtrx(unittest.TestCase):
def test_discover_light(self): def test_discover_light(self):
"""Test with discovery of lights.""" """Test with discovery of lights."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': {}}})) 'devices': {}}}))
@ -265,7 +265,7 @@ class TestLightRfxtrx(unittest.TestCase):
def test_discover_light_noautoadd(self): def test_discover_light_noautoadd(self):
"""Test with discover of light when auto add is False.""" """Test with discover of light when auto add is False."""
self.assertTrue(_setup_component(self.hass, 'light', { self.assertTrue(setup_component(self.hass, 'light', {
'light': {'platform': 'rfxtrx', 'light': {'platform': 'rfxtrx',
'automatic_add': False, 'automatic_add': False,
'devices': {}}})) 'devices': {}}}))

View File

@ -1,7 +1,7 @@
"""The tests for the MQTT lock platform.""" """The tests for the MQTT lock platform."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.const import (STATE_LOCKED, STATE_UNLOCKED, from homeassistant.const import (STATE_LOCKED, STATE_UNLOCKED,
ATTR_ASSUMED_STATE) ATTR_ASSUMED_STATE)
import homeassistant.components.lock as lock import homeassistant.components.lock as lock
@ -24,7 +24,7 @@ class TestLockMQTT(unittest.TestCase):
def test_controlling_state_via_topic(self): def test_controlling_state_via_topic(self):
"""Test the controlling state via topic.""" """Test the controlling state via topic."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, lock.DOMAIN, { assert setup_component(self.hass, lock.DOMAIN, {
lock.DOMAIN: { lock.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -54,7 +54,7 @@ class TestLockMQTT(unittest.TestCase):
def test_sending_mqtt_commands_and_optimistic(self): def test_sending_mqtt_commands_and_optimistic(self):
"""Test the sending MQTT commands in optimistic mode.""" """Test the sending MQTT commands in optimistic mode."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, lock.DOMAIN, { assert setup_component(self.hass, lock.DOMAIN, {
lock.DOMAIN: { lock.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -88,7 +88,7 @@ class TestLockMQTT(unittest.TestCase):
def test_controlling_state_via_topic_and_json_message(self): def test_controlling_state_via_topic_and_json_message(self):
"""Test the controlling state via topic and JSON message.""" """Test the controlling state via topic and JSON message."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, lock.DOMAIN, { assert setup_component(self.hass, lock.DOMAIN, {
lock.DOMAIN: { lock.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',

View File

@ -6,7 +6,7 @@ import socket
import voluptuous as vol import voluptuous as vol
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
from homeassistant.const import ( from homeassistant.const import (
EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START, EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START,
@ -52,7 +52,7 @@ class TestMQTT(unittest.TestCase):
with mock.patch('homeassistant.components.mqtt.MQTT', with mock.patch('homeassistant.components.mqtt.MQTT',
side_effect=socket.error()): side_effect=socket.error()):
self.hass.config.components = [] self.hass.config.components = []
assert not _setup_component(self.hass, mqtt.DOMAIN, { assert not setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: { mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'test-broker', mqtt.CONF_BROKER: 'test-broker',
} }
@ -62,7 +62,7 @@ class TestMQTT(unittest.TestCase):
"""Test for setup failure if connection to broker is missing.""" """Test for setup failure if connection to broker is missing."""
with mock.patch('paho.mqtt.client.Client'): with mock.patch('paho.mqtt.client.Client'):
self.hass.config.components = [] self.hass.config.components = []
assert _setup_component(self.hass, mqtt.DOMAIN, { assert setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: { mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'test-broker', mqtt.CONF_BROKER: 'test-broker',
mqtt.CONF_PROTOCOL: 3.1, mqtt.CONF_PROTOCOL: 3.1,
@ -222,7 +222,7 @@ class TestMQTTCallbacks(unittest.TestCase):
with mock.patch('paho.mqtt.client.Client'): with mock.patch('paho.mqtt.client.Client'):
self.hass.config.components = [] self.hass.config.components = []
assert _setup_component(self.hass, mqtt.DOMAIN, { assert setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: { mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'mock-broker', mqtt.CONF_BROKER: 'mock-broker',
} }

View File

@ -1,7 +1,7 @@
"""The tests for the MQTT component embedded server.""" """The tests for the MQTT component embedded server."""
from unittest.mock import Mock, MagicMock, patch from unittest.mock import Mock, MagicMock, patch
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -29,7 +29,7 @@ class TestMQTT:
password = 'super_secret' password = 'super_secret'
self.hass.config.api = MagicMock(api_password=password) self.hass.config.api = MagicMock(api_password=password)
assert _setup_component(self.hass, mqtt.DOMAIN, {}) assert setup_component(self.hass, mqtt.DOMAIN, {})
assert mock_mqtt.called assert mock_mqtt.called
assert mock_mqtt.mock_calls[0][1][5] == 'homeassistant' assert mock_mqtt.mock_calls[0][1][5] == 'homeassistant'
assert mock_mqtt.mock_calls[0][1][6] == password assert mock_mqtt.mock_calls[0][1][6] == password
@ -38,7 +38,7 @@ class TestMQTT:
self.hass.config.components = ['http'] self.hass.config.components = ['http']
self.hass.config.api = MagicMock(api_password=None) self.hass.config.api = MagicMock(api_password=None)
assert _setup_component(self.hass, mqtt.DOMAIN, {}) assert setup_component(self.hass, mqtt.DOMAIN, {})
assert mock_mqtt.called assert mock_mqtt.called
assert mock_mqtt.mock_calls[0][1][5] is None assert mock_mqtt.mock_calls[0][1][5] is None
assert mock_mqtt.mock_calls[0][1][6] is None assert mock_mqtt.mock_calls[0][1][6] is None
@ -54,6 +54,7 @@ class TestMQTT:
mock_gather.side_effect = BrokerException mock_gather.side_effect = BrokerException
self.hass.config.api = MagicMock(api_password=None) self.hass.config.api = MagicMock(api_password=None)
assert not _setup_component(self.hass, mqtt.DOMAIN, {
assert not setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: {mqtt.CONF_EMBEDDED: {}} mqtt.DOMAIN: {mqtt.CONF_EMBEDDED: {}}
}) })

View File

@ -8,9 +8,8 @@ import homeassistant.components.notify as notify
from homeassistant.components.notify import ( from homeassistant.components.notify import (
ATTR_TITLE_DEFAULT) ATTR_TITLE_DEFAULT)
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from homeassistant.bootstrap import _setup_component
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant, assert_setup_component
class TestNotifyFile(unittest.TestCase): class TestNotifyFile(unittest.TestCase):
@ -26,12 +25,13 @@ class TestNotifyFile(unittest.TestCase):
def test_bad_config(self): def test_bad_config(self):
"""Test set up the platform with bad/missing config.""" """Test set up the platform with bad/missing config."""
self.assertFalse(_setup_component(self.hass, notify.DOMAIN, { with assert_setup_component(0):
'notify': { assert not setup_component(self.hass, notify.DOMAIN, {
'name': 'test', 'notify': {
'platform': 'file', 'name': 'test',
}, 'platform': 'file',
})) },
})
@patch('homeassistant.components.notify.file.os.stat') @patch('homeassistant.components.notify.file.os.stat')
@patch('homeassistant.util.dt.utcnow') @patch('homeassistant.util.dt.utcnow')

View File

@ -6,7 +6,7 @@ import unittest
from homeassistant.const import MATCH_ALL from homeassistant.const import MATCH_ALL
from homeassistant.components import recorder from homeassistant.components import recorder
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -17,7 +17,7 @@ class TestRecorder(unittest.TestCase):
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
db_uri = 'sqlite://' # In memory DB db_uri = 'sqlite://' # In memory DB
_setup_component(self.hass, recorder.DOMAIN, { setup_component(self.hass, recorder.DOMAIN, {
recorder.DOMAIN: {recorder.CONF_DB_URL: db_uri}}) recorder.DOMAIN: {recorder.CONF_DB_URL: db_uri}})
self.hass.start() self.hass.start()
recorder._verify_instance() recorder._verify_instance()

View File

@ -1,7 +1,7 @@
"""The tests for the MQTT sensor platform.""" """The tests for the MQTT sensor platform."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.components.sensor as sensor import homeassistant.components.sensor as sensor
from tests.common import mock_mqtt_component, fire_mqtt_message from tests.common import mock_mqtt_component, fire_mqtt_message
@ -23,7 +23,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_setting_sensor_value_via_mqtt_message(self): def test_setting_sensor_value_via_mqtt_message(self):
"""Test the setting of the value via MQTT.""" """Test the setting of the value via MQTT."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, sensor.DOMAIN, { assert setup_component(self.hass, sensor.DOMAIN, {
sensor.DOMAIN: { sensor.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -43,7 +43,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_setting_sensor_value_via_mqtt_json_message(self): def test_setting_sensor_value_via_mqtt_json_message(self):
"""Test the setting of the value via MQTT with JSON playload.""" """Test the setting of the value via MQTT with JSON playload."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, sensor.DOMAIN, { assert setup_component(self.hass, sensor.DOMAIN, {
sensor.DOMAIN: { sensor.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',

View File

@ -3,7 +3,7 @@ import unittest
import pytest import pytest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import rfxtrx as rfxtrx_core from homeassistant.components import rfxtrx as rfxtrx_core
from homeassistant.const import TEMP_CELSIUS from homeassistant.const import TEMP_CELSIUS
@ -29,7 +29,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_default_config(self): def test_default_config(self):
"""Test with 0 sensor.""" """Test with 0 sensor."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'devices': 'devices':
{}}})) {}}}))
@ -37,7 +37,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_old_config_sensor(self): def test_old_config_sensor(self):
"""Test with 1 sensor.""" """Test with 1 sensor."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'devices': 'devices':
{'sensor_0502': { {'sensor_0502': {
@ -53,7 +53,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_one_sensor(self): def test_one_sensor(self):
"""Test with 1 sensor.""" """Test with 1 sensor."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'devices': 'devices':
{'0a52080705020095220269': { {'0a52080705020095220269': {
@ -68,7 +68,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_one_sensor_no_datatype(self): def test_one_sensor_no_datatype(self):
"""Test with 1 sensor.""" """Test with 1 sensor."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'devices': 'devices':
{'0a52080705020095220269': { {'0a52080705020095220269': {
@ -88,7 +88,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_several_sensors(self): def test_several_sensors(self):
"""Test with 3 sensors.""" """Test with 3 sensors."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'devices': 'devices':
{'0a52080705020095220269': { {'0a52080705020095220269': {
@ -124,7 +124,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_discover_sensor(self): def test_discover_sensor(self):
"""Test with discovery of sensor.""" """Test with discovery of sensor."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': {}}})) 'devices': {}}}))
@ -182,7 +182,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_discover_sensor_noautoadd(self): def test_discover_sensor_noautoadd(self):
"""Test with discover of sensor when auto add is False.""" """Test with discover of sensor when auto add is False."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'automatic_add': False, 'automatic_add': False,
'devices': {}}})) 'devices': {}}}))
@ -209,7 +209,7 @@ class TestSensorRfxtrx(unittest.TestCase):
def test_update_of_sensors(self): def test_update_of_sensors(self):
"""Test with 3 sensors.""" """Test with 3 sensors."""
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'devices': 'devices':
{'0a52080705020095220269': { {'0a52080705020095220269': {

View File

@ -2,7 +2,7 @@
from datetime import datetime from datetime import datetime
from unittest.mock import patch from unittest.mock import patch
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
from tests.common import get_test_home_assistant, load_fixture from tests.common import get_test_home_assistant, load_fixture
@ -28,7 +28,7 @@ class TestSensorYr:
with patch('homeassistant.components.sensor.yr.dt_util.utcnow', with patch('homeassistant.components.sensor.yr.dt_util.utcnow',
return_value=now): return_value=now):
assert _setup_component(self.hass, 'sensor', { assert setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'yr', 'sensor': {'platform': 'yr',
'elevation': 0}}) 'elevation': 0}})
@ -46,7 +46,7 @@ class TestSensorYr:
with patch('homeassistant.components.sensor.yr.dt_util.utcnow', with patch('homeassistant.components.sensor.yr.dt_util.utcnow',
return_value=now): return_value=now):
assert _setup_component(self.hass, 'sensor', { assert setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'yr', 'sensor': {'platform': 'yr',
'elevation': 0, 'elevation': 0,
'monitored_conditions': [ 'monitored_conditions': [

View File

@ -1,7 +1,7 @@
"""The tests for the MQTT switch platform.""" """The tests for the MQTT switch platform."""
import unittest import unittest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE from homeassistant.const import STATE_ON, STATE_OFF, ATTR_ASSUMED_STATE
import homeassistant.components.switch as switch import homeassistant.components.switch as switch
from tests.common import ( from tests.common import (
@ -23,7 +23,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_controlling_state_via_topic(self): def test_controlling_state_via_topic(self):
"""Test the controlling state via topic.""" """Test the controlling state via topic."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, switch.DOMAIN, { assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: { switch.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -53,7 +53,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_sending_mqtt_commands_and_optimistic(self): def test_sending_mqtt_commands_and_optimistic(self):
"""Test the sending MQTT commands in optimistic mode.""" """Test the sending MQTT commands in optimistic mode."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, switch.DOMAIN, { assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: { switch.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',
@ -87,7 +87,7 @@ class TestSensorMQTT(unittest.TestCase):
def test_controlling_state_via_topic_and_json_message(self): def test_controlling_state_via_topic_and_json_message(self):
"""Test the controlling state via topic and JSON message.""" """Test the controlling state via topic and JSON message."""
self.hass.config.components = ['mqtt'] self.hass.config.components = ['mqtt']
assert _setup_component(self.hass, switch.DOMAIN, { assert setup_component(self.hass, switch.DOMAIN, {
switch.DOMAIN: { switch.DOMAIN: {
'platform': 'mqtt', 'platform': 'mqtt',
'name': 'test', 'name': 'test',

View File

@ -3,7 +3,7 @@ import unittest
import pytest import pytest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import rfxtrx as rfxtrx_core from homeassistant.components import rfxtrx as rfxtrx_core
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -28,7 +28,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_valid_config(self): def test_valid_config(self):
"""Test configuration.""" """Test configuration."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -39,7 +39,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_valid_config_int_device_id(self): def test_valid_config_int_device_id(self):
"""Test configuration.""" """Test configuration."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -49,7 +49,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
}}})) }}}))
def test_invalid_config1(self): def test_invalid_config1(self):
self.assertFalse(_setup_component(self.hass, 'switch', { self.assertFalse(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -61,7 +61,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_invalid_config2(self): def test_invalid_config2(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'switch', { self.assertFalse(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'invalid_key': 'afda', 'invalid_key': 'afda',
@ -73,7 +73,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
}}})) }}}))
def test_invalid_config3(self): def test_invalid_config3(self):
self.assertFalse(_setup_component(self.hass, 'switch', { self.assertFalse(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -85,7 +85,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_invalid_config4(self): def test_invalid_config4(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'switch', { self.assertFalse(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -96,7 +96,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_default_config(self): def test_default_config(self):
"""Test with 0 switches.""" """Test with 0 switches."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'devices': 'devices':
{}}})) {}}}))
@ -104,7 +104,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_old_config(self): def test_old_config(self):
"""Test with 1 switch.""" """Test with 1 switch."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'devices': 'devices':
{'123efab1': { {'123efab1': {
@ -132,7 +132,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_one_switch(self): def test_one_switch(self):
"""Test with 1 switch.""" """Test with 1 switch."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'devices': 'devices':
{'0b1100cd0213c7f210010f51': { {'0b1100cd0213c7f210010f51': {
@ -170,7 +170,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_several_switches(self): def test_several_switches(self):
"""Test with 3 switches.""" """Test with 3 switches."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'signal_repetitions': 3, 'signal_repetitions': 3,
'devices': 'devices':
@ -203,7 +203,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_discover_switch(self): def test_discover_switch(self):
"""Test with discovery of switches.""" """Test with discovery of switches."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': {}}})) 'devices': {}}}))
@ -253,7 +253,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
def test_discover_switch_noautoadd(self): def test_discover_switch_noautoadd(self):
"""Test with discovery of switch when auto add is False.""" """Test with discovery of switch when auto add is False."""
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': False, 'automatic_add': False,
'devices': {}}})) 'devices': {}}}))

View File

@ -7,8 +7,9 @@ from homeassistant.bootstrap import setup_component
import homeassistant.components as core_components import homeassistant.components as core_components
from homeassistant.components import conversation from homeassistant.components import conversation
from homeassistant.const import ATTR_ENTITY_ID from homeassistant.const import ATTR_ENTITY_ID
from homeassistant.util.async import run_coroutine_threadsafe
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant, assert_setup_component
class TestConversation(unittest.TestCase): class TestConversation(unittest.TestCase):
@ -19,9 +20,13 @@ class TestConversation(unittest.TestCase):
self.ent_id = 'light.kitchen_lights' self.ent_id = 'light.kitchen_lights'
self.hass = get_test_home_assistant(3) self.hass = get_test_home_assistant(3)
self.hass.states.set(self.ent_id, 'on') self.hass.states.set(self.ent_id, 'on')
self.assertTrue(core_components.setup(self.hass, {})) self.assertTrue(run_coroutine_threadsafe(
self.assertTrue(setup_component(self.hass, conversation.DOMAIN, { core_components.async_setup(self.hass, {}), self.hass.loop
conversation.DOMAIN: {}})) ).result())
with assert_setup_component(0):
self.assertTrue(setup_component(self.hass, conversation.DOMAIN, {
conversation.DOMAIN: {}
}))
def tearDown(self): # pylint: disable=invalid-name def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started.""" """Stop everything that was started."""

View File

@ -1,425 +1,429 @@
"""The tests for the emulated Hue component.""" """The tests for the emulated Hue component."""
import time import time
import json import json
import threading import threading
import asyncio import asyncio
import unittest import unittest
import requests import requests
from homeassistant import bootstrap, const, core from homeassistant import bootstrap, const, core
import homeassistant.components as core_components import homeassistant.components as core_components
from homeassistant.components import emulated_hue, http, light from homeassistant.components import emulated_hue, http, light
from homeassistant.const import STATE_ON, STATE_OFF from homeassistant.const import STATE_ON, STATE_OFF
from homeassistant.components.emulated_hue import ( from homeassistant.components.emulated_hue import (
HUE_API_STATE_ON, HUE_API_STATE_BRI) HUE_API_STATE_ON, HUE_API_STATE_BRI)
from homeassistant.util.async import run_coroutine_threadsafe
from tests.common import get_test_instance_port, get_test_home_assistant
from tests.common import get_test_instance_port, get_test_home_assistant
HTTP_SERVER_PORT = get_test_instance_port()
BRIDGE_SERVER_PORT = get_test_instance_port() HTTP_SERVER_PORT = get_test_instance_port()
BRIDGE_SERVER_PORT = get_test_instance_port()
BRIDGE_URL_BASE = "http://127.0.0.1:{}".format(BRIDGE_SERVER_PORT) + "{}"
JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON} BRIDGE_URL_BASE = "http://127.0.0.1:{}".format(BRIDGE_SERVER_PORT) + "{}"
JSON_HEADERS = {const.HTTP_HEADER_CONTENT_TYPE: const.CONTENT_TYPE_JSON}
def setup_hass_instance(emulated_hue_config):
"""Setup the Home Assistant instance to test.""" def setup_hass_instance(emulated_hue_config):
hass = get_test_home_assistant() """Setup the Home Assistant instance to test."""
hass = get_test_home_assistant()
# We need to do this to get access to homeassistant/turn_(on,off)
core_components.setup(hass, {core.DOMAIN: {}}) # We need to do this to get access to homeassistant/turn_(on,off)
run_coroutine_threadsafe(
bootstrap.setup_component( core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop
hass, http.DOMAIN, ).result()
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}})
bootstrap.setup_component(
bootstrap.setup_component(hass, emulated_hue.DOMAIN, emulated_hue_config) hass, http.DOMAIN,
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}})
return hass
bootstrap.setup_component(hass, emulated_hue.DOMAIN, emulated_hue_config)
def start_hass_instance(hass): return hass
"""Start the Home Assistant instance to test."""
hass.start()
time.sleep(0.05) def start_hass_instance(hass):
"""Start the Home Assistant instance to test."""
hass.start()
class TestEmulatedHue(unittest.TestCase): time.sleep(0.05)
"""Test the emulated Hue component."""
hass = None class TestEmulatedHue(unittest.TestCase):
"""Test the emulated Hue component."""
@classmethod
def setUpClass(cls): hass = None
"""Setup the class."""
cls.hass = setup_hass_instance({ @classmethod
emulated_hue.DOMAIN: { def setUpClass(cls):
emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT """Setup the class."""
}}) cls.hass = setup_hass_instance({
emulated_hue.DOMAIN: {
start_hass_instance(cls.hass) emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT
}})
@classmethod
def tearDownClass(cls): start_hass_instance(cls.hass)
"""Stop the class."""
cls.hass.stop() @classmethod
def tearDownClass(cls):
def test_description_xml(self): """Stop the class."""
"""Test the description.""" cls.hass.stop()
import xml.etree.ElementTree as ET
def test_description_xml(self):
result = requests.get( """Test the description."""
BRIDGE_URL_BASE.format('/description.xml'), timeout=5) import xml.etree.ElementTree as ET
self.assertEqual(result.status_code, 200) result = requests.get(
self.assertTrue('text/xml' in result.headers['content-type']) BRIDGE_URL_BASE.format('/description.xml'), timeout=5)
# Make sure the XML is parsable self.assertEqual(result.status_code, 200)
try: self.assertTrue('text/xml' in result.headers['content-type'])
ET.fromstring(result.text)
except: # Make sure the XML is parsable
self.fail('description.xml is not valid XML!') try:
ET.fromstring(result.text)
def test_create_username(self): except:
"""Test the creation of an username.""" self.fail('description.xml is not valid XML!')
request_json = {'devicetype': 'my_device'}
def test_create_username(self):
result = requests.post( """Test the creation of an username."""
BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json), request_json = {'devicetype': 'my_device'}
timeout=5)
result = requests.post(
self.assertEqual(result.status_code, 200) BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json),
self.assertTrue('application/json' in result.headers['content-type']) timeout=5)
resp_json = result.json() self.assertEqual(result.status_code, 200)
success_json = resp_json[0] self.assertTrue('application/json' in result.headers['content-type'])
self.assertTrue('success' in success_json) resp_json = result.json()
self.assertTrue('username' in success_json['success']) success_json = resp_json[0]
def test_valid_username_request(self): self.assertTrue('success' in success_json)
"""Test request with a valid username.""" self.assertTrue('username' in success_json['success'])
request_json = {'invalid_key': 'my_device'}
def test_valid_username_request(self):
result = requests.post( """Test request with a valid username."""
BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json), request_json = {'invalid_key': 'my_device'}
timeout=5)
result = requests.post(
self.assertEqual(result.status_code, 400) BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json),
timeout=5)
class TestEmulatedHueExposedByDefault(unittest.TestCase): self.assertEqual(result.status_code, 400)
"""Test class for emulated hue component."""
@classmethod class TestEmulatedHueExposedByDefault(unittest.TestCase):
def setUpClass(cls): """Test class for emulated hue component."""
"""Setup the class."""
cls.hass = setup_hass_instance({ @classmethod
emulated_hue.DOMAIN: { def setUpClass(cls):
emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT, """Setup the class."""
emulated_hue.CONF_EXPOSE_BY_DEFAULT: True cls.hass = setup_hass_instance({
} emulated_hue.DOMAIN: {
}) emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT,
emulated_hue.CONF_EXPOSE_BY_DEFAULT: True
bootstrap.setup_component(cls.hass, light.DOMAIN, { }
'light': [ })
{
'platform': 'demo', bootstrap.setup_component(cls.hass, light.DOMAIN, {
} 'light': [
] {
}) 'platform': 'demo',
}
start_hass_instance(cls.hass) ]
})
# Kitchen light is explicitly excluded from being exposed
kitchen_light_entity = cls.hass.states.get('light.kitchen_lights') start_hass_instance(cls.hass)
attrs = dict(kitchen_light_entity.attributes)
attrs[emulated_hue.ATTR_EMULATED_HUE] = False # Kitchen light is explicitly excluded from being exposed
cls.hass.states.set( kitchen_light_entity = cls.hass.states.get('light.kitchen_lights')
kitchen_light_entity.entity_id, kitchen_light_entity.state, attrs = dict(kitchen_light_entity.attributes)
attributes=attrs) attrs[emulated_hue.ATTR_EMULATED_HUE] = False
cls.hass.states.set(
@classmethod kitchen_light_entity.entity_id, kitchen_light_entity.state,
def tearDownClass(cls): attributes=attrs)
"""Stop the class."""
cls.hass.stop() @classmethod
def tearDownClass(cls):
def test_discover_lights(self): """Stop the class."""
"""Test the discovery of lights.""" cls.hass.stop()
result = requests.get(
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5) def test_discover_lights(self):
"""Test the discovery of lights."""
self.assertEqual(result.status_code, 200) result = requests.get(
self.assertTrue('application/json' in result.headers['content-type']) BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5)
result_json = result.json() self.assertEqual(result.status_code, 200)
self.assertTrue('application/json' in result.headers['content-type'])
# Make sure the lights we added to the config are there
self.assertTrue('light.ceiling_lights' in result_json) result_json = result.json()
self.assertTrue('light.bed_light' in result_json)
self.assertTrue('light.kitchen_lights' not in result_json) # Make sure the lights we added to the config are there
self.assertTrue('light.ceiling_lights' in result_json)
def test_get_light_state(self): self.assertTrue('light.bed_light' in result_json)
"""Test the getting of light state.""" self.assertTrue('light.kitchen_lights' not in result_json)
# Turn office light on and set to 127 brightness
self.hass.services.call( def test_get_light_state(self):
light.DOMAIN, const.SERVICE_TURN_ON, """Test the getting of light state."""
{ # Turn office light on and set to 127 brightness
const.ATTR_ENTITY_ID: 'light.ceiling_lights', self.hass.services.call(
light.ATTR_BRIGHTNESS: 127 light.DOMAIN, const.SERVICE_TURN_ON,
}, {
blocking=True) const.ATTR_ENTITY_ID: 'light.ceiling_lights',
light.ATTR_BRIGHTNESS: 127
office_json = self.perform_get_light_state('light.ceiling_lights', 200) },
blocking=True)
self.assertEqual(office_json['state'][HUE_API_STATE_ON], True)
self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127) office_json = self.perform_get_light_state('light.ceiling_lights', 200)
# Turn bedroom light off self.assertEqual(office_json['state'][HUE_API_STATE_ON], True)
self.hass.services.call( self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127)
light.DOMAIN, const.SERVICE_TURN_OFF,
{ # Turn bedroom light off
const.ATTR_ENTITY_ID: 'light.bed_light' self.hass.services.call(
}, light.DOMAIN, const.SERVICE_TURN_OFF,
blocking=True) {
const.ATTR_ENTITY_ID: 'light.bed_light'
bedroom_json = self.perform_get_light_state('light.bed_light', 200) },
blocking=True)
self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False)
self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0) bedroom_json = self.perform_get_light_state('light.bed_light', 200)
# Make sure kitchen light isn't accessible self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False)
kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights') self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0)
kitchen_result = requests.get(
BRIDGE_URL_BASE.format(kitchen_url), timeout=5) # Make sure kitchen light isn't accessible
kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights')
self.assertEqual(kitchen_result.status_code, 404) kitchen_result = requests.get(
BRIDGE_URL_BASE.format(kitchen_url), timeout=5)
def test_put_light_state(self):
"""Test the seeting of light states.""" self.assertEqual(kitchen_result.status_code, 404)
self.perform_put_test_on_ceiling_lights()
def test_put_light_state(self):
# Turn the bedroom light on first """Test the seeting of light states."""
self.hass.services.call( self.perform_put_test_on_ceiling_lights()
light.DOMAIN, const.SERVICE_TURN_ON,
{const.ATTR_ENTITY_ID: 'light.bed_light', # Turn the bedroom light on first
light.ATTR_BRIGHTNESS: 153}, self.hass.services.call(
blocking=True) light.DOMAIN, const.SERVICE_TURN_ON,
{const.ATTR_ENTITY_ID: 'light.bed_light',
bed_light = self.hass.states.get('light.bed_light') light.ATTR_BRIGHTNESS: 153},
self.assertEqual(bed_light.state, STATE_ON) blocking=True)
self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153)
bed_light = self.hass.states.get('light.bed_light')
# Go through the API to turn it off self.assertEqual(bed_light.state, STATE_ON)
bedroom_result = self.perform_put_light_state( self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153)
'light.bed_light', False)
# Go through the API to turn it off
bedroom_result_json = bedroom_result.json() bedroom_result = self.perform_put_light_state(
'light.bed_light', False)
self.assertEqual(bedroom_result.status_code, 200)
self.assertTrue( bedroom_result_json = bedroom_result.json()
'application/json' in bedroom_result.headers['content-type'])
self.assertEqual(bedroom_result.status_code, 200)
self.assertEqual(len(bedroom_result_json), 1) self.assertTrue(
'application/json' in bedroom_result.headers['content-type'])
# Check to make sure the state changed
bed_light = self.hass.states.get('light.bed_light') self.assertEqual(len(bedroom_result_json), 1)
self.assertEqual(bed_light.state, STATE_OFF)
# Check to make sure the state changed
# Make sure we can't change the kitchen light state bed_light = self.hass.states.get('light.bed_light')
kitchen_result = self.perform_put_light_state( self.assertEqual(bed_light.state, STATE_OFF)
'light.kitchen_light', True)
self.assertEqual(kitchen_result.status_code, 404) # Make sure we can't change the kitchen light state
kitchen_result = self.perform_put_light_state(
def test_put_with_form_urlencoded_content_type(self): 'light.kitchen_light', True)
"""Test the form with urlencoded content.""" self.assertEqual(kitchen_result.status_code, 404)
# Needed for Alexa
self.perform_put_test_on_ceiling_lights( def test_put_with_form_urlencoded_content_type(self):
'application/x-www-form-urlencoded') """Test the form with urlencoded content."""
# Needed for Alexa
# Make sure we fail gracefully when we can't parse the data self.perform_put_test_on_ceiling_lights(
data = {'key1': 'value1', 'key2': 'value2'} 'application/x-www-form-urlencoded')
result = requests.put(
BRIDGE_URL_BASE.format( # Make sure we fail gracefully when we can't parse the data
'/api/username/lights/{}/state'.format( data = {'key1': 'value1', 'key2': 'value2'}
"light.ceiling_lights")), data=data) result = requests.put(
BRIDGE_URL_BASE.format(
self.assertEqual(result.status_code, 400) '/api/username/lights/{}/state'.format(
"light.ceiling_lights")), data=data)
def test_entity_not_found(self):
"""Test for entity which are not found.""" self.assertEqual(result.status_code, 400)
result = requests.get(
BRIDGE_URL_BASE.format( def test_entity_not_found(self):
'/api/username/lights/{}'.format("not.existant_entity")), """Test for entity which are not found."""
timeout=5) result = requests.get(
BRIDGE_URL_BASE.format(
self.assertEqual(result.status_code, 404) '/api/username/lights/{}'.format("not.existant_entity")),
timeout=5)
result = requests.put(
BRIDGE_URL_BASE.format( self.assertEqual(result.status_code, 404)
'/api/username/lights/{}/state'.format("non.existant_entity")),
timeout=5) result = requests.put(
BRIDGE_URL_BASE.format(
self.assertEqual(result.status_code, 404) '/api/username/lights/{}/state'.format("non.existant_entity")),
timeout=5)
def test_allowed_methods(self):
"""Test the allowed methods.""" self.assertEqual(result.status_code, 404)
result = requests.get(
BRIDGE_URL_BASE.format( def test_allowed_methods(self):
'/api/username/lights/{}/state'.format( """Test the allowed methods."""
"light.ceiling_lights"))) result = requests.get(
BRIDGE_URL_BASE.format(
self.assertEqual(result.status_code, 405) '/api/username/lights/{}/state'.format(
"light.ceiling_lights")))
result = requests.put(
BRIDGE_URL_BASE.format( self.assertEqual(result.status_code, 405)
'/api/username/lights/{}'.format("light.ceiling_lights")),
data={'key1': 'value1'}) result = requests.put(
BRIDGE_URL_BASE.format(
self.assertEqual(result.status_code, 405) '/api/username/lights/{}'.format("light.ceiling_lights")),
data={'key1': 'value1'})
result = requests.put(
BRIDGE_URL_BASE.format('/api/username/lights'), self.assertEqual(result.status_code, 405)
data={'key1': 'value1'})
result = requests.put(
self.assertEqual(result.status_code, 405) BRIDGE_URL_BASE.format('/api/username/lights'),
data={'key1': 'value1'})
def test_proper_put_state_request(self):
"""Test the request to set the state.""" self.assertEqual(result.status_code, 405)
# Test proper on value parsing
result = requests.put( def test_proper_put_state_request(self):
BRIDGE_URL_BASE.format( """Test the request to set the state."""
'/api/username/lights/{}/state'.format( # Test proper on value parsing
"light.ceiling_lights")), result = requests.put(
data=json.dumps({HUE_API_STATE_ON: 1234})) BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format(
self.assertEqual(result.status_code, 400) "light.ceiling_lights")),
data=json.dumps({HUE_API_STATE_ON: 1234}))
# Test proper brightness value parsing
result = requests.put( self.assertEqual(result.status_code, 400)
BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format( # Test proper brightness value parsing
"light.ceiling_lights")), data=json.dumps({ result = requests.put(
HUE_API_STATE_ON: True, BRIDGE_URL_BASE.format(
HUE_API_STATE_BRI: 'Hello world!' '/api/username/lights/{}/state'.format(
})) "light.ceiling_lights")), data=json.dumps({
HUE_API_STATE_ON: True,
self.assertEqual(result.status_code, 400) HUE_API_STATE_BRI: 'Hello world!'
}))
def perform_put_test_on_ceiling_lights(self,
content_type='application/json'): self.assertEqual(result.status_code, 400)
"""Test the setting of a light."""
# Turn the office light off first def perform_put_test_on_ceiling_lights(self,
self.hass.services.call( content_type='application/json'):
light.DOMAIN, const.SERVICE_TURN_OFF, """Test the setting of a light."""
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'}, # Turn the office light off first
blocking=True) self.hass.services.call(
light.DOMAIN, const.SERVICE_TURN_OFF,
ceiling_lights = self.hass.states.get('light.ceiling_lights') {const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
self.assertEqual(ceiling_lights.state, STATE_OFF) blocking=True)
# Go through the API to turn it on ceiling_lights = self.hass.states.get('light.ceiling_lights')
office_result = self.perform_put_light_state( self.assertEqual(ceiling_lights.state, STATE_OFF)
'light.ceiling_lights', True, 56, content_type)
# Go through the API to turn it on
office_result_json = office_result.json() office_result = self.perform_put_light_state(
'light.ceiling_lights', True, 56, content_type)
self.assertEqual(office_result.status_code, 200)
self.assertTrue( office_result_json = office_result.json()
'application/json' in office_result.headers['content-type'])
self.assertEqual(office_result.status_code, 200)
self.assertEqual(len(office_result_json), 2) self.assertTrue(
'application/json' in office_result.headers['content-type'])
# Check to make sure the state changed
ceiling_lights = self.hass.states.get('light.ceiling_lights') self.assertEqual(len(office_result_json), 2)
self.assertEqual(ceiling_lights.state, STATE_ON)
self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56) # Check to make sure the state changed
ceiling_lights = self.hass.states.get('light.ceiling_lights')
def perform_get_light_state(self, entity_id, expected_status): self.assertEqual(ceiling_lights.state, STATE_ON)
"""Test the gettting of a light state.""" self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56)
result = requests.get(
BRIDGE_URL_BASE.format( def perform_get_light_state(self, entity_id, expected_status):
'/api/username/lights/{}'.format(entity_id)), timeout=5) """Test the gettting of a light state."""
result = requests.get(
self.assertEqual(result.status_code, expected_status) BRIDGE_URL_BASE.format(
'/api/username/lights/{}'.format(entity_id)), timeout=5)
if expected_status == 200:
self.assertTrue( self.assertEqual(result.status_code, expected_status)
'application/json' in result.headers['content-type'])
if expected_status == 200:
return result.json() self.assertTrue(
'application/json' in result.headers['content-type'])
return None
return result.json()
def perform_put_light_state(self, entity_id, is_on, brightness=None,
content_type='application/json'): return None
"""Test the setting of a light state."""
url = BRIDGE_URL_BASE.format( def perform_put_light_state(self, entity_id, is_on, brightness=None,
'/api/username/lights/{}/state'.format(entity_id)) content_type='application/json'):
"""Test the setting of a light state."""
req_headers = {'Content-Type': content_type} url = BRIDGE_URL_BASE.format(
'/api/username/lights/{}/state'.format(entity_id))
data = {HUE_API_STATE_ON: is_on}
req_headers = {'Content-Type': content_type}
if brightness is not None:
data[HUE_API_STATE_BRI] = brightness data = {HUE_API_STATE_ON: is_on}
result = requests.put( if brightness is not None:
url, data=json.dumps(data), timeout=5, headers=req_headers) data[HUE_API_STATE_BRI] = brightness
return result
result = requests.put(
url, data=json.dumps(data), timeout=5, headers=req_headers)
class MQTTBroker(object):
"""Encapsulates an embedded MQTT broker.""" return result
def __init__(self, host, port):
"""Initialize a new instance.""" class MQTTBroker(object):
from hbmqtt.broker import Broker """Encapsulates an embedded MQTT broker."""
self._loop = asyncio.new_event_loop() def __init__(self, host, port):
"""Initialize a new instance."""
hbmqtt_config = { from hbmqtt.broker import Broker
'listeners': {
'default': { self._loop = asyncio.new_event_loop()
'max-connections': 50000,
'type': 'tcp', hbmqtt_config = {
'bind': '{}:{}'.format(host, port) 'listeners': {
} 'default': {
}, 'max-connections': 50000,
'auth': { 'type': 'tcp',
'plugins': ['auth.anonymous'], 'bind': '{}:{}'.format(host, port)
'allow-anonymous': True }
} },
} 'auth': {
'plugins': ['auth.anonymous'],
self._broker = Broker(config=hbmqtt_config, loop=self._loop) 'allow-anonymous': True
}
self._thread = threading.Thread(target=self._run_loop) }
self._started_ev = threading.Event()
self._broker = Broker(config=hbmqtt_config, loop=self._loop)
def start(self):
"""Start the broker.""" self._thread = threading.Thread(target=self._run_loop)
self._thread.start() self._started_ev = threading.Event()
self._started_ev.wait()
def start(self):
def stop(self): """Start the broker."""
"""Stop the broker.""" self._thread.start()
self._loop.call_soon_threadsafe(asyncio.async, self._broker.shutdown()) self._started_ev.wait()
self._loop.call_soon_threadsafe(self._loop.stop)
self._thread.join() def stop(self):
"""Stop the broker."""
def _run_loop(self): self._loop.call_soon_threadsafe(asyncio.async, self._broker.shutdown())
"""Run the loop.""" self._loop.call_soon_threadsafe(self._loop.stop)
asyncio.set_event_loop(self._loop) self._thread.join()
self._loop.run_until_complete(self._broker_coroutine())
def _run_loop(self):
self._started_ev.set() """Run the loop."""
asyncio.set_event_loop(self._loop)
self._loop.run_forever() self._loop.run_until_complete(self._broker_coroutine())
self._loop.close()
self._started_ev.set()
@asyncio.coroutine
def _broker_coroutine(self): self._loop.run_forever()
"""The Broker coroutine.""" self._loop.close()
yield from self._broker.start()
@asyncio.coroutine
def _broker_coroutine(self):
"""The Broker coroutine."""
yield from self._broker.start()

View File

@ -1,7 +1,6 @@
"""The tests for the InfluxDB component.""" """The tests for the InfluxDB component."""
import unittest import unittest
from unittest import mock from unittest import mock
from unittest.mock import patch
import influxdb as influx_client import influxdb as influx_client
@ -9,6 +8,8 @@ from homeassistant.bootstrap import setup_component
import homeassistant.components.influxdb as influxdb import homeassistant.components.influxdb as influxdb
from homeassistant.const import EVENT_STATE_CHANGED, STATE_OFF, STATE_ON from homeassistant.const import EVENT_STATE_CHANGED, STATE_OFF, STATE_ON
from tests.common import get_test_home_assistant
@mock.patch('influxdb.InfluxDBClient') @mock.patch('influxdb.InfluxDBClient')
class TestInfluxDB(unittest.TestCase): class TestInfluxDB(unittest.TestCase):
@ -16,9 +17,13 @@ class TestInfluxDB(unittest.TestCase):
def setUp(self): def setUp(self):
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = mock.MagicMock() self.hass = get_test_home_assistant(2)
self.hass.pool.worker_count = 2
self.handler_method = None self.handler_method = None
self.hass.bus.listen = mock.Mock()
def tearDown(self):
"""Clear data."""
self.hass.stop()
def test_setup_config_full(self, mock_client): def test_setup_config_full(self, mock_client):
"""Test the setup with full configuration.""" """Test the setup with full configuration."""
@ -61,8 +66,6 @@ class TestInfluxDB(unittest.TestCase):
assert setup_component(self.hass, influxdb.DOMAIN, config) assert setup_component(self.hass, influxdb.DOMAIN, config)
@patch('homeassistant.components.persistent_notification.create',
mock.MagicMock())
def test_setup_missing_password(self, mock_client): def test_setup_missing_password(self, mock_client):
"""Test the setup with existing username and missing password.""" """Test the setup with existing username and missing password."""
config = { config = {

View File

@ -1,5 +1,6 @@
"""The testd for Core components.""" """The testd for Core components."""
# pylint: disable=protected-access,too-many-public-methods # pylint: disable=protected-access,too-many-public-methods
import asyncio
import unittest import unittest
from unittest.mock import patch, Mock from unittest.mock import patch, Mock
@ -11,6 +12,7 @@ from homeassistant.const import (
STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE) STATE_ON, STATE_OFF, SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE)
import homeassistant.components as comps import homeassistant.components as comps
from homeassistant.helpers import entity from homeassistant.helpers import entity
from homeassistant.util.async import run_coroutine_threadsafe
from tests.common import ( from tests.common import (
get_test_home_assistant, mock_service, patch_yaml_files) get_test_home_assistant, mock_service, patch_yaml_files)
@ -22,7 +24,9 @@ class TestComponentsCore(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
self.assertTrue(comps.setup(self.hass, {})) self.assertTrue(run_coroutine_threadsafe(
comps.async_setup(self.hass, {}), self.hass.loop
).result())
self.hass.states.set('light.Bowl', STATE_ON) self.hass.states.set('light.Bowl', STATE_ON)
self.hass.states.set('light.Ceiling', STATE_OFF) self.hass.states.set('light.Ceiling', STATE_OFF)
@ -66,6 +70,7 @@ class TestComponentsCore(unittest.TestCase):
self.hass.block_till_done() self.hass.block_till_done()
self.assertEqual(1, len(calls)) self.assertEqual(1, len(calls))
@asyncio.coroutine
@patch('homeassistant.core.ServiceRegistry.call') @patch('homeassistant.core.ServiceRegistry.call')
def test_turn_on_to_not_block_for_domains_without_service(self, mock_call): def test_turn_on_to_not_block_for_domains_without_service(self, mock_call):
"""Test if turn_on is blocking domain with no service.""" """Test if turn_on is blocking domain with no service."""
@ -78,7 +83,7 @@ class TestComponentsCore(unittest.TestCase):
'entity_id': ['light.test', 'sensor.bla', 'light.bla'] 'entity_id': ['light.test', 'sensor.bla', 'light.bla']
}) })
service = self.hass.services._services['homeassistant']['turn_on'] service = self.hass.services._services['homeassistant']['turn_on']
service.func(service_call) yield from service.func(service_call)
self.assertEqual(2, mock_call.call_count) self.assertEqual(2, mock_call.call_count)
self.assertEqual( self.assertEqual(
@ -131,7 +136,7 @@ class TestComponentsCore(unittest.TestCase):
@patch('homeassistant.config.os.path.isfile', Mock(return_value=True)) @patch('homeassistant.config.os.path.isfile', Mock(return_value=True))
@patch('homeassistant.components._LOGGER.error') @patch('homeassistant.components._LOGGER.error')
@patch('homeassistant.config.process_ha_core_config') @patch('homeassistant.config.async_process_ha_core_config')
def test_reload_core_with_wrong_conf(self, mock_process, mock_error): def test_reload_core_with_wrong_conf(self, mock_process, mock_error):
"""Test reload core conf service.""" """Test reload core conf service."""
files = { files = {

View File

@ -7,10 +7,20 @@ from homeassistant.bootstrap import setup_component
import homeassistant.components.logentries as logentries import homeassistant.components.logentries as logentries
from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED
from tests.common import get_test_home_assistant
class TestLogentries(unittest.TestCase): class TestLogentries(unittest.TestCase):
"""Test the Logentries component.""" """Test the Logentries component."""
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant(2)
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""
self.hass.stop()
def test_setup_config_full(self): def test_setup_config_full(self):
"""Test setup with all data.""" """Test setup with all data."""
config = { config = {
@ -18,12 +28,11 @@ class TestLogentries(unittest.TestCase):
'token': 'secret', 'token': 'secret',
} }
} }
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 self.assertTrue(setup_component(self.hass, logentries.DOMAIN, config))
self.assertTrue(setup_component(hass, logentries.DOMAIN, config)) self.assertTrue(self.hass.bus.listen.called)
self.assertTrue(hass.bus.listen.called)
self.assertEqual(EVENT_STATE_CHANGED, self.assertEqual(EVENT_STATE_CHANGED,
hass.bus.listen.call_args_list[0][0][0]) self.hass.bus.listen.call_args_list[0][0][0])
def test_setup_config_defaults(self): def test_setup_config_defaults(self):
"""Test setup with defaults.""" """Test setup with defaults."""
@ -32,12 +41,11 @@ class TestLogentries(unittest.TestCase):
'token': 'token', 'token': 'token',
} }
} }
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 self.assertTrue(setup_component(self.hass, logentries.DOMAIN, config))
self.assertTrue(setup_component(hass, logentries.DOMAIN, config)) self.assertTrue(self.hass.bus.listen.called)
self.assertTrue(hass.bus.listen.called)
self.assertEqual(EVENT_STATE_CHANGED, self.assertEqual(EVENT_STATE_CHANGED,
hass.bus.listen.call_args_list[0][0][0]) self.hass.bus.listen.call_args_list[0][0][0])
def _setup(self, mock_requests): def _setup(self, mock_requests):
"""Test the setup.""" """Test the setup."""
@ -49,8 +57,7 @@ class TestLogentries(unittest.TestCase):
'token': 'token' 'token': 'token'
} }
} }
self.hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
self.hass.pool.worker_count = 2
setup_component(self.hass, logentries.DOMAIN, config) setup_component(self.hass, logentries.DOMAIN, config)
self.handler_method = self.hass.bus.listen.call_args_list[0][0][1] self.handler_method = self.hass.bus.listen.call_args_list[0][0][1]

View File

@ -2,11 +2,12 @@
from collections import namedtuple from collections import namedtuple
import logging import logging
import unittest import unittest
from unittest.mock import MagicMock
from homeassistant.bootstrap import setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import logger from homeassistant.components import logger
from tests.common import get_test_home_assistant
RECORD = namedtuple('record', ('name', 'levelno')) RECORD = namedtuple('record', ('name', 'levelno'))
@ -15,18 +16,18 @@ class TestUpdater(unittest.TestCase):
def setUp(self): def setUp(self):
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant(2)
self.log_config = {'logger': self.log_config = {'logger':
{'default': 'warning', 'logs': {'test': 'info'}}} {'default': 'warning', 'logs': {'test': 'info'}}}
def tearDown(self): def tearDown(self):
"""Stop everything that was started.""" """Stop everything that was started."""
del logging.root.handlers[-1] del logging.root.handlers[-1]
self.hass.stop()
def test_logger_setup(self): def test_logger_setup(self):
"""Use logger to create a logging filter.""" """Use logger to create a logging filter."""
hass = MagicMock() setup_component(self.hass, logger.DOMAIN, self.log_config)
hass.pool.worker_count = 2
setup_component(hass, logger.DOMAIN, self.log_config)
self.assertTrue(len(logging.root.handlers) > 0) self.assertTrue(len(logging.root.handlers) > 0)
handler = logging.root.handlers[-1] handler = logging.root.handlers[-1]
@ -39,9 +40,7 @@ class TestUpdater(unittest.TestCase):
def test_logger_test_filters(self): def test_logger_test_filters(self):
"""Test resulting filter operation.""" """Test resulting filter operation."""
hass = MagicMock() setup_component(self.hass, logger.DOMAIN, self.log_config)
hass.pool.worker_count = 2
setup_component(hass, logger.DOMAIN, self.log_config)
log_filter = logging.root.handlers[-1].filters[0] log_filter = logging.root.handlers[-1].filters[0]

View File

@ -10,7 +10,8 @@ from homeassistant.components import panel_custom
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@patch('homeassistant.components.frontend.setup', return_value=True) @patch('homeassistant.components.frontend.setup',
autospec=True, return_value=True)
class TestPanelCustom(unittest.TestCase): class TestPanelCustom(unittest.TestCase):
"""Test the panel_custom component.""" """Test the panel_custom component."""

View File

@ -4,7 +4,7 @@ import unittest
import pytest import pytest
from homeassistant.bootstrap import _setup_component from homeassistant.bootstrap import setup_component
from homeassistant.components import rfxtrx as rfxtrx from homeassistant.components import rfxtrx as rfxtrx
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -27,14 +27,14 @@ class TestRFXTRX(unittest.TestCase):
def test_default_config(self): def test_default_config(self):
"""Test configuration.""" """Test configuration."""
self.assertTrue(_setup_component(self.hass, 'rfxtrx', { self.assertTrue(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': { 'rfxtrx': {
'device': '/dev/serial/by-id/usb' + 'device': '/dev/serial/by-id/usb' +
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0', '-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
'dummy': True} 'dummy': True}
})) }))
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': {}}})) 'devices': {}}}))
@ -43,7 +43,7 @@ class TestRFXTRX(unittest.TestCase):
def test_valid_config(self): def test_valid_config(self):
"""Test configuration.""" """Test configuration."""
self.assertTrue(_setup_component(self.hass, 'rfxtrx', { self.assertTrue(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': { 'rfxtrx': {
'device': '/dev/serial/by-id/usb' + 'device': '/dev/serial/by-id/usb' +
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0', '-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
@ -51,7 +51,7 @@ class TestRFXTRX(unittest.TestCase):
self.hass.config.components.remove('rfxtrx') self.hass.config.components.remove('rfxtrx')
self.assertTrue(_setup_component(self.hass, 'rfxtrx', { self.assertTrue(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': { 'rfxtrx': {
'device': '/dev/serial/by-id/usb' + 'device': '/dev/serial/by-id/usb' +
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0', '-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
@ -60,11 +60,11 @@ class TestRFXTRX(unittest.TestCase):
def test_invalid_config(self): def test_invalid_config(self):
"""Test configuration.""" """Test configuration."""
self.assertFalse(_setup_component(self.hass, 'rfxtrx', { self.assertFalse(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': {} 'rfxtrx': {}
})) }))
self.assertFalse(_setup_component(self.hass, 'rfxtrx', { self.assertFalse(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': { 'rfxtrx': {
'device': '/dev/serial/by-id/usb' + 'device': '/dev/serial/by-id/usb' +
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0', '-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
@ -72,13 +72,13 @@ class TestRFXTRX(unittest.TestCase):
def test_fire_event(self): def test_fire_event(self):
"""Test fire event.""" """Test fire event."""
self.assertTrue(_setup_component(self.hass, 'rfxtrx', { self.assertTrue(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': { 'rfxtrx': {
'device': '/dev/serial/by-id/usb' + 'device': '/dev/serial/by-id/usb' +
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0', '-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
'dummy': True} 'dummy': True}
})) }))
self.assertTrue(_setup_component(self.hass, 'switch', { self.assertTrue(setup_component(self.hass, 'switch', {
'switch': {'platform': 'rfxtrx', 'switch': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':
@ -116,13 +116,13 @@ class TestRFXTRX(unittest.TestCase):
def test_fire_event_sensor(self): def test_fire_event_sensor(self):
"""Test fire event.""" """Test fire event."""
self.assertTrue(_setup_component(self.hass, 'rfxtrx', { self.assertTrue(setup_component(self.hass, 'rfxtrx', {
'rfxtrx': { 'rfxtrx': {
'device': '/dev/serial/by-id/usb' + 'device': '/dev/serial/by-id/usb' +
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0', '-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
'dummy': True} 'dummy': True}
})) }))
self.assertTrue(_setup_component(self.hass, 'sensor', { self.assertTrue(setup_component(self.hass, 'sensor', {
'sensor': {'platform': 'rfxtrx', 'sensor': {'platform': 'rfxtrx',
'automatic_add': True, 'automatic_add': True,
'devices': 'devices':

View File

@ -65,11 +65,11 @@ class TestSleepIQ(unittest.TestCase):
"""Test the setup when no login is configured.""" """Test the setup when no login is configured."""
conf = self.config.copy() conf = self.config.copy()
del conf['sleepiq']['username'] del conf['sleepiq']['username']
assert not bootstrap._setup_component(self.hass, sleepiq.DOMAIN, conf) assert not bootstrap.setup_component(self.hass, sleepiq.DOMAIN, conf)
def test_setup_component_no_password(self): def test_setup_component_no_password(self):
"""Test the setup when no password is configured.""" """Test the setup when no password is configured."""
conf = self.config.copy() conf = self.config.copy()
del conf['sleepiq']['password'] del conf['sleepiq']['password']
assert not bootstrap._setup_component(self.hass, sleepiq.DOMAIN, conf) assert not bootstrap.setup_component(self.hass, sleepiq.DOMAIN, conf)

View File

@ -6,10 +6,20 @@ from homeassistant.bootstrap import setup_component
import homeassistant.components.splunk as splunk import homeassistant.components.splunk as splunk
from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED
from tests.common import get_test_home_assistant
class TestSplunk(unittest.TestCase): class TestSplunk(unittest.TestCase):
"""Test the Splunk component.""" """Test the Splunk component."""
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant(2)
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""
self.hass.stop()
def test_setup_config_full(self): def test_setup_config_full(self):
"""Test setup with all data.""" """Test setup with all data."""
config = { config = {
@ -21,12 +31,11 @@ class TestSplunk(unittest.TestCase):
} }
} }
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 self.assertTrue(setup_component(self.hass, splunk.DOMAIN, config))
self.assertTrue(setup_component(hass, splunk.DOMAIN, config)) self.assertTrue(self.hass.bus.listen.called)
self.assertTrue(hass.bus.listen.called)
self.assertEqual(EVENT_STATE_CHANGED, self.assertEqual(EVENT_STATE_CHANGED,
hass.bus.listen.call_args_list[0][0][0]) self.hass.bus.listen.call_args_list[0][0][0])
def test_setup_config_defaults(self): def test_setup_config_defaults(self):
"""Test setup with defaults.""" """Test setup with defaults."""
@ -37,12 +46,11 @@ class TestSplunk(unittest.TestCase):
} }
} }
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 self.assertTrue(setup_component(self.hass, splunk.DOMAIN, config))
self.assertTrue(setup_component(hass, splunk.DOMAIN, config)) self.assertTrue(self.hass.bus.listen.called)
self.assertTrue(hass.bus.listen.called)
self.assertEqual(EVENT_STATE_CHANGED, self.assertEqual(EVENT_STATE_CHANGED,
hass.bus.listen.call_args_list[0][0][0]) self.hass.bus.listen.call_args_list[0][0][0])
def _setup(self, mock_requests): def _setup(self, mock_requests):
"""Test the setup.""" """Test the setup."""
@ -57,8 +65,7 @@ class TestSplunk(unittest.TestCase):
} }
} }
self.hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
self.hass.pool.worker_count = 2
setup_component(self.hass, splunk.DOMAIN, config) setup_component(self.hass, splunk.DOMAIN, config)
self.handler_method = self.hass.bus.listen.call_args_list[0][0][1] self.handler_method = self.hass.bus.listen.call_args_list[0][0][1]

View File

@ -9,10 +9,20 @@ import homeassistant.core as ha
import homeassistant.components.statsd as statsd import homeassistant.components.statsd as statsd
from homeassistant.const import (STATE_ON, STATE_OFF, EVENT_STATE_CHANGED) from homeassistant.const import (STATE_ON, STATE_OFF, EVENT_STATE_CHANGED)
from tests.common import get_test_home_assistant
class TestStatsd(unittest.TestCase): class TestStatsd(unittest.TestCase):
"""Test the StatsD component.""" """Test the StatsD component."""
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant(2)
def tearDown(self): # pylint: disable=invalid-name
"""Stop everything that was started."""
self.hass.stop()
def test_invalid_config(self): def test_invalid_config(self):
"""Test configuration with defaults.""" """Test configuration with defaults."""
config = { config = {
@ -37,18 +47,17 @@ class TestStatsd(unittest.TestCase):
'prefix': 'foo', 'prefix': 'foo',
} }
} }
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 self.assertTrue(setup_component(self.hass, statsd.DOMAIN, config))
self.assertTrue(setup_component(hass, statsd.DOMAIN, config))
self.assertEqual(mock_connection.call_count, 1) self.assertEqual(mock_connection.call_count, 1)
self.assertEqual( self.assertEqual(
mock_connection.call_args, mock_connection.call_args,
mock.call(host='host', port=123, prefix='foo') mock.call(host='host', port=123, prefix='foo')
) )
self.assertTrue(hass.bus.listen.called) self.assertTrue(self.hass.bus.listen.called)
self.assertEqual(EVENT_STATE_CHANGED, self.assertEqual(EVENT_STATE_CHANGED,
hass.bus.listen.call_args_list[0][0][0]) self.hass.bus.listen.call_args_list[0][0][0])
@mock.patch('statsd.StatsClient') @mock.patch('statsd.StatsClient')
def test_statsd_setup_defaults(self, mock_connection): def test_statsd_setup_defaults(self, mock_connection):
@ -62,15 +71,14 @@ class TestStatsd(unittest.TestCase):
config['statsd'][statsd.CONF_PORT] = statsd.DEFAULT_PORT config['statsd'][statsd.CONF_PORT] = statsd.DEFAULT_PORT
config['statsd'][statsd.CONF_PREFIX] = statsd.DEFAULT_PREFIX config['statsd'][statsd.CONF_PREFIX] = statsd.DEFAULT_PREFIX
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 self.assertTrue(setup_component(self.hass, statsd.DOMAIN, config))
self.assertTrue(setup_component(hass, statsd.DOMAIN, config))
self.assertEqual(mock_connection.call_count, 1) self.assertEqual(mock_connection.call_count, 1)
self.assertEqual( self.assertEqual(
mock_connection.call_args, mock_connection.call_args,
mock.call(host='host', port=8125, prefix='hass') mock.call(host='host', port=8125, prefix='hass')
) )
self.assertTrue(hass.bus.listen.called) self.assertTrue(self.hass.bus.listen.called)
@mock.patch('statsd.StatsClient') @mock.patch('statsd.StatsClient')
def test_event_listener_defaults(self, mock_client): def test_event_listener_defaults(self, mock_client):
@ -83,11 +91,10 @@ class TestStatsd(unittest.TestCase):
config['statsd'][statsd.CONF_RATE] = statsd.DEFAULT_RATE config['statsd'][statsd.CONF_RATE] = statsd.DEFAULT_RATE
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 setup_component(self.hass, statsd.DOMAIN, config)
setup_component(hass, statsd.DOMAIN, config) self.assertTrue(self.hass.bus.listen.called)
self.assertTrue(hass.bus.listen.called) handler_method = self.hass.bus.listen.call_args_list[0][0][1]
handler_method = hass.bus.listen.call_args_list[0][0][1]
valid = {'1': 1, valid = {'1': 1,
'1.0': 1.0, '1.0': 1.0,
@ -128,11 +135,10 @@ class TestStatsd(unittest.TestCase):
config['statsd'][statsd.CONF_RATE] = statsd.DEFAULT_RATE config['statsd'][statsd.CONF_RATE] = statsd.DEFAULT_RATE
hass = mock.MagicMock() self.hass.bus.listen = mock.MagicMock()
hass.pool.worker_count = 2 setup_component(self.hass, statsd.DOMAIN, config)
setup_component(hass, statsd.DOMAIN, config) self.assertTrue(self.hass.bus.listen.called)
self.assertTrue(hass.bus.listen.called) handler_method = self.hass.bus.listen.call_args_list[0][0][1]
handler_method = hass.bus.listen.call_args_list[0][0][1]
valid = {'1': 1, valid = {'1': 1,
'1.0': 1.0, '1.0': 1.0,

View File

@ -127,4 +127,4 @@ class TestHelpersDiscovery:
assert 'test_component' in self.hass.config.components assert 'test_component' in self.hass.config.components
assert 'switch' in self.hass.config.components assert 'switch' in self.hass.config.components
assert len(component_calls) == 1 assert len(component_calls) == 1
assert len(platform_calls) == 2 assert len(platform_calls) == 1

View File

@ -7,6 +7,7 @@ from unittest.mock import patch
import homeassistant.core as ha import homeassistant.core as ha
import homeassistant.components as core_components import homeassistant.components as core_components
from homeassistant.const import (SERVICE_TURN_ON, SERVICE_TURN_OFF) from homeassistant.const import (SERVICE_TURN_ON, SERVICE_TURN_OFF)
from homeassistant.util.async import run_coroutine_threadsafe
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from homeassistant.helpers import state from homeassistant.helpers import state
from homeassistant.const import ( from homeassistant.const import (
@ -63,7 +64,8 @@ class TestStateHelpers(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name def setUp(self): # pylint: disable=invalid-name
"""Run when tests are started.""" """Run when tests are started."""
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
core_components.setup(self.hass, {}) run_coroutine_threadsafe(core_components.async_setup(
self.hass, {}), self.hass.loop).result()
def tearDown(self): # pylint: disable=invalid-name def tearDown(self): # pylint: disable=invalid-name
"""Stop when tests are finished.""" """Stop when tests are finished."""

View File

@ -3,7 +3,6 @@ import asyncio
import logging import logging
import os import os
import unittest import unittest
from unittest.mock import patch
import homeassistant.scripts.check_config as check_config import homeassistant.scripts.check_config as check_config
from tests.common import patch_yaml_files, get_test_config_dir from tests.common import patch_yaml_files, get_test_config_dir
@ -45,12 +44,22 @@ def tearDownModule(self): # pylint: disable=invalid-name
os.remove(path) os.remove(path)
@patch('asyncio.get_event_loop', return_value=asyncio.new_event_loop())
class TestCheckConfig(unittest.TestCase): class TestCheckConfig(unittest.TestCase):
"""Tests for the homeassistant.scripts.check_config module.""" """Tests for the homeassistant.scripts.check_config module."""
def setUp(self):
"""Prepare the test."""
# Somewhere in the tests our event loop gets killed,
# this ensures we have one.
try:
asyncio.get_event_loop()
except (RuntimeError, AssertionError):
# Py35: RuntimeError
# Py34: AssertionError
asyncio.set_event_loop(asyncio.new_event_loop())
# pylint: disable=no-self-use,invalid-name # pylint: disable=no-self-use,invalid-name
def test_config_platform_valid(self, mock_get_loop): def test_config_platform_valid(self):
"""Test a valid platform setup.""" """Test a valid platform setup."""
files = { files = {
'light.yaml': BASE_CONFIG + 'light:\n platform: demo', 'light.yaml': BASE_CONFIG + 'light:\n platform: demo',
@ -66,7 +75,7 @@ class TestCheckConfig(unittest.TestCase):
'yaml_files': ['.../light.yaml'] 'yaml_files': ['.../light.yaml']
}, res) }, res)
def test_config_component_platform_fail_validation(self, mock_get_loop): def test_config_component_platform_fail_validation(self):
"""Test errors if component & platform not found.""" """Test errors if component & platform not found."""
files = { files = {
'component.yaml': BASE_CONFIG + 'http:\n password: err123', 'component.yaml': BASE_CONFIG + 'http:\n password: err123',
@ -104,7 +113,7 @@ class TestCheckConfig(unittest.TestCase):
self.assertDictEqual({}, res['secrets']) self.assertDictEqual({}, res['secrets'])
self.assertListEqual(['.../platform.yaml'], res['yaml_files']) self.assertListEqual(['.../platform.yaml'], res['yaml_files'])
def test_component_platform_not_found(self, mock_get_loop): def test_component_platform_not_found(self):
"""Test errors if component or platform not found.""" """Test errors if component or platform not found."""
files = { files = {
'badcomponent.yaml': BASE_CONFIG + 'beer:', 'badcomponent.yaml': BASE_CONFIG + 'beer:',
@ -131,7 +140,7 @@ class TestCheckConfig(unittest.TestCase):
self.assertDictEqual({}, res['secrets']) self.assertDictEqual({}, res['secrets'])
self.assertListEqual(['.../badplatform.yaml'], res['yaml_files']) self.assertListEqual(['.../badplatform.yaml'], res['yaml_files'])
def test_secrets(self, mock_get_loop): def test_secrets(self):
"""Test secrets config checking method.""" """Test secrets config checking method."""
files = { files = {
get_test_config_dir('secret.yaml'): ( get_test_config_dir('secret.yaml'): (

View File

@ -48,11 +48,10 @@ class TestBootstrap:
@mock.patch( @mock.patch(
# prevent .HA_VERISON file from being written # prevent .HA_VERISON file from being written
'homeassistant.bootstrap.conf_util.process_ha_config_upgrade', 'homeassistant.bootstrap.conf_util.process_ha_config_upgrade',
mock.Mock() autospec=True)
)
@mock.patch('homeassistant.util.location.detect_location_info', @mock.patch('homeassistant.util.location.detect_location_info',
return_value=None) autospec=True, return_value=None)
def test_from_config_file(self, mock_detect): def test_from_config_file(self, mock_upgrade, mock_detect):
"""Test with configuration file.""" """Test with configuration file."""
components = ['browser', 'conversation', 'script'] components = ['browser', 'conversation', 'script']
files = { files = {
@ -94,28 +93,33 @@ class TestBootstrap:
loader.set_component( loader.set_component(
'comp_conf', MockModule('comp_conf', config_schema=config_schema)) 'comp_conf', MockModule('comp_conf', config_schema=config_schema))
assert not bootstrap._setup_component(self.hass, 'comp_conf', {}) with assert_setup_component(0):
assert not bootstrap.setup_component(self.hass, 'comp_conf', {})
assert not bootstrap._setup_component(self.hass, 'comp_conf', { with assert_setup_component(0):
'comp_conf': None assert not bootstrap.setup_component(self.hass, 'comp_conf', {
}) 'comp_conf': None
})
assert not bootstrap._setup_component(self.hass, 'comp_conf', { with assert_setup_component(0):
'comp_conf': {} assert not bootstrap.setup_component(self.hass, 'comp_conf', {
}) 'comp_conf': {}
})
assert not bootstrap._setup_component(self.hass, 'comp_conf', { with assert_setup_component(0):
'comp_conf': { assert not bootstrap.setup_component(self.hass, 'comp_conf', {
'hello': 'world', 'comp_conf': {
'invalid': 'extra', 'hello': 'world',
} 'invalid': 'extra',
}) }
})
assert bootstrap._setup_component(self.hass, 'comp_conf', { with assert_setup_component(1):
'comp_conf': { assert bootstrap.setup_component(self.hass, 'comp_conf', {
'hello': 'world', 'comp_conf': {
} 'hello': 'world',
}) }
})
def test_validate_platform_config(self): def test_validate_platform_config(self):
"""Test validating platform configuration.""" """Test validating platform configuration."""
@ -130,7 +134,7 @@ class TestBootstrap:
'platform_conf.whatever', MockPlatform('whatever')) 'platform_conf.whatever', MockPlatform('whatever'))
with assert_setup_component(0): with assert_setup_component(0):
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': { 'platform_conf': {
'hello': 'world', 'hello': 'world',
'invalid': 'extra', 'invalid': 'extra',
@ -140,7 +144,7 @@ class TestBootstrap:
self.hass.config.components.remove('platform_conf') self.hass.config.components.remove('platform_conf')
with assert_setup_component(1): with assert_setup_component(1):
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': { 'platform_conf': {
'platform': 'whatever', 'platform': 'whatever',
'hello': 'world', 'hello': 'world',
@ -153,7 +157,7 @@ class TestBootstrap:
self.hass.config.components.remove('platform_conf') self.hass.config.components.remove('platform_conf')
with assert_setup_component(0): with assert_setup_component(0):
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': { 'platform_conf': {
'platform': 'not_existing', 'platform': 'not_existing',
'hello': 'world', 'hello': 'world',
@ -163,7 +167,7 @@ class TestBootstrap:
self.hass.config.components.remove('platform_conf') self.hass.config.components.remove('platform_conf')
with assert_setup_component(1): with assert_setup_component(1):
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': { 'platform_conf': {
'platform': 'whatever', 'platform': 'whatever',
'hello': 'world', 'hello': 'world',
@ -173,7 +177,7 @@ class TestBootstrap:
self.hass.config.components.remove('platform_conf') self.hass.config.components.remove('platform_conf')
with assert_setup_component(1): with assert_setup_component(1):
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': [{ 'platform_conf': [{
'platform': 'whatever', 'platform': 'whatever',
'hello': 'world', 'hello': 'world',
@ -184,13 +188,13 @@ class TestBootstrap:
# Any falsey platform config will be ignored (None, {}, etc) # Any falsey platform config will be ignored (None, {}, etc)
with assert_setup_component(0) as config: with assert_setup_component(0) as config:
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': None 'platform_conf': None
}) })
assert 'platform_conf' in self.hass.config.components assert 'platform_conf' in self.hass.config.components
assert not config['platform_conf'] # empty assert not config['platform_conf'] # empty
assert bootstrap._setup_component(self.hass, 'platform_conf', { assert bootstrap.setup_component(self.hass, 'platform_conf', {
'platform_conf': {} 'platform_conf': {}
}) })
assert 'platform_conf' in self.hass.config.components assert 'platform_conf' in self.hass.config.components
@ -235,10 +239,9 @@ class TestBootstrap:
"""Setup the component.""" """Setup the component."""
result.append(bootstrap.setup_component(self.hass, 'comp')) result.append(bootstrap.setup_component(self.hass, 'comp'))
with bootstrap._SETUP_LOCK: thread = threading.Thread(target=setup_component)
thread = threading.Thread(target=setup_component) thread.start()
thread.start() self.hass.config.components.append('comp')
self.hass.config.components.append('comp')
thread.join() thread.join()
@ -250,19 +253,19 @@ class TestBootstrap:
deps = ['non_existing'] deps = ['non_existing']
loader.set_component('comp', MockModule('comp', dependencies=deps)) loader.set_component('comp', MockModule('comp', dependencies=deps))
assert not bootstrap._setup_component(self.hass, 'comp', {}) assert not bootstrap.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components assert 'comp' not in self.hass.config.components
self.hass.config.components.append('non_existing') loader.set_component('non_existing', MockModule('non_existing'))
assert bootstrap._setup_component(self.hass, 'comp', {}) assert bootstrap.setup_component(self.hass, 'comp', {})
def test_component_failing_setup(self): def test_component_failing_setup(self):
"""Test component that fails setup.""" """Test component that fails setup."""
loader.set_component( loader.set_component(
'comp', MockModule('comp', setup=lambda hass, config: False)) 'comp', MockModule('comp', setup=lambda hass, config: False))
assert not bootstrap._setup_component(self.hass, 'comp', {}) assert not bootstrap.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components assert 'comp' not in self.hass.config.components
def test_component_exception_setup(self): def test_component_exception_setup(self):
@ -273,18 +276,17 @@ class TestBootstrap:
loader.set_component('comp', MockModule('comp', setup=exception_setup)) loader.set_component('comp', MockModule('comp', setup=exception_setup))
assert not bootstrap._setup_component(self.hass, 'comp', {}) assert not bootstrap.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components assert 'comp' not in self.hass.config.components
def test_home_assistant_core_config_validation(self): def test_home_assistant_core_config_validation(self):
"""Test if we pass in wrong information for HA conf.""" """Test if we pass in wrong information for HA conf."""
# Extensive HA conf validation testing is done in test_config.py # Extensive HA conf validation testing is done in test_config.py
hass = get_test_home_assistant()
assert None is bootstrap.from_config_dict({ assert None is bootstrap.from_config_dict({
'homeassistant': { 'homeassistant': {
'latitude': 'some string' 'latitude': 'some string'
} }
}, hass=hass) })
def test_component_setup_with_validation_and_dependency(self): def test_component_setup_with_validation_and_dependency(self):
"""Test all config is passed to dependencies.""" """Test all config is passed to dependencies."""
@ -316,7 +318,7 @@ class TestBootstrap:
'valid': True, 'valid': True,
}, extra=vol.PREVENT_EXTRA) }, extra=vol.PREVENT_EXTRA)
mock_setup = mock.MagicMock() mock_setup = mock.MagicMock(spec_set=True)
loader.set_component( loader.set_component(
'switch.platform_a', 'switch.platform_a',

View File

@ -14,6 +14,7 @@ from homeassistant.const import (
CONF_TIME_ZONE, CONF_ELEVATION, CONF_CUSTOMIZE, __version__, CONF_TIME_ZONE, CONF_ELEVATION, CONF_CUSTOMIZE, __version__,
CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT) CONF_UNIT_SYSTEM_METRIC, CONF_UNIT_SYSTEM_IMPERIAL, CONF_TEMPERATURE_UNIT)
from homeassistant.util import location as location_util, dt as dt_util from homeassistant.util import location as location_util, dt as dt_util
from homeassistant.util.async import run_coroutine_threadsafe
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from tests.common import ( from tests.common import (
@ -34,6 +35,10 @@ def create_file(path):
class TestConfig(unittest.TestCase): class TestConfig(unittest.TestCase):
"""Test the configutils.""" """Test the configutils."""
def setUp(self): # pylint: disable=invalid-name
"""Initialize a test Home Assistant instance."""
self.hass = get_test_home_assistant()
def tearDown(self): # pylint: disable=invalid-name def tearDown(self): # pylint: disable=invalid-name
"""Clean up.""" """Clean up."""
dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE
@ -44,8 +49,7 @@ class TestConfig(unittest.TestCase):
if os.path.isfile(VERSION_PATH): if os.path.isfile(VERSION_PATH):
os.remove(VERSION_PATH) os.remove(VERSION_PATH)
if hasattr(self, 'hass'): self.hass.stop()
self.hass.stop()
def test_create_default_config(self): def test_create_default_config(self):
"""Test creation of default config.""" """Test creation of default config."""
@ -165,6 +169,7 @@ class TestConfig(unittest.TestCase):
self.assertTrue(mock_print.called) self.assertTrue(mock_print.called)
def test_core_config_schema(self): def test_core_config_schema(self):
"""Test core config schema."""
for value in ( for value in (
{CONF_UNIT_SYSTEM: 'K'}, {CONF_UNIT_SYSTEM: 'K'},
{'time_zone': 'non-exist'}, {'time_zone': 'non-exist'},
@ -191,14 +196,14 @@ class TestConfig(unittest.TestCase):
def test_entity_customization(self): def test_entity_customization(self):
"""Test entity customization through configuration.""" """Test entity customization through configuration."""
self.hass = get_test_home_assistant()
config = {CONF_LATITUDE: 50, config = {CONF_LATITUDE: 50,
CONF_LONGITUDE: 50, CONF_LONGITUDE: 50,
CONF_NAME: 'Test', CONF_NAME: 'Test',
CONF_CUSTOMIZE: {'test.test': {'hidden': True}}} CONF_CUSTOMIZE: {'test.test': {'hidden': True}}}
config_util.process_ha_core_config(self.hass, config) run_coroutine_threadsafe(
config_util.async_process_ha_core_config(self.hass, config),
self.hass.loop).result()
entity = Entity() entity = Entity()
entity.entity_id = 'test.test' entity.entity_id = 'test.test'
@ -224,7 +229,6 @@ class TestConfig(unittest.TestCase):
opened_file = mock_open.return_value opened_file = mock_open.return_value
opened_file.readline.return_value = ha_version opened_file.readline.return_value = ha_version
self.hass = get_test_home_assistant()
self.hass.config.path = mock.Mock() self.hass.config.path = mock.Mock()
config_util.process_ha_config_upgrade(self.hass) config_util.process_ha_config_upgrade(self.hass)
@ -254,7 +258,6 @@ class TestConfig(unittest.TestCase):
opened_file = mock_open.return_value opened_file = mock_open.return_value
opened_file.readline.return_value = ha_version opened_file.readline.return_value = ha_version
self.hass = get_test_home_assistant()
self.hass.config.path = mock.Mock() self.hass.config.path = mock.Mock()
config_util.process_ha_config_upgrade(self.hass) config_util.process_ha_config_upgrade(self.hass)
@ -264,82 +267,91 @@ class TestConfig(unittest.TestCase):
def test_loading_configuration(self): def test_loading_configuration(self):
"""Test loading core config onto hass object.""" """Test loading core config onto hass object."""
config = Config() self.hass.config = mock.Mock()
hass = mock.Mock(config=config)
config_util.process_ha_core_config(hass, { run_coroutine_threadsafe(
'latitude': 60, config_util.async_process_ha_core_config(self.hass, {
'longitude': 50, 'latitude': 60,
'elevation': 25, 'longitude': 50,
'name': 'Huis', 'elevation': 25,
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL, 'name': 'Huis',
'time_zone': 'America/New_York', CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL,
}) 'time_zone': 'America/New_York',
}), self.hass.loop).result()
assert config.latitude == 60 assert self.hass.config.latitude == 60
assert config.longitude == 50 assert self.hass.config.longitude == 50
assert config.elevation == 25 assert self.hass.config.elevation == 25
assert config.location_name == 'Huis' assert self.hass.config.location_name == 'Huis'
assert config.units.name == CONF_UNIT_SYSTEM_IMPERIAL assert self.hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
assert config.time_zone.zone == 'America/New_York' assert self.hass.config.time_zone.zone == 'America/New_York'
def test_loading_configuration_temperature_unit(self): def test_loading_configuration_temperature_unit(self):
"""Test backward compatibility when loading core config.""" """Test backward compatibility when loading core config."""
config = Config() self.hass.config = mock.Mock()
hass = mock.Mock(config=config)
config_util.process_ha_core_config(hass, { run_coroutine_threadsafe(
'latitude': 60, config_util.async_process_ha_core_config(self.hass, {
'longitude': 50, 'latitude': 60,
'elevation': 25, 'longitude': 50,
'name': 'Huis', 'elevation': 25,
CONF_TEMPERATURE_UNIT: 'C', 'name': 'Huis',
'time_zone': 'America/New_York', CONF_TEMPERATURE_UNIT: 'C',
}) 'time_zone': 'America/New_York',
}), self.hass.loop).result()
assert config.latitude == 60 assert self.hass.config.latitude == 60
assert config.longitude == 50 assert self.hass.config.longitude == 50
assert config.elevation == 25 assert self.hass.config.elevation == 25
assert config.location_name == 'Huis' assert self.hass.config.location_name == 'Huis'
assert config.units.name == CONF_UNIT_SYSTEM_METRIC assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
assert config.time_zone.zone == 'America/New_York' assert self.hass.config.time_zone.zone == 'America/New_York'
@mock.patch('homeassistant.util.location.detect_location_info', @mock.patch('homeassistant.util.location.detect_location_info',
return_value=location_util.LocationInfo( autospec=True, return_value=location_util.LocationInfo(
'0.0.0.0', 'US', 'United States', 'CA', 'California', '0.0.0.0', 'US', 'United States', 'CA', 'California',
'San Diego', '92122', 'America/Los_Angeles', 32.8594, 'San Diego', '92122', 'America/Los_Angeles', 32.8594,
-117.2073, True)) -117.2073, True))
@mock.patch('homeassistant.util.location.elevation', return_value=101) @mock.patch('homeassistant.util.location.elevation',
autospec=True, return_value=101)
def test_discovering_configuration(self, mock_detect, mock_elevation): def test_discovering_configuration(self, mock_detect, mock_elevation):
"""Test auto discovery for missing core configs.""" """Test auto discovery for missing core configs."""
config = Config() self.hass.config.latitude = None
hass = mock.Mock(config=config) self.hass.config.longitude = None
self.hass.config.elevation = None
self.hass.config.location_name = None
self.hass.config.time_zone = None
config_util.process_ha_core_config(hass, {}) run_coroutine_threadsafe(
config_util.async_process_ha_core_config(
self.hass, {}), self.hass.loop
).result()
assert config.latitude == 32.8594 assert self.hass.config.latitude == 32.8594
assert config.longitude == -117.2073 assert self.hass.config.longitude == -117.2073
assert config.elevation == 101 assert self.hass.config.elevation == 101
assert config.location_name == 'San Diego' assert self.hass.config.location_name == 'San Diego'
assert config.units.name == CONF_UNIT_SYSTEM_METRIC assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
assert config.units.is_metric assert self.hass.config.units.is_metric
assert config.time_zone.zone == 'America/Los_Angeles' assert self.hass.config.time_zone.zone == 'America/Los_Angeles'
@mock.patch('homeassistant.util.location.detect_location_info', @mock.patch('homeassistant.util.location.detect_location_info',
return_value=None) autospec=True, return_value=None)
@mock.patch('homeassistant.util.location.elevation', return_value=0) @mock.patch('homeassistant.util.location.elevation', return_value=0)
def test_discovering_configuration_auto_detect_fails(self, mock_detect, def test_discovering_configuration_auto_detect_fails(self, mock_detect,
mock_elevation): mock_elevation):
"""Test config remains unchanged if discovery fails.""" """Test config remains unchanged if discovery fails."""
config = Config() self.hass.config = Config()
hass = mock.Mock(config=config)
config_util.process_ha_core_config(hass, {}) run_coroutine_threadsafe(
config_util.async_process_ha_core_config(
self.hass, {}), self.hass.loop
).result()
blankConfig = Config() blankConfig = Config()
assert config.latitude == blankConfig.latitude assert self.hass.config.latitude == blankConfig.latitude
assert config.longitude == blankConfig.longitude assert self.hass.config.longitude == blankConfig.longitude
assert config.elevation == blankConfig.elevation assert self.hass.config.elevation == blankConfig.elevation
assert config.location_name == blankConfig.location_name assert self.hass.config.location_name == blankConfig.location_name
assert config.units == blankConfig.units assert self.hass.config.units == blankConfig.units
assert config.time_zone == blankConfig.time_zone assert self.hass.config.time_zone == blankConfig.time_zone