Config validation for MQTT

This commit is contained in:
Jan Harkes 2016-04-04 00:22:04 -04:00
parent 2e9bf42688
commit 8cca2bb344
4 changed files with 47 additions and 24 deletions

View file

@ -14,7 +14,6 @@ import voluptuous as vol
from homeassistant.bootstrap import prepare_setup_platform from homeassistant.bootstrap import prepare_setup_platform
from homeassistant.config import load_yaml_config_file from homeassistant.config import load_yaml_config_file
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
import homeassistant.util as util
from homeassistant.helpers import template from homeassistant.helpers import template
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.const import ( from homeassistant.const import (
@ -58,6 +57,25 @@ ATTR_RETAIN = 'retain'
MAX_RECONNECT_WAIT = 300 # seconds MAX_RECONNECT_WAIT = 300 # seconds
_HBMQTT_CONFIG_SCHEMA = vol.Schema(dict)
CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({
vol.Optional(CONF_CLIENT_ID): cv.string,
vol.Optional(CONF_KEEPALIVE, default=DEFAULT_KEEPALIVE):
vol.All(vol.Coerce(int), vol.Range(min=15)),
vol.Optional(CONF_BROKER): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT):
vol.All(vol.Coerce(int), vol.Range(min=1, max=65535)),
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_CERTIFICATE): vol.IsFile,
vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL):
[PROTOCOL_31, PROTOCOL_311],
vol.Optional(CONF_EMBEDDED): _HBMQTT_CONFIG_SCHEMA,
}),
})
# Service call validation schema # Service call validation schema
def mqtt_topic(value): def mqtt_topic(value):
@ -136,8 +154,8 @@ def setup(hass, config):
# pylint: disable=too-many-locals # pylint: disable=too-many-locals
conf = config.get(DOMAIN, {}) conf = config.get(DOMAIN, {})
client_id = util.convert(conf.get(CONF_CLIENT_ID), str) client_id = conf.get(CONF_CLIENT_ID)
keepalive = util.convert(conf.get(CONF_KEEPALIVE), int, DEFAULT_KEEPALIVE) keepalive = conf.get(CONF_KEEPALIVE)
broker_config = _setup_server(hass, config) broker_config = _setup_server(hass, config)
@ -151,16 +169,11 @@ def setup(hass, config):
if CONF_BROKER in conf: if CONF_BROKER in conf:
broker = conf[CONF_BROKER] broker = conf[CONF_BROKER]
port = util.convert(conf.get(CONF_PORT), int, DEFAULT_PORT) port = conf[CONF_PORT]
username = util.convert(conf.get(CONF_USERNAME), str) username = conf.get(CONF_USERNAME)
password = util.convert(conf.get(CONF_PASSWORD), str) password = conf.get(CONF_PASSWORD)
certificate = util.convert(conf.get(CONF_CERTIFICATE), str) certificate = conf.get(CONF_CERTIFICATE)
protocol = util.convert(conf.get(CONF_PROTOCOL), str, DEFAULT_PROTOCOL) protocol = conf[CONF_PROTOCOL]
if protocol not in (PROTOCOL_31, PROTOCOL_311):
_LOGGER.error('Invalid protocol specified: %s. Allowed values: %s, %s',
protocol, PROTOCOL_31, PROTOCOL_311)
return False
# For cloudmqtt.com, secured connection, auto fill in certificate # For cloudmqtt.com, secured connection, auto fill in certificate
if certificate is None and 19999 < port < 30000 and \ if certificate is None and 19999 < port < 30000 and \

View file

@ -4,6 +4,7 @@ from datetime import timedelta
from unittest import mock from unittest import mock
from homeassistant import core as ha, loader from homeassistant import core as ha, loader
from homeassistant.bootstrap import _setup_component
from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity import ToggleEntity
from homeassistant.const import ( from homeassistant.const import (
STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED, STATE_ON, STATE_OFF, DEVICE_DEFAULT_NAME, EVENT_TIME_CHANGED,
@ -123,7 +124,7 @@ def mock_http_component(hass):
@mock.patch('homeassistant.components.mqtt.MQTT') @mock.patch('homeassistant.components.mqtt.MQTT')
def mock_mqtt_component(hass, mock_mqtt): def mock_mqtt_component(hass, mock_mqtt):
"""Mock the MQTT component.""" """Mock the MQTT component."""
mqtt.setup(hass, { _setup_component(hass, mqtt.DOMAIN, {
mqtt.DOMAIN: { mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'mock-broker', mqtt.CONF_BROKER: 'mock-broker',
} }

View file

@ -4,6 +4,7 @@ import unittest
from unittest import mock from unittest import mock
import socket import socket
from homeassistant.bootstrap import _setup_component
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
from homeassistant.const import ( from homeassistant.const import (
EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START, EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE, EVENT_HOMEASSISTANT_START,
@ -48,9 +49,11 @@ class TestMQTT(unittest.TestCase):
"""Test for setup failure if connection to broker is missing.""" """Test for setup failure if connection to broker is missing."""
with mock.patch('homeassistant.components.mqtt.MQTT', with mock.patch('homeassistant.components.mqtt.MQTT',
side_effect=socket.error()): side_effect=socket.error()):
self.assertFalse(mqtt.setup(self.hass, {mqtt.DOMAIN: { assert not _setup_component(self.hass, mqtt.DOMAIN, {
mqtt.CONF_BROKER: 'test-broker', mqtt.DOMAIN: {
}})) mqtt.CONF_BROKER: 'test-broker',
}
})
def test_publish_calls_service(self): def test_publish_calls_service(self):
"""Test the publishing of call to services.""" """Test the publishing of call to services."""
@ -211,7 +214,7 @@ class TestMQTTCallbacks(unittest.TestCase):
# mock_mqtt_component(self.hass) # mock_mqtt_component(self.hass)
with mock.patch('paho.mqtt.client.Client'): with mock.patch('paho.mqtt.client.Client'):
mqtt.setup(self.hass, { _setup_component(self.hass, mqtt.DOMAIN, {
mqtt.DOMAIN: { mqtt.DOMAIN: {
mqtt.CONF_BROKER: 'mock-broker', mqtt.CONF_BROKER: 'mock-broker',
} }

View file

@ -1,6 +1,7 @@
"""The tests for the MQTT component embedded server.""" """The tests for the MQTT component embedded server."""
from unittest.mock import MagicMock, patch from unittest.mock import MagicMock, patch
from homeassistant.bootstrap import _setup_component
import homeassistant.components.mqtt as mqtt import homeassistant.components.mqtt as mqtt
from tests.common import get_test_home_assistant from tests.common import get_test_home_assistant
@ -27,15 +28,20 @@ class TestMQTT:
password = 'super_secret' password = 'super_secret'
self.hass.config.api = MagicMock(api_password=password) self.hass.config.api = MagicMock(api_password=password)
assert mqtt.setup(self.hass, {}) assert _setup_component(self.hass, mqtt.DOMAIN, {})
assert mock_mqtt.called assert mock_mqtt.called
assert mock_mqtt.mock_calls[0][1][5] == 'homeassistant' assert mock_mqtt.mock_calls[0][1][5] == 'homeassistant'
assert mock_mqtt.mock_calls[0][1][6] == password assert mock_mqtt.mock_calls[0][1][6] == password
mock_mqtt.reset_mock() @patch('homeassistant.components.mqtt.MQTT')
@patch('asyncio.gather')
@patch('asyncio.new_event_loop')
def test_creating_config_no_http_pass(self, mock_new_loop, mock_gather,
mock_mqtt):
"""Test if the MQTT server gets started and subscribe/publish msg."""
self.hass.config.components.append('http')
self.hass.config.api = MagicMock(api_password=None) self.hass.config.api = MagicMock(api_password=None)
assert mqtt.setup(self.hass, {}) assert _setup_component(self.hass, mqtt.DOMAIN, {})
assert mock_mqtt.called assert mock_mqtt.called
assert mock_mqtt.mock_calls[0][1][5] is None assert mock_mqtt.mock_calls[0][1][5] is None
assert mock_mqtt.mock_calls[0][1][6] is None assert mock_mqtt.mock_calls[0][1][6] is None
@ -50,6 +56,6 @@ class TestMQTT:
mock_gather.side_effect = BrokerException mock_gather.side_effect = BrokerException
self.hass.config.api = MagicMock(api_password=None) self.hass.config.api = MagicMock(api_password=None)
assert not mqtt.setup(self.hass, { assert not _setup_component(self.hass, mqtt.DOMAIN, {
'mqtt': {'embedded': {}} mqtt.DOMAIN: {mqtt.CONF_EMBEDDED: {}}
}) })