393 lines
15 KiB
Python
393 lines
15 KiB
Python
"""The tests for the MQTT statestream component."""
|
|
from unittest.mock import ANY, call, patch
|
|
|
|
from homeassistant.setup import setup_component
|
|
import homeassistant.components.mqtt_statestream as statestream
|
|
from homeassistant.core import State
|
|
|
|
from tests.common import (
|
|
get_test_home_assistant,
|
|
mock_mqtt_component,
|
|
mock_state_change_event
|
|
)
|
|
|
|
|
|
class TestMqttStateStream:
|
|
"""Test the MQTT statestream module."""
|
|
|
|
def setup_method(self):
|
|
"""Set up things to be run when tests are started."""
|
|
self.hass = get_test_home_assistant()
|
|
self.mock_mqtt = mock_mqtt_component(self.hass)
|
|
|
|
def teardown_method(self):
|
|
"""Stop everything that was started."""
|
|
self.hass.stop()
|
|
|
|
def add_statestream(self, base_topic=None, publish_attributes=None,
|
|
publish_timestamps=None, publish_include=None,
|
|
publish_exclude=None):
|
|
"""Add a mqtt_statestream component."""
|
|
config = {}
|
|
if base_topic:
|
|
config['base_topic'] = base_topic
|
|
if publish_attributes:
|
|
config['publish_attributes'] = publish_attributes
|
|
if publish_timestamps:
|
|
config['publish_timestamps'] = publish_timestamps
|
|
if publish_include:
|
|
config['include'] = publish_include
|
|
if publish_exclude:
|
|
config['exclude'] = publish_exclude
|
|
return setup_component(self.hass, statestream.DOMAIN, {
|
|
statestream.DOMAIN: config})
|
|
|
|
def test_fails_with_no_base(self):
|
|
"""Setup should fail if no base_topic is set."""
|
|
assert self.add_statestream() is False
|
|
|
|
def test_setup_succeeds_without_attributes(self):
|
|
"""Test the success of the setup with a valid base_topic."""
|
|
assert self.add_statestream(base_topic='pub')
|
|
|
|
def test_setup_succeeds_with_attributes(self):
|
|
"""Test setup with a valid base_topic and publish_attributes."""
|
|
assert self.add_statestream(base_topic='pub', publish_attributes=True)
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_sends_message(self, mock_utcnow, mock_pub):
|
|
"""Test the sending of a new message if event changed."""
|
|
e_id = 'fake.entity'
|
|
base_topic = 'pub'
|
|
|
|
# Add the statestream component for publishing state updates
|
|
assert self.add_statestream(base_topic=base_topic)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State(e_id, 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_sends_message_and_timestamp(
|
|
self,
|
|
mock_utcnow,
|
|
mock_pub):
|
|
"""Test the sending of a message and timestamps if event changed."""
|
|
e_id = 'another.entity'
|
|
base_topic = 'pub'
|
|
|
|
# Add the statestream component for publishing state updates
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_attributes=None,
|
|
publish_timestamps=True)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State(e_id, 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
calls = [
|
|
call.async_publish(self.hass, 'pub/another/entity/state', 'on', 1,
|
|
True),
|
|
call.async_publish(self.hass, 'pub/another/entity/last_changed',
|
|
ANY, 1, True),
|
|
call.async_publish(self.hass, 'pub/another/entity/last_updated',
|
|
ANY, 1, True),
|
|
]
|
|
|
|
mock_pub.assert_has_calls(calls, any_order=True)
|
|
assert mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_attr_sends_message(self, mock_utcnow, mock_pub):
|
|
"""Test the sending of a new message if attribute changed."""
|
|
e_id = 'fake.entity'
|
|
base_topic = 'pub'
|
|
|
|
# Add the statestream component for publishing state updates
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_attributes=True)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
test_attributes = {
|
|
"testing": "YES",
|
|
"list": ["a", "b", "c"],
|
|
"bool": False
|
|
}
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State(e_id, 'off',
|
|
attributes=test_attributes))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
calls = [
|
|
call.async_publish(self.hass, 'pub/fake/entity/state', 'off', 1,
|
|
True),
|
|
call.async_publish(self.hass, 'pub/fake/entity/testing', '"YES"',
|
|
1, True),
|
|
call.async_publish(self.hass, 'pub/fake/entity/list',
|
|
'["a", "b", "c"]', 1, True),
|
|
call.async_publish(self.hass, 'pub/fake/entity/bool', "false",
|
|
1, True)
|
|
]
|
|
|
|
mock_pub.assert_has_calls(calls, any_order=True)
|
|
assert mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_include_domain(self, mock_utcnow, mock_pub):
|
|
"""Test that filtering on included domain works as expected."""
|
|
base_topic = 'pub'
|
|
|
|
incl = {
|
|
'domains': ['fake']
|
|
}
|
|
excl = {}
|
|
|
|
# Add the statestream component for publishing state updates
|
|
# Set the filter to allow fake.* items
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_include=incl,
|
|
publish_exclude=excl)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State('fake.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
mock_pub.reset_mock()
|
|
# Set a state of an entity that shouldn't be included
|
|
mock_state_change_event(self.hass, State('fake2.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
assert not mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_include_entity(self, mock_utcnow, mock_pub):
|
|
"""Test that filtering on included entity works as expected."""
|
|
base_topic = 'pub'
|
|
|
|
incl = {
|
|
'entities': ['fake.entity']
|
|
}
|
|
excl = {}
|
|
|
|
# Add the statestream component for publishing state updates
|
|
# Set the filter to allow fake.* items
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_include=incl,
|
|
publish_exclude=excl)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State('fake.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
mock_pub.reset_mock()
|
|
# Set a state of an entity that shouldn't be included
|
|
mock_state_change_event(self.hass, State('fake.entity2', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
assert not mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_exclude_domain(self, mock_utcnow, mock_pub):
|
|
"""Test that filtering on excluded domain works as expected."""
|
|
base_topic = 'pub'
|
|
|
|
incl = {}
|
|
excl = {
|
|
'domains': ['fake2']
|
|
}
|
|
|
|
# Add the statestream component for publishing state updates
|
|
# Set the filter to allow fake.* items
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_include=incl,
|
|
publish_exclude=excl)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State('fake.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
mock_pub.reset_mock()
|
|
# Set a state of an entity that shouldn't be included
|
|
mock_state_change_event(self.hass, State('fake2.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
assert not mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_exclude_entity(self, mock_utcnow, mock_pub):
|
|
"""Test that filtering on excluded entity works as expected."""
|
|
base_topic = 'pub'
|
|
|
|
incl = {}
|
|
excl = {
|
|
'entities': ['fake.entity2']
|
|
}
|
|
|
|
# Add the statestream component for publishing state updates
|
|
# Set the filter to allow fake.* items
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_include=incl,
|
|
publish_exclude=excl)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State('fake.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
mock_pub.reset_mock()
|
|
# Set a state of an entity that shouldn't be included
|
|
mock_state_change_event(self.hass, State('fake.entity2', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
assert not mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_exclude_domain_include_entity(
|
|
self, mock_utcnow, mock_pub):
|
|
"""Test filtering with excluded domain and included entity."""
|
|
base_topic = 'pub'
|
|
|
|
incl = {
|
|
'entities': ['fake.entity']
|
|
}
|
|
excl = {
|
|
'domains': ['fake']
|
|
}
|
|
|
|
# Add the statestream component for publishing state updates
|
|
# Set the filter to allow fake.* items
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_include=incl,
|
|
publish_exclude=excl)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State('fake.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
mock_pub.reset_mock()
|
|
# Set a state of an entity that shouldn't be included
|
|
mock_state_change_event(self.hass, State('fake.entity2', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
assert not mock_pub.called
|
|
|
|
@patch('homeassistant.components.mqtt.async_publish')
|
|
@patch('homeassistant.core.dt_util.utcnow')
|
|
def test_state_changed_event_include_domain_exclude_entity(
|
|
self, mock_utcnow, mock_pub):
|
|
"""Test filtering with included domain and excluded entity."""
|
|
base_topic = 'pub'
|
|
|
|
incl = {
|
|
'domains': ['fake']
|
|
}
|
|
excl = {
|
|
'entities': ['fake.entity2']
|
|
}
|
|
|
|
# Add the statestream component for publishing state updates
|
|
# Set the filter to allow fake.* items
|
|
assert self.add_statestream(base_topic=base_topic,
|
|
publish_include=incl,
|
|
publish_exclude=excl)
|
|
self.hass.block_till_done()
|
|
|
|
# Reset the mock because it will have already gotten calls for the
|
|
# mqtt_statestream state change on initialization, etc.
|
|
mock_pub.reset_mock()
|
|
|
|
# Set a state of an entity
|
|
mock_state_change_event(self.hass, State('fake.entity', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
# Make sure 'on' was published to pub/fake/entity/state
|
|
mock_pub.assert_called_with(self.hass, 'pub/fake/entity/state', 'on',
|
|
1, True)
|
|
assert mock_pub.called
|
|
|
|
mock_pub.reset_mock()
|
|
# Set a state of an entity that shouldn't be included
|
|
mock_state_change_event(self.hass, State('fake.entity2', 'on'))
|
|
self.hass.block_till_done()
|
|
|
|
assert not mock_pub.called
|