Merge pull request #2776 from home-assistant/add-notify-test
Add notify demo data testpull/2779/head
commit
1726c4b45a
|
@ -11,12 +11,12 @@ from types import ModuleType
|
||||||
from typing import Any, Optional, Dict
|
from typing import Any, Optional, Dict
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
from voluptuous.humanize import humanize_error
|
||||||
|
|
||||||
import homeassistant.components as core_components
|
import homeassistant.components as core_components
|
||||||
from homeassistant.components import group, persistent_notification
|
from homeassistant.components import group, persistent_notification
|
||||||
import homeassistant.config as conf_util
|
import homeassistant.config as conf_util
|
||||||
import homeassistant.core as core
|
import homeassistant.core as core
|
||||||
import homeassistant.helpers.config_validation as cv
|
|
||||||
import homeassistant.loader as loader
|
import homeassistant.loader as loader
|
||||||
import homeassistant.util.package as pkg_util
|
import homeassistant.util.package as pkg_util
|
||||||
from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT
|
from homeassistant.const import EVENT_COMPONENT_LOADED, PLATFORM_FORMAT
|
||||||
|
@ -103,7 +103,7 @@ def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
|
||||||
try:
|
try:
|
||||||
config = component.CONFIG_SCHEMA(config)
|
config = component.CONFIG_SCHEMA(config)
|
||||||
except vol.MultipleInvalid as ex:
|
except vol.MultipleInvalid as ex:
|
||||||
cv.log_exception(_LOGGER, ex, domain, config)
|
_log_exception(ex, domain, config)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
elif hasattr(component, 'PLATFORM_SCHEMA'):
|
elif hasattr(component, 'PLATFORM_SCHEMA'):
|
||||||
|
@ -113,7 +113,7 @@ def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
|
||||||
try:
|
try:
|
||||||
p_validated = component.PLATFORM_SCHEMA(p_config)
|
p_validated = component.PLATFORM_SCHEMA(p_config)
|
||||||
except vol.MultipleInvalid as ex:
|
except vol.MultipleInvalid as ex:
|
||||||
cv.log_exception(_LOGGER, ex, domain, p_config)
|
_log_exception(ex, domain, p_config)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Not all platform components follow same pattern for platforms
|
# Not all platform components follow same pattern for platforms
|
||||||
|
@ -134,8 +134,8 @@ def _setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
|
||||||
try:
|
try:
|
||||||
p_validated = platform.PLATFORM_SCHEMA(p_validated)
|
p_validated = platform.PLATFORM_SCHEMA(p_validated)
|
||||||
except vol.MultipleInvalid as ex:
|
except vol.MultipleInvalid as ex:
|
||||||
cv.log_exception(_LOGGER, ex, '{}.{}'
|
_log_exception(ex, '{}.{}'.format(domain, p_name),
|
||||||
.format(domain, p_name), p_validated)
|
p_validated)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
platforms.append(p_validated)
|
platforms.append(p_validated)
|
||||||
|
@ -239,7 +239,7 @@ def from_config_dict(config: Dict[str, Any],
|
||||||
try:
|
try:
|
||||||
conf_util.process_ha_core_config(hass, core_config)
|
conf_util.process_ha_core_config(hass, core_config)
|
||||||
except vol.Invalid as ex:
|
except vol.Invalid as ex:
|
||||||
cv.log_exception(_LOGGER, ex, 'homeassistant', core_config)
|
_log_exception(ex, 'homeassistant', core_config)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
conf_util.process_ha_config_upgrade(hass)
|
conf_util.process_ha_config_upgrade(hass)
|
||||||
|
@ -374,3 +374,20 @@ def _ensure_loader_prepared(hass: core.HomeAssistant) -> None:
|
||||||
def _mount_local_lib_path(config_dir: str) -> None:
|
def _mount_local_lib_path(config_dir: str) -> None:
|
||||||
"""Add local library to Python Path."""
|
"""Add local library to Python Path."""
|
||||||
sys.path.insert(0, os.path.join(config_dir, 'deps'))
|
sys.path.insert(0, os.path.join(config_dir, 'deps'))
|
||||||
|
|
||||||
|
|
||||||
|
def _log_exception(ex, domain, config):
|
||||||
|
"""Generate log exception for config validation."""
|
||||||
|
message = 'Invalid config for [{}]: '.format(domain)
|
||||||
|
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))
|
||||||
|
else:
|
||||||
|
message += humanize_error(config, ex)
|
||||||
|
|
||||||
|
if hasattr(config, '__line__'):
|
||||||
|
message += " (See {}:{})".format(config.__config_file__,
|
||||||
|
config.__line__ or '?')
|
||||||
|
|
||||||
|
_LOGGER.error(message)
|
||||||
|
|
|
@ -44,16 +44,19 @@ NOTIFY_SERVICE_SCHEMA = vol.Schema({
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def send_message(hass, message, title=None):
|
def send_message(hass, message, title=None, data=None):
|
||||||
"""Send a notification message."""
|
"""Send a notification message."""
|
||||||
data = {
|
info = {
|
||||||
ATTR_MESSAGE: message
|
ATTR_MESSAGE: message
|
||||||
}
|
}
|
||||||
|
|
||||||
if title is not None:
|
if title is not None:
|
||||||
data[ATTR_TITLE] = title
|
info[ATTR_TITLE] = title
|
||||||
|
|
||||||
hass.services.call(DOMAIN, SERVICE_NOTIFY, data)
|
if data is not None:
|
||||||
|
info[ATTR_DATA] = data
|
||||||
|
|
||||||
|
hass.services.call(DOMAIN, SERVICE_NOTIFY, info)
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
def setup(hass, config):
|
||||||
|
|
|
@ -4,7 +4,7 @@ Demo notification service.
|
||||||
For more details about this platform, please refer to the documentation
|
For more details about this platform, please refer to the documentation
|
||||||
https://home-assistant.io/components/demo/
|
https://home-assistant.io/components/demo/
|
||||||
"""
|
"""
|
||||||
from homeassistant.components.notify import ATTR_TITLE, BaseNotificationService
|
from homeassistant.components.notify import BaseNotificationService
|
||||||
|
|
||||||
EVENT_NOTIFY = "notify"
|
EVENT_NOTIFY = "notify"
|
||||||
|
|
||||||
|
@ -24,5 +24,5 @@ class DemoNotificationService(BaseNotificationService):
|
||||||
|
|
||||||
def send_message(self, message="", **kwargs):
|
def send_message(self, message="", **kwargs):
|
||||||
"""Send a message to a user."""
|
"""Send a message to a user."""
|
||||||
title = kwargs.get(ATTR_TITLE)
|
kwargs['message'] = message
|
||||||
self.hass.bus.fire(EVENT_NOTIFY, {"title": title, "message": message})
|
self.hass.bus.fire(EVENT_NOTIFY, kwargs)
|
||||||
|
|
|
@ -19,6 +19,7 @@ from types import MappingProxyType
|
||||||
from typing import Optional, Any, Callable, List # NOQA
|
from typing import Optional, Any, Callable, List # NOQA
|
||||||
|
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
from voluptuous.humanize import humanize_error
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_DOMAIN, ATTR_FRIENDLY_NAME, ATTR_NOW, ATTR_SERVICE,
|
ATTR_DOMAIN, ATTR_FRIENDLY_NAME, ATTR_NOW, ATTR_SERVICE,
|
||||||
|
@ -571,7 +572,8 @@ class Service(object):
|
||||||
self.func(call)
|
self.func(call)
|
||||||
except vol.MultipleInvalid as ex:
|
except vol.MultipleInvalid as ex:
|
||||||
_LOGGER.error('Invalid service data for %s.%s: %s',
|
_LOGGER.error('Invalid service data for %s.%s: %s',
|
||||||
call.domain, call.service, ex)
|
call.domain, call.service,
|
||||||
|
humanize_error(call.data, ex))
|
||||||
|
|
||||||
|
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
|
|
|
@ -152,23 +152,6 @@ def time_period_str(value: str) -> timedelta:
|
||||||
time_period = vol.Any(time_period_str, timedelta, time_period_dict)
|
time_period = vol.Any(time_period_str, timedelta, time_period_dict)
|
||||||
|
|
||||||
|
|
||||||
def log_exception(logger, ex, domain, config):
|
|
||||||
"""Generate log exception for config validation."""
|
|
||||||
message = 'Invalid config for [{}]: '.format(domain)
|
|
||||||
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))
|
|
||||||
else:
|
|
||||||
message += str(ex)
|
|
||||||
|
|
||||||
if hasattr(config, '__line__'):
|
|
||||||
message += " (See {}:{})".format(config.__config_file__,
|
|
||||||
config.__line__ or '?')
|
|
||||||
|
|
||||||
logger.error(message)
|
|
||||||
|
|
||||||
|
|
||||||
def match_all(value):
|
def match_all(value):
|
||||||
"""Validator that matches all values."""
|
"""Validator that matches all values."""
|
||||||
return value
|
return value
|
||||||
|
@ -239,6 +222,8 @@ def template(value):
|
||||||
"""Validate a jinja2 template."""
|
"""Validate a jinja2 template."""
|
||||||
if value is None:
|
if value is None:
|
||||||
raise vol.Invalid('template value is None')
|
raise vol.Invalid('template value is None')
|
||||||
|
if isinstance(value, (list, dict)):
|
||||||
|
raise vol.Invalid('template value should be a string')
|
||||||
|
|
||||||
value = str(value)
|
value = str(value)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
"""The tests for the notify demo platform."""
|
"""The tests for the notify demo platform."""
|
||||||
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import homeassistant.components.notify as notify
|
import homeassistant.components.notify as notify
|
||||||
from homeassistant.components.notify import demo
|
from homeassistant.components.notify import demo
|
||||||
|
from homeassistant.helpers import script
|
||||||
|
from homeassistant.util import yaml
|
||||||
|
|
||||||
from tests.common import get_test_home_assistant
|
from tests.common import get_test_home_assistant
|
||||||
|
|
||||||
|
@ -45,3 +48,48 @@ class TestNotifyDemo(unittest.TestCase):
|
||||||
last_event = self.events[-1]
|
last_event = self.events[-1]
|
||||||
self.assertEqual(last_event.data[notify.ATTR_TITLE], 'temperature')
|
self.assertEqual(last_event.data[notify.ATTR_TITLE], 'temperature')
|
||||||
self.assertEqual(last_event.data[notify.ATTR_MESSAGE], '10')
|
self.assertEqual(last_event.data[notify.ATTR_MESSAGE], '10')
|
||||||
|
|
||||||
|
def test_method_forwards_correct_data(self):
|
||||||
|
"""Test that all data from the service gets forwarded to service."""
|
||||||
|
notify.send_message(self.hass, 'my message', 'my title',
|
||||||
|
{'hello': 'world'})
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertTrue(len(self.events) == 1)
|
||||||
|
data = self.events[0].data
|
||||||
|
assert {
|
||||||
|
'message': 'my message',
|
||||||
|
'target': None,
|
||||||
|
'title': 'my title',
|
||||||
|
'data': {'hello': 'world'}
|
||||||
|
} == data
|
||||||
|
|
||||||
|
def test_calling_notify_from_script_loaded_from_yaml(self):
|
||||||
|
"""Test if we can call a notify from a script."""
|
||||||
|
yaml_conf = """
|
||||||
|
service: notify.notify
|
||||||
|
data:
|
||||||
|
data:
|
||||||
|
push:
|
||||||
|
sound: US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav
|
||||||
|
data_template:
|
||||||
|
message: >
|
||||||
|
Test 123 {{ 2 + 2 }}
|
||||||
|
"""
|
||||||
|
|
||||||
|
with tempfile.NamedTemporaryFile() as fp:
|
||||||
|
fp.write(yaml_conf.encode('utf-8'))
|
||||||
|
fp.flush()
|
||||||
|
conf = yaml.load_yaml(fp.name)
|
||||||
|
|
||||||
|
script.call_from_config(self.hass, conf)
|
||||||
|
self.hass.pool.block_till_done()
|
||||||
|
self.assertTrue(len(self.events) == 1)
|
||||||
|
assert {
|
||||||
|
'message': 'Test 123 4',
|
||||||
|
'target': None,
|
||||||
|
'title': 'Home Assistant',
|
||||||
|
'data': {
|
||||||
|
'push': {
|
||||||
|
'sound':
|
||||||
|
'US-EN-Morgan-Freeman-Roommate-Is-Arriving.wav'}}
|
||||||
|
} == self.events[0].data
|
||||||
|
|
|
@ -253,7 +253,7 @@ def test_template():
|
||||||
schema = vol.Schema(cv.template)
|
schema = vol.Schema(cv.template)
|
||||||
|
|
||||||
for value in (
|
for value in (
|
||||||
None, '{{ partial_print }', '{% if True %}Hello'
|
None, '{{ partial_print }', '{% if True %}Hello', {'dict': 'isbad'}
|
||||||
):
|
):
|
||||||
with pytest.raises(vol.MultipleInvalid):
|
with pytest.raises(vol.MultipleInvalid):
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
Loading…
Reference in New Issue