mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 13:47:35 +00:00
Async bootstrap / component init (#3991)
* Async bootstrap * Adress comments * Fix tests * More fixes * Tests fixes
This commit is contained in:
parent
d9999f36e8
commit
d5368f6f78
@ -1,11 +1,10 @@
|
||||
"""Provides methods to bootstrap a home assistant instance."""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from threading import RLock
|
||||
|
||||
from types import ModuleType
|
||||
from typing import Any, Optional, Dict
|
||||
@ -19,6 +18,8 @@ import homeassistant.config as conf_util
|
||||
import homeassistant.core as core
|
||||
import homeassistant.loader as loader
|
||||
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.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
@ -26,7 +27,6 @@ from homeassistant.helpers import (
|
||||
event_decorators, service, config_per_platform, extract_domain_configs)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_SETUP_LOCK = RLock()
|
||||
_CURRENT_SETUP = []
|
||||
|
||||
ATTR_COMPONENT = 'component'
|
||||
@ -39,11 +39,23 @@ _PERSISTENT_VALIDATION = set()
|
||||
def setup_component(hass: core.HomeAssistant, domain: str,
|
||||
config: Optional[Dict]=None) -> bool:
|
||||
"""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:
|
||||
_LOGGER.debug('Component %s already set up.', domain)
|
||||
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:
|
||||
config = defaultdict(dict)
|
||||
@ -55,7 +67,8 @@ def setup_component(hass: core.HomeAssistant, domain: str,
|
||||
return False
|
||||
|
||||
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)
|
||||
return False
|
||||
|
||||
@ -64,7 +77,11 @@ def setup_component(hass: core.HomeAssistant, domain: str,
|
||||
|
||||
def _handle_requirements(hass: core.HomeAssistant, component,
|
||||
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'):
|
||||
return True
|
||||
|
||||
@ -77,65 +94,82 @@ def _handle_requirements(hass: core.HomeAssistant, component,
|
||||
return True
|
||||
|
||||
|
||||
def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
|
||||
"""Setup a component for Home Assistant."""
|
||||
@asyncio.coroutine
|
||||
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-statements
|
||||
if domain in hass.config.components:
|
||||
return True
|
||||
|
||||
with _SETUP_LOCK:
|
||||
# It might have been loaded while waiting for lock
|
||||
if domain in hass.config.components:
|
||||
return True
|
||||
if domain in _CURRENT_SETUP:
|
||||
_LOGGER.error('Attempt made to setup %s during setup of %s',
|
||||
domain, domain)
|
||||
return False
|
||||
|
||||
if domain in _CURRENT_SETUP:
|
||||
_LOGGER.error('Attempt made to setup %s during setup of %s',
|
||||
domain, domain)
|
||||
config = yield from async_prepare_setup_component(hass, config, 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
|
||||
|
||||
config = prepare_setup_component(hass, config, domain)
|
||||
|
||||
if config is None:
|
||||
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)
|
||||
|
||||
component = loader.get_component(domain)
|
||||
_CURRENT_SETUP.append(domain)
|
||||
hass.config.components.append(component.DOMAIN)
|
||||
|
||||
try:
|
||||
result = component.setup(hass, config)
|
||||
if result is False:
|
||||
_LOGGER.error('component %s failed to initialize', domain)
|
||||
return False
|
||||
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)
|
||||
# Assumption: if a component does not depend on groups
|
||||
# it communicates with devices
|
||||
if 'group' not in getattr(component, 'DEPENDENCIES', []) and \
|
||||
hass.pool.worker_count <= 10:
|
||||
hass.pool.add_worker()
|
||||
|
||||
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
|
||||
# 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
|
||||
return True
|
||||
|
||||
|
||||
def prepare_setup_component(hass: core.HomeAssistant, config: dict,
|
||||
domain: str):
|
||||
"""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
|
||||
component = loader.get_component(domain)
|
||||
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
|
||||
@ -151,7 +185,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
|
||||
try:
|
||||
config = component.CONFIG_SCHEMA(config)
|
||||
except vol.Invalid as ex:
|
||||
log_exception(ex, domain, config, hass)
|
||||
async_log_exception(ex, domain, config, hass)
|
||||
return None
|
||||
|
||||
elif hasattr(component, 'PLATFORM_SCHEMA'):
|
||||
@ -161,7 +195,7 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
|
||||
try:
|
||||
p_validated = component.PLATFORM_SCHEMA(p_config)
|
||||
except vol.Invalid as ex:
|
||||
log_exception(ex, domain, config, hass)
|
||||
async_log_exception(ex, domain, config, hass)
|
||||
continue
|
||||
|
||||
# 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)
|
||||
continue
|
||||
|
||||
platform = prepare_setup_platform(hass, config, domain,
|
||||
p_name)
|
||||
platform = yield from async_prepare_setup_platform(
|
||||
hass, config, domain, p_name)
|
||||
|
||||
if platform is None:
|
||||
continue
|
||||
@ -180,10 +214,11 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
|
||||
# Validate platform specific schema
|
||||
if hasattr(platform, 'PLATFORM_SCHEMA'):
|
||||
try:
|
||||
# pylint: disable=no-member
|
||||
p_validated = platform.PLATFORM_SCHEMA(p_validated)
|
||||
except vol.Invalid as ex:
|
||||
log_exception(ex, '{}.{}'.format(domain, p_name),
|
||||
p_validated, hass)
|
||||
async_log_exception(ex, '{}.{}'.format(domain, p_name),
|
||||
p_validated, hass)
|
||||
continue
|
||||
|
||||
platforms.append(p_validated)
|
||||
@ -195,7 +230,9 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
|
||||
if key not in filter_keys}
|
||||
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 config
|
||||
@ -204,7 +241,22 @@ def prepare_setup_component(hass: core.HomeAssistant, config: dict,
|
||||
def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
|
||||
platform_name: str) -> Optional[ModuleType]:
|
||||
"""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)
|
||||
|
||||
@ -218,7 +270,7 @@ def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
|
||||
message = ('Unable to find the following platforms: ' +
|
||||
', '.join(list(_PERSISTENT_PLATFORMS)) +
|
||||
'(please check your configuration)')
|
||||
persistent_notification.create(
|
||||
persistent_notification.async_create(
|
||||
hass, message, 'Invalid platforms', 'platform_errors')
|
||||
return None
|
||||
|
||||
@ -228,14 +280,17 @@ def prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
|
||||
|
||||
# Load 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(
|
||||
'Unable to prepare setup for platform %s because '
|
||||
'dependency %s could not be initialized', platform_path,
|
||||
component)
|
||||
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 platform
|
||||
@ -261,15 +316,50 @@ def from_config_dict(config: Dict[str, Any],
|
||||
hass.config.config_dir = 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, {})
|
||||
|
||||
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:
|
||||
log_exception(ex, 'homeassistant', core_config, hass)
|
||||
async_log_exception(ex, 'homeassistant', core_config, hass)
|
||||
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:
|
||||
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. '
|
||||
'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.
|
||||
# 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()
|
||||
if key != core.DOMAIN)
|
||||
|
||||
# Setup in a thread to avoid blocking
|
||||
def component_setup():
|
||||
"""Set up a component."""
|
||||
if not core_components.setup(hass, config):
|
||||
_LOGGER.error('Home Assistant core failed to initialize. '
|
||||
'Further initialization aborted.')
|
||||
return hass
|
||||
# setup components
|
||||
# pylint: disable=not-an-iterable
|
||||
res = yield from core_components.async_setup(hass, config)
|
||||
if not res:
|
||||
_LOGGER.error('Home Assistant core failed to initialize. '
|
||||
'Further initialization aborted.')
|
||||
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
|
||||
event_decorators.HASS = hass
|
||||
service.HASS = hass
|
||||
# Give event decorators access to HASS
|
||||
event_decorators.HASS = hass
|
||||
service.HASS = hass
|
||||
|
||||
# Setup the components
|
||||
for domain in loader.load_order_components(components):
|
||||
_setup_component(hass, domain, config)
|
||||
|
||||
hass.loop.run_until_complete(
|
||||
hass.loop.run_in_executor(None, component_setup)
|
||||
)
|
||||
# Setup the components
|
||||
for domain in loader.load_order_components(components):
|
||||
yield from _async_setup_component(hass, domain, config)
|
||||
|
||||
return hass
|
||||
|
||||
@ -331,27 +418,62 @@ def from_config_file(config_path: str,
|
||||
if hass is None:
|
||||
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
|
||||
config_dir = os.path.abspath(os.path.dirname(config_path))
|
||||
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)
|
||||
|
||||
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:
|
||||
return None
|
||||
finally:
|
||||
clear_secret_cache()
|
||||
|
||||
return from_config_dict(config_dict, hass, enable_log=False,
|
||||
skip_pip=skip_pip)
|
||||
hass = yield from async_from_config_dict(
|
||||
config_dict, hass, enable_log=False, skip_pip=skip_pip)
|
||||
return hass
|
||||
|
||||
|
||||
def enable_logging(hass: core.HomeAssistant, verbose: bool=False,
|
||||
log_rotate_days=None) -> None:
|
||||
"""Setup the logging."""
|
||||
"""Setup the logging.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
fmt = ("%(log_color)s%(asctime)s %(levelname)s (%(threadName)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)
|
||||
|
||||
|
||||
def _ensure_loader_prepared(hass: core.HomeAssistant) -> None:
|
||||
"""Ensure Home Assistant loader is prepared."""
|
||||
if not loader.PREPARED:
|
||||
loader.prepare(hass)
|
||||
|
||||
|
||||
def log_exception(ex, domain, config, hass=None):
|
||||
def log_exception(ex, domain, config, hass):
|
||||
"""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)
|
||||
if hass is not None:
|
||||
_PERSISTENT_VALIDATION.add(domain)
|
||||
message = ('The following platforms contain invalid configuration: ' +
|
||||
', '.join(list(_PERSISTENT_VALIDATION)) +
|
||||
' (please check your configuration)')
|
||||
persistent_notification.create(
|
||||
hass, message, 'Invalid config', 'invalid_config')
|
||||
_PERSISTENT_VALIDATION.add(domain)
|
||||
message = ('The following platforms contain invalid configuration: ' +
|
||||
', '.join(list(_PERSISTENT_VALIDATION)) +
|
||||
' (please check your configuration). ')
|
||||
persistent_notification.async_create(
|
||||
hass, message, 'Invalid config', 'invalid_config')
|
||||
|
||||
if 'extra keys not allowed' in ex.error_message:
|
||||
message += '[{}] is an invalid option for [{}]. Check: {}->{}.'\
|
||||
.format(ex.path[-1], domain, domain,
|
||||
'->'.join('%s' % m for m in ex.path))
|
||||
'->'.join(str(m) for m in ex.path))
|
||||
else:
|
||||
message += '{}.'.format(humanize_error(config, ex))
|
||||
|
||||
domain_config = config.get(domain, config)
|
||||
message += " (See {}:{})".format(
|
||||
message += " (See {}:{}). ".format(
|
||||
getattr(domain_config, '__config_file__', '?'),
|
||||
getattr(domain_config, '__line__', '?'))
|
||||
|
||||
if domain != 'homeassistant':
|
||||
message += (' Please check the docs at '
|
||||
message += ('Please check the docs at '
|
||||
'https://home-assistant.io/components/{}/'.format(domain))
|
||||
|
||||
_LOGGER.error(message)
|
||||
|
||||
|
||||
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')
|
||||
if deps_dir not in sys.path:
|
||||
sys.path.insert(0, os.path.join(config_dir, 'deps'))
|
||||
|
@ -7,6 +7,7 @@ Component design guidelines:
|
||||
format "<DOMAIN>.<OBJECT_ID>".
|
||||
- Each component should publish services only under its own domain.
|
||||
"""
|
||||
import asyncio
|
||||
import itertools as it
|
||||
import logging
|
||||
|
||||
@ -79,8 +80,10 @@ def reload_core_config(hass):
|
||||
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."""
|
||||
@asyncio.coroutine
|
||||
def handle_turn_service(service):
|
||||
"""Method to handle calls to homeassistant.turn_on/off."""
|
||||
entity_ids = extract_entity_ids(hass, service)
|
||||
@ -96,6 +99,8 @@ def setup(hass, config):
|
||||
by_domain = it.groupby(sorted(entity_ids),
|
||||
lambda item: ha.split_entity_id(item)[0])
|
||||
|
||||
tasks = []
|
||||
|
||||
for domain, ent_ids in by_domain:
|
||||
# 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
|
||||
@ -111,27 +116,34 @@ def setup(hass, config):
|
||||
# ent_ids is a generator, convert it to a list.
|
||||
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)
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TURN_ON, handle_turn_service)
|
||||
hass.services.register(ha.DOMAIN, SERVICE_TOGGLE, handle_turn_service)
|
||||
yield from asyncio.gather(*tasks, loop=hass.loop)
|
||||
|
||||
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):
|
||||
"""Service handler for reloading core config."""
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant import config as conf_util
|
||||
|
||||
try:
|
||||
path = conf_util.find_config_file(hass.config.config_dir)
|
||||
conf = conf_util.load_yaml_config_file(path)
|
||||
conf = yield from conf_util.async_hass_config_yaml(hass)
|
||||
except HomeAssistantError as err:
|
||||
_LOGGER.error(err)
|
||||
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,
|
||||
handle_reload_config)
|
||||
hass.services.async_register(
|
||||
ha.DOMAIN, SERVICE_RELOAD_CORE_CONFIG, handle_reload_config)
|
||||
|
||||
return True
|
||||
|
@ -11,7 +11,6 @@ import os
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.bootstrap import prepare_setup_platform
|
||||
from homeassistant import config as conf_util
|
||||
from homeassistant.const import (
|
||||
@ -25,7 +24,6 @@ from homeassistant.helpers.entity_component import EntityComponent
|
||||
from homeassistant.loader import get_platform
|
||||
from homeassistant.util.dt import utcnow
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.util.async import run_coroutine_threadsafe
|
||||
|
||||
DOMAIN = 'automation'
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
@ -144,42 +142,50 @@ def reload(hass):
|
||||
hass.services.call(DOMAIN, SERVICE_RELOAD)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Setup the automation."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass,
|
||||
group_name=GROUP_NAME_ALL_AUTOMATIONS)
|
||||
|
||||
success = run_coroutine_threadsafe(
|
||||
_async_process_config(hass, config, component), hass.loop).result()
|
||||
success = yield from _async_process_config(hass, config, component)
|
||||
|
||||
if not success:
|
||||
return False
|
||||
|
||||
descriptions = conf_util.load_yaml_config_file(
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
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):
|
||||
"""Handle automation triggers."""
|
||||
tasks = []
|
||||
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))
|
||||
yield from asyncio.gather(*tasks, loop=hass.loop)
|
||||
|
||||
@callback
|
||||
@asyncio.coroutine
|
||||
def turn_onoff_service_handler(service_call):
|
||||
"""Handle automation turn on/off service calls."""
|
||||
tasks = []
|
||||
method = 'async_{}'.format(service_call.service)
|
||||
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):
|
||||
"""Handle automation toggle service calls."""
|
||||
tasks = []
|
||||
for entity in component.async_extract_from_service(service_call):
|
||||
if entity.is_on:
|
||||
hass.loop.create_task(entity.async_turn_off())
|
||||
tasks.append(entity.async_turn_off())
|
||||
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
|
||||
def reload_service_handler(service_call):
|
||||
@ -187,24 +193,24 @@ def setup(hass, config):
|
||||
conf = yield from component.async_prepare_reload()
|
||||
if conf is None:
|
||||
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,
|
||||
descriptions.get(SERVICE_TRIGGER),
|
||||
schema=TRIGGER_SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_TRIGGER, trigger_service_handler,
|
||||
descriptions.get(SERVICE_TRIGGER), schema=TRIGGER_SERVICE_SCHEMA)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_RELOAD, reload_service_handler,
|
||||
descriptions.get(SERVICE_RELOAD),
|
||||
schema=RELOAD_SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_RELOAD, reload_service_handler,
|
||||
descriptions.get(SERVICE_RELOAD), schema=RELOAD_SERVICE_SCHEMA)
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_TOGGLE, toggle_service_handler,
|
||||
descriptions.get(SERVICE_TOGGLE),
|
||||
schema=SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_TOGGLE, toggle_service_handler,
|
||||
descriptions.get(SERVICE_TOGGLE), schema=SERVICE_SCHEMA)
|
||||
|
||||
for service in (SERVICE_TURN_ON, SERVICE_TURN_OFF):
|
||||
hass.services.register(DOMAIN, service, turn_onoff_service_handler,
|
||||
descriptions.get(service),
|
||||
schema=SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, service, turn_onoff_service_handler,
|
||||
descriptions.get(service), schema=SERVICE_SCHEMA)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -114,7 +114,7 @@ def setup(hass: HomeAssistantType, config: ConfigType):
|
||||
try:
|
||||
conf = config.get(DOMAIN, [])
|
||||
except vol.Invalid as ex:
|
||||
log_exception(ex, DOMAIN, config)
|
||||
log_exception(ex, DOMAIN, config, hass)
|
||||
return False
|
||||
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_id'] = cv.slugify(dev_id)
|
||||
except vol.Invalid as exp:
|
||||
log_exception(exp, dev_id, devices)
|
||||
log_exception(exp, dev_id, devices, hass)
|
||||
else:
|
||||
result.append(Device(hass, **device))
|
||||
return result
|
||||
|
@ -144,15 +144,17 @@ def get_entity_ids(hass, entity_id, domain_filter=None):
|
||||
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."""
|
||||
component = EntityComponent(_LOGGER, DOMAIN, hass)
|
||||
|
||||
run_coroutine_threadsafe(
|
||||
_async_process_config(hass, config, component), hass.loop).result()
|
||||
yield from _async_process_config(hass, config, component)
|
||||
|
||||
descriptions = conf_util.load_yaml_config_file(
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
None, conf_util.load_yaml_config_file, os.path.join(
|
||||
os.path.dirname(__file__), 'services.yaml')
|
||||
)
|
||||
|
||||
@asyncio.coroutine
|
||||
def reload_service_handler(service_call):
|
||||
@ -162,9 +164,9 @@ def setup(hass, config):
|
||||
return
|
||||
hass.loop.create_task(_async_process_config(hass, conf, component))
|
||||
|
||||
hass.services.register(DOMAIN, SERVICE_RELOAD, reload_service_handler,
|
||||
descriptions[DOMAIN][SERVICE_RELOAD],
|
||||
schema=RELOAD_SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_RELOAD, reload_service_handler,
|
||||
descriptions[DOMAIN][SERVICE_RELOAD], schema=RELOAD_SERVICE_SCHEMA)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -10,12 +10,13 @@ import logging
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.exceptions import TemplateError
|
||||
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.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'
|
||||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
@ -38,12 +39,12 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
def create(hass, message, title=None, notification_id=None):
|
||||
"""Generate a notification."""
|
||||
run_coroutine_threadsafe(
|
||||
async_create(hass, message, title, notification_id), hass.loop
|
||||
run_callback_threadsafe(
|
||||
hass.loop, async_create, hass, message, title, notification_id
|
||||
).result()
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
@callback
|
||||
def async_create(hass, message, title=None, notification_id=None):
|
||||
"""Generate a notification."""
|
||||
data = {
|
||||
@ -54,11 +55,14 @@ def async_create(hass, message, title=None, notification_id=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."""
|
||||
@callback
|
||||
def create_service(call):
|
||||
"""Handle a create notification service call."""
|
||||
title = call.data.get(ATTR_TITLE)
|
||||
@ -68,13 +72,13 @@ def setup(hass, config):
|
||||
if notification_id is not None:
|
||||
entity_id = ENTITY_ID_FORMAT.format(slugify(notification_id))
|
||||
else:
|
||||
entity_id = generate_entity_id(ENTITY_ID_FORMAT, DEFAULT_OBJECT_ID,
|
||||
hass=hass)
|
||||
entity_id = async_generate_entity_id(
|
||||
ENTITY_ID_FORMAT, DEFAULT_OBJECT_ID, hass=hass)
|
||||
attr = {}
|
||||
if title is not None:
|
||||
try:
|
||||
title.hass = hass
|
||||
title = title.render()
|
||||
title = title.async_render()
|
||||
except TemplateError as ex:
|
||||
_LOGGER.error('Error rendering title %s: %s', title, ex)
|
||||
title = title.template
|
||||
@ -83,17 +87,19 @@ def setup(hass, config):
|
||||
|
||||
try:
|
||||
message.hass = hass
|
||||
message = message.render()
|
||||
message = message.async_render()
|
||||
except TemplateError as ex:
|
||||
_LOGGER.error('Error rendering message %s: %s', message, ex)
|
||||
message = message.template
|
||||
|
||||
hass.states.set(entity_id, message, attr)
|
||||
hass.states.async_set(entity_id, message, attr)
|
||||
|
||||
descriptions = load_yaml_config_file(
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||
hass.services.register(DOMAIN, SERVICE_CREATE, create_service,
|
||||
descriptions[DOMAIN][SERVICE_CREATE],
|
||||
SCHEMA_SERVICE_CREATE)
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
None, load_yaml_config_file, os.path.join(
|
||||
os.path.dirname(__file__), 'services.yaml')
|
||||
)
|
||||
hass.services.async_register(DOMAIN, SERVICE_CREATE, create_service,
|
||||
descriptions[DOMAIN][SERVICE_CREATE],
|
||||
SCHEMA_SERVICE_CREATE)
|
||||
|
||||
return True
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Module to help with parsing and generating configuration files."""
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import shutil
|
||||
@ -180,6 +181,24 @@ def create_default_config(config_dir, detect_location=True):
|
||||
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):
|
||||
"""Look in given directory for supported configuration files."""
|
||||
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):
|
||||
"""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)
|
||||
|
||||
try:
|
||||
@ -225,8 +248,12 @@ def process_ha_config_upgrade(hass):
|
||||
outp.write(__version__)
|
||||
|
||||
|
||||
def process_ha_core_config(hass, config):
|
||||
"""Process the [homeassistant] section from the config."""
|
||||
@asyncio.coroutine
|
||||
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
|
||||
config = CORE_CONFIG_SCHEMA(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 None in (hac.latitude, hac.longitude, hac.units,
|
||||
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:
|
||||
_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 \
|
||||
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
|
||||
discovered.append(('elevation', elevation))
|
||||
|
||||
|
@ -56,7 +56,10 @@ def async_generate_entity_id(entity_id_format: str, name: Optional[str],
|
||||
|
||||
|
||||
def set_customize(customize: Dict[str, Any]) -> None:
|
||||
"""Overwrite all current customize settings."""
|
||||
"""Overwrite all current customize settings.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
global _OVERWRITE
|
||||
|
||||
_OVERWRITE = {key.lower(): val for key, val in customize.items()}
|
||||
|
@ -2,8 +2,8 @@
|
||||
import asyncio
|
||||
|
||||
from homeassistant import config as conf_util
|
||||
from homeassistant.bootstrap import (prepare_setup_platform,
|
||||
prepare_setup_component)
|
||||
from homeassistant.bootstrap import (
|
||||
async_prepare_setup_platform, async_prepare_setup_component)
|
||||
from homeassistant.const import (
|
||||
ATTR_ENTITY_ID, CONF_SCAN_INTERVAL, CONF_ENTITY_NAMESPACE,
|
||||
DEVICE_DEFAULT_NAME)
|
||||
@ -118,10 +118,8 @@ class EntityComponent(object):
|
||||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
platform = yield from self.hass.loop.run_in_executor(
|
||||
None, prepare_setup_platform, self.hass, self.config, self.domain,
|
||||
platform_type
|
||||
)
|
||||
platform = yield from async_prepare_setup_platform(
|
||||
self.hass, self.config, self.domain, platform_type)
|
||||
|
||||
if platform is None:
|
||||
return
|
||||
@ -238,20 +236,8 @@ class EntityComponent(object):
|
||||
|
||||
def prepare_reload(self):
|
||||
"""Prepare reloading this entity component."""
|
||||
try:
|
||||
path = conf_util.find_config_file(self.hass.config.config_dir)
|
||||
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
|
||||
return run_coroutine_threadsafe(
|
||||
self.async_prepare_reload(), loop=self.hass.loop).result()
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_prepare_reload(self):
|
||||
@ -259,9 +245,20 @@ class EntityComponent(object):
|
||||
|
||||
This method must be run in the event loop.
|
||||
"""
|
||||
conf = yield from self.hass.loop.run_in_executor(
|
||||
None, self.prepare_reload
|
||||
)
|
||||
try:
|
||||
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
|
||||
|
||||
|
||||
|
@ -40,7 +40,11 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
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
|
||||
|
||||
# Load the built-in components
|
||||
@ -81,14 +85,20 @@ def prepare(hass: 'HomeAssistant'):
|
||||
|
||||
|
||||
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()
|
||||
|
||||
_COMPONENT_CACHE[comp_name] = component
|
||||
|
||||
|
||||
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))
|
||||
|
||||
|
||||
@ -97,6 +107,8 @@ def get_component(comp_name) -> Optional[ModuleType]:
|
||||
|
||||
Looks in config dir first, then built-in components.
|
||||
Only returns it if also found to be valid.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
if comp_name in _COMPONENT_CACHE:
|
||||
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
|
||||
the group component will be loaded before the group component.
|
||||
- returns an OrderedSet load order.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
_check_prepared()
|
||||
|
||||
@ -192,13 +206,18 @@ def load_order_component(comp_name: str) -> OrderedSet:
|
||||
|
||||
Raises HomeAssistantError if a circular dependency is detected.
|
||||
Returns an empty list if component could not be loaded.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
return _load_order_component(comp_name, OrderedSet(), set())
|
||||
|
||||
|
||||
def _load_order_component(comp_name: str, load_order: 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)
|
||||
|
||||
# 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:
|
||||
"""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:
|
||||
_LOGGER.warning((
|
||||
"You did not call loader.prepare() yet. "
|
||||
|
@ -26,8 +26,8 @@ MOCKS = {
|
||||
'load*': ("homeassistant.config.load_yaml", yaml.load_yaml),
|
||||
'get': ("homeassistant.loader.get_component", loader.get_component),
|
||||
'secrets': ("homeassistant.util.yaml._secret_yaml", yaml._secret_yaml),
|
||||
'except': ("homeassistant.bootstrap.log_exception",
|
||||
bootstrap.log_exception)
|
||||
'except': ("homeassistant.bootstrap.async_log_exception",
|
||||
bootstrap.async_log_exception)
|
||||
}
|
||||
SILENCE = (
|
||||
'homeassistant.bootstrap.clear_secret_cache',
|
||||
@ -185,9 +185,15 @@ def check(config_path):
|
||||
# Test if platform/component and overwrite setup
|
||||
if '.' in comp_name:
|
||||
module.setup_platform = mock_setup
|
||||
|
||||
if hasattr(module, 'async_setup_platform'):
|
||||
del module.async_setup_platform
|
||||
else:
|
||||
module.setup = mock_setup
|
||||
|
||||
if hasattr(module, 'async_setup'):
|
||||
del module.async_setup
|
||||
|
||||
return module
|
||||
|
||||
def mock_secrets(ldr, node): # pylint: disable=unused-variable
|
||||
|
@ -23,7 +23,10 @@ DATETIME_RE = re.compile(
|
||||
|
||||
|
||||
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
|
||||
|
||||
# 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]:
|
||||
"""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:
|
||||
return pytz.timezone(time_zone_str)
|
||||
except pytz.exceptions.UnknownTimeZoneError:
|
||||
|
@ -49,7 +49,10 @@ def load_yaml(fname: str) -> Union[List, Dict]:
|
||||
|
||||
|
||||
def clear_secret_cache() -> None:
|
||||
"""Clear the secret cache."""
|
||||
"""Clear the secret cache.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
__SECRET_CACHE.clear()
|
||||
|
||||
|
||||
|
@ -10,7 +10,8 @@ import threading
|
||||
from contextlib import contextmanager
|
||||
|
||||
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.util.unit_system import METRIC_SYSTEM
|
||||
import homeassistant.util.dt as date_util
|
||||
@ -234,6 +235,7 @@ class MockModule(object):
|
||||
self.DOMAIN = domain
|
||||
self.DEPENDENCIES = dependencies or []
|
||||
self.REQUIREMENTS = requirements or []
|
||||
self._setup = setup
|
||||
|
||||
if config_schema is not None:
|
||||
self.CONFIG_SCHEMA = config_schema
|
||||
@ -241,11 +243,11 @@ class MockModule(object):
|
||||
if platform_schema is not None:
|
||||
self.PLATFORM_SCHEMA = platform_schema
|
||||
|
||||
# Setup a mock setup if none given.
|
||||
if setup is None:
|
||||
self.setup = lambda hass, config: True
|
||||
else:
|
||||
self.setup = setup
|
||||
def setup(self, hass, config):
|
||||
"""Setup the component."""
|
||||
if self._setup is not None:
|
||||
return self._setup(hass, config)
|
||||
return True
|
||||
|
||||
|
||||
class MockPlatform(object):
|
||||
@ -366,16 +368,19 @@ def assert_setup_component(count, domain=None):
|
||||
"""
|
||||
config = {}
|
||||
|
||||
@asyncio.coroutine
|
||||
def mock_psc(hass, config_input, domain):
|
||||
"""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)
|
||||
_LOGGER.debug('Configuration for %s, Validated: %s, Original %s',
|
||||
domain, config[domain], config_input.get(domain))
|
||||
return res
|
||||
|
||||
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
|
||||
|
||||
if domain is None:
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the Event automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -28,7 +28,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_event(self):
|
||||
"""Test the firing of events."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -53,7 +53,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_event_with_data(self):
|
||||
"""Test the firing of events with data."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -73,7 +73,7 @@ class TestAutomationEvent(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_event_data_not_matches(self):
|
||||
"""Test firing of event if no match."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -379,21 +379,22 @@ class TestAutomation(unittest.TestCase):
|
||||
self.hass.block_till_done()
|
||||
assert automation.is_on(self.hass, entity_id)
|
||||
|
||||
@patch('homeassistant.config.load_yaml_config_file', return_value={
|
||||
automation.DOMAIN: {
|
||||
'alias': 'bye',
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'test_event2',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation',
|
||||
'data_template': {
|
||||
'event': '{{ trigger.event.event_type }}'
|
||||
@patch('homeassistant.config.load_yaml_config_file', autospec=True,
|
||||
return_value={
|
||||
automation.DOMAIN: {
|
||||
'alias': 'bye',
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'test_event2',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation',
|
||||
'data_template': {
|
||||
'event': '{{ trigger.event.event_type }}'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
def test_reload_config_service(self, mock_load_yaml):
|
||||
"""Test the reload config service."""
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
@ -443,9 +444,8 @@ class TestAutomation(unittest.TestCase):
|
||||
assert len(self.calls) == 2
|
||||
assert self.calls[1].data.get('event') == 'test_event2'
|
||||
|
||||
@patch('homeassistant.config.load_yaml_config_file', return_value={
|
||||
automation.DOMAIN: 'not valid',
|
||||
})
|
||||
@patch('homeassistant.config.load_yaml_config_file', autospec=True,
|
||||
return_value={automation.DOMAIN: 'not valid'})
|
||||
def test_reload_config_when_invalid_config(self, mock_load_yaml):
|
||||
"""Test the reload config service handling invalid config."""
|
||||
with assert_setup_component(1):
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the MQTT automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
from tests.common import (
|
||||
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):
|
||||
"""Test if message is fired on topic match."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'mqtt',
|
||||
@ -58,7 +58,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_topic_and_payload_match(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'mqtt',
|
||||
@ -77,7 +77,7 @@ class TestAutomationMQTT(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_topic_but_no_payload_match(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'mqtt',
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for numeric state automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.automation as automation
|
||||
|
||||
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):
|
||||
""""Test the firing with changed entity."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -58,7 +58,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -81,7 +81,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -101,7 +101,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_above(self):
|
||||
""""Test the firing with changed entity."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -124,7 +124,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 9)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -148,7 +148,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -168,7 +168,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below_range(self):
|
||||
""""Test the firing with changed entity."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -188,7 +188,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below_above_range(self):
|
||||
""""Test the firing with changed entity."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -211,7 +211,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -235,7 +235,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 11)
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -256,7 +256,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_entity_not_match(self):
|
||||
""""Test if not fired with non matching entity."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -275,7 +275,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_below_with_attribute(self):
|
||||
""""Test attributes change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -294,7 +294,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_entity_change_not_below_with_attribute(self):
|
||||
""""Test attributes."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -313,7 +313,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_attribute_change_with_attribute_below(self):
|
||||
""""Test attributes change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -333,7 +333,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_attribute_change_with_attribute_not_below(self):
|
||||
""""Test attributes change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -353,7 +353,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_entity_change_with_attribute_below(self):
|
||||
""""Test attributes change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -373,7 +373,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_entity_change_with_not_attribute_below(self):
|
||||
""""Test attributes change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -393,7 +393,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_fires_on_attr_change_with_attribute_below_and_multiple_attr(self):
|
||||
""""Test attributes change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -414,7 +414,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_template_list(self):
|
||||
""""Test template list."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -436,7 +436,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
|
||||
def test_template_string(self):
|
||||
""""Test template string."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'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):
|
||||
""""Test if not fired changed attributes."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'numeric_state',
|
||||
@ -492,7 +492,7 @@ class TestAutomationNumericState(unittest.TestCase):
|
||||
""""Test if action."""
|
||||
entity_id = 'domain.test_entity'
|
||||
test_state = 10
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -3,11 +3,12 @@ import unittest
|
||||
from datetime import timedelta
|
||||
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.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):
|
||||
@ -34,7 +35,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
self.hass.states.set('test.entity', 'hello')
|
||||
self.hass.block_till_done()
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -67,7 +68,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_from_filter(self):
|
||||
"""Test for firing on entity change with filter."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -86,7 +87,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_to_filter(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -105,7 +106,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_state_filter(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -124,7 +125,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_both_filters(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -144,7 +145,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_to_filter_not_match(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -166,7 +167,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
"""Test for not firing if from filter is not a match."""
|
||||
self.hass.states.set('test.entity', 'bye')
|
||||
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -186,7 +187,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_if_entity_not_match(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -206,7 +207,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
"""Test for to action."""
|
||||
entity_id = 'domain.test_entity'
|
||||
test_state = 'new_state'
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -237,68 +238,72 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fails_setup_if_to_boolean_value(self):
|
||||
"""Test for setup failure for boolean to."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': True,
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': True,
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_if_from_boolean_value(self):
|
||||
"""Test for setup failure for boolean from."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'from': True,
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'from': True,
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_bad_for(self):
|
||||
"""Test for setup failure for bad for."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': 'world',
|
||||
'for': {
|
||||
'invalid': 5
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'to': 'world',
|
||||
'for': {
|
||||
'invalid': 5
|
||||
},
|
||||
},
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_for_without_to(self):
|
||||
"""Test for setup failures for missing to."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
},
|
||||
},
|
||||
},
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
'action': {
|
||||
'service': 'homeassistant.turn_on',
|
||||
}
|
||||
}})
|
||||
|
||||
def test_if_not_fires_on_entity_change_with_for(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -324,7 +329,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_entity_change_with_for(self):
|
||||
"""Test for firing on entity change with for."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'state',
|
||||
@ -353,7 +358,7 @@ class TestAutomationState(unittest.TestCase):
|
||||
with patch('homeassistant.core.dt_util.utcnow') as mock_utcnow:
|
||||
mock_utcnow.return_value = point1
|
||||
self.hass.states.set('test.entity', 'on')
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -384,32 +389,34 @@ class TestAutomationState(unittest.TestCase):
|
||||
|
||||
def test_if_fails_setup_for_without_time(self):
|
||||
"""Test for setup failure if no time is provided."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'bla'
|
||||
},
|
||||
'condition': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'state': 'on',
|
||||
'for': {},
|
||||
},
|
||||
'action': {'service': 'test.automation'},
|
||||
}})
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
'event_type': 'bla'
|
||||
},
|
||||
'condition': {
|
||||
'platform': 'state',
|
||||
'entity_id': 'test.entity',
|
||||
'state': 'on',
|
||||
'for': {},
|
||||
},
|
||||
'action': {'service': 'test.automation'},
|
||||
}})
|
||||
|
||||
def test_if_fails_setup_for_without_entity(self):
|
||||
"""Test for setup failure if no entity is provided."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {'event_type': 'bla'},
|
||||
'condition': {
|
||||
'platform': 'state',
|
||||
'state': 'on',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {'event_type': 'bla'},
|
||||
'condition': {
|
||||
'platform': 'state',
|
||||
'state': 'on',
|
||||
'for': {
|
||||
'seconds': 5
|
||||
},
|
||||
},
|
||||
},
|
||||
'action': {'service': 'test.automation'},
|
||||
}})
|
||||
'action': {'service': 'test.automation'},
|
||||
}})
|
||||
|
@ -3,7 +3,7 @@ from datetime import datetime
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import sun
|
||||
import homeassistant.components.automation as automation
|
||||
import homeassistant.util.dt as dt_util
|
||||
@ -42,7 +42,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.util.dt.utcnow',
|
||||
return_value=now):
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -81,7 +81,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.util.dt.utcnow',
|
||||
return_value=now):
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -108,7 +108,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.util.dt.utcnow',
|
||||
return_value=now):
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -142,7 +142,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
|
||||
with patch('homeassistant.util.dt.utcnow',
|
||||
return_value=now):
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'sun',
|
||||
@ -165,7 +165,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
|
||||
})
|
||||
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -201,7 +201,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
|
||||
})
|
||||
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -237,7 +237,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
|
||||
})
|
||||
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -274,7 +274,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_RISING: '2015-09-16T14:00:00Z',
|
||||
})
|
||||
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -312,7 +312,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T15:00:00Z',
|
||||
})
|
||||
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -358,7 +358,7 @@ class TestAutomationSun(unittest.TestCase):
|
||||
sun.STATE_ATTR_NEXT_SETTING: '2015-09-16T17:30:00Z',
|
||||
})
|
||||
|
||||
_setup_component(self.hass, automation.DOMAIN, {
|
||||
setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -1,10 +1,10 @@
|
||||
"""The tests for the Template automation."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
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):
|
||||
@ -29,7 +29,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_bool(self):
|
||||
"""Test for firing on boolean change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -54,7 +54,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_str(self):
|
||||
"""Test for firing on change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -72,7 +72,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_str_crazy(self):
|
||||
"""Test for firing on change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -90,7 +90,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_bool(self):
|
||||
"""Test for not firing on boolean change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -108,7 +108,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_str(self):
|
||||
"""Test for not firing on string change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -126,7 +126,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_str_crazy(self):
|
||||
"""Test for not firing on string change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -144,7 +144,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_no_change(self):
|
||||
"""Test for firing on no change."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -165,7 +165,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_two_change(self):
|
||||
"""Test for firing on two changes."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -189,7 +189,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_template(self):
|
||||
"""Test for firing on change with template."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -207,7 +207,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_not_fires_on_change_with_template(self):
|
||||
"""Test for not firing on change with template."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -228,7 +228,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_template_advanced(self):
|
||||
"""Test for firing on change with template advanced."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -262,7 +262,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_no_change_with_template_advanced(self):
|
||||
"""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: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -290,7 +290,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_template_2(self):
|
||||
"""Test for firing on change with template."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
@ -332,7 +332,7 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_action(self):
|
||||
"""Test for firing if action."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -365,21 +365,22 @@ class TestAutomationTemplate(unittest.TestCase):
|
||||
|
||||
def test_if_fires_on_change_with_bad_template(self):
|
||||
"""Test for firing on change with bad template."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
'value_template': '{{ ',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
'value_template': '{{ ',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
def test_if_fires_on_change_with_bad_template_2(self):
|
||||
"""Test for firing on change with bad template."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'template',
|
||||
|
@ -3,11 +3,12 @@ from datetime import timedelta
|
||||
import unittest
|
||||
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.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):
|
||||
@ -30,7 +31,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_hour_matches(self):
|
||||
"""Test for firing if hour is matching."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -55,7 +56,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_minute_matches(self):
|
||||
"""Test for firing if minutes are matching."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -74,7 +75,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_second_matches(self):
|
||||
"""Test for firing if seconds are matching."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -93,7 +94,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_when_all_matches(self):
|
||||
"""Test for firing if everything matches."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -115,7 +116,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_periodic_seconds(self):
|
||||
"""Test for firing periodically every second."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -135,7 +136,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_periodic_minutes(self):
|
||||
"""Test for firing periodically every minute."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -155,7 +156,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_periodic_hours(self):
|
||||
"""Test for firing periodically every hour."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -175,7 +176,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_fires_using_after(self):
|
||||
"""Test for firing after."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
@ -200,16 +201,17 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_not_working_if_no_values_in_conf_provided(self):
|
||||
"""Test for failure if no configuration."""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=5, minute=0, second=0))
|
||||
@ -222,18 +224,19 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
This should break the before rule.
|
||||
"""
|
||||
assert not _setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
'after': 3605,
|
||||
# Total seconds. Hour = 3600 second
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'time',
|
||||
'after': 3605,
|
||||
# Total seconds. Hour = 3600 second
|
||||
},
|
||||
'action': {
|
||||
'service': 'test.automation'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
fire_time_changed(self.hass, dt_util.utcnow().replace(
|
||||
hour=1, minute=0, second=5))
|
||||
@ -243,7 +246,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_before(self):
|
||||
"""Test for if action before."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -278,7 +281,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_after(self):
|
||||
"""Test for if action after."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -313,7 +316,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_one_weekday(self):
|
||||
"""Test for if action with one weekday."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
@ -349,7 +352,7 @@ class TestAutomationTime(unittest.TestCase):
|
||||
|
||||
def test_if_action_list_weekday(self):
|
||||
"""Test for action with a list of weekdays."""
|
||||
assert _setup_component(self.hass, automation.DOMAIN, {
|
||||
assert setup_component(self.hass, automation.DOMAIN, {
|
||||
automation.DOMAIN: {
|
||||
'trigger': {
|
||||
'platform': 'event',
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the MQTT binary sensor platform."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.binary_sensor as binary_sensor
|
||||
from tests.common import mock_mqtt_component, fire_mqtt_message
|
||||
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):
|
||||
"""Test the setting of the value via 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: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -50,7 +50,7 @@ class TestSensorMQTT(unittest.TestCase):
|
||||
def test_valid_sensor_class(self):
|
||||
"""Test the setting of a valid sensor class."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, binary_sensor.DOMAIN, {
|
||||
assert setup_component(self.hass, binary_sensor.DOMAIN, {
|
||||
binary_sensor.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -65,7 +65,7 @@ class TestSensorMQTT(unittest.TestCase):
|
||||
def test_invalid_sensor_class(self):
|
||||
"""Test the setting of an invalid sensor class."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, binary_sensor.DOMAIN, {
|
||||
assert setup_component(self.hass, binary_sensor.DOMAIN, {
|
||||
binary_sensor.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
|
@ -8,6 +8,8 @@ from nx584 import client as nx584_client
|
||||
from homeassistant.components.binary_sensor import nx584
|
||||
from homeassistant.bootstrap import setup_component
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
class StopMe(Exception):
|
||||
"""Stop helper."""
|
||||
@ -20,6 +22,7 @@ class TestNX584SensorSetup(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""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.start()
|
||||
|
||||
@ -35,6 +38,7 @@ class TestNX584SensorSetup(unittest.TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
"""Stop everything that was started."""
|
||||
self.hass.stop()
|
||||
self._mock_client.stop()
|
||||
|
||||
@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):
|
||||
"""Test the setup with no configuration."""
|
||||
add_devices = mock.MagicMock()
|
||||
hass = mock.MagicMock()
|
||||
config = {
|
||||
'host': nx584.DEFAULT_HOST,
|
||||
'port': nx584.DEFAULT_PORT,
|
||||
'exclude_zones': [],
|
||||
'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.call(zone, 'opening') for zone in self.fake_zones])
|
||||
self.assertTrue(add_devices.called)
|
||||
@ -69,8 +72,7 @@ class TestNX584SensorSetup(unittest.TestCase):
|
||||
'zone_types': {3: 'motion'},
|
||||
}
|
||||
add_devices = mock.MagicMock()
|
||||
hass = mock.MagicMock()
|
||||
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.call(self.fake_zones[0], 'opening'),
|
||||
mock.call(self.fake_zones[2], 'motion'),
|
||||
@ -84,9 +86,8 @@ class TestNX584SensorSetup(unittest.TestCase):
|
||||
|
||||
def _test_assert_graceful_fail(self, config):
|
||||
"""Test the failing."""
|
||||
hass = add_devices = mock.MagicMock()
|
||||
self.assertFalse(setup_component(hass, 'binary_sensor.nx584', config))
|
||||
self.assertFalse(add_devices.called)
|
||||
self.assertFalse(setup_component(
|
||||
self.hass, 'binary_sensor.nx584', config))
|
||||
|
||||
def test_setup_bad_config(self):
|
||||
"""Test the setup with bad configuration."""
|
||||
@ -113,8 +114,8 @@ class TestNX584SensorSetup(unittest.TestCase):
|
||||
def test_setup_no_zones(self):
|
||||
"""Test the setup with no zones."""
|
||||
nx584_client.Client.return_value.list_zones.return_value = []
|
||||
hass = add_devices = mock.MagicMock()
|
||||
self.assertTrue(nx584.setup_platform(hass, {}, add_devices))
|
||||
add_devices = mock.MagicMock()
|
||||
self.assertTrue(nx584.setup_platform(self.hass, {}, add_devices))
|
||||
self.assertFalse(add_devices.called)
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@ import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import rfxtrx as rfxtrx_core
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -28,7 +28,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_valid_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertTrue(_setup_component(self.hass, 'cover', {
|
||||
self.assertTrue(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -39,7 +39,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config_capital_letters(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'cover', {
|
||||
self.assertFalse(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -51,7 +51,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config_extra_key(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'cover', {
|
||||
self.assertFalse(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'invalid_key': 'afda',
|
||||
@ -64,7 +64,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config_capital_packetid(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'cover', {
|
||||
self.assertFalse(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -76,7 +76,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config_missing_packetid(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'cover', {
|
||||
self.assertFalse(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -87,14 +87,14 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_default_config(self):
|
||||
"""Test with 0 cover."""
|
||||
self.assertTrue(_setup_component(self.hass, 'cover', {
|
||||
self.assertTrue(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'devices': {}}}))
|
||||
self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES))
|
||||
|
||||
def test_one_cover(self):
|
||||
"""Test with 1 cover."""
|
||||
self.assertTrue(_setup_component(self.hass, 'cover', {
|
||||
self.assertTrue(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0b1400cd0213c7f210010f51': {
|
||||
@ -117,7 +117,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_several_covers(self):
|
||||
"""Test with 3 covers."""
|
||||
self.assertTrue(_setup_component(self.hass, 'cover', {
|
||||
self.assertTrue(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'signal_repetitions': 3,
|
||||
'devices':
|
||||
@ -145,7 +145,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_covers(self):
|
||||
"""Test with discovery of covers."""
|
||||
self.assertTrue(_setup_component(self.hass, 'cover', {
|
||||
self.assertTrue(setup_component(self.hass, 'cover', {
|
||||
'cover': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices': {}}}))
|
||||
@ -183,7 +183,7 @@ class TestCoverRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_cover_noautoadd(self):
|
||||
"""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',
|
||||
'automatic_add': False,
|
||||
'devices': {}}}))
|
||||
|
@ -4,7 +4,7 @@ from unittest.mock import patch
|
||||
import logging
|
||||
import os
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import device_tracker
|
||||
from homeassistant.const import CONF_PLATFORM
|
||||
|
||||
@ -42,7 +42,7 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase):
|
||||
dev_id = 'paulus'
|
||||
topic = '/location/paulus'
|
||||
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: {
|
||||
CONF_PLATFORM: 'mqtt',
|
||||
'devices': {dev_id: topic}
|
||||
@ -58,7 +58,7 @@ class TestComponentsDeviceTrackerMQTT(unittest.TestCase):
|
||||
location = 'work'
|
||||
|
||||
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: {
|
||||
CONF_PLATFORM: 'mqtt',
|
||||
'devices': {dev_id: topic}
|
||||
|
@ -30,7 +30,7 @@ light:
|
||||
import json
|
||||
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
|
||||
import homeassistant.components.light as light
|
||||
from tests.common import (
|
||||
@ -67,7 +67,7 @@ class TestLightMQTTJSON(unittest.TestCase):
|
||||
# pylint: disable=invalid-name
|
||||
"""Test if there is no color and brightness if they aren't defined."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, light.DOMAIN, {
|
||||
assert setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
@ -93,7 +93,7 @@ class TestLightMQTTJSON(unittest.TestCase):
|
||||
# pylint: disable=invalid-name
|
||||
"""Test the controlling of the state via topic."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, light.DOMAIN, {
|
||||
assert setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
@ -153,7 +153,7 @@ class TestLightMQTTJSON(unittest.TestCase):
|
||||
# pylint: disable=invalid-name
|
||||
"""Test the sending of command in optimistic mode."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, light.DOMAIN, {
|
||||
assert setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
@ -209,7 +209,7 @@ class TestLightMQTTJSON(unittest.TestCase):
|
||||
# pylint: disable=invalid-name
|
||||
"""Test for flash length being sent when included."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, light.DOMAIN, {
|
||||
assert setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
@ -251,7 +251,7 @@ class TestLightMQTTJSON(unittest.TestCase):
|
||||
def test_transition(self):
|
||||
"""Test for transition time being sent when included."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, light.DOMAIN, {
|
||||
assert setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
@ -293,7 +293,7 @@ class TestLightMQTTJSON(unittest.TestCase):
|
||||
# pylint: disable=invalid-name
|
||||
"""Test that invalid color/brightness values are ignored."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, light.DOMAIN, {
|
||||
assert setup_component(self.hass, light.DOMAIN, {
|
||||
light.DOMAIN: {
|
||||
'platform': 'mqtt_json',
|
||||
'name': 'test',
|
||||
|
@ -3,7 +3,7 @@ import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import rfxtrx as rfxtrx_core
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -28,7 +28,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_valid_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -36,7 +36,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
'name': 'Test',
|
||||
rfxtrx_core.ATTR_FIREEVENT: True}}}}))
|
||||
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -47,7 +47,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'light', {
|
||||
self.assertFalse(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'invalid_key': 'afda',
|
||||
@ -59,14 +59,14 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_default_config(self):
|
||||
"""Test with 0 switches."""
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'devices': {}}}))
|
||||
self.assertEqual(0, len(rfxtrx_core.RFX_DEVICES))
|
||||
|
||||
def test_old_config(self):
|
||||
"""Test with 1 light."""
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'123efab1': {
|
||||
@ -110,7 +110,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_one_light(self):
|
||||
"""Test with 1 light."""
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0b1100cd0213c7f210010f51': {
|
||||
@ -179,7 +179,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_several_lights(self):
|
||||
"""Test with 3 lights."""
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'signal_repetitions': 3,
|
||||
'devices':
|
||||
@ -212,7 +212,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_light(self):
|
||||
"""Test with discovery of lights."""
|
||||
self.assertTrue(_setup_component(self.hass, 'light', {
|
||||
self.assertTrue(setup_component(self.hass, 'light', {
|
||||
'light': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices': {}}}))
|
||||
@ -265,7 +265,7 @@ class TestLightRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_light_noautoadd(self):
|
||||
"""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',
|
||||
'automatic_add': False,
|
||||
'devices': {}}}))
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the MQTT lock platform."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.const import (STATE_LOCKED, STATE_UNLOCKED,
|
||||
ATTR_ASSUMED_STATE)
|
||||
import homeassistant.components.lock as lock
|
||||
@ -24,7 +24,7 @@ class TestLockMQTT(unittest.TestCase):
|
||||
def test_controlling_state_via_topic(self):
|
||||
"""Test the controlling state via topic."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, lock.DOMAIN, {
|
||||
assert setup_component(self.hass, lock.DOMAIN, {
|
||||
lock.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -54,7 +54,7 @@ class TestLockMQTT(unittest.TestCase):
|
||||
def test_sending_mqtt_commands_and_optimistic(self):
|
||||
"""Test the sending MQTT commands in optimistic mode."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, lock.DOMAIN, {
|
||||
assert setup_component(self.hass, lock.DOMAIN, {
|
||||
lock.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -88,7 +88,7 @@ class TestLockMQTT(unittest.TestCase):
|
||||
def test_controlling_state_via_topic_and_json_message(self):
|
||||
"""Test the controlling state via topic and JSON message."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, lock.DOMAIN, {
|
||||
assert setup_component(self.hass, lock.DOMAIN, {
|
||||
lock.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
|
@ -6,7 +6,7 @@ import socket
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.mqtt as mqtt
|
||||
from homeassistant.const import (
|
||||
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',
|
||||
side_effect=socket.error()):
|
||||
self.hass.config.components = []
|
||||
assert not _setup_component(self.hass, mqtt.DOMAIN, {
|
||||
assert not setup_component(self.hass, mqtt.DOMAIN, {
|
||||
mqtt.DOMAIN: {
|
||||
mqtt.CONF_BROKER: 'test-broker',
|
||||
}
|
||||
@ -62,7 +62,7 @@ class TestMQTT(unittest.TestCase):
|
||||
"""Test for setup failure if connection to broker is missing."""
|
||||
with mock.patch('paho.mqtt.client.Client'):
|
||||
self.hass.config.components = []
|
||||
assert _setup_component(self.hass, mqtt.DOMAIN, {
|
||||
assert setup_component(self.hass, mqtt.DOMAIN, {
|
||||
mqtt.DOMAIN: {
|
||||
mqtt.CONF_BROKER: 'test-broker',
|
||||
mqtt.CONF_PROTOCOL: 3.1,
|
||||
@ -222,7 +222,7 @@ class TestMQTTCallbacks(unittest.TestCase):
|
||||
|
||||
with mock.patch('paho.mqtt.client.Client'):
|
||||
self.hass.config.components = []
|
||||
assert _setup_component(self.hass, mqtt.DOMAIN, {
|
||||
assert setup_component(self.hass, mqtt.DOMAIN, {
|
||||
mqtt.DOMAIN: {
|
||||
mqtt.CONF_BROKER: 'mock-broker',
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the MQTT component embedded server."""
|
||||
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
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -29,7 +29,7 @@ class TestMQTT:
|
||||
password = 'super_secret'
|
||||
|
||||
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.mock_calls[0][1][5] == 'homeassistant'
|
||||
assert mock_mqtt.mock_calls[0][1][6] == password
|
||||
@ -38,7 +38,7 @@ class TestMQTT:
|
||||
|
||||
self.hass.config.components = ['http']
|
||||
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.mock_calls[0][1][5] is None
|
||||
assert mock_mqtt.mock_calls[0][1][6] is None
|
||||
@ -54,6 +54,7 @@ class TestMQTT:
|
||||
mock_gather.side_effect = BrokerException
|
||||
|
||||
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: {}}
|
||||
})
|
||||
|
@ -8,9 +8,8 @@ import homeassistant.components.notify as notify
|
||||
from homeassistant.components.notify import (
|
||||
ATTR_TITLE_DEFAULT)
|
||||
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):
|
||||
@ -26,12 +25,13 @@ class TestNotifyFile(unittest.TestCase):
|
||||
|
||||
def test_bad_config(self):
|
||||
"""Test set up the platform with bad/missing config."""
|
||||
self.assertFalse(_setup_component(self.hass, notify.DOMAIN, {
|
||||
'notify': {
|
||||
'name': 'test',
|
||||
'platform': 'file',
|
||||
},
|
||||
}))
|
||||
with assert_setup_component(0):
|
||||
assert not setup_component(self.hass, notify.DOMAIN, {
|
||||
'notify': {
|
||||
'name': 'test',
|
||||
'platform': 'file',
|
||||
},
|
||||
})
|
||||
|
||||
@patch('homeassistant.components.notify.file.os.stat')
|
||||
@patch('homeassistant.util.dt.utcnow')
|
||||
|
@ -6,7 +6,7 @@ import unittest
|
||||
|
||||
from homeassistant.const import MATCH_ALL
|
||||
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
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ class TestRecorder(unittest.TestCase):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant()
|
||||
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}})
|
||||
self.hass.start()
|
||||
recorder._verify_instance()
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the MQTT sensor platform."""
|
||||
import unittest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.sensor as sensor
|
||||
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):
|
||||
"""Test the setting of the value via MQTT."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, sensor.DOMAIN, {
|
||||
assert setup_component(self.hass, sensor.DOMAIN, {
|
||||
sensor.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -43,7 +43,7 @@ class TestSensorMQTT(unittest.TestCase):
|
||||
def test_setting_sensor_value_via_mqtt_json_message(self):
|
||||
"""Test the setting of the value via MQTT with JSON playload."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, sensor.DOMAIN, {
|
||||
assert setup_component(self.hass, sensor.DOMAIN, {
|
||||
sensor.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
|
@ -3,7 +3,7 @@ import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import rfxtrx as rfxtrx_core
|
||||
from homeassistant.const import TEMP_CELSIUS
|
||||
|
||||
@ -29,7 +29,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_default_config(self):
|
||||
"""Test with 0 sensor."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{}}}))
|
||||
@ -37,7 +37,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_old_config_sensor(self):
|
||||
"""Test with 1 sensor."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'sensor_0502': {
|
||||
@ -53,7 +53,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_one_sensor(self):
|
||||
"""Test with 1 sensor."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0a52080705020095220269': {
|
||||
@ -68,7 +68,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_one_sensor_no_datatype(self):
|
||||
"""Test with 1 sensor."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0a52080705020095220269': {
|
||||
@ -88,7 +88,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_several_sensors(self):
|
||||
"""Test with 3 sensors."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0a52080705020095220269': {
|
||||
@ -124,7 +124,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_sensor(self):
|
||||
"""Test with discovery of sensor."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices': {}}}))
|
||||
@ -182,7 +182,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_sensor_noautoadd(self):
|
||||
"""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',
|
||||
'automatic_add': False,
|
||||
'devices': {}}}))
|
||||
@ -209,7 +209,7 @@ class TestSensorRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_update_of_sensors(self):
|
||||
"""Test with 3 sensors."""
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0a52080705020095220269': {
|
||||
|
@ -2,7 +2,7 @@
|
||||
from datetime import datetime
|
||||
from unittest.mock import patch
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
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',
|
||||
return_value=now):
|
||||
assert _setup_component(self.hass, 'sensor', {
|
||||
assert setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'yr',
|
||||
'elevation': 0}})
|
||||
|
||||
@ -46,7 +46,7 @@ class TestSensorYr:
|
||||
|
||||
with patch('homeassistant.components.sensor.yr.dt_util.utcnow',
|
||||
return_value=now):
|
||||
assert _setup_component(self.hass, 'sensor', {
|
||||
assert setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'yr',
|
||||
'elevation': 0,
|
||||
'monitored_conditions': [
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""The tests for the MQTT switch platform."""
|
||||
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
|
||||
import homeassistant.components.switch as switch
|
||||
from tests.common import (
|
||||
@ -23,7 +23,7 @@ class TestSensorMQTT(unittest.TestCase):
|
||||
def test_controlling_state_via_topic(self):
|
||||
"""Test the controlling state via topic."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, switch.DOMAIN, {
|
||||
assert setup_component(self.hass, switch.DOMAIN, {
|
||||
switch.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -53,7 +53,7 @@ class TestSensorMQTT(unittest.TestCase):
|
||||
def test_sending_mqtt_commands_and_optimistic(self):
|
||||
"""Test the sending MQTT commands in optimistic mode."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, switch.DOMAIN, {
|
||||
assert setup_component(self.hass, switch.DOMAIN, {
|
||||
switch.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
@ -87,7 +87,7 @@ class TestSensorMQTT(unittest.TestCase):
|
||||
def test_controlling_state_via_topic_and_json_message(self):
|
||||
"""Test the controlling state via topic and JSON message."""
|
||||
self.hass.config.components = ['mqtt']
|
||||
assert _setup_component(self.hass, switch.DOMAIN, {
|
||||
assert setup_component(self.hass, switch.DOMAIN, {
|
||||
switch.DOMAIN: {
|
||||
'platform': 'mqtt',
|
||||
'name': 'test',
|
||||
|
@ -3,7 +3,7 @@ import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import rfxtrx as rfxtrx_core
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
@ -28,7 +28,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_valid_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -39,7 +39,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_valid_config_int_device_id(self):
|
||||
"""Test configuration."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -49,7 +49,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
}}}))
|
||||
|
||||
def test_invalid_config1(self):
|
||||
self.assertFalse(_setup_component(self.hass, 'switch', {
|
||||
self.assertFalse(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -61,7 +61,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config2(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'switch', {
|
||||
self.assertFalse(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'invalid_key': 'afda',
|
||||
@ -73,7 +73,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
}}}))
|
||||
|
||||
def test_invalid_config3(self):
|
||||
self.assertFalse(_setup_component(self.hass, 'switch', {
|
||||
self.assertFalse(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -85,7 +85,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_invalid_config4(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'switch', {
|
||||
self.assertFalse(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -96,7 +96,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_default_config(self):
|
||||
"""Test with 0 switches."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{}}}))
|
||||
@ -104,7 +104,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_old_config(self):
|
||||
"""Test with 1 switch."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'123efab1': {
|
||||
@ -132,7 +132,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_one_switch(self):
|
||||
"""Test with 1 switch."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'devices':
|
||||
{'0b1100cd0213c7f210010f51': {
|
||||
@ -170,7 +170,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_several_switches(self):
|
||||
"""Test with 3 switches."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'signal_repetitions': 3,
|
||||
'devices':
|
||||
@ -203,7 +203,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_switch(self):
|
||||
"""Test with discovery of switches."""
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices': {}}}))
|
||||
@ -253,7 +253,7 @@ class TestSwitchRfxtrx(unittest.TestCase):
|
||||
|
||||
def test_discover_switch_noautoadd(self):
|
||||
"""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',
|
||||
'automatic_add': False,
|
||||
'devices': {}}}))
|
||||
|
@ -7,8 +7,9 @@ from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components as core_components
|
||||
from homeassistant.components import conversation
|
||||
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):
|
||||
@ -19,9 +20,13 @@ class TestConversation(unittest.TestCase):
|
||||
self.ent_id = 'light.kitchen_lights'
|
||||
self.hass = get_test_home_assistant(3)
|
||||
self.hass.states.set(self.ent_id, 'on')
|
||||
self.assertTrue(core_components.setup(self.hass, {}))
|
||||
self.assertTrue(setup_component(self.hass, conversation.DOMAIN, {
|
||||
conversation.DOMAIN: {}}))
|
||||
self.assertTrue(run_coroutine_threadsafe(
|
||||
core_components.async_setup(self.hass, {}), self.hass.loop
|
||||
).result())
|
||||
with assert_setup_component(0):
|
||||
self.assertTrue(setup_component(self.hass, conversation.DOMAIN, {
|
||||
conversation.DOMAIN: {}
|
||||
}))
|
||||
|
||||
def tearDown(self): # pylint: disable=invalid-name
|
||||
"""Stop everything that was started."""
|
||||
|
@ -1,425 +1,429 @@
|
||||
"""The tests for the emulated Hue component."""
|
||||
import time
|
||||
import json
|
||||
import threading
|
||||
import asyncio
|
||||
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from homeassistant import bootstrap, const, core
|
||||
import homeassistant.components as core_components
|
||||
from homeassistant.components import emulated_hue, http, light
|
||||
from homeassistant.const import STATE_ON, STATE_OFF
|
||||
from homeassistant.components.emulated_hue import (
|
||||
HUE_API_STATE_ON, HUE_API_STATE_BRI)
|
||||
|
||||
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()
|
||||
|
||||
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."""
|
||||
hass = get_test_home_assistant()
|
||||
|
||||
# We need to do this to get access to homeassistant/turn_(on,off)
|
||||
core_components.setup(hass, {core.DOMAIN: {}})
|
||||
|
||||
bootstrap.setup_component(
|
||||
hass, http.DOMAIN,
|
||||
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}})
|
||||
|
||||
bootstrap.setup_component(hass, emulated_hue.DOMAIN, emulated_hue_config)
|
||||
|
||||
return hass
|
||||
|
||||
|
||||
def start_hass_instance(hass):
|
||||
"""Start the Home Assistant instance to test."""
|
||||
hass.start()
|
||||
time.sleep(0.05)
|
||||
|
||||
|
||||
class TestEmulatedHue(unittest.TestCase):
|
||||
"""Test the emulated Hue component."""
|
||||
|
||||
hass = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Setup the class."""
|
||||
cls.hass = setup_hass_instance({
|
||||
emulated_hue.DOMAIN: {
|
||||
emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT
|
||||
}})
|
||||
|
||||
start_hass_instance(cls.hass)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Stop the class."""
|
||||
cls.hass.stop()
|
||||
|
||||
def test_description_xml(self):
|
||||
"""Test the description."""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format('/description.xml'), timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertTrue('text/xml' in result.headers['content-type'])
|
||||
|
||||
# Make sure the XML is parsable
|
||||
try:
|
||||
ET.fromstring(result.text)
|
||||
except:
|
||||
self.fail('description.xml is not valid XML!')
|
||||
|
||||
def test_create_username(self):
|
||||
"""Test the creation of an username."""
|
||||
request_json = {'devicetype': 'my_device'}
|
||||
|
||||
result = requests.post(
|
||||
BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertTrue('application/json' in result.headers['content-type'])
|
||||
|
||||
resp_json = result.json()
|
||||
success_json = resp_json[0]
|
||||
|
||||
self.assertTrue('success' in success_json)
|
||||
self.assertTrue('username' in success_json['success'])
|
||||
|
||||
def test_valid_username_request(self):
|
||||
"""Test request with a valid username."""
|
||||
request_json = {'invalid_key': 'my_device'}
|
||||
|
||||
result = requests.post(
|
||||
BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
|
||||
class TestEmulatedHueExposedByDefault(unittest.TestCase):
|
||||
"""Test class for emulated hue component."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Setup the class."""
|
||||
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',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
start_hass_instance(cls.hass)
|
||||
|
||||
# Kitchen light is explicitly excluded from being exposed
|
||||
kitchen_light_entity = cls.hass.states.get('light.kitchen_lights')
|
||||
attrs = dict(kitchen_light_entity.attributes)
|
||||
attrs[emulated_hue.ATTR_EMULATED_HUE] = False
|
||||
cls.hass.states.set(
|
||||
kitchen_light_entity.entity_id, kitchen_light_entity.state,
|
||||
attributes=attrs)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Stop the class."""
|
||||
cls.hass.stop()
|
||||
|
||||
def test_discover_lights(self):
|
||||
"""Test the discovery of lights."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertTrue('application/json' in result.headers['content-type'])
|
||||
|
||||
result_json = result.json()
|
||||
|
||||
# Make sure the lights we added to the config are there
|
||||
self.assertTrue('light.ceiling_lights' in result_json)
|
||||
self.assertTrue('light.bed_light' in result_json)
|
||||
self.assertTrue('light.kitchen_lights' not in result_json)
|
||||
|
||||
def test_get_light_state(self):
|
||||
"""Test the getting of light state."""
|
||||
# Turn office light on and set to 127 brightness
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_ON,
|
||||
{
|
||||
const.ATTR_ENTITY_ID: 'light.ceiling_lights',
|
||||
light.ATTR_BRIGHTNESS: 127
|
||||
},
|
||||
blocking=True)
|
||||
|
||||
office_json = self.perform_get_light_state('light.ceiling_lights', 200)
|
||||
|
||||
self.assertEqual(office_json['state'][HUE_API_STATE_ON], True)
|
||||
self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127)
|
||||
|
||||
# Turn bedroom light off
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_OFF,
|
||||
{
|
||||
const.ATTR_ENTITY_ID: 'light.bed_light'
|
||||
},
|
||||
blocking=True)
|
||||
|
||||
bedroom_json = self.perform_get_light_state('light.bed_light', 200)
|
||||
|
||||
self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False)
|
||||
self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0)
|
||||
|
||||
# Make sure kitchen light isn't accessible
|
||||
kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights')
|
||||
kitchen_result = requests.get(
|
||||
BRIDGE_URL_BASE.format(kitchen_url), timeout=5)
|
||||
|
||||
self.assertEqual(kitchen_result.status_code, 404)
|
||||
|
||||
def test_put_light_state(self):
|
||||
"""Test the seeting of light states."""
|
||||
self.perform_put_test_on_ceiling_lights()
|
||||
|
||||
# Turn the bedroom light on first
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_ON,
|
||||
{const.ATTR_ENTITY_ID: 'light.bed_light',
|
||||
light.ATTR_BRIGHTNESS: 153},
|
||||
blocking=True)
|
||||
|
||||
bed_light = self.hass.states.get('light.bed_light')
|
||||
self.assertEqual(bed_light.state, STATE_ON)
|
||||
self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153)
|
||||
|
||||
# Go through the API to turn it off
|
||||
bedroom_result = self.perform_put_light_state(
|
||||
'light.bed_light', False)
|
||||
|
||||
bedroom_result_json = bedroom_result.json()
|
||||
|
||||
self.assertEqual(bedroom_result.status_code, 200)
|
||||
self.assertTrue(
|
||||
'application/json' in bedroom_result.headers['content-type'])
|
||||
|
||||
self.assertEqual(len(bedroom_result_json), 1)
|
||||
|
||||
# Check to make sure the state changed
|
||||
bed_light = self.hass.states.get('light.bed_light')
|
||||
self.assertEqual(bed_light.state, STATE_OFF)
|
||||
|
||||
# Make sure we can't change the kitchen light state
|
||||
kitchen_result = self.perform_put_light_state(
|
||||
'light.kitchen_light', True)
|
||||
self.assertEqual(kitchen_result.status_code, 404)
|
||||
|
||||
def test_put_with_form_urlencoded_content_type(self):
|
||||
"""Test the form with urlencoded content."""
|
||||
# Needed for Alexa
|
||||
self.perform_put_test_on_ceiling_lights(
|
||||
'application/x-www-form-urlencoded')
|
||||
|
||||
# Make sure we fail gracefully when we can't parse the data
|
||||
data = {'key1': 'value1', 'key2': 'value2'}
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")), data=data)
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
def test_entity_not_found(self):
|
||||
"""Test for entity which are not found."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}'.format("not.existant_entity")),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format("non.existant_entity")),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
def test_allowed_methods(self):
|
||||
"""Test the allowed methods."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")))
|
||||
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}'.format("light.ceiling_lights")),
|
||||
data={'key1': 'value1'})
|
||||
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format('/api/username/lights'),
|
||||
data={'key1': 'value1'})
|
||||
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
def test_proper_put_state_request(self):
|
||||
"""Test the request to set the state."""
|
||||
# Test proper on value parsing
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")),
|
||||
data=json.dumps({HUE_API_STATE_ON: 1234}))
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
# Test proper brightness value parsing
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")), data=json.dumps({
|
||||
HUE_API_STATE_ON: True,
|
||||
HUE_API_STATE_BRI: 'Hello world!'
|
||||
}))
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
def perform_put_test_on_ceiling_lights(self,
|
||||
content_type='application/json'):
|
||||
"""Test the setting of a light."""
|
||||
# Turn the office light off first
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_OFF,
|
||||
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
|
||||
blocking=True)
|
||||
|
||||
ceiling_lights = self.hass.states.get('light.ceiling_lights')
|
||||
self.assertEqual(ceiling_lights.state, STATE_OFF)
|
||||
|
||||
# Go through the API to turn it on
|
||||
office_result = self.perform_put_light_state(
|
||||
'light.ceiling_lights', True, 56, content_type)
|
||||
|
||||
office_result_json = office_result.json()
|
||||
|
||||
self.assertEqual(office_result.status_code, 200)
|
||||
self.assertTrue(
|
||||
'application/json' in office_result.headers['content-type'])
|
||||
|
||||
self.assertEqual(len(office_result_json), 2)
|
||||
|
||||
# Check to make sure the state changed
|
||||
ceiling_lights = self.hass.states.get('light.ceiling_lights')
|
||||
self.assertEqual(ceiling_lights.state, STATE_ON)
|
||||
self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56)
|
||||
|
||||
def perform_get_light_state(self, entity_id, expected_status):
|
||||
"""Test the gettting of a light state."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}'.format(entity_id)), timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, expected_status)
|
||||
|
||||
if expected_status == 200:
|
||||
self.assertTrue(
|
||||
'application/json' in result.headers['content-type'])
|
||||
|
||||
return result.json()
|
||||
|
||||
return None
|
||||
|
||||
def perform_put_light_state(self, entity_id, is_on, brightness=None,
|
||||
content_type='application/json'):
|
||||
"""Test the setting of a light state."""
|
||||
url = BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(entity_id))
|
||||
|
||||
req_headers = {'Content-Type': content_type}
|
||||
|
||||
data = {HUE_API_STATE_ON: is_on}
|
||||
|
||||
if brightness is not None:
|
||||
data[HUE_API_STATE_BRI] = brightness
|
||||
|
||||
result = requests.put(
|
||||
url, data=json.dumps(data), timeout=5, headers=req_headers)
|
||||
return result
|
||||
|
||||
|
||||
class MQTTBroker(object):
|
||||
"""Encapsulates an embedded MQTT broker."""
|
||||
|
||||
def __init__(self, host, port):
|
||||
"""Initialize a new instance."""
|
||||
from hbmqtt.broker import Broker
|
||||
|
||||
self._loop = asyncio.new_event_loop()
|
||||
|
||||
hbmqtt_config = {
|
||||
'listeners': {
|
||||
'default': {
|
||||
'max-connections': 50000,
|
||||
'type': 'tcp',
|
||||
'bind': '{}:{}'.format(host, port)
|
||||
}
|
||||
},
|
||||
'auth': {
|
||||
'plugins': ['auth.anonymous'],
|
||||
'allow-anonymous': True
|
||||
}
|
||||
}
|
||||
|
||||
self._broker = Broker(config=hbmqtt_config, loop=self._loop)
|
||||
|
||||
self._thread = threading.Thread(target=self._run_loop)
|
||||
self._started_ev = threading.Event()
|
||||
|
||||
def start(self):
|
||||
"""Start the broker."""
|
||||
self._thread.start()
|
||||
self._started_ev.wait()
|
||||
|
||||
def stop(self):
|
||||
"""Stop the broker."""
|
||||
self._loop.call_soon_threadsafe(asyncio.async, self._broker.shutdown())
|
||||
self._loop.call_soon_threadsafe(self._loop.stop)
|
||||
self._thread.join()
|
||||
|
||||
def _run_loop(self):
|
||||
"""Run the loop."""
|
||||
asyncio.set_event_loop(self._loop)
|
||||
self._loop.run_until_complete(self._broker_coroutine())
|
||||
|
||||
self._started_ev.set()
|
||||
|
||||
self._loop.run_forever()
|
||||
self._loop.close()
|
||||
|
||||
@asyncio.coroutine
|
||||
def _broker_coroutine(self):
|
||||
"""The Broker coroutine."""
|
||||
yield from self._broker.start()
|
||||
"""The tests for the emulated Hue component."""
|
||||
import time
|
||||
import json
|
||||
import threading
|
||||
import asyncio
|
||||
|
||||
import unittest
|
||||
import requests
|
||||
|
||||
from homeassistant import bootstrap, const, core
|
||||
import homeassistant.components as core_components
|
||||
from homeassistant.components import emulated_hue, http, light
|
||||
from homeassistant.const import STATE_ON, STATE_OFF
|
||||
from homeassistant.components.emulated_hue import (
|
||||
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
|
||||
|
||||
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}
|
||||
|
||||
|
||||
def setup_hass_instance(emulated_hue_config):
|
||||
"""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)
|
||||
run_coroutine_threadsafe(
|
||||
core_components.async_setup(hass, {core.DOMAIN: {}}), hass.loop
|
||||
).result()
|
||||
|
||||
bootstrap.setup_component(
|
||||
hass, http.DOMAIN,
|
||||
{http.DOMAIN: {http.CONF_SERVER_PORT: HTTP_SERVER_PORT}})
|
||||
|
||||
bootstrap.setup_component(hass, emulated_hue.DOMAIN, emulated_hue_config)
|
||||
|
||||
return hass
|
||||
|
||||
|
||||
def start_hass_instance(hass):
|
||||
"""Start the Home Assistant instance to test."""
|
||||
hass.start()
|
||||
time.sleep(0.05)
|
||||
|
||||
|
||||
class TestEmulatedHue(unittest.TestCase):
|
||||
"""Test the emulated Hue component."""
|
||||
|
||||
hass = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Setup the class."""
|
||||
cls.hass = setup_hass_instance({
|
||||
emulated_hue.DOMAIN: {
|
||||
emulated_hue.CONF_LISTEN_PORT: BRIDGE_SERVER_PORT
|
||||
}})
|
||||
|
||||
start_hass_instance(cls.hass)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Stop the class."""
|
||||
cls.hass.stop()
|
||||
|
||||
def test_description_xml(self):
|
||||
"""Test the description."""
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format('/description.xml'), timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertTrue('text/xml' in result.headers['content-type'])
|
||||
|
||||
# Make sure the XML is parsable
|
||||
try:
|
||||
ET.fromstring(result.text)
|
||||
except:
|
||||
self.fail('description.xml is not valid XML!')
|
||||
|
||||
def test_create_username(self):
|
||||
"""Test the creation of an username."""
|
||||
request_json = {'devicetype': 'my_device'}
|
||||
|
||||
result = requests.post(
|
||||
BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertTrue('application/json' in result.headers['content-type'])
|
||||
|
||||
resp_json = result.json()
|
||||
success_json = resp_json[0]
|
||||
|
||||
self.assertTrue('success' in success_json)
|
||||
self.assertTrue('username' in success_json['success'])
|
||||
|
||||
def test_valid_username_request(self):
|
||||
"""Test request with a valid username."""
|
||||
request_json = {'invalid_key': 'my_device'}
|
||||
|
||||
result = requests.post(
|
||||
BRIDGE_URL_BASE.format('/api'), data=json.dumps(request_json),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
|
||||
class TestEmulatedHueExposedByDefault(unittest.TestCase):
|
||||
"""Test class for emulated hue component."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Setup the class."""
|
||||
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',
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
start_hass_instance(cls.hass)
|
||||
|
||||
# Kitchen light is explicitly excluded from being exposed
|
||||
kitchen_light_entity = cls.hass.states.get('light.kitchen_lights')
|
||||
attrs = dict(kitchen_light_entity.attributes)
|
||||
attrs[emulated_hue.ATTR_EMULATED_HUE] = False
|
||||
cls.hass.states.set(
|
||||
kitchen_light_entity.entity_id, kitchen_light_entity.state,
|
||||
attributes=attrs)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Stop the class."""
|
||||
cls.hass.stop()
|
||||
|
||||
def test_discover_lights(self):
|
||||
"""Test the discovery of lights."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format('/api/username/lights'), timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 200)
|
||||
self.assertTrue('application/json' in result.headers['content-type'])
|
||||
|
||||
result_json = result.json()
|
||||
|
||||
# Make sure the lights we added to the config are there
|
||||
self.assertTrue('light.ceiling_lights' in result_json)
|
||||
self.assertTrue('light.bed_light' in result_json)
|
||||
self.assertTrue('light.kitchen_lights' not in result_json)
|
||||
|
||||
def test_get_light_state(self):
|
||||
"""Test the getting of light state."""
|
||||
# Turn office light on and set to 127 brightness
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_ON,
|
||||
{
|
||||
const.ATTR_ENTITY_ID: 'light.ceiling_lights',
|
||||
light.ATTR_BRIGHTNESS: 127
|
||||
},
|
||||
blocking=True)
|
||||
|
||||
office_json = self.perform_get_light_state('light.ceiling_lights', 200)
|
||||
|
||||
self.assertEqual(office_json['state'][HUE_API_STATE_ON], True)
|
||||
self.assertEqual(office_json['state'][HUE_API_STATE_BRI], 127)
|
||||
|
||||
# Turn bedroom light off
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_OFF,
|
||||
{
|
||||
const.ATTR_ENTITY_ID: 'light.bed_light'
|
||||
},
|
||||
blocking=True)
|
||||
|
||||
bedroom_json = self.perform_get_light_state('light.bed_light', 200)
|
||||
|
||||
self.assertEqual(bedroom_json['state'][HUE_API_STATE_ON], False)
|
||||
self.assertEqual(bedroom_json['state'][HUE_API_STATE_BRI], 0)
|
||||
|
||||
# Make sure kitchen light isn't accessible
|
||||
kitchen_url = '/api/username/lights/{}'.format('light.kitchen_lights')
|
||||
kitchen_result = requests.get(
|
||||
BRIDGE_URL_BASE.format(kitchen_url), timeout=5)
|
||||
|
||||
self.assertEqual(kitchen_result.status_code, 404)
|
||||
|
||||
def test_put_light_state(self):
|
||||
"""Test the seeting of light states."""
|
||||
self.perform_put_test_on_ceiling_lights()
|
||||
|
||||
# Turn the bedroom light on first
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_ON,
|
||||
{const.ATTR_ENTITY_ID: 'light.bed_light',
|
||||
light.ATTR_BRIGHTNESS: 153},
|
||||
blocking=True)
|
||||
|
||||
bed_light = self.hass.states.get('light.bed_light')
|
||||
self.assertEqual(bed_light.state, STATE_ON)
|
||||
self.assertEqual(bed_light.attributes[light.ATTR_BRIGHTNESS], 153)
|
||||
|
||||
# Go through the API to turn it off
|
||||
bedroom_result = self.perform_put_light_state(
|
||||
'light.bed_light', False)
|
||||
|
||||
bedroom_result_json = bedroom_result.json()
|
||||
|
||||
self.assertEqual(bedroom_result.status_code, 200)
|
||||
self.assertTrue(
|
||||
'application/json' in bedroom_result.headers['content-type'])
|
||||
|
||||
self.assertEqual(len(bedroom_result_json), 1)
|
||||
|
||||
# Check to make sure the state changed
|
||||
bed_light = self.hass.states.get('light.bed_light')
|
||||
self.assertEqual(bed_light.state, STATE_OFF)
|
||||
|
||||
# Make sure we can't change the kitchen light state
|
||||
kitchen_result = self.perform_put_light_state(
|
||||
'light.kitchen_light', True)
|
||||
self.assertEqual(kitchen_result.status_code, 404)
|
||||
|
||||
def test_put_with_form_urlencoded_content_type(self):
|
||||
"""Test the form with urlencoded content."""
|
||||
# Needed for Alexa
|
||||
self.perform_put_test_on_ceiling_lights(
|
||||
'application/x-www-form-urlencoded')
|
||||
|
||||
# Make sure we fail gracefully when we can't parse the data
|
||||
data = {'key1': 'value1', 'key2': 'value2'}
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")), data=data)
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
def test_entity_not_found(self):
|
||||
"""Test for entity which are not found."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}'.format("not.existant_entity")),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format("non.existant_entity")),
|
||||
timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, 404)
|
||||
|
||||
def test_allowed_methods(self):
|
||||
"""Test the allowed methods."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")))
|
||||
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}'.format("light.ceiling_lights")),
|
||||
data={'key1': 'value1'})
|
||||
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format('/api/username/lights'),
|
||||
data={'key1': 'value1'})
|
||||
|
||||
self.assertEqual(result.status_code, 405)
|
||||
|
||||
def test_proper_put_state_request(self):
|
||||
"""Test the request to set the state."""
|
||||
# Test proper on value parsing
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")),
|
||||
data=json.dumps({HUE_API_STATE_ON: 1234}))
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
# Test proper brightness value parsing
|
||||
result = requests.put(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(
|
||||
"light.ceiling_lights")), data=json.dumps({
|
||||
HUE_API_STATE_ON: True,
|
||||
HUE_API_STATE_BRI: 'Hello world!'
|
||||
}))
|
||||
|
||||
self.assertEqual(result.status_code, 400)
|
||||
|
||||
def perform_put_test_on_ceiling_lights(self,
|
||||
content_type='application/json'):
|
||||
"""Test the setting of a light."""
|
||||
# Turn the office light off first
|
||||
self.hass.services.call(
|
||||
light.DOMAIN, const.SERVICE_TURN_OFF,
|
||||
{const.ATTR_ENTITY_ID: 'light.ceiling_lights'},
|
||||
blocking=True)
|
||||
|
||||
ceiling_lights = self.hass.states.get('light.ceiling_lights')
|
||||
self.assertEqual(ceiling_lights.state, STATE_OFF)
|
||||
|
||||
# Go through the API to turn it on
|
||||
office_result = self.perform_put_light_state(
|
||||
'light.ceiling_lights', True, 56, content_type)
|
||||
|
||||
office_result_json = office_result.json()
|
||||
|
||||
self.assertEqual(office_result.status_code, 200)
|
||||
self.assertTrue(
|
||||
'application/json' in office_result.headers['content-type'])
|
||||
|
||||
self.assertEqual(len(office_result_json), 2)
|
||||
|
||||
# Check to make sure the state changed
|
||||
ceiling_lights = self.hass.states.get('light.ceiling_lights')
|
||||
self.assertEqual(ceiling_lights.state, STATE_ON)
|
||||
self.assertEqual(ceiling_lights.attributes[light.ATTR_BRIGHTNESS], 56)
|
||||
|
||||
def perform_get_light_state(self, entity_id, expected_status):
|
||||
"""Test the gettting of a light state."""
|
||||
result = requests.get(
|
||||
BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}'.format(entity_id)), timeout=5)
|
||||
|
||||
self.assertEqual(result.status_code, expected_status)
|
||||
|
||||
if expected_status == 200:
|
||||
self.assertTrue(
|
||||
'application/json' in result.headers['content-type'])
|
||||
|
||||
return result.json()
|
||||
|
||||
return None
|
||||
|
||||
def perform_put_light_state(self, entity_id, is_on, brightness=None,
|
||||
content_type='application/json'):
|
||||
"""Test the setting of a light state."""
|
||||
url = BRIDGE_URL_BASE.format(
|
||||
'/api/username/lights/{}/state'.format(entity_id))
|
||||
|
||||
req_headers = {'Content-Type': content_type}
|
||||
|
||||
data = {HUE_API_STATE_ON: is_on}
|
||||
|
||||
if brightness is not None:
|
||||
data[HUE_API_STATE_BRI] = brightness
|
||||
|
||||
result = requests.put(
|
||||
url, data=json.dumps(data), timeout=5, headers=req_headers)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class MQTTBroker(object):
|
||||
"""Encapsulates an embedded MQTT broker."""
|
||||
|
||||
def __init__(self, host, port):
|
||||
"""Initialize a new instance."""
|
||||
from hbmqtt.broker import Broker
|
||||
|
||||
self._loop = asyncio.new_event_loop()
|
||||
|
||||
hbmqtt_config = {
|
||||
'listeners': {
|
||||
'default': {
|
||||
'max-connections': 50000,
|
||||
'type': 'tcp',
|
||||
'bind': '{}:{}'.format(host, port)
|
||||
}
|
||||
},
|
||||
'auth': {
|
||||
'plugins': ['auth.anonymous'],
|
||||
'allow-anonymous': True
|
||||
}
|
||||
}
|
||||
|
||||
self._broker = Broker(config=hbmqtt_config, loop=self._loop)
|
||||
|
||||
self._thread = threading.Thread(target=self._run_loop)
|
||||
self._started_ev = threading.Event()
|
||||
|
||||
def start(self):
|
||||
"""Start the broker."""
|
||||
self._thread.start()
|
||||
self._started_ev.wait()
|
||||
|
||||
def stop(self):
|
||||
"""Stop the broker."""
|
||||
self._loop.call_soon_threadsafe(asyncio.async, self._broker.shutdown())
|
||||
self._loop.call_soon_threadsafe(self._loop.stop)
|
||||
self._thread.join()
|
||||
|
||||
def _run_loop(self):
|
||||
"""Run the loop."""
|
||||
asyncio.set_event_loop(self._loop)
|
||||
self._loop.run_until_complete(self._broker_coroutine())
|
||||
|
||||
self._started_ev.set()
|
||||
|
||||
self._loop.run_forever()
|
||||
self._loop.close()
|
||||
|
||||
@asyncio.coroutine
|
||||
def _broker_coroutine(self):
|
||||
"""The Broker coroutine."""
|
||||
yield from self._broker.start()
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""The tests for the InfluxDB component."""
|
||||
import unittest
|
||||
from unittest import mock
|
||||
from unittest.mock import patch
|
||||
|
||||
import influxdb as influx_client
|
||||
|
||||
@ -9,6 +8,8 @@ from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.influxdb as influxdb
|
||||
from homeassistant.const import EVENT_STATE_CHANGED, STATE_OFF, STATE_ON
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
@mock.patch('influxdb.InfluxDBClient')
|
||||
class TestInfluxDB(unittest.TestCase):
|
||||
@ -16,9 +17,13 @@ class TestInfluxDB(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = mock.MagicMock()
|
||||
self.hass.pool.worker_count = 2
|
||||
self.hass = get_test_home_assistant(2)
|
||||
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):
|
||||
"""Test the setup with full configuration."""
|
||||
@ -61,8 +66,6 @@ class TestInfluxDB(unittest.TestCase):
|
||||
|
||||
assert setup_component(self.hass, influxdb.DOMAIN, config)
|
||||
|
||||
@patch('homeassistant.components.persistent_notification.create',
|
||||
mock.MagicMock())
|
||||
def test_setup_missing_password(self, mock_client):
|
||||
"""Test the setup with existing username and missing password."""
|
||||
config = {
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""The testd for Core components."""
|
||||
# pylint: disable=protected-access,too-many-public-methods
|
||||
import asyncio
|
||||
import unittest
|
||||
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)
|
||||
import homeassistant.components as comps
|
||||
from homeassistant.helpers import entity
|
||||
from homeassistant.util.async import run_coroutine_threadsafe
|
||||
|
||||
from tests.common import (
|
||||
get_test_home_assistant, mock_service, patch_yaml_files)
|
||||
@ -22,7 +24,9 @@ class TestComponentsCore(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Setup things to be run when tests are started."""
|
||||
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.Ceiling', STATE_OFF)
|
||||
@ -66,6 +70,7 @@ class TestComponentsCore(unittest.TestCase):
|
||||
self.hass.block_till_done()
|
||||
self.assertEqual(1, len(calls))
|
||||
|
||||
@asyncio.coroutine
|
||||
@patch('homeassistant.core.ServiceRegistry.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."""
|
||||
@ -78,7 +83,7 @@ class TestComponentsCore(unittest.TestCase):
|
||||
'entity_id': ['light.test', 'sensor.bla', 'light.bla']
|
||||
})
|
||||
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(
|
||||
@ -131,7 +136,7 @@ class TestComponentsCore(unittest.TestCase):
|
||||
|
||||
@patch('homeassistant.config.os.path.isfile', Mock(return_value=True))
|
||||
@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):
|
||||
"""Test reload core conf service."""
|
||||
files = {
|
||||
|
@ -7,10 +7,20 @@ from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.logentries as logentries
|
||||
from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
class TestLogentries(unittest.TestCase):
|
||||
"""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):
|
||||
"""Test setup with all data."""
|
||||
config = {
|
||||
@ -18,12 +28,11 @@ class TestLogentries(unittest.TestCase):
|
||||
'token': 'secret',
|
||||
}
|
||||
}
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
self.assertTrue(setup_component(hass, logentries.DOMAIN, config))
|
||||
self.assertTrue(hass.bus.listen.called)
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
self.assertTrue(setup_component(self.hass, logentries.DOMAIN, config))
|
||||
self.assertTrue(self.hass.bus.listen.called)
|
||||
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):
|
||||
"""Test setup with defaults."""
|
||||
@ -32,12 +41,11 @@ class TestLogentries(unittest.TestCase):
|
||||
'token': 'token',
|
||||
}
|
||||
}
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
self.assertTrue(setup_component(hass, logentries.DOMAIN, config))
|
||||
self.assertTrue(hass.bus.listen.called)
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
self.assertTrue(setup_component(self.hass, logentries.DOMAIN, config))
|
||||
self.assertTrue(self.hass.bus.listen.called)
|
||||
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):
|
||||
"""Test the setup."""
|
||||
@ -49,8 +57,7 @@ class TestLogentries(unittest.TestCase):
|
||||
'token': 'token'
|
||||
}
|
||||
}
|
||||
self.hass = mock.MagicMock()
|
||||
self.hass.pool.worker_count = 2
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
setup_component(self.hass, logentries.DOMAIN, config)
|
||||
self.handler_method = self.hass.bus.listen.call_args_list[0][0][1]
|
||||
|
||||
|
@ -2,11 +2,12 @@
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import unittest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import logger
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
RECORD = namedtuple('record', ('name', 'levelno'))
|
||||
|
||||
|
||||
@ -15,18 +16,18 @@ class TestUpdater(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Setup things to be run when tests are started."""
|
||||
self.hass = get_test_home_assistant(2)
|
||||
self.log_config = {'logger':
|
||||
{'default': 'warning', 'logs': {'test': 'info'}}}
|
||||
|
||||
def tearDown(self):
|
||||
"""Stop everything that was started."""
|
||||
del logging.root.handlers[-1]
|
||||
self.hass.stop()
|
||||
|
||||
def test_logger_setup(self):
|
||||
"""Use logger to create a logging filter."""
|
||||
hass = MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
setup_component(hass, logger.DOMAIN, self.log_config)
|
||||
setup_component(self.hass, logger.DOMAIN, self.log_config)
|
||||
|
||||
self.assertTrue(len(logging.root.handlers) > 0)
|
||||
handler = logging.root.handlers[-1]
|
||||
@ -39,9 +40,7 @@ class TestUpdater(unittest.TestCase):
|
||||
|
||||
def test_logger_test_filters(self):
|
||||
"""Test resulting filter operation."""
|
||||
hass = MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
setup_component(hass, logger.DOMAIN, self.log_config)
|
||||
setup_component(self.hass, logger.DOMAIN, self.log_config)
|
||||
|
||||
log_filter = logging.root.handlers[-1].filters[0]
|
||||
|
||||
|
@ -10,7 +10,8 @@ from homeassistant.components import panel_custom
|
||||
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):
|
||||
"""Test the panel_custom component."""
|
||||
|
||||
|
@ -4,7 +4,7 @@ import unittest
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.bootstrap import _setup_component
|
||||
from homeassistant.bootstrap import setup_component
|
||||
from homeassistant.components import rfxtrx as rfxtrx
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
@ -27,14 +27,14 @@ class TestRFXTRX(unittest.TestCase):
|
||||
|
||||
def test_default_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertTrue(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertTrue(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {
|
||||
'device': '/dev/serial/by-id/usb' +
|
||||
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
|
||||
'dummy': True}
|
||||
}))
|
||||
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices': {}}}))
|
||||
@ -43,7 +43,7 @@ class TestRFXTRX(unittest.TestCase):
|
||||
|
||||
def test_valid_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertTrue(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertTrue(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {
|
||||
'device': '/dev/serial/by-id/usb' +
|
||||
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
|
||||
@ -51,7 +51,7 @@ class TestRFXTRX(unittest.TestCase):
|
||||
|
||||
self.hass.config.components.remove('rfxtrx')
|
||||
|
||||
self.assertTrue(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertTrue(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {
|
||||
'device': '/dev/serial/by-id/usb' +
|
||||
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
|
||||
@ -60,11 +60,11 @@ class TestRFXTRX(unittest.TestCase):
|
||||
|
||||
def test_invalid_config(self):
|
||||
"""Test configuration."""
|
||||
self.assertFalse(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertFalse(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {}
|
||||
}))
|
||||
|
||||
self.assertFalse(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertFalse(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {
|
||||
'device': '/dev/serial/by-id/usb' +
|
||||
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
|
||||
@ -72,13 +72,13 @@ class TestRFXTRX(unittest.TestCase):
|
||||
|
||||
def test_fire_event(self):
|
||||
"""Test fire event."""
|
||||
self.assertTrue(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertTrue(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {
|
||||
'device': '/dev/serial/by-id/usb' +
|
||||
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
|
||||
'dummy': True}
|
||||
}))
|
||||
self.assertTrue(_setup_component(self.hass, 'switch', {
|
||||
self.assertTrue(setup_component(self.hass, 'switch', {
|
||||
'switch': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
@ -116,13 +116,13 @@ class TestRFXTRX(unittest.TestCase):
|
||||
|
||||
def test_fire_event_sensor(self):
|
||||
"""Test fire event."""
|
||||
self.assertTrue(_setup_component(self.hass, 'rfxtrx', {
|
||||
self.assertTrue(setup_component(self.hass, 'rfxtrx', {
|
||||
'rfxtrx': {
|
||||
'device': '/dev/serial/by-id/usb' +
|
||||
'-RFXCOM_RFXtrx433_A1Y0NJGR-if00-port0',
|
||||
'dummy': True}
|
||||
}))
|
||||
self.assertTrue(_setup_component(self.hass, 'sensor', {
|
||||
self.assertTrue(setup_component(self.hass, 'sensor', {
|
||||
'sensor': {'platform': 'rfxtrx',
|
||||
'automatic_add': True,
|
||||
'devices':
|
||||
|
@ -65,11 +65,11 @@ class TestSleepIQ(unittest.TestCase):
|
||||
"""Test the setup when no login is configured."""
|
||||
conf = self.config.copy()
|
||||
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):
|
||||
"""Test the setup when no password is configured."""
|
||||
conf = self.config.copy()
|
||||
del conf['sleepiq']['password']
|
||||
|
||||
assert not bootstrap._setup_component(self.hass, sleepiq.DOMAIN, conf)
|
||||
assert not bootstrap.setup_component(self.hass, sleepiq.DOMAIN, conf)
|
||||
|
@ -6,10 +6,20 @@ from homeassistant.bootstrap import setup_component
|
||||
import homeassistant.components.splunk as splunk
|
||||
from homeassistant.const import STATE_ON, STATE_OFF, EVENT_STATE_CHANGED
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
class TestSplunk(unittest.TestCase):
|
||||
"""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):
|
||||
"""Test setup with all data."""
|
||||
config = {
|
||||
@ -21,12 +31,11 @@ class TestSplunk(unittest.TestCase):
|
||||
}
|
||||
}
|
||||
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
self.assertTrue(setup_component(hass, splunk.DOMAIN, config))
|
||||
self.assertTrue(hass.bus.listen.called)
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
self.assertTrue(setup_component(self.hass, splunk.DOMAIN, config))
|
||||
self.assertTrue(self.hass.bus.listen.called)
|
||||
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):
|
||||
"""Test setup with defaults."""
|
||||
@ -37,12 +46,11 @@ class TestSplunk(unittest.TestCase):
|
||||
}
|
||||
}
|
||||
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
self.assertTrue(setup_component(hass, splunk.DOMAIN, config))
|
||||
self.assertTrue(hass.bus.listen.called)
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
self.assertTrue(setup_component(self.hass, splunk.DOMAIN, config))
|
||||
self.assertTrue(self.hass.bus.listen.called)
|
||||
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):
|
||||
"""Test the setup."""
|
||||
@ -57,8 +65,7 @@ class TestSplunk(unittest.TestCase):
|
||||
}
|
||||
}
|
||||
|
||||
self.hass = mock.MagicMock()
|
||||
self.hass.pool.worker_count = 2
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
setup_component(self.hass, splunk.DOMAIN, config)
|
||||
self.handler_method = self.hass.bus.listen.call_args_list[0][0][1]
|
||||
|
||||
|
@ -9,10 +9,20 @@ import homeassistant.core as ha
|
||||
import homeassistant.components.statsd as statsd
|
||||
from homeassistant.const import (STATE_ON, STATE_OFF, EVENT_STATE_CHANGED)
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
|
||||
|
||||
class TestStatsd(unittest.TestCase):
|
||||
"""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):
|
||||
"""Test configuration with defaults."""
|
||||
config = {
|
||||
@ -37,18 +47,17 @@ class TestStatsd(unittest.TestCase):
|
||||
'prefix': 'foo',
|
||||
}
|
||||
}
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
self.assertTrue(setup_component(hass, statsd.DOMAIN, config))
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
self.assertTrue(setup_component(self.hass, statsd.DOMAIN, config))
|
||||
self.assertEqual(mock_connection.call_count, 1)
|
||||
self.assertEqual(
|
||||
mock_connection.call_args,
|
||||
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,
|
||||
hass.bus.listen.call_args_list[0][0][0])
|
||||
self.hass.bus.listen.call_args_list[0][0][0])
|
||||
|
||||
@mock.patch('statsd.StatsClient')
|
||||
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_PREFIX] = statsd.DEFAULT_PREFIX
|
||||
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
self.assertTrue(setup_component(hass, statsd.DOMAIN, config))
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
self.assertTrue(setup_component(self.hass, statsd.DOMAIN, config))
|
||||
self.assertEqual(mock_connection.call_count, 1)
|
||||
self.assertEqual(
|
||||
mock_connection.call_args,
|
||||
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')
|
||||
def test_event_listener_defaults(self, mock_client):
|
||||
@ -83,11 +91,10 @@ class TestStatsd(unittest.TestCase):
|
||||
|
||||
config['statsd'][statsd.CONF_RATE] = statsd.DEFAULT_RATE
|
||||
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
setup_component(hass, statsd.DOMAIN, config)
|
||||
self.assertTrue(hass.bus.listen.called)
|
||||
handler_method = hass.bus.listen.call_args_list[0][0][1]
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
setup_component(self.hass, statsd.DOMAIN, config)
|
||||
self.assertTrue(self.hass.bus.listen.called)
|
||||
handler_method = self.hass.bus.listen.call_args_list[0][0][1]
|
||||
|
||||
valid = {'1': 1,
|
||||
'1.0': 1.0,
|
||||
@ -128,11 +135,10 @@ class TestStatsd(unittest.TestCase):
|
||||
|
||||
config['statsd'][statsd.CONF_RATE] = statsd.DEFAULT_RATE
|
||||
|
||||
hass = mock.MagicMock()
|
||||
hass.pool.worker_count = 2
|
||||
setup_component(hass, statsd.DOMAIN, config)
|
||||
self.assertTrue(hass.bus.listen.called)
|
||||
handler_method = hass.bus.listen.call_args_list[0][0][1]
|
||||
self.hass.bus.listen = mock.MagicMock()
|
||||
setup_component(self.hass, statsd.DOMAIN, config)
|
||||
self.assertTrue(self.hass.bus.listen.called)
|
||||
handler_method = self.hass.bus.listen.call_args_list[0][0][1]
|
||||
|
||||
valid = {'1': 1,
|
||||
'1.0': 1.0,
|
||||
|
@ -127,4 +127,4 @@ class TestHelpersDiscovery:
|
||||
assert 'test_component' in self.hass.config.components
|
||||
assert 'switch' in self.hass.config.components
|
||||
assert len(component_calls) == 1
|
||||
assert len(platform_calls) == 2
|
||||
assert len(platform_calls) == 1
|
||||
|
@ -7,6 +7,7 @@ from unittest.mock import patch
|
||||
import homeassistant.core as ha
|
||||
import homeassistant.components as core_components
|
||||
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.helpers import state
|
||||
from homeassistant.const import (
|
||||
@ -63,7 +64,8 @@ class TestStateHelpers(unittest.TestCase):
|
||||
def setUp(self): # pylint: disable=invalid-name
|
||||
"""Run when tests are started."""
|
||||
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
|
||||
"""Stop when tests are finished."""
|
||||
|
@ -3,7 +3,6 @@ import asyncio
|
||||
import logging
|
||||
import os
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
|
||||
import homeassistant.scripts.check_config as check_config
|
||||
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)
|
||||
|
||||
|
||||
@patch('asyncio.get_event_loop', return_value=asyncio.new_event_loop())
|
||||
class TestCheckConfig(unittest.TestCase):
|
||||
"""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
|
||||
def test_config_platform_valid(self, mock_get_loop):
|
||||
def test_config_platform_valid(self):
|
||||
"""Test a valid platform setup."""
|
||||
files = {
|
||||
'light.yaml': BASE_CONFIG + 'light:\n platform: demo',
|
||||
@ -66,7 +75,7 @@ class TestCheckConfig(unittest.TestCase):
|
||||
'yaml_files': ['.../light.yaml']
|
||||
}, 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."""
|
||||
files = {
|
||||
'component.yaml': BASE_CONFIG + 'http:\n password: err123',
|
||||
@ -104,7 +113,7 @@ class TestCheckConfig(unittest.TestCase):
|
||||
self.assertDictEqual({}, res['secrets'])
|
||||
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."""
|
||||
files = {
|
||||
'badcomponent.yaml': BASE_CONFIG + 'beer:',
|
||||
@ -131,7 +140,7 @@ class TestCheckConfig(unittest.TestCase):
|
||||
self.assertDictEqual({}, res['secrets'])
|
||||
self.assertListEqual(['.../badplatform.yaml'], res['yaml_files'])
|
||||
|
||||
def test_secrets(self, mock_get_loop):
|
||||
def test_secrets(self):
|
||||
"""Test secrets config checking method."""
|
||||
files = {
|
||||
get_test_config_dir('secret.yaml'): (
|
||||
|
@ -48,11 +48,10 @@ class TestBootstrap:
|
||||
@mock.patch(
|
||||
# prevent .HA_VERISON file from being written
|
||||
'homeassistant.bootstrap.conf_util.process_ha_config_upgrade',
|
||||
mock.Mock()
|
||||
)
|
||||
autospec=True)
|
||||
@mock.patch('homeassistant.util.location.detect_location_info',
|
||||
return_value=None)
|
||||
def test_from_config_file(self, mock_detect):
|
||||
autospec=True, return_value=None)
|
||||
def test_from_config_file(self, mock_upgrade, mock_detect):
|
||||
"""Test with configuration file."""
|
||||
components = ['browser', 'conversation', 'script']
|
||||
files = {
|
||||
@ -94,28 +93,33 @@ class TestBootstrap:
|
||||
loader.set_component(
|
||||
'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', {
|
||||
'comp_conf': None
|
||||
})
|
||||
with assert_setup_component(0):
|
||||
assert not bootstrap.setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': None
|
||||
})
|
||||
|
||||
assert not bootstrap._setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': {}
|
||||
})
|
||||
with assert_setup_component(0):
|
||||
assert not bootstrap.setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': {}
|
||||
})
|
||||
|
||||
assert not bootstrap._setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': {
|
||||
'hello': 'world',
|
||||
'invalid': 'extra',
|
||||
}
|
||||
})
|
||||
with assert_setup_component(0):
|
||||
assert not bootstrap.setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': {
|
||||
'hello': 'world',
|
||||
'invalid': 'extra',
|
||||
}
|
||||
})
|
||||
|
||||
assert bootstrap._setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': {
|
||||
'hello': 'world',
|
||||
}
|
||||
})
|
||||
with assert_setup_component(1):
|
||||
assert bootstrap.setup_component(self.hass, 'comp_conf', {
|
||||
'comp_conf': {
|
||||
'hello': 'world',
|
||||
}
|
||||
})
|
||||
|
||||
def test_validate_platform_config(self):
|
||||
"""Test validating platform configuration."""
|
||||
@ -130,7 +134,7 @@ class TestBootstrap:
|
||||
'platform_conf.whatever', MockPlatform('whatever'))
|
||||
|
||||
with assert_setup_component(0):
|
||||
assert bootstrap._setup_component(self.hass, 'platform_conf', {
|
||||
assert bootstrap.setup_component(self.hass, 'platform_conf', {
|
||||
'platform_conf': {
|
||||
'hello': 'world',
|
||||
'invalid': 'extra',
|
||||
@ -140,7 +144,7 @@ class TestBootstrap:
|
||||
self.hass.config.components.remove('platform_conf')
|
||||
|
||||
with assert_setup_component(1):
|
||||
assert bootstrap._setup_component(self.hass, 'platform_conf', {
|
||||
assert bootstrap.setup_component(self.hass, 'platform_conf', {
|
||||
'platform_conf': {
|
||||
'platform': 'whatever',
|
||||
'hello': 'world',
|
||||
@ -153,7 +157,7 @@ class TestBootstrap:
|
||||
self.hass.config.components.remove('platform_conf')
|
||||
|
||||
with assert_setup_component(0):
|
||||
assert bootstrap._setup_component(self.hass, 'platform_conf', {
|
||||
assert bootstrap.setup_component(self.hass, 'platform_conf', {
|
||||
'platform_conf': {
|
||||
'platform': 'not_existing',
|
||||
'hello': 'world',
|
||||
@ -163,7 +167,7 @@ class TestBootstrap:
|
||||
self.hass.config.components.remove('platform_conf')
|
||||
|
||||
with assert_setup_component(1):
|
||||
assert bootstrap._setup_component(self.hass, 'platform_conf', {
|
||||
assert bootstrap.setup_component(self.hass, 'platform_conf', {
|
||||
'platform_conf': {
|
||||
'platform': 'whatever',
|
||||
'hello': 'world',
|
||||
@ -173,7 +177,7 @@ class TestBootstrap:
|
||||
self.hass.config.components.remove('platform_conf')
|
||||
|
||||
with assert_setup_component(1):
|
||||
assert bootstrap._setup_component(self.hass, 'platform_conf', {
|
||||
assert bootstrap.setup_component(self.hass, 'platform_conf', {
|
||||
'platform_conf': [{
|
||||
'platform': 'whatever',
|
||||
'hello': 'world',
|
||||
@ -184,13 +188,13 @@ class TestBootstrap:
|
||||
|
||||
# Any falsey platform config will be ignored (None, {}, etc)
|
||||
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
|
||||
})
|
||||
assert 'platform_conf' in self.hass.config.components
|
||||
assert not config['platform_conf'] # empty
|
||||
|
||||
assert bootstrap._setup_component(self.hass, 'platform_conf', {
|
||||
assert bootstrap.setup_component(self.hass, 'platform_conf', {
|
||||
'platform_conf': {}
|
||||
})
|
||||
assert 'platform_conf' in self.hass.config.components
|
||||
@ -235,10 +239,9 @@ class TestBootstrap:
|
||||
"""Setup the component."""
|
||||
result.append(bootstrap.setup_component(self.hass, 'comp'))
|
||||
|
||||
with bootstrap._SETUP_LOCK:
|
||||
thread = threading.Thread(target=setup_component)
|
||||
thread.start()
|
||||
self.hass.config.components.append('comp')
|
||||
thread = threading.Thread(target=setup_component)
|
||||
thread.start()
|
||||
self.hass.config.components.append('comp')
|
||||
|
||||
thread.join()
|
||||
|
||||
@ -250,19 +253,19 @@ class TestBootstrap:
|
||||
deps = ['non_existing']
|
||||
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
|
||||
|
||||
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):
|
||||
"""Test component that fails setup."""
|
||||
loader.set_component(
|
||||
'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
|
||||
|
||||
def test_component_exception_setup(self):
|
||||
@ -273,18 +276,17 @@ class TestBootstrap:
|
||||
|
||||
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
|
||||
|
||||
def test_home_assistant_core_config_validation(self):
|
||||
"""Test if we pass in wrong information for HA conf."""
|
||||
# Extensive HA conf validation testing is done in test_config.py
|
||||
hass = get_test_home_assistant()
|
||||
assert None is bootstrap.from_config_dict({
|
||||
'homeassistant': {
|
||||
'latitude': 'some string'
|
||||
}
|
||||
}, hass=hass)
|
||||
})
|
||||
|
||||
def test_component_setup_with_validation_and_dependency(self):
|
||||
"""Test all config is passed to dependencies."""
|
||||
@ -316,7 +318,7 @@ class TestBootstrap:
|
||||
'valid': True,
|
||||
}, extra=vol.PREVENT_EXTRA)
|
||||
|
||||
mock_setup = mock.MagicMock()
|
||||
mock_setup = mock.MagicMock(spec_set=True)
|
||||
|
||||
loader.set_component(
|
||||
'switch.platform_a',
|
||||
|
@ -14,6 +14,7 @@ from homeassistant.const import (
|
||||
CONF_TIME_ZONE, CONF_ELEVATION, CONF_CUSTOMIZE, __version__,
|
||||
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.async import run_coroutine_threadsafe
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from tests.common import (
|
||||
@ -34,6 +35,10 @@ def create_file(path):
|
||||
class TestConfig(unittest.TestCase):
|
||||
"""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
|
||||
"""Clean up."""
|
||||
dt_util.DEFAULT_TIME_ZONE = ORIG_TIMEZONE
|
||||
@ -44,8 +49,7 @@ class TestConfig(unittest.TestCase):
|
||||
if os.path.isfile(VERSION_PATH):
|
||||
os.remove(VERSION_PATH)
|
||||
|
||||
if hasattr(self, 'hass'):
|
||||
self.hass.stop()
|
||||
self.hass.stop()
|
||||
|
||||
def test_create_default_config(self):
|
||||
"""Test creation of default config."""
|
||||
@ -165,6 +169,7 @@ class TestConfig(unittest.TestCase):
|
||||
self.assertTrue(mock_print.called)
|
||||
|
||||
def test_core_config_schema(self):
|
||||
"""Test core config schema."""
|
||||
for value in (
|
||||
{CONF_UNIT_SYSTEM: 'K'},
|
||||
{'time_zone': 'non-exist'},
|
||||
@ -191,14 +196,14 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_entity_customization(self):
|
||||
"""Test entity customization through configuration."""
|
||||
self.hass = get_test_home_assistant()
|
||||
|
||||
config = {CONF_LATITUDE: 50,
|
||||
CONF_LONGITUDE: 50,
|
||||
CONF_NAME: 'Test',
|
||||
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_id = 'test.test'
|
||||
@ -224,7 +229,6 @@ class TestConfig(unittest.TestCase):
|
||||
opened_file = mock_open.return_value
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.path = mock.Mock()
|
||||
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
@ -254,7 +258,6 @@ class TestConfig(unittest.TestCase):
|
||||
opened_file = mock_open.return_value
|
||||
opened_file.readline.return_value = ha_version
|
||||
|
||||
self.hass = get_test_home_assistant()
|
||||
self.hass.config.path = mock.Mock()
|
||||
|
||||
config_util.process_ha_config_upgrade(self.hass)
|
||||
@ -264,82 +267,91 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_loading_configuration(self):
|
||||
"""Test loading core config onto hass object."""
|
||||
config = Config()
|
||||
hass = mock.Mock(config=config)
|
||||
self.hass.config = mock.Mock()
|
||||
|
||||
config_util.process_ha_core_config(hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL,
|
||||
'time_zone': 'America/New_York',
|
||||
})
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_UNIT_SYSTEM: CONF_UNIT_SYSTEM_IMPERIAL,
|
||||
'time_zone': 'America/New_York',
|
||||
}), self.hass.loop).result()
|
||||
|
||||
assert config.latitude == 60
|
||||
assert config.longitude == 50
|
||||
assert config.elevation == 25
|
||||
assert config.location_name == 'Huis'
|
||||
assert config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
|
||||
assert config.time_zone.zone == 'America/New_York'
|
||||
assert self.hass.config.latitude == 60
|
||||
assert self.hass.config.longitude == 50
|
||||
assert self.hass.config.elevation == 25
|
||||
assert self.hass.config.location_name == 'Huis'
|
||||
assert self.hass.config.units.name == CONF_UNIT_SYSTEM_IMPERIAL
|
||||
assert self.hass.config.time_zone.zone == 'America/New_York'
|
||||
|
||||
def test_loading_configuration_temperature_unit(self):
|
||||
"""Test backward compatibility when loading core config."""
|
||||
config = Config()
|
||||
hass = mock.Mock(config=config)
|
||||
self.hass.config = mock.Mock()
|
||||
|
||||
config_util.process_ha_core_config(hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'America/New_York',
|
||||
})
|
||||
run_coroutine_threadsafe(
|
||||
config_util.async_process_ha_core_config(self.hass, {
|
||||
'latitude': 60,
|
||||
'longitude': 50,
|
||||
'elevation': 25,
|
||||
'name': 'Huis',
|
||||
CONF_TEMPERATURE_UNIT: 'C',
|
||||
'time_zone': 'America/New_York',
|
||||
}), self.hass.loop).result()
|
||||
|
||||
assert config.latitude == 60
|
||||
assert config.longitude == 50
|
||||
assert config.elevation == 25
|
||||
assert config.location_name == 'Huis'
|
||||
assert config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert config.time_zone.zone == 'America/New_York'
|
||||
assert self.hass.config.latitude == 60
|
||||
assert self.hass.config.longitude == 50
|
||||
assert self.hass.config.elevation == 25
|
||||
assert self.hass.config.location_name == 'Huis'
|
||||
assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert self.hass.config.time_zone.zone == 'America/New_York'
|
||||
|
||||
@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',
|
||||
'San Diego', '92122', 'America/Los_Angeles', 32.8594,
|
||||
-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):
|
||||
"""Test auto discovery for missing core configs."""
|
||||
config = Config()
|
||||
hass = mock.Mock(config=config)
|
||||
self.hass.config.latitude = None
|
||||
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 config.longitude == -117.2073
|
||||
assert config.elevation == 101
|
||||
assert config.location_name == 'San Diego'
|
||||
assert config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert config.units.is_metric
|
||||
assert config.time_zone.zone == 'America/Los_Angeles'
|
||||
assert self.hass.config.latitude == 32.8594
|
||||
assert self.hass.config.longitude == -117.2073
|
||||
assert self.hass.config.elevation == 101
|
||||
assert self.hass.config.location_name == 'San Diego'
|
||||
assert self.hass.config.units.name == CONF_UNIT_SYSTEM_METRIC
|
||||
assert self.hass.config.units.is_metric
|
||||
assert self.hass.config.time_zone.zone == 'America/Los_Angeles'
|
||||
|
||||
@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)
|
||||
def test_discovering_configuration_auto_detect_fails(self, mock_detect,
|
||||
mock_elevation):
|
||||
"""Test config remains unchanged if discovery fails."""
|
||||
config = Config()
|
||||
hass = mock.Mock(config=config)
|
||||
self.hass.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()
|
||||
assert config.latitude == blankConfig.latitude
|
||||
assert config.longitude == blankConfig.longitude
|
||||
assert config.elevation == blankConfig.elevation
|
||||
assert config.location_name == blankConfig.location_name
|
||||
assert config.units == blankConfig.units
|
||||
assert config.time_zone == blankConfig.time_zone
|
||||
assert self.hass.config.latitude == blankConfig.latitude
|
||||
assert self.hass.config.longitude == blankConfig.longitude
|
||||
assert self.hass.config.elevation == blankConfig.elevation
|
||||
assert self.hass.config.location_name == blankConfig.location_name
|
||||
assert self.hass.config.units == blankConfig.units
|
||||
assert self.hass.config.time_zone == blankConfig.time_zone
|
||||
|
Loading…
x
Reference in New Issue
Block a user