Minor cleanup and test coverage improvement for MQTT (#55265)
This commit is contained in:
parent
eae828a15a
commit
4d7e3cde5a
2 changed files with 137 additions and 22 deletions
|
@ -38,7 +38,7 @@ from homeassistant.core import (
|
|||
ServiceCall,
|
||||
callback,
|
||||
)
|
||||
from homeassistant.exceptions import HomeAssistantError, Unauthorized
|
||||
from homeassistant.exceptions import HomeAssistantError, TemplateError, Unauthorized
|
||||
from homeassistant.helpers import config_validation as cv, event, template
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect, dispatcher_send
|
||||
from homeassistant.helpers.typing import ConfigType, ServiceDataType
|
||||
|
@ -153,16 +153,6 @@ MQTT_WILL_BIRTH_SCHEMA = vol.Schema(
|
|||
)
|
||||
|
||||
|
||||
def embedded_broker_deprecated(value):
|
||||
"""Warn user that embedded MQTT broker is deprecated."""
|
||||
_LOGGER.warning(
|
||||
"The embedded MQTT broker has been deprecated and will stop working"
|
||||
"after June 5th, 2019. Use an external broker instead. For"
|
||||
"instructions, see https://www.home-assistant.io/docs/mqtt/broker"
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.All(
|
||||
|
@ -495,7 +485,7 @@ async def async_setup_entry(hass, entry):
|
|||
payload = template.Template(payload_template, hass).async_render(
|
||||
parse_result=False
|
||||
)
|
||||
except template.jinja2.TemplateError as exc:
|
||||
except (template.jinja2.TemplateError, TemplateError) as exc:
|
||||
_LOGGER.error(
|
||||
"Unable to publish to %s: rendering payload template of "
|
||||
"%s failed because %s",
|
||||
|
|
|
@ -12,13 +12,13 @@ from homeassistant.components import mqtt, websocket_api
|
|||
from homeassistant.components.mqtt import debug_info
|
||||
from homeassistant.components.mqtt.mixins import MQTT_ENTITY_DEVICE_INFO_SCHEMA
|
||||
from homeassistant.const import (
|
||||
ATTR_DOMAIN,
|
||||
ATTR_SERVICE,
|
||||
EVENT_CALL_SERVICE,
|
||||
EVENT_HOMEASSISTANT_STARTED,
|
||||
EVENT_HOMEASSISTANT_STOP,
|
||||
TEMP_CELSIUS,
|
||||
)
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.core import CoreState, callback
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import device_registry as dr
|
||||
from homeassistant.setup import async_setup_component
|
||||
from homeassistant.util.dt import utcnow
|
||||
|
@ -97,21 +97,35 @@ async def test_publish_calls_service(hass, mqtt_mock, calls, record_calls):
|
|||
hass.bus.async_listen_once(EVENT_CALL_SERVICE, record_calls)
|
||||
|
||||
mqtt.async_publish(hass, "test-topic", "test-payload")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0][0].data["service_data"][mqtt.ATTR_TOPIC] == "test-topic"
|
||||
assert calls[0][0].data["service_data"][mqtt.ATTR_PAYLOAD] == "test-payload"
|
||||
assert mqtt.ATTR_QOS not in calls[0][0].data["service_data"]
|
||||
assert mqtt.ATTR_RETAIN not in calls[0][0].data["service_data"]
|
||||
|
||||
hass.bus.async_listen_once(EVENT_CALL_SERVICE, record_calls)
|
||||
|
||||
mqtt.async_publish(hass, "test-topic", "test-payload", 2, True)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert len(calls) == 2
|
||||
assert calls[1][0].data["service_data"][mqtt.ATTR_TOPIC] == "test-topic"
|
||||
assert calls[1][0].data["service_data"][mqtt.ATTR_PAYLOAD] == "test-payload"
|
||||
assert calls[1][0].data["service_data"][mqtt.ATTR_QOS] == 2
|
||||
assert calls[1][0].data["service_data"][mqtt.ATTR_RETAIN] is True
|
||||
|
||||
|
||||
async def test_service_call_without_topic_does_not_publish(hass, mqtt_mock):
|
||||
"""Test the service call if topic is missing."""
|
||||
hass.bus.fire(
|
||||
EVENT_CALL_SERVICE,
|
||||
{ATTR_DOMAIN: mqtt.DOMAIN, ATTR_SERVICE: mqtt.SERVICE_PUBLISH},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
with pytest.raises(vol.Invalid):
|
||||
await hass.services.async_call(
|
||||
mqtt.DOMAIN,
|
||||
mqtt.SERVICE_PUBLISH,
|
||||
{},
|
||||
blocking=True,
|
||||
)
|
||||
assert not mqtt_mock.async_publish.called
|
||||
|
||||
|
||||
|
@ -120,10 +134,37 @@ async def test_service_call_with_template_payload_renders_template(hass, mqtt_mo
|
|||
|
||||
If 'payload_template' is provided and 'payload' is not, then render it.
|
||||
"""
|
||||
mqtt.async_publish_template(hass, "test/topic", "{{ 1+1 }}")
|
||||
mqtt.publish_template(hass, "test/topic", "{{ 1+1 }}")
|
||||
await hass.async_block_till_done()
|
||||
assert mqtt_mock.async_publish.called
|
||||
assert mqtt_mock.async_publish.call_args[0][1] == "2"
|
||||
mqtt_mock.reset_mock()
|
||||
|
||||
mqtt.async_publish_template(hass, "test/topic", "{{ 2+2 }}")
|
||||
await hass.async_block_till_done()
|
||||
assert mqtt_mock.async_publish.called
|
||||
assert mqtt_mock.async_publish.call_args[0][1] == "4"
|
||||
mqtt_mock.reset_mock()
|
||||
|
||||
await hass.services.async_call(
|
||||
mqtt.DOMAIN,
|
||||
mqtt.SERVICE_PUBLISH,
|
||||
{mqtt.ATTR_TOPIC: "test/topic", mqtt.ATTR_PAYLOAD_TEMPLATE: "{{ 4+4 }}"},
|
||||
blocking=True,
|
||||
)
|
||||
assert mqtt_mock.async_publish.called
|
||||
assert mqtt_mock.async_publish.call_args[0][1] == "8"
|
||||
|
||||
|
||||
async def test_service_call_with_bad_template(hass, mqtt_mock):
|
||||
"""Test the service call with a bad template does not publish."""
|
||||
await hass.services.async_call(
|
||||
mqtt.DOMAIN,
|
||||
mqtt.SERVICE_PUBLISH,
|
||||
{mqtt.ATTR_TOPIC: "test/topic", mqtt.ATTR_PAYLOAD_TEMPLATE: "{{ 1 | bad }}"},
|
||||
blocking=True,
|
||||
)
|
||||
assert not mqtt_mock.async_publish.called
|
||||
|
||||
|
||||
async def test_service_call_with_payload_doesnt_render_template(hass, mqtt_mock):
|
||||
|
@ -340,6 +381,34 @@ async def test_subscribe_topic(hass, mqtt_mock, calls, record_calls):
|
|||
assert len(calls) == 1
|
||||
|
||||
|
||||
async def test_subscribe_topic_non_async(hass, mqtt_mock, calls, record_calls):
|
||||
"""Test the subscription of a topic using the non-async function."""
|
||||
unsub = await hass.async_add_executor_job(
|
||||
mqtt.subscribe, hass, "test-topic", record_calls
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
async_fire_mqtt_message(hass, "test-topic", "test-payload")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
assert calls[0][0].topic == "test-topic"
|
||||
assert calls[0][0].payload == "test-payload"
|
||||
|
||||
await hass.async_add_executor_job(unsub)
|
||||
|
||||
async_fire_mqtt_message(hass, "test-topic", "test-payload")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
|
||||
|
||||
async def test_subscribe_bad_topic(hass, mqtt_mock, calls, record_calls):
|
||||
"""Test the subscription of a topic."""
|
||||
with pytest.raises(HomeAssistantError):
|
||||
await mqtt.async_subscribe(hass, 55, record_calls)
|
||||
|
||||
|
||||
async def test_subscribe_deprecated(hass, mqtt_mock):
|
||||
"""Test the subscription of a topic using deprecated callback signature."""
|
||||
calls = []
|
||||
|
@ -833,6 +902,62 @@ async def test_no_birth_message(hass, mqtt_client_mock, mqtt_mock):
|
|||
mqtt_client_mock.publish.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config",
|
||||
[
|
||||
{
|
||||
mqtt.CONF_BROKER: "mock-broker",
|
||||
mqtt.CONF_BIRTH_MESSAGE: {
|
||||
mqtt.ATTR_TOPIC: "homeassistant/status",
|
||||
mqtt.ATTR_PAYLOAD: "online",
|
||||
},
|
||||
}
|
||||
],
|
||||
)
|
||||
async def test_delayed_birth_message(hass, mqtt_client_mock, mqtt_config):
|
||||
"""Test sending birth message does not happen until Home Assistant starts."""
|
||||
hass.state = CoreState.starting
|
||||
birth = asyncio.Event()
|
||||
|
||||
result = await async_setup_component(hass, mqtt.DOMAIN, {mqtt.DOMAIN: mqtt_config})
|
||||
assert result
|
||||
await hass.async_block_till_done()
|
||||
|
||||
# Workaround: asynctest==0.13 fails on @functools.lru_cache
|
||||
spec = dir(hass.data["mqtt"])
|
||||
spec.remove("_matching_subscriptions")
|
||||
|
||||
mqtt_component_mock = MagicMock(
|
||||
return_value=hass.data["mqtt"],
|
||||
spec_set=spec,
|
||||
wraps=hass.data["mqtt"],
|
||||
)
|
||||
mqtt_component_mock._mqttc = mqtt_client_mock
|
||||
|
||||
hass.data["mqtt"] = mqtt_component_mock
|
||||
mqtt_mock = hass.data["mqtt"]
|
||||
mqtt_mock.reset_mock()
|
||||
|
||||
async def wait_birth(topic, payload, qos):
|
||||
"""Handle birth message."""
|
||||
birth.set()
|
||||
|
||||
with patch("homeassistant.components.mqtt.DISCOVERY_COOLDOWN", 0.1):
|
||||
await mqtt.async_subscribe(hass, "homeassistant/status", wait_birth)
|
||||
mqtt_mock._mqtt_on_connect(None, None, 0, 0)
|
||||
await hass.async_block_till_done()
|
||||
with pytest.raises(asyncio.TimeoutError):
|
||||
await asyncio.wait_for(birth.wait(), 0.2)
|
||||
assert not mqtt_client_mock.publish.called
|
||||
assert not birth.is_set()
|
||||
|
||||
hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED)
|
||||
await birth.wait()
|
||||
mqtt_client_mock.publish.assert_called_with(
|
||||
"homeassistant/status", "online", 0, False
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mqtt_config",
|
||||
[
|
||||
|
|
Loading…
Add table
Reference in a new issue