Async bootstrap / component init (#3991)

* Async bootstrap

* Adress comments

* Fix tests

* More fixes

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

View File

@ -1,11 +1,10 @@
"""Provides methods to bootstrap a home assistant instance."""
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'))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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))

View File

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

View File

@ -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

View File

@ -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. "

View File

@ -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

View File

@ -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:

View File

@ -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()

View File

@ -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:

View File

@ -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',

View File

@ -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):

View File

@ -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',

View File

@ -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',

View File

@ -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'},
}})

View File

@ -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',

View File

@ -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',

View File

@ -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',

View File

@ -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',

View File

@ -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)

View File

@ -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': {}}}))

View File

@ -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}

View File

@ -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',

View File

@ -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': {}}}))

View File

@ -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',

View File

@ -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',
}

View File

@ -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: {}}
})

View File

@ -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')

View File

@ -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()

View File

@ -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',

View File

@ -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': {

View File

@ -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': [

View File

@ -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',

View File

@ -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': {}}}))

View File

@ -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."""

View File

@ -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()

View File

@ -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 = {

View File

@ -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 = {

View File

@ -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]

View File

@ -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]

View File

@ -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."""

View File

@ -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':

View File

@ -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)

View File

@ -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]

View File

@ -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,

View File

@ -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

View File

@ -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."""

View File

@ -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'): (

View File

@ -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',

View File

@ -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