From 4bb9f1800dd6d01ed58b4af1ba9114876927a386 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 9 Mar 2020 17:40:00 +0100 Subject: [PATCH] Deduplicate MQTT mixin tests (#32563) * Deduplicate MQTT mixin tests * Remove test of not yet merged function --- .../components/mqtt/vacuum/schema_legacy.py | 4 +- .../components/mqtt/vacuum/schema_state.py | 4 +- tests/components/mqtt/common.py | 221 +++++++++++ .../mqtt/test_alarm_control_panel.py | 336 +++++------------ tests/components/mqtt/test_binary_sensor.py | 316 +++++----------- tests/components/mqtt/test_climate.py | 321 +++++----------- tests/components/mqtt/test_cover.py | 340 ++++++----------- tests/components/mqtt/test_fan.py | 344 ++++++----------- tests/components/mqtt/test_legacy_vacuum.py | 307 ++++++---------- tests/components/mqtt/test_light.py | 318 +++++----------- tests/components/mqtt/test_light_json.py | 329 +++++------------ tests/components/mqtt/test_light_template.py | 345 ++++++------------ tests/components/mqtt/test_lock.py | 322 +++++----------- tests/components/mqtt/test_sensor.py | 308 +++++----------- tests/components/mqtt/test_state_vacuum.py | 314 ++++++---------- tests/components/mqtt/test_switch.py | 326 +++++------------ 16 files changed, 1499 insertions(+), 2956 deletions(-) create mode 100644 tests/components/mqtt/common.py diff --git a/homeassistant/components/mqtt/vacuum/schema_legacy.py b/homeassistant/components/mqtt/vacuum/schema_legacy.py index eff7cc1b039..7679b97d62e 100644 --- a/homeassistant/components/mqtt/vacuum/schema_legacy.py +++ b/homeassistant/components/mqtt/vacuum/schema_legacy.py @@ -266,7 +266,9 @@ class MqttVacuum( async def async_will_remove_from_hass(self): """Unsubscribe when removed.""" - await subscription.async_unsubscribe_topics(self.hass, self._sub_state) + self._sub_state = await subscription.async_unsubscribe_topics( + self.hass, self._sub_state + ) await MqttAttributes.async_will_remove_from_hass(self) await MqttAvailability.async_will_remove_from_hass(self) await MqttDiscoveryUpdate.async_will_remove_from_hass(self) diff --git a/homeassistant/components/mqtt/vacuum/schema_state.py b/homeassistant/components/mqtt/vacuum/schema_state.py index f9bcc7e845e..126a2432cb0 100644 --- a/homeassistant/components/mqtt/vacuum/schema_state.py +++ b/homeassistant/components/mqtt/vacuum/schema_state.py @@ -231,7 +231,9 @@ class MqttStateVacuum( async def async_will_remove_from_hass(self): """Unsubscribe when removed.""" - await subscription.async_unsubscribe_topics(self.hass, self._sub_state) + self._sub_state = await subscription.async_unsubscribe_topics( + self.hass, self._sub_state + ) await MqttAttributes.async_will_remove_from_hass(self) await MqttAvailability.async_will_remove_from_hass(self) await MqttDiscoveryUpdate.async_will_remove_from_hass(self) diff --git a/tests/components/mqtt/common.py b/tests/components/mqtt/common.py new file mode 100644 index 00000000000..f8c57101445 --- /dev/null +++ b/tests/components/mqtt/common.py @@ -0,0 +1,221 @@ +"""Common test objects.""" +import json +from unittest.mock import ANY + +from homeassistant.components import mqtt +from homeassistant.components.mqtt.discovery import async_start + +from tests.common import ( + MockConfigEntry, + async_fire_mqtt_message, + async_mock_mqtt_component, + async_setup_component, + mock_registry, +) + + +async def help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, domain, config +): + """Test the setting of attribute via MQTT with JSON payload.""" + assert await async_setup_component(hass, domain, config,) + + async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') + state = hass.states.get(f"{domain}.test") + + assert state.attributes.get("val") == "100" + + +async def help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, domain, config +): + """Test attributes get extracted from a JSON result.""" + assert await async_setup_component(hass, domain, config,) + + async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') + state = hass.states.get(f"{domain}.test") + + assert state.attributes.get("val") is None + assert "JSON result was not a dictionary" in caplog.text + + +async def help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, domain, config +): + """Test attributes get extracted from a JSON result.""" + assert await async_setup_component(hass, domain, config,) + + async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") + + state = hass.states.get(f"{domain}.test") + assert state.attributes.get("val") is None + assert "Erroneous JSON: This is not JSON" in caplog.text + + +async def help_test_discovery_update_attr( + hass, mqtt_mock, caplog, domain, data1, data2 +): + """Test update of discovered MQTTAttributes.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN) + await async_start(hass, "homeassistant", {}, entry) + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1) + await hass.async_block_till_done() + async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') + state = hass.states.get(f"{domain}.beer") + assert state.attributes.get("val") == "100" + + # Change json_attributes_topic + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data2) + await hass.async_block_till_done() + + # Verify we are no longer subscribing to the old topic + async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') + state = hass.states.get(f"{domain}.beer") + assert state.attributes.get("val") == "100" + + # Verify we are subscribing to the new topic + async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') + state = hass.states.get(f"{domain}.beer") + assert state.attributes.get("val") == "75" + + +async def help_test_unique_id(hass, domain, config): + """Test unique id option only creates one alarm per unique_id.""" + await async_mock_mqtt_component(hass) + assert await async_setup_component(hass, domain, config,) + async_fire_mqtt_message(hass, "test-topic", "payload") + assert len(hass.states.async_entity_ids(domain)) == 1 + + +async def help_test_discovery_removal(hass, mqtt_mock, caplog, domain, data): + """Test removal of discovered component.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN) + await async_start(hass, "homeassistant", {}, entry) + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data) + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.beer") + assert state is not None + assert state.name == "Beer" + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", "") + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.beer") + assert state is None + + +async def help_test_discovery_update(hass, mqtt_mock, caplog, domain, data1, data2): + """Test update of discovered component.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN) + await async_start(hass, "homeassistant", {}, entry) + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1) + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.beer") + assert state is not None + assert state.name == "Beer" + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data2) + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.beer") + assert state is not None + assert state.name == "Milk" + + state = hass.states.get(f"{domain}.milk") + assert state is None + + +async def help_test_discovery_broken(hass, mqtt_mock, caplog, domain, data1, data2): + """Test handling of bad discovery message.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN) + await async_start(hass, "homeassistant", {}, entry) + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data1) + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.beer") + assert state is None + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data2) + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.milk") + assert state is not None + assert state.name == "Milk" + state = hass.states.get(f"{domain}.beer") + assert state is None + + +async def help_test_entity_device_info_with_identifier(hass, mqtt_mock, domain, data): + """Test MQTT alarm control panel device registry integration.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN) + entry.add_to_hass(hass) + await async_start(hass, "homeassistant", {}, entry) + registry = await hass.helpers.device_registry.async_get_registry() + + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data) + await hass.async_block_till_done() + + device = registry.async_get_device({("mqtt", "helloworld")}, set()) + assert device is not None + assert device.identifiers == {("mqtt", "helloworld")} + assert device.connections == {("mac", "02:5b:26:a8:dc:12")} + assert device.manufacturer == "Whatever" + assert device.name == "Beer" + assert device.model == "Glass" + assert device.sw_version == "0.1-beta" + + +async def help_test_entity_device_info_update(hass, mqtt_mock, domain, config): + """Test device registry update.""" + entry = MockConfigEntry(domain=mqtt.DOMAIN) + entry.add_to_hass(hass) + await async_start(hass, "homeassistant", {}, entry) + registry = await hass.helpers.device_registry.async_get_registry() + + data = json.dumps(config) + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data) + await hass.async_block_till_done() + + device = registry.async_get_device({("mqtt", "helloworld")}, set()) + assert device is not None + assert device.name == "Beer" + + config["device"]["name"] = "Milk" + data = json.dumps(config) + async_fire_mqtt_message(hass, f"homeassistant/{domain}/bla/config", data) + await hass.async_block_till_done() + + device = registry.async_get_device({("mqtt", "helloworld")}, set()) + assert device is not None + assert device.name == "Milk" + + +async def help_test_entity_id_update(hass, mqtt_mock, domain, config): + """Test MQTT subscriptions are managed when entity_id is updated.""" + registry = mock_registry(hass, {}) + mock_mqtt = await async_mock_mqtt_component(hass) + assert await async_setup_component(hass, domain, config,) + + state = hass.states.get(f"{domain}.beer") + assert state is not None + assert mock_mqtt.async_subscribe.call_count == 2 + mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") + mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + mock_mqtt.async_subscribe.reset_mock() + + registry.async_update_entity(f"{domain}.beer", new_entity_id=f"{domain}.milk") + await hass.async_block_till_done() + + state = hass.states.get(f"{domain}.beer") + assert state is None + + state = hass.states.get(f"{domain}.milk") + assert state is not None + assert mock_mqtt.async_subscribe.call_count == 2 + mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") + mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") diff --git a/tests/components/mqtt/test_alarm_control_panel.py b/tests/components/mqtt/test_alarm_control_panel.py index 6ec28b04e4d..6a14f2ebbda 100644 --- a/tests/components/mqtt/test_alarm_control_panel.py +++ b/tests/components/mqtt/test_alarm_control_panel.py @@ -1,9 +1,7 @@ """The tests the MQTT alarm control panel component.""" import json -from unittest.mock import ANY -from homeassistant.components import alarm_control_panel, mqtt -from homeassistant.components.mqtt.discovery import async_start +from homeassistant.components import alarm_control_panel from homeassistant.const import ( STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME, @@ -15,13 +13,24 @@ from homeassistant.const import ( STATE_UNKNOWN, ) +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, +) + from tests.common import ( - MockConfigEntry, assert_setup_component, async_fire_mqtt_message, - async_mock_mqtt_component, async_setup_component, - mock_registry, ) from tests.components.alarm_control_panel import common @@ -489,25 +498,19 @@ async def test_custom_availability_payload(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + alarm_control_panel.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, alarm_control_panel.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("alarm_control_panel.test") - - assert state.attributes.get("val") == "100" - async def test_update_state_via_state_topic_template(hass, mqtt_mock): """Test updating with template_value via state topic.""" @@ -541,54 +544,38 @@ async def test_update_state_via_state_topic_template(hass, mqtt_mock): async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + alarm_control_panel.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("alarm_control_panel.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - alarm_control_panel.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + alarm_control_panel.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("alarm_control_panel.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -599,86 +586,48 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("alarm_control_panel.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("alarm_control_panel.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("alarm_control_panel.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one alarm per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - alarm_control_panel.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(alarm_control_panel.DOMAIN)) == 1 + config = { + alarm_control_panel.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "command_topic": "command-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "command_topic": "command-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, alarm_control_panel.DOMAIN, config) async def test_discovery_removal_alarm(hass, mqtt_mock, caplog): """Test removal of discovered alarm_control_panel.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", "") - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.beer") - assert state is None + await help_test_discovery_removal( + hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data + ) async def test_discovery_update_alarm(hass, mqtt_mock, caplog): """Test update of discovered alarm_control_panel.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -689,66 +638,32 @@ async def test_discovery_update_alarm(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.beer") - assert state is not None - assert state.name == "Milk" - - state = hass.states.get("alarm_control_panel.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer" }' data2 = ( '{ "name": "Milk",' ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("alarm_control_panel.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, alarm_control_panel.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT alarm control panel device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", "name": "Test 1", "state_topic": "test-topic", - "command_topic": "test-topic", + "command_topic": "test-command-topic", "device": { "identifiers": ["helloworld"], "connections": [["mac", "02:5b:26:a8:dc:12"]], @@ -760,26 +675,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, alarm_control_panel.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -795,63 +697,25 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/alarm_control_panel/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update( + hass, mqtt_mock, alarm_control_panel.DOMAIN, config + ) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - alarm_control_panel.DOMAIN, - { - alarm_control_panel.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "command_topic": "command-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, + config = { + alarm_control_panel.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update( + hass, mqtt_mock, alarm_control_panel.DOMAIN, config ) - - state = hass.states.get("alarm_control_panel.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity( - "alarm_control_panel.beer", new_entity_id="alarm_control_panel.milk" - ) - await hass.async_block_till_done() - - state = hass.states.get("alarm_control_panel.beer") - assert state is None - - state = hass.states.get("alarm_control_panel.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") diff --git a/tests/components/mqtt/test_binary_sensor.py b/tests/components/mqtt/test_binary_sensor.py index 3bfe32633b3..e77cddda76d 100644 --- a/tests/components/mqtt/test_binary_sensor.py +++ b/tests/components/mqtt/test_binary_sensor.py @@ -1,10 +1,9 @@ """The tests for the MQTT binary sensor platform.""" from datetime import datetime, timedelta import json -from unittest.mock import ANY, patch +from unittest.mock import patch -from homeassistant.components import binary_sensor, mqtt -from homeassistant.components.mqtt.discovery import async_start +from homeassistant.components import binary_sensor from homeassistant.const import ( EVENT_STATE_CHANGED, STATE_OFF, @@ -15,14 +14,22 @@ import homeassistant.core as ha from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_fire_time_changed, - async_mock_mqtt_component, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) +from tests.common import async_fire_mqtt_message, async_fire_time_changed + async def test_setting_sensor_value_expires_availability_topic(hass, mqtt_mock, caplog): """Test the expiration of the value.""" @@ -417,73 +424,51 @@ async def test_off_delay(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - binary_sensor.DOMAIN, - { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + binary_sensor.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, binary_sensor.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("binary_sensor.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - binary_sensor.DOMAIN, - { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + binary_sensor.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, binary_sensor.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("binary_sensor.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - binary_sensor.DOMAIN, - { - binary_sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + binary_sensor.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, binary_sensor.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("binary_sensor.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -494,78 +479,46 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("binary_sensor.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("binary_sensor.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("binary_sensor.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one sensor per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - binary_sensor.DOMAIN, - { - binary_sensor.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_all()) == 1 + config = { + binary_sensor.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, binary_sensor.DOMAIN, config) async def test_discovery_removal_binary_sensor(hass, mqtt_mock, caplog): """Test removal of discovered binary_sensor.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' ' "availability_topic": "availability_topic" }' ) - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("binary_sensor.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("binary_sensor.beer") - assert state is None + await help_test_discovery_removal( + hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data + ) async def test_discovery_update_binary_sensor(hass, mqtt_mock, caplog): """Test update of discovered binary_sensor.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -576,52 +529,22 @@ async def test_discovery_update_binary_sensor(hass, mqtt_mock, caplog): ' "state_topic": "test_topic2",' ' "availability_topic": "availability_topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data1) - await hass.async_block_till_done() - state = hass.states.get("binary_sensor.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data2) - await hass.async_block_till_done() - state = hass.states.get("binary_sensor.beer") - assert state is not None - assert state.name == "Milk" - - state = hass.states.get("binary_sensor.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer",' ' "off_delay": -1 }' data2 = '{ "name": "Milk",' ' "state_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("binary_sensor.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, binary_sensor.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT binary sensor device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -638,26 +561,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, binary_sensor.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -672,62 +582,22 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/binary_sensor/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update( + hass, mqtt_mock, binary_sensor.DOMAIN, config + ) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - binary_sensor.DOMAIN, - { - binary_sensor.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("binary_sensor.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity( - "binary_sensor.beer", new_entity_id="binary_sensor.milk" - ) - await hass.async_block_till_done() - - state = hass.states.get("binary_sensor.beer") - assert state is None - - state = hass.states.get("binary_sensor.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + binary_sensor.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, binary_sensor.DOMAIN, config) diff --git a/tests/components/mqtt/test_climate.py b/tests/components/mqtt/test_climate.py index 29962287dd7..677fef06f22 100644 --- a/tests/components/mqtt/test_climate.py +++ b/tests/components/mqtt/test_climate.py @@ -2,12 +2,10 @@ import copy import json import unittest -from unittest.mock import ANY import pytest import voluptuous as vol -from homeassistant.components import mqtt from homeassistant.components.climate import DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP from homeassistant.components.climate.const import ( DOMAIN as CLIMATE_DOMAIN, @@ -25,16 +23,23 @@ from homeassistant.components.climate.const import ( SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE_RANGE, ) -from homeassistant.components.mqtt.discovery import async_start from homeassistant.const import STATE_OFF, STATE_UNAVAILABLE -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, - async_setup_component, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import async_fire_mqtt_message, async_setup_component from tests.components.climate import common ENTITY_CLIMATE = "climate.test" @@ -768,76 +773,54 @@ async def test_temp_step_custom(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - CLIMATE_DOMAIN, - { - CLIMATE_DOMAIN: { - "platform": "mqtt", - "name": "test", - "power_state_topic": "test-topic", - "power_command_topic": "test_topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + CLIMATE_DOMAIN: { + "platform": "mqtt", + "name": "test", + "power_state_topic": "test-topic", + "power_command_topic": "test_topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, CLIMATE_DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("climate.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - CLIMATE_DOMAIN, - { - CLIMATE_DOMAIN: { - "platform": "mqtt", - "name": "test", - "power_state_topic": "test-topic", - "power_command_topic": "test_topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + CLIMATE_DOMAIN: { + "platform": "mqtt", + "name": "test", + "power_state_topic": "test-topic", + "power_command_topic": "test_topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, CLIMATE_DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("climate.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - CLIMATE_DOMAIN, - { - CLIMATE_DOMAIN: { - "platform": "mqtt", - "name": "test", - "power_state_topic": "test-topic", - "power_command_topic": "test_topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + CLIMATE_DOMAIN: { + "platform": "mqtt", + "name": "test", + "power_state_topic": "test-topic", + "power_command_topic": "test_topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, CLIMATE_DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("climate.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "power_state_topic": "test-topic",' @@ -850,127 +833,60 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "power_command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("climate.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("climate.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("climate.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one climate per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - CLIMATE_DOMAIN, - { - CLIMATE_DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "power_state_topic": "test-topic", - "power_command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "power_state_topic": "test-topic", - "power_command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(CLIMATE_DOMAIN)) == 1 + config = { + CLIMATE_DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "power_state_topic": "test-topic", + "power_command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "power_state_topic": "test-topic", + "power_command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, CLIMATE_DOMAIN, config) async def test_discovery_removal_climate(hass, mqtt_mock, caplog): """Test removal of discovered climate.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data = '{ "name": "Beer" }' - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("climate.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("climate.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data) async def test_discovery_update_climate(hass, mqtt_mock, caplog): """Test update of discovered climate.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = '{ "name": "Beer" }' data2 = '{ "name": "Milk" }' - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("climate.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("climate.beer") - assert state is not None - assert state.name == "Milk" - - state = hass.states.get("climate.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer",' ' "power_command_topic": "test_topic#" }' data2 = '{ "name": "Milk", ' ' "power_command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("climate.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("climate.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("climate.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, CLIMATE_DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT climate device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -986,26 +902,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, CLIMATE_DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -1021,63 +924,23 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/climate/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, CLIMATE_DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - CLIMATE_DOMAIN, - { - CLIMATE_DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "mode_state_topic": "test-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("climate.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("climate.beer", new_entity_id="climate.milk") - await hass.async_block_till_done() - - state = hass.states.get("climate.beer") - assert state is None - - state = hass.states.get("climate.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + CLIMATE_DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "mode_state_topic": "test-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, CLIMATE_DOMAIN, config) async def test_precision_default(hass, mqtt_mock): diff --git a/tests/components/mqtt/test_cover.py b/tests/components/mqtt/test_cover.py index 128c18de8df..0bf8aa92150 100644 --- a/tests/components/mqtt/test_cover.py +++ b/tests/components/mqtt/test_cover.py @@ -1,11 +1,9 @@ """The tests for the MQTT cover platform.""" import json -from unittest.mock import ANY -from homeassistant.components import cover, mqtt +from homeassistant.components import cover from homeassistant.components.cover import ATTR_POSITION, ATTR_TILT_POSITION from homeassistant.components.mqtt.cover import MqttCover -from homeassistant.components.mqtt.discovery import async_start from homeassistant.const import ( ATTR_ASSUMED_STATE, ATTR_ENTITY_ID, @@ -27,13 +25,22 @@ from homeassistant.const import ( ) from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) +from tests.common import async_fire_mqtt_message + async def test_state_via_state_topic(hass, mqtt_mock): """Test the controlling state via topic.""" @@ -1693,73 +1700,51 @@ async def test_invalid_device_class(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - cover.DOMAIN, - { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + cover.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, cover.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("cover.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - cover.DOMAIN, - { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + cover.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, cover.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("cover.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - cover.DOMAIN, - { - cover.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + cover.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, cover.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("cover.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -1770,126 +1755,58 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("cover.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("cover.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("cover.beer") - assert state.attributes.get("val") == "75" - - -async def test_discovery_removal_cover(hass, mqtt_mock, caplog): - """Test removal of discovered cover.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("cover.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("cover.beer") - assert state is None - - -async def test_discovery_update_cover(hass, mqtt_mock, caplog): - """Test update of discovered cover.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data1) - await hass.async_block_till_done() - state = hass.states.get("cover.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("cover.beer") - assert state is not None - assert state.name == "Milk" - - state = hass.states.get("cover.milk") - assert state is None - - -async def test_discovery_broken(hass, mqtt_mock, caplog): - """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic#" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("cover.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("cover.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("cover.beer") - assert state is None + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, cover.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique_id option only creates one cover per id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - cover.DOMAIN, - { - cover.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, + config = { + cover.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, cover.DOMAIN, config) + + +async def test_discovery_removal_cover(hass, mqtt_mock, caplog): + """Test removal of discovered cover.""" + data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' + await help_test_discovery_removal(hass, mqtt_mock, caplog, cover.DOMAIN, data) + + +async def test_discovery_update_cover(hass, mqtt_mock, caplog): + """Test update of discovered cover.""" + data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_update( + hass, mqtt_mock, caplog, cover.DOMAIN, data1, data2 ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(cover.DOMAIN)) == 1 +async def test_discovery_broken(hass, mqtt_mock, caplog): + """Test handling of bad discovery message.""" + data1 = '{ "name": "Beer",' ' "command_topic": "test_topic#" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_broken( + hass, mqtt_mock, caplog, cover.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT cover device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -1907,26 +1824,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, cover.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -1942,60 +1846,20 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/cover/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, cover.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - cover.DOMAIN, - { - cover.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("cover.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("cover.beer", new_entity_id="cover.milk") - await hass.async_block_till_done() - - state = hass.states.get("cover.beer") - assert state is None - - state = hass.states.get("cover.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + cover.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, cover.DOMAIN, config) diff --git a/tests/components/mqtt/test_fan.py b/tests/components/mqtt/test_fan.py index 65e170fba91..556dbbe5528 100644 --- a/tests/components/mqtt/test_fan.py +++ b/tests/components/mqtt/test_fan.py @@ -1,9 +1,7 @@ """Test MQTT fans.""" import json -from unittest.mock import ANY -from homeassistant.components import fan, mqtt -from homeassistant.components.mqtt.discovery import async_start +from homeassistant.components import fan from homeassistant.const import ( ATTR_ASSUMED_STATE, STATE_OFF, @@ -12,12 +10,21 @@ from homeassistant.const import ( ) from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import async_fire_mqtt_message from tests.components.fan import common @@ -438,138 +445,53 @@ async def test_custom_availability_payload(hass, mqtt_mock): assert state.state is not STATE_UNAVAILABLE -async def test_discovery_removal_fan(hass, mqtt_mock, caplog): - """Test removal of discovered fan.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("fan.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("fan.beer") - assert state is None - - -async def test_discovery_update_fan(hass, mqtt_mock, caplog): - """Test update of discovered fan.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("fan.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("fan.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("fan.milk") - assert state is None - - -async def test_discovery_broken(hass, mqtt_mock, caplog): - """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("fan.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("fan.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("fan.beer") - assert state is None - - async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - fan.DOMAIN, - { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + fan.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, fan.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("fan.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - fan.DOMAIN, - { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + fan.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, fan.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("fan.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - fan.DOMAIN, - { - fan.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + fan.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, fan.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("fan.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -580,65 +502,56 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("fan.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("fan.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("fan.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, fan.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique_id option only creates one fan per id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - fan.DOMAIN, - { - fan.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "command_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "command_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) + config = { + fan.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, fan.DOMAIN, config) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(fan.DOMAIN)) == 1 +async def test_discovery_removal_fan(hass, mqtt_mock, caplog): + """Test removal of discovered fan.""" + data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' + await help_test_discovery_removal(hass, mqtt_mock, caplog, fan.DOMAIN, data) + + +async def test_discovery_update_fan(hass, mqtt_mock, caplog): + """Test update of discovered fan.""" + data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_update(hass, mqtt_mock, caplog, fan.DOMAIN, data1, data2) + + +async def test_discovery_broken(hass, mqtt_mock, caplog): + """Test handling of bad discovery message.""" + data1 = '{ "name": "Beer" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_broken(hass, mqtt_mock, caplog, fan.DOMAIN, data1, data2) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT fan device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -656,26 +569,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, fan.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -691,61 +591,21 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/fan/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, fan.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - fan.DOMAIN, - { - fan.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "command_topic": "command-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("fan.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("fan.beer", new_entity_id="fan.milk") - await hass.async_block_till_done() - - state = hass.states.get("fan.beer") - assert state is None - - state = hass.states.get("fan.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + fan.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, fan.DOMAIN, config) diff --git a/tests/components/mqtt/test_legacy_vacuum.py b/tests/components/mqtt/test_legacy_vacuum.py index f6128decc1a..558a185dbb0 100644 --- a/tests/components/mqtt/test_legacy_vacuum.py +++ b/tests/components/mqtt/test_legacy_vacuum.py @@ -2,9 +2,8 @@ from copy import deepcopy import json -from homeassistant.components import mqtt, vacuum +from homeassistant.components import vacuum from homeassistant.components.mqtt import CONF_COMMAND_TOPIC -from homeassistant.components.mqtt.discovery import async_start from homeassistant.components.mqtt.vacuum import schema_legacy as mqttvacuum from homeassistant.components.mqtt.vacuum.schema import services_to_strings from homeassistant.components.mqtt.vacuum.schema_legacy import ( @@ -26,11 +25,21 @@ from homeassistant.const import ( ) from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import async_fire_mqtt_message from tests.components.vacuum import common DEFAULT_CONFIG = { @@ -514,142 +523,50 @@ async def test_custom_availability_payload(hass, mqtt_mock): assert state.state == STATE_UNAVAILABLE -async def test_discovery_removal_vacuum(hass, mqtt_mock): - """Test removal of discovered vacuum.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", "") - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is None - - -async def test_discovery_broken(hass, mqtt_mock, caplog): - """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic#" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("vacuum.beer") - assert state is None - - -async def test_discovery_update_vacuum(hass, mqtt_mock): - """Test update of discovered vacuum.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("vacuum.milk") - assert state is None - - async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: { - "platform": "mqtt", - "name": "test", - "json_attributes_topic": "attr-topic", - } - }, + config = { + vacuum.DOMAIN: { + "platform": "mqtt", + "name": "test", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, vacuum.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("vacuum.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: { - "platform": "mqtt", - "name": "test", - "json_attributes_topic": "attr-topic", - } - }, + config = { + vacuum.DOMAIN: { + "platform": "mqtt", + "name": "test", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, vacuum.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("vacuum.test") - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - - -async def test_update_with_json_attrs_bad_json(hass, mqtt_mock, caplog): +async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: { - "platform": "mqtt", - "name": "test", - "json_attributes_topic": "attr-topic", - } - }, + config = { + vacuum.DOMAIN: { + "platform": "mqtt", + "name": "test", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, vacuum.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("vacuum.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -660,63 +577,58 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("vacuum.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("vacuum.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("vacuum.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 + ) async def test_unique_id(hass, mqtt_mock): """Test unique id option only creates one vacuum per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "command_topic": "command-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "command_topic": "command-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, + config = { + vacuum.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, vacuum.DOMAIN, config) + + +async def test_discovery_removal_vacuum(hass, mqtt_mock, caplog): + """Test removal of discovered vacuum.""" + data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' + await help_test_discovery_removal(hass, mqtt_mock, caplog, vacuum.DOMAIN, data) + + +async def test_discovery_update_vacuum(hass, mqtt_mock, caplog): + """Test update of discovered vacuum.""" + data1 = '{ "name": "Beer",' ' "command_topic": "test_topic" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_update( + hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids()) == 1 +async def test_discovery_broken(hass, mqtt_mock, caplog): + """Test handling of bad discovery message.""" + data1 = '{ "name": "Beer",' ' "command_topic": "test_topic#" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_broken( + hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT vacuum device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -733,26 +645,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, vacuum.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -767,20 +666,22 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } + await help_test_entity_device_info_update(hass, mqtt_mock, vacuum.DOMAIN, config) - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" +async def test_entity_id_update(hass, mqtt_mock): + """Test MQTT subscriptions are managed when entity_id is updated.""" + config = { + vacuum.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "battery_level_topic": "test-topic", + "battery_level_template": "{{ value_json.battery_level }}", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, vacuum.DOMAIN, config) diff --git a/tests/components/mqtt/test_light.py b/tests/components/mqtt/test_light.py index 43ccaf6dea5..389806a2b20 100644 --- a/tests/components/mqtt/test_light.py +++ b/tests/components/mqtt/test_light.py @@ -155,7 +155,7 @@ light: """ import json from unittest import mock -from unittest.mock import ANY, patch +from unittest.mock import patch from homeassistant.components import light, mqtt from homeassistant.components.mqtt.discovery import async_start @@ -168,13 +168,25 @@ from homeassistant.const import ( import homeassistant.core as ha from homeassistant.setup import async_setup_component +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, +) + from tests.common import ( MockConfigEntry, assert_setup_component, async_fire_mqtt_message, - async_mock_mqtt_component, mock_coro, - mock_registry, ) from tests.components.light import common @@ -1063,73 +1075,51 @@ async def test_custom_availability_payload(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("light.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("light.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("light.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -1140,79 +1130,42 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one light per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(light.DOMAIN)) == 1 + config = { + light.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, light.DOMAIN, config) async def test_discovery_removal_light(hass, mqtt_mock, caplog): """Test removal of discovered light.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", "") - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data) async def test_discovery_deprecated(hass, mqtt_mock, caplog): @@ -1231,9 +1184,6 @@ async def test_discovery_deprecated(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog): """Test update of discovered light.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -1244,59 +1194,26 @@ async def test_discovery_update_light(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("light.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer" }' data2 = ( '{ "name": "Milk",' ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("light.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("light.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT light device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -1314,26 +1231,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, light.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -1349,61 +1253,21 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, light.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "command_topic": "command-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("light.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("light.beer", new_entity_id="light.milk") - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None - - state = hass.states.get("light.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + light.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, light.DOMAIN, config) diff --git a/tests/components/mqtt/test_light_json.py b/tests/components/mqtt/test_light_json.py index 355451f6469..8783f16c9af 100644 --- a/tests/components/mqtt/test_light_json.py +++ b/tests/components/mqtt/test_light_json.py @@ -89,7 +89,7 @@ light: """ import json from unittest import mock -from unittest.mock import ANY, patch +from unittest.mock import patch from homeassistant.components import light, mqtt from homeassistant.components.mqtt.discovery import async_start @@ -103,13 +103,21 @@ from homeassistant.const import ( import homeassistant.core as ha from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, - mock_coro, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import MockConfigEntry, async_fire_mqtt_message, mock_coro from tests.components.light import common @@ -913,76 +921,54 @@ async def test_custom_availability_payload(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "schema": "json", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "schema": "json", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("light.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "schema": "json", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "schema": "json", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("light.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "schema": "json", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "schema": "json", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("light.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "schema": "json",' @@ -995,72 +981,40 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one light per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "schema": "json", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "schema": "json", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(light.DOMAIN)) == 1 + config = { + light.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "schema": "json", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "schema": "json", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, light.DOMAIN, config) async def test_discovery_removal(hass, mqtt_mock, caplog): """Test removal of discovered mqtt_json lights.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {"mqtt": {}}, entry) data = '{ "name": "Beer",' ' "schema": "json",' ' "command_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("light.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data) async def test_discovery_deprecated(hass, mqtt_mock, caplog): @@ -1081,9 +1035,6 @@ async def test_discovery_deprecated(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog): """Test update of discovered light.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = ( '{ "name": "Beer",' ' "schema": "json",' @@ -1096,29 +1047,13 @@ async def test_discovery_update_light(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("light.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer" }' data2 = ( '{ "name": "Milk",' @@ -1126,30 +1061,13 @@ async def test_discovery_broken(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("light.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("light.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT light device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -1168,26 +1086,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, light.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -1204,62 +1109,22 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, light.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "schema": "json", - "state_topic": "test-topic", - "command_topic": "command-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("light.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("light.beer", new_entity_id="light.milk") - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None - - state = hass.states.get("light.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + light.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "schema": "json", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, light.DOMAIN, config) diff --git a/tests/components/mqtt/test_light_template.py b/tests/components/mqtt/test_light_template.py index 1d109af5930..26c58b7522c 100644 --- a/tests/components/mqtt/test_light_template.py +++ b/tests/components/mqtt/test_light_template.py @@ -27,7 +27,7 @@ If your light doesn't support white value feature, omit `white_value_template`. If your light doesn't support RGB feature, omit `(red|green|blue)_template`. """ import json -from unittest.mock import ANY, patch +from unittest.mock import patch from homeassistant.components import light, mqtt from homeassistant.components.mqtt.discovery import async_start @@ -40,13 +40,25 @@ from homeassistant.const import ( import homeassistant.core as ha from homeassistant.setup import async_setup_component +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, +) + from tests.common import ( MockConfigEntry, assert_setup_component, async_fire_mqtt_message, - async_mock_mqtt_component, mock_coro, - mock_registry, ) @@ -510,82 +522,60 @@ async def test_custom_availability_payload(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "schema": "template", - "name": "test", - "command_topic": "test-topic", - "command_on_template": "on,{{ transition }}", - "command_off_template": "off,{{ transition|d }}", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "schema": "template", + "name": "test", + "command_topic": "test-topic", + "command_on_template": "on,{{ transition }}", + "command_off_template": "off,{{ transition|d }}", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("light.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "schema": "template", - "name": "test", - "command_topic": "test-topic", - "command_on_template": "on,{{ transition }}", - "command_off_template": "off,{{ transition|d }}", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "schema": "template", + "name": "test", + "command_topic": "test-topic", + "command_on_template": "on,{{ transition }}", + "command_off_template": "off,{{ transition|d }}", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("light.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: { - "platform": "mqtt", - "schema": "template", - "name": "test", - "command_topic": "test-topic", - "command_on_template": "on,{{ transition }}", - "command_off_template": "off,{{ transition|d }}", - "json_attributes_topic": "attr-topic", - } - }, + config = { + light.DOMAIN: { + "platform": "mqtt", + "schema": "template", + "name": "test", + "command_topic": "test-topic", + "command_on_template": "on,{{ transition }}", + "command_off_template": "off,{{ transition|d }}", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, light.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("light.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "schema": "template",' @@ -602,64 +592,40 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_off_template": "off",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("light.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one light per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "schema": "template", - "state_topic": "test-topic", - "command_topic": "test_topic", - "command_on_template": "on,{{ transition }}", - "command_off_template": "off,{{ transition|d }}", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "schema": "template", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(light.DOMAIN)) == 1 + config = { + light.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "schema": "template", + "state_topic": "test-topic", + "command_topic": "test_topic", + "command_on_template": "on,{{ transition }}", + "command_off_template": "off,{{ transition|d }}", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "schema": "template", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, light.DOMAIN, config) async def test_discovery_removal(hass, mqtt_mock, caplog): """Test removal of discovered mqtt_json lights.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {"mqtt": {}}, entry) data = ( '{ "name": "Beer",' ' "schema": "template",' @@ -667,15 +633,7 @@ async def test_discovery_removal(hass, mqtt_mock, caplog): ' "command_on_template": "on",' ' "command_off_template": "off"}' ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("light.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, light.DOMAIN, data) async def test_discovery_deprecated(hass, mqtt_mock, caplog): @@ -698,9 +656,6 @@ async def test_discovery_deprecated(hass, mqtt_mock, caplog): async def test_discovery_update_light(hass, mqtt_mock, caplog): """Test update of discovered light.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = ( '{ "name": "Beer",' ' "schema": "template",' @@ -717,29 +672,13 @@ async def test_discovery_update_light(hass, mqtt_mock, caplog): ' "command_on_template": "on",' ' "command_off_template": "off"}' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("light.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer" }' data2 = ( '{ "name": "Milk",' @@ -749,30 +688,13 @@ async def test_discovery_broken(hass, mqtt_mock, caplog): ' "command_on_template": "on",' ' "command_off_template": "off"}' ) - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("light.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("light.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, light.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT light device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -793,26 +715,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, light.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -831,64 +740,24 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/light/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, light.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - light.DOMAIN, - { - light.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "schema": "template", - "state_topic": "test-topic", - "command_topic": "command-topic", - "command_on_template": "on,{{ transition }}", - "command_off_template": "off,{{ transition|d }}", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("light.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("light.beer", new_entity_id="light.milk") - await hass.async_block_till_done() - - state = hass.states.get("light.beer") - assert state is None - - state = hass.states.get("light.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + light.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "schema": "template", + "state_topic": "test-topic", + "command_topic": "command-topic", + "command_on_template": "on,{{ transition }}", + "command_off_template": "off,{{ transition|d }}", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, light.DOMAIN, config) diff --git a/tests/components/mqtt/test_lock.py b/tests/components/mqtt/test_lock.py index 9b89fa7159d..a9c1fe73952 100644 --- a/tests/components/mqtt/test_lock.py +++ b/tests/components/mqtt/test_lock.py @@ -1,9 +1,7 @@ """The tests for the MQTT lock platform.""" import json -from unittest.mock import ANY -from homeassistant.components import lock, mqtt -from homeassistant.components.mqtt.discovery import async_start +from homeassistant.components import lock from homeassistant.const import ( ATTR_ASSUMED_STATE, STATE_LOCKED, @@ -12,12 +10,21 @@ from homeassistant.const import ( ) from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import async_fire_mqtt_message from tests.components.lock import common @@ -309,73 +316,51 @@ async def test_custom_availability_payload(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - lock.DOMAIN, - { - lock.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + lock.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, lock.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("lock.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - lock.DOMAIN, - { - lock.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + lock.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, lock.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("lock.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - lock.DOMAIN, - { - lock.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + lock.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, lock.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("lock.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -386,100 +371,42 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("lock.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("lock.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("lock.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, lock.DOMAIN, data1, data2 + ) async def test_unique_id(hass): - """Test unique id option only creates one light per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - lock.DOMAIN, - { - lock.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "command_topic": "test_topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids(lock.DOMAIN)) == 1 + """Test unique id option only creates one lock per unique_id.""" + config = { + lock.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "command_topic": "test_topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, lock.DOMAIN, config) async def test_discovery_removal_lock(hass, mqtt_mock, caplog): """Test removal of discovered lock.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data = '{ "name": "Beer",' ' "command_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("lock.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("lock.beer") - assert state is None - - -async def test_discovery_broken(hass, mqtt_mock, caplog): - """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer" }' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("lock.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("lock.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("lock.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, lock.DOMAIN, data) async def test_discovery_update_lock(hass, mqtt_mock, caplog): """Test update of discovered lock.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -492,28 +419,18 @@ async def test_discovery_update_lock(hass, mqtt_mock, caplog): ' "command_topic": "command_topic",' ' "availability_topic": "availability_topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data1) - await hass.async_block_till_done() - state = hass.states.get("lock.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data2) - await hass.async_block_till_done() - state = hass.states.get("lock.beer") - assert state is not None - assert state.name == "Milk" + await help_test_discovery_update(hass, mqtt_mock, caplog, lock.DOMAIN, data1, data2) - state = hass.states.get("lock.milk") - assert state is None + +async def test_discovery_broken(hass, mqtt_mock, caplog): + """Test handling of bad discovery message.""" + data1 = '{ "name": "Beer" }' + data2 = '{ "name": "Milk",' ' "command_topic": "test_topic" }' + await help_test_discovery_broken(hass, mqtt_mock, caplog, lock.DOMAIN, data1, data2) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT lock device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -531,26 +448,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, lock.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -566,61 +470,21 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/lock/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, lock.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - lock.DOMAIN, - { - lock.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "command_topic": "test-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("lock.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("lock.beer", new_entity_id="lock.milk") - await hass.async_block_till_done() - - state = hass.states.get("lock.beer") - assert state is None - - state = hass.states.get("lock.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + lock.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, lock.DOMAIN, config) diff --git a/tests/components/mqtt/test_sensor.py b/tests/components/mqtt/test_sensor.py index 66f8996bc2e..be29a297d3d 100644 --- a/tests/components/mqtt/test_sensor.py +++ b/tests/components/mqtt/test_sensor.py @@ -1,7 +1,7 @@ """The tests for the MQTT sensor platform.""" from datetime import datetime, timedelta import json -from unittest.mock import ANY, patch +from unittest.mock import patch from homeassistant.components import mqtt from homeassistant.components.mqtt.discovery import async_start @@ -11,12 +11,24 @@ import homeassistant.core as ha from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, +) + from tests.common import ( MockConfigEntry, async_fire_mqtt_message, async_fire_time_changed, - async_mock_mqtt_component, - mock_registry, ) @@ -395,24 +407,18 @@ async def test_valid_device_class(hass, mqtt_mock): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - sensor.DOMAIN, - { - sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + sensor.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, sensor.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("sensor.test") - - assert state.attributes.get("val") == "100" - async def test_setting_attribute_with_template(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" @@ -441,52 +447,36 @@ async def test_setting_attribute_with_template(hass, mqtt_mock): async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - sensor.DOMAIN, - { - sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + sensor.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, sensor.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("sensor.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - sensor.DOMAIN, - { - sensor.DOMAIN: { - "platform": "mqtt", - "name": "test", - "state_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + sensor.DOMAIN: { + "platform": "mqtt", + "name": "test", + "state_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, sensor.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("sensor.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -497,127 +487,58 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("sensor.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("sensor.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("sensor.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, sensor.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one sensor per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - sensor.DOMAIN, - { - sensor.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - - async_fire_mqtt_message(hass, "test-topic", "payload") - - assert len(hass.states.async_all()) == 1 + config = { + sensor.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, sensor.DOMAIN, config) async def test_discovery_removal_sensor(hass, mqtt_mock, caplog): """Test removal of discovered sensor.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data = '{ "name": "Beer",' ' "state_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) - await hass.async_block_till_done() - state = hass.states.get("sensor.beer") - assert state is not None - assert state.name == "Beer" - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", "") - await hass.async_block_till_done() - state = hass.states.get("sensor.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, sensor.DOMAIN, data) async def test_discovery_update_sensor(hass, mqtt_mock, caplog): """Test update of discovered sensor.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = '{ "name": "Beer",' ' "state_topic": "test_topic" }' data2 = '{ "name": "Milk",' ' "state_topic": "test_topic" }' - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("sensor.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("sensor.beer") - assert state is not None - assert state.name == "Milk" - - state = hass.states.get("sensor.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, sensor.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer",' ' "state_topic": "test_topic#" }' data2 = '{ "name": "Milk",' ' "state_topic": "test_topic" }' - - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("sensor.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("sensor.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("sensor.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, sensor.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT sensor device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -634,26 +555,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, sensor.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -668,63 +576,23 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/sensor/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, sensor.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - sensor.DOMAIN, - { - sensor.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("sensor.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("sensor.beer", new_entity_id="sensor.milk") - await hass.async_block_till_done() - - state = hass.states.get("sensor.beer") - assert state is None - - state = hass.states.get("sensor.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + sensor.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, sensor.DOMAIN, config) async def test_entity_device_info_with_hub(hass, mqtt_mock): diff --git a/tests/components/mqtt/test_state_vacuum.py b/tests/components/mqtt/test_state_vacuum.py index d7e45004f13..146f69b30d7 100644 --- a/tests/components/mqtt/test_state_vacuum.py +++ b/tests/components/mqtt/test_state_vacuum.py @@ -2,9 +2,8 @@ from copy import deepcopy import json -from homeassistant.components import mqtt, vacuum +from homeassistant.components import vacuum from homeassistant.components.mqtt import CONF_COMMAND_TOPIC, CONF_STATE_TOPIC -from homeassistant.components.mqtt.discovery import async_start from homeassistant.components.mqtt.vacuum import CONF_SCHEMA, schema_state as mqttvacuum from homeassistant.components.mqtt.vacuum.schema import services_to_strings from homeassistant.components.mqtt.vacuum.schema_state import SERVICE_TO_STRING @@ -32,11 +31,21 @@ from homeassistant.const import ( ) from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import async_fire_mqtt_message from tests.components.vacuum import common COMMAND_TOPIC = "vacuum/command" @@ -340,212 +349,123 @@ async def test_custom_availability_payload(hass, mqtt_mock): assert state.state == STATE_UNAVAILABLE -async def test_discovery_removal_vacuum(hass, mqtt_mock): - """Test removal of discovered vacuum.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data = '{ "name": "Beer",' ' "command_topic": "test_topic"}' - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", "") - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is None - - -async def test_discovery_broken(hass, mqtt_mock, caplog): - """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic#"}' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic"}' - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("vacuum.beer") - assert state is None - - -async def test_discovery_update_vacuum(hass, mqtt_mock): - """Test update of discovered vacuum.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - - data1 = '{ "name": "Beer",' ' "command_topic": "test_topic"}' - data2 = '{ "name": "Milk",' ' "command_topic": "test_topic"}' - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("vacuum.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("vacuum.milk") - assert state is None - - async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: { - "platform": "mqtt", - "name": "test", - "json_attributes_topic": "attr-topic", - } - }, + config = { + vacuum.DOMAIN: { + "platform": "mqtt", + "schema": "state", + "name": "test", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, vacuum.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("vacuum.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: { - "platform": "mqtt", - "name": "test", - "json_attributes_topic": "attr-topic", - } - }, + config = { + vacuum.DOMAIN: { + "platform": "mqtt", + "schema": "state", + "name": "test", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, vacuum.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("vacuum.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_json(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: { - "platform": "mqtt", - "name": "test", - "json_attributes_topic": "attr-topic", - } - }, + config = { + vacuum.DOMAIN: { + "platform": "mqtt", + "schema": "state", + "name": "test", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, vacuum.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("vacuum.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' + ' "schema": "state",' ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic1" }' ) data2 = ( '{ "name": "Beer",' + ' "schema": "state",' ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("vacuum.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("vacuum.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("vacuum.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 + ) async def test_unique_id(hass, mqtt_mock): """Test unique id option only creates one vacuum per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - vacuum.DOMAIN, - { - vacuum.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "command_topic": "command-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "command_topic": "command-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, + config = { + vacuum.DOMAIN: [ + { + "platform": "mqtt", + "schema": "state", + "name": "Test 1", + "command_topic": "command-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "schema": "state", + "name": "Test 2", + "command_topic": "command-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, vacuum.DOMAIN, config) + + +async def test_discovery_removal_vacuum(hass, mqtt_mock, caplog): + """Test removal of discovered vacuum.""" + data = '{ "schema": "state", "name": "Beer",' ' "command_topic": "test_topic"}' + await help_test_discovery_removal(hass, mqtt_mock, caplog, vacuum.DOMAIN, data) + + +async def test_discovery_update_vacuum(hass, mqtt_mock, caplog): + """Test update of discovered vacuum.""" + data1 = '{ "schema": "state", "name": "Beer",' ' "command_topic": "test_topic"}' + data2 = '{ "schema": "state", "name": "Milk",' ' "command_topic": "test_topic"}' + await help_test_discovery_update( + hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 ) - async_fire_mqtt_message(hass, "test-topic", "payload") - assert len(hass.states.async_entity_ids()) == 1 +async def test_discovery_broken(hass, mqtt_mock, caplog): + """Test handling of bad discovery message.""" + data1 = '{ "schema": "state", "name": "Beer",' ' "command_topic": "test_topic#"}' + data2 = '{ "schema": "state", "name": "Milk",' ' "command_topic": "test_topic"}' + await help_test_discovery_broken( + hass, mqtt_mock, caplog, vacuum.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT vacuum device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", + "schema": "state", "name": "Test 1", "command_topic": "test-command-topic", "device": { @@ -559,28 +479,16 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, vacuum.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", + "schema": "state", "name": "Test 1", "command_topic": "test-command-topic", "device": { @@ -593,20 +501,22 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } + await help_test_entity_device_info_update(hass, mqtt_mock, vacuum.DOMAIN, config) - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/vacuum/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" +async def test_entity_id_update(hass, mqtt_mock): + """Test MQTT subscriptions are managed when entity_id is updated.""" + config = { + vacuum.DOMAIN: [ + { + "platform": "mqtt", + "schema": "state", + "name": "beer", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, vacuum.DOMAIN, config) diff --git a/tests/components/mqtt/test_switch.py b/tests/components/mqtt/test_switch.py index 8412edffbbe..cfb5c3598b2 100644 --- a/tests/components/mqtt/test_switch.py +++ b/tests/components/mqtt/test_switch.py @@ -1,12 +1,10 @@ """The tests for the MQTT switch platform.""" import json -from unittest.mock import ANY from asynctest import patch import pytest -from homeassistant.components import mqtt, switch -from homeassistant.components.mqtt.discovery import async_start +from homeassistant.components import switch from homeassistant.const import ( ATTR_ASSUMED_STATE, STATE_OFF, @@ -16,13 +14,21 @@ from homeassistant.const import ( import homeassistant.core as ha from homeassistant.setup import async_setup_component -from tests.common import ( - MockConfigEntry, - async_fire_mqtt_message, - async_mock_mqtt_component, - mock_coro, - mock_registry, +from .common import ( + help_test_discovery_broken, + help_test_discovery_removal, + help_test_discovery_update, + help_test_discovery_update_attr, + help_test_entity_device_info_update, + help_test_entity_device_info_with_identifier, + help_test_entity_id_update, + help_test_setting_attribute_via_mqtt_json_message, + help_test_unique_id, + help_test_update_with_json_attrs_bad_JSON, + help_test_update_with_json_attrs_not_dict, ) + +from tests.common import async_fire_mqtt_message, async_mock_mqtt_component, mock_coro from tests.components.switch import common @@ -265,73 +271,51 @@ async def test_custom_state_payload(hass, mock_publish): async def test_setting_attribute_via_mqtt_json_message(hass, mqtt_mock): """Test the setting of attribute via MQTT with JSON payload.""" - assert await async_setup_component( - hass, - switch.DOMAIN, - { - switch.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + switch.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_setting_attribute_via_mqtt_json_message( + hass, mqtt_mock, switch.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '{ "val": "100" }') - state = hass.states.get("switch.test") - - assert state.attributes.get("val") == "100" - async def test_update_with_json_attrs_not_dict(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - switch.DOMAIN, - { - switch.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + switch.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_not_dict( + hass, mqtt_mock, caplog, switch.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", '[ "list", "of", "things"]') - state = hass.states.get("switch.test") - - assert state.attributes.get("val") is None - assert "JSON result was not a dictionary" in caplog.text - async def test_update_with_json_attrs_bad_JSON(hass, mqtt_mock, caplog): """Test attributes get extracted from a JSON result.""" - assert await async_setup_component( - hass, - switch.DOMAIN, - { - switch.DOMAIN: { - "platform": "mqtt", - "name": "test", - "command_topic": "test-topic", - "json_attributes_topic": "attr-topic", - } - }, + config = { + switch.DOMAIN: { + "platform": "mqtt", + "name": "test", + "command_topic": "test-topic", + "json_attributes_topic": "attr-topic", + } + } + await help_test_update_with_json_attrs_bad_JSON( + hass, mqtt_mock, caplog, switch.DOMAIN, config ) - async_fire_mqtt_message(hass, "attr-topic", "This is not JSON") - - state = hass.states.get("switch.test") - assert state.attributes.get("val") is None - assert "Erroneous JSON: This is not JSON" in caplog.text - async def test_discovery_update_attr(hass, mqtt_mock, caplog): """Test update of discovered MQTTAttributes.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) data1 = ( '{ "name": "Beer",' ' "command_topic": "test_topic",' @@ -342,88 +326,46 @@ async def test_discovery_update_attr(hass, mqtt_mock, caplog): ' "command_topic": "test_topic",' ' "json_attributes_topic": "attr-topic2" }' ) - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data1) - await hass.async_block_till_done() - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "100" }') - state = hass.states.get("switch.beer") - assert state.attributes.get("val") == "100" - - # Change json_attributes_topic - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data2) - await hass.async_block_till_done() - - # Verify we are no longer subscribing to the old topic - async_fire_mqtt_message(hass, "attr-topic1", '{ "val": "50" }') - state = hass.states.get("switch.beer") - assert state.attributes.get("val") == "100" - - # Verify we are subscribing to the new topic - async_fire_mqtt_message(hass, "attr-topic2", '{ "val": "75" }') - state = hass.states.get("switch.beer") - assert state.attributes.get("val") == "75" + await help_test_discovery_update_attr( + hass, mqtt_mock, caplog, switch.DOMAIN, data1, data2 + ) async def test_unique_id(hass): """Test unique id option only creates one switch per unique_id.""" - await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - switch.DOMAIN, - { - switch.DOMAIN: [ - { - "platform": "mqtt", - "name": "Test 1", - "state_topic": "test-topic", - "command_topic": "command-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - { - "platform": "mqtt", - "name": "Test 2", - "state_topic": "test-topic", - "command_topic": "command-topic", - "unique_id": "TOTALLY_UNIQUE", - }, - ] - }, - ) - - async_fire_mqtt_message(hass, "test-topic", "payload") - - assert len(hass.states.async_entity_ids()) == 1 + config = { + switch.DOMAIN: [ + { + "platform": "mqtt", + "name": "Test 1", + "state_topic": "test-topic", + "command_topic": "command-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + { + "platform": "mqtt", + "name": "Test 2", + "state_topic": "test-topic", + "command_topic": "command-topic", + "unique_id": "TOTALLY_UNIQUE", + }, + ] + } + await help_test_unique_id(hass, switch.DOMAIN, config) async def test_discovery_removal_switch(hass, mqtt_mock, caplog): """Test removal of discovered switch.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data) - await hass.async_block_till_done() - - state = hass.states.get("switch.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", "") - await hass.async_block_till_done() - - state = hass.states.get("switch.beer") - assert state is None + await help_test_discovery_removal(hass, mqtt_mock, caplog, switch.DOMAIN, data) async def test_discovery_update_switch(hass, mqtt_mock, caplog): """Test update of discovered switch.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = ( '{ "name": "Beer",' ' "state_topic": "test_topic",' @@ -434,59 +376,26 @@ async def test_discovery_update_switch(hass, mqtt_mock, caplog): ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("switch.beer") - assert state is not None - assert state.name == "Beer" - - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("switch.beer") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("switch.milk") - assert state is None + await help_test_discovery_update( + hass, mqtt_mock, caplog, switch.DOMAIN, data1, data2 + ) async def test_discovery_broken(hass, mqtt_mock, caplog): """Test handling of bad discovery message.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - await async_start(hass, "homeassistant", {}, entry) - data1 = '{ "name": "Beer" }' data2 = ( '{ "name": "Milk",' ' "state_topic": "test_topic",' ' "command_topic": "test_topic" }' ) - - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data1) - await hass.async_block_till_done() - - state = hass.states.get("switch.beer") - assert state is None - - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data2) - await hass.async_block_till_done() - - state = hass.states.get("switch.milk") - assert state is not None - assert state.name == "Milk" - state = hass.states.get("switch.beer") - assert state is None + await help_test_discovery_broken( + hass, mqtt_mock, caplog, switch.DOMAIN, data1, data2 + ) async def test_entity_device_info_with_identifier(hass, mqtt_mock): """Test MQTT switch device registry integration.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - data = json.dumps( { "platform": "mqtt", @@ -504,26 +413,13 @@ async def test_entity_device_info_with_identifier(hass, mqtt_mock): "unique_id": "veryunique", } ) - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.identifiers == {("mqtt", "helloworld")} - assert device.connections == {("mac", "02:5b:26:a8:dc:12")} - assert device.manufacturer == "Whatever" - assert device.name == "Beer" - assert device.model == "Glass" - assert device.sw_version == "0.1-beta" + await help_test_entity_device_info_with_identifier( + hass, mqtt_mock, switch.DOMAIN, data + ) async def test_entity_device_info_update(hass, mqtt_mock): """Test device registry update.""" - entry = MockConfigEntry(domain=mqtt.DOMAIN) - entry.add_to_hass(hass) - await async_start(hass, "homeassistant", {}, entry) - registry = await hass.helpers.device_registry.async_get_registry() - config = { "platform": "mqtt", "name": "Test 1", @@ -539,61 +435,21 @@ async def test_entity_device_info_update(hass, mqtt_mock): }, "unique_id": "veryunique", } - - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Beer" - - config["device"]["name"] = "Milk" - data = json.dumps(config) - async_fire_mqtt_message(hass, "homeassistant/switch/bla/config", data) - await hass.async_block_till_done() - - device = registry.async_get_device({("mqtt", "helloworld")}, set()) - assert device is not None - assert device.name == "Milk" + await help_test_entity_device_info_update(hass, mqtt_mock, switch.DOMAIN, config) async def test_entity_id_update(hass, mqtt_mock): """Test MQTT subscriptions are managed when entity_id is updated.""" - registry = mock_registry(hass, {}) - mock_mqtt = await async_mock_mqtt_component(hass) - assert await async_setup_component( - hass, - switch.DOMAIN, - { - switch.DOMAIN: [ - { - "platform": "mqtt", - "name": "beer", - "state_topic": "test-topic", - "command_topic": "command-topic", - "availability_topic": "avty-topic", - "unique_id": "TOTALLY_UNIQUE", - } - ] - }, - ) - - state = hass.states.get("switch.beer") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.reset_mock() - - registry.async_update_entity("switch.beer", new_entity_id="switch.milk") - await hass.async_block_till_done() - - state = hass.states.get("switch.beer") - assert state is None - - state = hass.states.get("switch.milk") - assert state is not None - assert mock_mqtt.async_subscribe.call_count == 2 - mock_mqtt.async_subscribe.assert_any_call("test-topic", ANY, 0, "utf-8") - mock_mqtt.async_subscribe.assert_any_call("avty-topic", ANY, 0, "utf-8") + config = { + switch.DOMAIN: [ + { + "platform": "mqtt", + "name": "beer", + "state_topic": "test-topic", + "command_topic": "command-topic", + "availability_topic": "avty-topic", + "unique_id": "TOTALLY_UNIQUE", + } + ] + } + await help_test_entity_id_update(hass, mqtt_mock, switch.DOMAIN, config)