MQTT config entry (#16594)

* MQTT config entry

* Solely rely on config entry

* Improve wawrning

* Lint

* Lint2
This commit is contained in:
Paulus Schoutsen 2018-09-14 11:57:31 +02:00 committed by GitHub
parent 05c0717167
commit 72e746d240
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 435 additions and 133 deletions

View file

@ -14,6 +14,7 @@
"data": {
"2fa": "2FA Pin"
},
"description": "",
"title": "2-Factor-Authentication"
},
"user": {
@ -21,6 +22,7 @@
"email": "E-Mail Address",
"password": "Password"
},
"description": "",
"title": "Google Hangouts Login"
}
},

View file

@ -2,7 +2,6 @@
"config": {
"abort": {
"already_configured": "Access point is already configured",
"conection_aborted": "Could not connect to HMIP server",
"connection_aborted": "Could not connect to HMIP server",
"unknown": "Unknown error occurred."
},

View file

@ -0,0 +1,23 @@
{
"config": {
"abort": {
"single_instance_allowed": "Only a single configuration of MQTT is allowed."
},
"error": {
"cannot_connect": "Unable to connect to the broker."
},
"step": {
"broker": {
"data": {
"broker": "Broker",
"password": "Password",
"port": "Port",
"username": "Username"
},
"description": "Please enter the connection information of your MQTT broker.",
"title": "MQTT"
}
},
"title": "MQTT"
}
}

View file

@ -18,6 +18,7 @@ import attr
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.helpers.typing import HomeAssistantType, ConfigType, \
ServiceDataType
from homeassistant.core import callback, Event, ServiceCall
@ -30,8 +31,12 @@ from homeassistant.util.async_ import (
run_coroutine_threadsafe, run_callback_threadsafe)
from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP, CONF_VALUE_TEMPLATE, CONF_USERNAME,
CONF_PASSWORD, CONF_PORT, CONF_PROTOCOL, CONF_PAYLOAD)
CONF_PASSWORD, CONF_PORT, CONF_PROTOCOL, CONF_PAYLOAD,
EVENT_HOMEASSISTANT_START)
# Loading the config flow file will register the flow
from . import config_flow # noqa # pylint: disable=unused-import
from .const import CONF_BROKER
from .server import HBMQTT_CONFIG_SCHEMA
REQUIREMENTS = ['paho-mqtt==1.3.1']
@ -41,11 +46,12 @@ _LOGGER = logging.getLogger(__name__)
DOMAIN = 'mqtt'
DATA_MQTT = 'mqtt'
DATA_MQTT_CONFIG = 'mqtt_config'
SERVICE_PUBLISH = 'publish'
CONF_EMBEDDED = 'embedded'
CONF_BROKER = 'broker'
CONF_CLIENT_ID = 'client_id'
CONF_DISCOVERY = 'discovery'
CONF_DISCOVERY_PREFIX = 'discovery_prefix'
@ -311,6 +317,7 @@ async def _async_setup_server(hass: HomeAssistantType,
if not success:
return None
return broker_config
@ -340,19 +347,15 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
conf = config.get(DOMAIN) # type: Optional[ConfigType]
if conf is None:
conf = CONFIG_SCHEMA({DOMAIN: {}})[DOMAIN]
conf = cast(ConfigType, conf)
# If we have a config entry, setup is done by that config entry.
# If there is no config entry, this should fail.
return bool(hass.config_entries.async_entries(DOMAIN))
client_id = conf.get(CONF_CLIENT_ID) # type: Optional[str]
keepalive = conf.get(CONF_KEEPALIVE) # type: int
conf = dict(conf)
# Only setup if embedded config passed in or no broker specified
if CONF_EMBEDDED not in conf and CONF_BROKER in conf:
broker_config = None
else:
if CONF_EMBEDDED in conf or CONF_BROKER not in conf:
if (conf.get(CONF_PASSWORD) is None and
config.get('http') is not None and
config['http'].get('api_password') is not None):
config.get('http', {}).get('api_password') is not None):
_LOGGER.error(
"Starting from release 0.76, the embedded MQTT broker does not"
" use api_password as default password anymore. Please set"
@ -362,48 +365,98 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
broker_config = await _async_setup_server(hass, config)
if CONF_BROKER in conf:
broker = conf[CONF_BROKER] # type: str
port = conf[CONF_PORT] # type: int
username = conf.get(CONF_USERNAME) # type: Optional[str]
password = conf.get(CONF_PASSWORD) # type: Optional[str]
certificate = conf.get(CONF_CERTIFICATE) # type: Optional[str]
client_key = conf.get(CONF_CLIENT_KEY) # type: Optional[str]
client_cert = conf.get(CONF_CLIENT_CERT) # type: Optional[str]
tls_insecure = conf.get(CONF_TLS_INSECURE) # type: Optional[bool]
protocol = conf[CONF_PROTOCOL] # type: str
elif broker_config is not None:
# If no broker passed in, auto config to internal server
broker, port, username, password, certificate, protocol = broker_config
# Embedded broker doesn't have some ssl variables
client_key, client_cert, tls_insecure = None, None, None
# hbmqtt requires a client id to be set.
if client_id is None:
client_id = 'home-assistant'
else:
err = "Unable to start MQTT broker."
if conf.get(CONF_EMBEDDED) is not None:
# Explicit embedded config, requires explicit broker config
err += " (Broker configuration required.)"
_LOGGER.error(err)
if broker_config is None:
_LOGGER.error('Unable to start embedded MQTT broker')
return False
conf.update({
CONF_BROKER: broker_config[0],
CONF_PORT: broker_config[1],
CONF_USERNAME: broker_config[2],
CONF_PASSWORD: broker_config[3],
CONF_CERTIFICATE: broker_config[4],
CONF_PROTOCOL: broker_config[5],
CONF_CLIENT_KEY: None,
CONF_CLIENT_CERT: None,
CONF_TLS_INSECURE: None,
})
hass.data[DATA_MQTT_CONFIG] = conf
# Only import if we haven't before.
if not hass.config_entries.async_entries(DOMAIN):
hass.async_create_task(hass.config_entries.flow.async_init(
DOMAIN, context={'source': config_entries.SOURCE_IMPORT},
data={}
))
if conf.get(CONF_DISCOVERY):
async def async_setup_discovery(event):
await _async_setup_discovery(hass, config)
hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_START, async_setup_discovery)
return True
async def async_setup_entry(hass, entry):
"""Load a config entry."""
conf = hass.data.get(DATA_MQTT_CONFIG)
# Config entry was created because user had configuration.yaml entry
# They removed that, so remove entry.
if conf is None and entry.source == config_entries.SOURCE_IMPORT:
hass.async_create_task(
hass.config_entries.async_remove(entry.entry_id))
return False
# If user didn't have configuration.yaml config, generate defaults
if conf is None:
conf = CONFIG_SCHEMA({
DOMAIN: entry.data
})[DOMAIN]
elif any(key in conf for key in entry.data):
_LOGGER.warning(
'Data in your config entry is going to override your '
'configuration.yaml: %s', entry.data)
conf.update(entry.data)
broker = conf[CONF_BROKER]
port = conf[CONF_PORT]
client_id = conf.get(CONF_CLIENT_ID)
keepalive = conf[CONF_KEEPALIVE]
username = conf.get(CONF_USERNAME)
password = conf.get(CONF_PASSWORD)
client_key = conf.get(CONF_CLIENT_KEY)
client_cert = conf.get(CONF_CLIENT_CERT)
tls_insecure = conf.get(CONF_TLS_INSECURE)
protocol = conf[CONF_PROTOCOL]
# For cloudmqtt.com, secured connection, auto fill in certificate
if (certificate is None and 19999 < port < 30000 and
broker.endswith('.cloudmqtt.com')):
if (conf.get(CONF_CERTIFICATE) is None and
19999 < conf[CONF_PORT] < 30000 and
conf[CONF_BROKER].endswith('.cloudmqtt.com')):
certificate = os.path.join(os.path.dirname(__file__),
'addtrustexternalcaroot.crt')
# When the certificate is set to auto, use bundled certs from requests
if certificate == 'auto':
elif conf.get(CONF_CERTIFICATE) == 'auto':
certificate = requests.certs.where()
will_message = None # type: Optional[Message]
if conf.get(CONF_WILL_MESSAGE) is not None:
will_message = Message(**conf.get(CONF_WILL_MESSAGE))
birth_message = None # type: Optional[Message]
if conf.get(CONF_BIRTH_MESSAGE) is not None:
birth_message = Message(**conf.get(CONF_BIRTH_MESSAGE))
else:
certificate = None
if CONF_WILL_MESSAGE in conf:
will_message = Message(**conf[CONF_WILL_MESSAGE])
else:
will_message = None
if CONF_BIRTH_MESSAGE in conf:
birth_message = Message(**conf[CONF_BIRTH_MESSAGE])
else:
birth_message = None
# Be able to override versions other than TLSv1.0 under Python3.6
conf_tls_version = conf.get(CONF_TLS_VERSION) # type: str
@ -421,14 +474,27 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
else:
tls_version = ssl.PROTOCOL_TLSv1
try:
hass.data[DATA_MQTT] = MQTT(
hass, broker, port, client_id, keepalive, username, password,
certificate, client_key, client_cert, tls_insecure, protocol,
will_message, birth_message, tls_version)
except socket.error:
_LOGGER.exception("Can't connect to the broker. "
"Please check your settings and the broker itself")
hass.data[DATA_MQTT] = MQTT(
hass,
broker=broker,
port=port,
client_id=client_id,
keepalive=keepalive,
username=username,
password=password,
certificate=certificate,
client_key=client_key,
client_cert=client_cert,
tls_insecure=tls_insecure,
protocol=protocol,
will_message=will_message,
birth_message=birth_message,
tls_version=tls_version,
)
success = await hass.data[DATA_MQTT].async_connect() # type: bool
if not success:
return False
async def async_stop_mqtt(event: Event):
@ -437,10 +503,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_stop_mqtt)
success = await hass.data[DATA_MQTT].async_connect() # type: bool
if not success:
return False
async def async_publish_service(call: ServiceCall):
"""Handle MQTT publish service calls."""
msg_topic = call.data[ATTR_TOPIC] # type: str
@ -466,9 +528,6 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
DOMAIN, SERVICE_PUBLISH, async_publish_service,
schema=MQTT_PUBLISH_SCHEMA)
if conf.get(CONF_DISCOVERY):
await _async_setup_discovery(hass, config)
return True
@ -501,7 +560,8 @@ class MQTT:
certificate: Optional[str], client_key: Optional[str],
client_cert: Optional[str], tls_insecure: Optional[bool],
protocol: Optional[str], will_message: Optional[Message],
birth_message: Optional[Message], tls_version) -> None:
birth_message: Optional[Message],
tls_version: Optional[int]) -> None:
"""Initialize Home Assistant MQTT client."""
import paho.mqtt.client as mqtt

View file

@ -0,0 +1,98 @@
"""Config flow for MQTT."""
from collections import OrderedDict
import queue
import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_USERNAME, CONF_PASSWORD, CONF_PORT
from .const import CONF_BROKER
@config_entries.HANDLERS.register('mqtt')
class FlowHandler(config_entries.ConfigFlow):
"""Handle a config flow."""
VERSION = 1
async def async_step_user(self, user_input=None):
"""Handle a flow initialized by the user."""
if self._async_current_entries():
return self.async_abort(
reason='single_instance_allowed'
)
return await self.async_step_broker()
async def async_step_broker(self, user_input=None):
"""Confirm setup."""
errors = {}
if user_input is not None:
can_connect = await self.hass.async_add_executor_job(
try_connection, user_input[CONF_BROKER], user_input[CONF_PORT],
user_input.get(CONF_USERNAME), user_input.get(CONF_PASSWORD))
if can_connect:
return self.async_create_entry(
title=user_input[CONF_BROKER],
data=user_input
)
errors['base'] = 'cannot_connect'
fields = OrderedDict()
fields[vol.Required(CONF_BROKER)] = str
fields[vol.Required(CONF_PORT, default=1883)] = vol.Coerce(int)
fields[vol.Optional(CONF_USERNAME)] = str
fields[vol.Optional(CONF_PASSWORD)] = str
return self.async_show_form(
step_id='broker',
data_schema=vol.Schema(fields),
errors=errors,
)
async def async_step_import(self, user_input):
"""Import a config entry.
Special type of import, we're not actually going to store any data.
Instead, we're going to rely on the values that are in config file.
"""
if self._async_current_entries():
return self.async_abort(
reason='single_instance_allowed'
)
return self.async_create_entry(
title='configuration.yaml',
data={}
)
def try_connection(broker, port, username, password):
"""Test if we can connect to an MQTT broker."""
import paho.mqtt.client as mqtt
client = mqtt.Client()
if username and password:
client.username_pw_set(username, password)
result = queue.Queue(maxsize=1)
def on_connect(client_, userdata, flags, result_code):
"""Handle connection result."""
result.put(result_code == mqtt.CONNACK_ACCEPTED)
client.on_connect = on_connect
client.connect_async(broker, port)
client.loop_start()
try:
return result.get(timeout=5)
except queue.Empty:
return False
finally:
client.disconnect()
client.loop_stop()

View file

@ -0,0 +1,2 @@
"""Constants used by multiple MQTT modules."""
CONF_BROKER = 'broker'

View file

@ -0,0 +1,23 @@
{
"config": {
"title": "MQTT",
"step": {
"broker": {
"title": "MQTT",
"description": "Please enter the connection information of your MQTT broker.",
"data": {
"broker": "Broker",
"port": "Port",
"username": "Username",
"password": "Password"
}
}
},
"abort": {
"single_instance_allowed": "Only a single configuration of MQTT is allowed."
},
"error": {
"cannot_connect": "Unable to connect to the broker."
}
}
}

View file

@ -141,6 +141,7 @@ FLOWS = [
'homematicip_cloud',
'hue',
'ios',
'mqtt',
'nest',
'openuv',
'sonos',
@ -463,3 +464,19 @@ class ConfigEntries:
async def _old_conf_migrator(old_config):
"""Migrate the pre-0.73 config format to the latest version."""
return {'entries': old_config}
class ConfigFlow(data_entry_flow.FlowHandler):
"""Base class for config flows with some helpers."""
@callback
def _async_current_entries(self):
"""Return current entries."""
return self.hass.config_entries.async_entries(self.handler)
@callback
def _async_in_progress(self):
"""Return other in progress flows for current domain."""
return [flw for flw in self.hass.config_entries.flow.async_progress()
if flw['handler'] == self.handler and
flw['flow_id'] != self.flow_id]

View file

@ -0,0 +1,85 @@
"""Test config flow."""
from unittest.mock import patch
import pytest
from homeassistant.setup import async_setup_component
from tests.common import mock_coro
@pytest.fixture(autouse=True)
def mock_finish_setup():
"""Mock out the finish setup method."""
with patch('homeassistant.components.mqtt.MQTT.async_connect',
return_value=mock_coro(True)) as mock_finish:
yield mock_finish
@pytest.fixture
def mock_try_connection():
"""Mock the try connection method."""
with patch(
'homeassistant.components.mqtt.config_flow.try_connection'
) as mock_try:
yield mock_try
async def test_user_connection_works(hass, mock_try_connection,
mock_finish_setup):
"""Test we can finish a config flow."""
mock_try_connection.return_value = True
result = await hass.config_entries.flow.async_init(
'mqtt', context={'source': 'user'})
assert result['type'] == 'form'
result = await hass.config_entries.flow.async_configure(
result['flow_id'], {
'broker': '127.0.0.1',
}
)
assert result['type'] == 'create_entry'
# Check we tried the connection
assert len(mock_try_connection.mock_calls) == 1
# Check config entry got setup
assert len(mock_finish_setup.mock_calls) == 1
async def test_user_connection_fails(hass, mock_try_connection,
mock_finish_setup):
"""Test if connnection cannot be made."""
mock_try_connection.return_value = False
result = await hass.config_entries.flow.async_init(
'mqtt', context={'source': 'user'})
assert result['type'] == 'form'
result = await hass.config_entries.flow.async_configure(
result['flow_id'], {
'broker': '127.0.0.1',
}
)
assert result['type'] == 'form'
assert result['errors']['base'] == 'cannot_connect'
# Check we tried the connection
assert len(mock_try_connection.mock_calls) == 1
# Check config entry did not setup
assert len(mock_finish_setup.mock_calls) == 0
async def test_manual_config_set(hass, mock_try_connection,
mock_finish_setup):
"""Test we ignore entry if manual config available."""
assert await async_setup_component(
hass, 'mqtt', {'mqtt': {'broker': 'bla'}})
assert len(mock_finish_setup.mock_calls) == 1
mock_try_connection.return_value = True
result = await hass.config_entries.flow.async_init(
'mqtt', context={'source': 'user'})
assert result['type'] == 'abort'

View file

@ -2,21 +2,29 @@
import asyncio
import unittest
from unittest import mock
import socket
import ssl
import pytest
import voluptuous as vol
from homeassistant.core import callback
from homeassistant.setup import async_setup_component
import homeassistant.components.mqtt as mqtt
from homeassistant.components import mqtt
from homeassistant.const import (EVENT_CALL_SERVICE, ATTR_DOMAIN, ATTR_SERVICE,
EVENT_HOMEASSISTANT_STOP)
from tests.common import (get_test_home_assistant, mock_coro,
mock_mqtt_component,
threadsafe_coroutine_factory, fire_mqtt_message,
async_fire_mqtt_message)
async_fire_mqtt_message, MockConfigEntry)
@pytest.fixture
def mock_MQTT():
"""Make sure connection is established."""
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
mock_MQTT.return_value.async_connect.return_value = mock_coro(True)
yield mock_MQTT
@asyncio.coroutine
@ -533,64 +541,59 @@ def test_setup_embedded_with_embedded(hass):
assert _start.call_count == 1
@asyncio.coroutine
def test_setup_fails_if_no_connect_broker(hass):
async def test_setup_fails_if_no_connect_broker(hass):
"""Test for setup failure if connection to broker is missing."""
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker'}}
with mock.patch('homeassistant.components.mqtt.MQTT',
side_effect=socket.error()):
result = yield from async_setup_component(hass, mqtt.DOMAIN,
test_broker_cfg)
assert not result
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
mqtt.CONF_BROKER: 'test-broker'
})
with mock.patch('paho.mqtt.client.Client') as mock_client:
mock_client().connect = lambda *args: 1
result = yield from async_setup_component(hass, mqtt.DOMAIN,
test_broker_cfg)
assert not result
assert not await mqtt.async_setup_entry(hass, entry)
@asyncio.coroutine
def test_setup_uses_certificate_on_certificate_set_to_auto(hass):
async def test_setup_uses_certificate_on_certificate_set_to_auto(
hass, mock_MQTT):
"""Test setup uses bundled certs when certificate is set to auto."""
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker',
'certificate': 'auto'}}
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
mqtt.CONF_BROKER: 'test-broker',
'certificate': 'auto'
})
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
assert await mqtt.async_setup_entry(hass, entry)
assert mock_MQTT.called
import requests.certs
expectedCertificate = requests.certs.where()
assert mock_MQTT.mock_calls[0][1][7] == expectedCertificate
assert mock_MQTT.mock_calls[0][2]['certificate'] == expectedCertificate
@asyncio.coroutine
def test_setup_does_not_use_certificate_on_mqtts_port(hass):
"""Test setup doesn't use bundled certs when certificate is not set."""
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker',
'port': 8883}}
async def test_setup_does_not_use_certificate_on_mqtts_port(hass, mock_MQTT):
"""Test setup doesn't use bundled certs when ssl set."""
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
mqtt.CONF_BROKER: 'test-broker',
'port': 8883
})
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
assert await mqtt.async_setup_entry(hass, entry)
assert mock_MQTT.called
assert mock_MQTT.mock_calls[0][1][2] == 8883
assert mock_MQTT.mock_calls[0][2]['port'] == 8883
import requests.certs
mqttsCertificateBundle = requests.certs.where()
assert mock_MQTT.mock_calls[0][1][7] != mqttsCertificateBundle
assert mock_MQTT.mock_calls[0][2]['port'] != mqttsCertificateBundle
@asyncio.coroutine
def test_setup_without_tls_config_uses_tlsv1_under_python36(hass):
async def test_setup_without_tls_config_uses_tlsv1_under_python36(
hass, mock_MQTT):
"""Test setup defaults to TLSv1 under python3.6."""
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker'}}
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
mqtt.CONF_BROKER: 'test-broker',
})
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
assert await mqtt.async_setup_entry(hass, entry)
assert mock_MQTT.called
@ -600,34 +603,35 @@ def test_setup_without_tls_config_uses_tlsv1_under_python36(hass):
else:
expectedTlsVersion = ssl.PROTOCOL_TLSv1
assert mock_MQTT.mock_calls[0][1][14] == expectedTlsVersion
assert mock_MQTT.mock_calls[0][2]['tls_version'] == expectedTlsVersion
@asyncio.coroutine
def test_setup_with_tls_config_uses_tls_version1_2(hass):
async def test_setup_with_tls_config_uses_tls_version1_2(hass, mock_MQTT):
"""Test setup uses specified TLS version."""
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker',
'tls_version': '1.2'}}
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
mqtt.CONF_BROKER: 'test-broker',
'tls_version': '1.2'
})
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
assert await mqtt.async_setup_entry(hass, entry)
assert mock_MQTT.called
assert mock_MQTT.mock_calls[0][1][14] == ssl.PROTOCOL_TLSv1_2
assert mock_MQTT.mock_calls[0][2]['tls_version'] == ssl.PROTOCOL_TLSv1_2
@asyncio.coroutine
def test_setup_with_tls_config_of_v1_under_python36_only_uses_v1(hass):
async def test_setup_with_tls_config_of_v1_under_python36_only_uses_v1(
hass, mock_MQTT):
"""Test setup uses TLSv1.0 if explicitly chosen."""
test_broker_cfg = {mqtt.DOMAIN: {mqtt.CONF_BROKER: 'test-broker',
'tls_version': '1.0'}}
entry = MockConfigEntry(domain=mqtt.DOMAIN, data={
mqtt.CONF_BROKER: 'test-broker',
'tls_version': '1.0'
})
with mock.patch('homeassistant.components.mqtt.MQTT') as mock_MQTT:
yield from async_setup_component(hass, mqtt.DOMAIN, test_broker_cfg)
assert await mqtt.async_setup_entry(hass, entry)
assert mock_MQTT.called
assert mock_MQTT.mock_calls[0][1][14] == ssl.PROTOCOL_TLSv1
assert mock_MQTT.mock_calls[0][2]['tls_version'] == ssl.PROTOCOL_TLSv1
@asyncio.coroutine
@ -671,3 +675,8 @@ def test_mqtt_subscribes_topics_on_connect(hass):
}
calls = {call[1][1]: call[1][2] for call in hass.add_job.mock_calls}
assert calls == expected
async def test_setup_fails_without_config(hass):
"""Test if the MQTT component fails to load with no config."""
assert not await async_setup_component(hass, mqtt.DOMAIN, {})

View file

@ -57,8 +57,8 @@ class TestMQTT:
assert mock_mqtt.called
from pprint import pprint
pprint(mock_mqtt.mock_calls)
assert mock_mqtt.mock_calls[1][1][5] == 'homeassistant'
assert mock_mqtt.mock_calls[1][1][6] == password
assert mock_mqtt.mock_calls[1][2]['username'] == 'homeassistant'
assert mock_mqtt.mock_calls[1][2]['password'] == password
@patch('passlib.apps.custom_app_context', Mock(return_value=''))
@patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock()))
@ -82,24 +82,8 @@ class TestMQTT:
assert mock_mqtt.called
from pprint import pprint
pprint(mock_mqtt.mock_calls)
assert mock_mqtt.mock_calls[1][1][5] == 'homeassistant'
assert mock_mqtt.mock_calls[1][1][6] == password
@patch('passlib.apps.custom_app_context', Mock(return_value=''))
@patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock()))
@patch('hbmqtt.broker.Broker', Mock(return_value=MagicMock()))
@patch('hbmqtt.broker.Broker.start', Mock(return_value=mock_coro()))
@patch('homeassistant.components.mqtt.MQTT')
def test_creating_config_without_pass(self, mock_mqtt):
"""Test if the MQTT server gets started without password."""
mock_mqtt().async_connect.return_value = mock_coro(True)
self.hass.bus.listen_once = MagicMock()
self.hass.config.api = MagicMock(api_password=None)
assert setup_component(self.hass, mqtt.DOMAIN, {})
assert mock_mqtt.called
assert mock_mqtt.mock_calls[1][1][5] is None
assert mock_mqtt.mock_calls[1][1][6] is None
assert mock_mqtt.mock_calls[1][2]['username'] == 'homeassistant'
assert mock_mqtt.mock_calls[1][2]['password'] == password
@patch('tempfile.NamedTemporaryFile', Mock(return_value=MagicMock()))
@patch('hbmqtt.broker.Broker.start', return_value=mock_coro())