From 214286acb93a07e95ae4094ba0499d2aa5c946cf Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Wed, 22 Mar 2023 10:23:08 +0100 Subject: [PATCH] Prepare MQTT platorm tests part1 (#90051) * Add help_custom_config * Tests alarm_control_panel * Tests binary_sensor * Only use help_custom_config with iterable options --- .../mqtt/test_alarm_control_panel.py | 323 ++++++++------- tests/components/mqtt/test_binary_sensor.py | 382 ++++++++++-------- tests/components/mqtt/test_common.py | 24 ++ 3 files changed, 410 insertions(+), 319 deletions(-) diff --git a/tests/components/mqtt/test_alarm_control_panel.py b/tests/components/mqtt/test_alarm_control_panel.py index a7e5678a3b7..79c06d7a5f3 100644 --- a/tests/components/mqtt/test_alarm_control_panel.py +++ b/tests/components/mqtt/test_alarm_control_panel.py @@ -35,9 +35,9 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant -from homeassistant.setup import async_setup_component from .test_common import ( + help_custom_config, help_test_availability_when_connection_lost, help_test_availability_without_topic, help_test_custom_availability_payload, @@ -204,17 +204,12 @@ async def test_update_state_via_state_topic( assert hass.states.get(entity_id).state == state +@pytest.mark.parametrize("hass_config", [DEFAULT_CONFIG]) async def test_ignore_update_state_if_unknown_via_state_topic( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator ) -> None: """Test ignoring updates via state topic.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, - DEFAULT_CONFIG, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + await mqtt_mock_entry_no_yaml_config() entity_id = "alarm_control_panel.test" @@ -225,31 +220,25 @@ async def test_ignore_update_state_if_unknown_via_state_topic( @pytest.mark.parametrize( - ("service", "payload"), + ("hass_config", "service", "payload"), [ - (SERVICE_ALARM_ARM_HOME, "ARM_HOME"), - (SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), - (SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), - (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), - (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), - (SERVICE_ALARM_DISARM, "DISARM"), - (SERVICE_ALARM_TRIGGER, "TRIGGER"), + (DEFAULT_CONFIG, SERVICE_ALARM_ARM_HOME, "ARM_HOME"), + (DEFAULT_CONFIG, SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), + (DEFAULT_CONFIG, SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), + (DEFAULT_CONFIG, SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), + (DEFAULT_CONFIG, SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), + (DEFAULT_CONFIG, SERVICE_ALARM_DISARM, "DISARM"), + (DEFAULT_CONFIG, SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_no_code( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, service, payload, ) -> None: """Test publishing of MQTT messages when no code is configured.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, - DEFAULT_CONFIG, - ) - await hass.async_block_till_done() - mqtt_mock = await mqtt_mock_entry_with_yaml_config() + mqtt_mock = await mqtt_mock_entry_no_yaml_config() await hass.services.async_call( alarm_control_panel.DOMAIN, @@ -262,31 +251,25 @@ async def test_publish_mqtt_no_code( @pytest.mark.parametrize( - ("service", "payload"), + ("hass_config", "service", "payload"), [ - (SERVICE_ALARM_ARM_HOME, "ARM_HOME"), - (SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), - (SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), - (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), - (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), - (SERVICE_ALARM_DISARM, "DISARM"), - (SERVICE_ALARM_TRIGGER, "TRIGGER"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_ARM_HOME, "ARM_HOME"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_DISARM, "DISARM"), + (DEFAULT_CONFIG_CODE, SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_with_code( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, service, payload, ) -> None: """Test publishing of MQTT messages when code is configured.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, - DEFAULT_CONFIG_CODE, - ) - await hass.async_block_till_done() - mqtt_mock = await mqtt_mock_entry_with_yaml_config() + mqtt_mock = await mqtt_mock_entry_no_yaml_config() call_count = mqtt_mock.async_publish.call_count # No code provided, should not publish @@ -318,31 +301,29 @@ async def test_publish_mqtt_with_code( @pytest.mark.parametrize( - ("service", "payload"), + ("hass_config", "service", "payload"), [ - (SERVICE_ALARM_ARM_HOME, "ARM_HOME"), - (SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), - (SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), - (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), - (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), - (SERVICE_ALARM_DISARM, "DISARM"), - (SERVICE_ALARM_TRIGGER, "TRIGGER"), + (DEFAULT_CONFIG_REMOTE_CODE, SERVICE_ALARM_ARM_HOME, "ARM_HOME"), + (DEFAULT_CONFIG_REMOTE_CODE, SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), + (DEFAULT_CONFIG_REMOTE_CODE, SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), + (DEFAULT_CONFIG_REMOTE_CODE, SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), + ( + DEFAULT_CONFIG_REMOTE_CODE, + SERVICE_ALARM_ARM_CUSTOM_BYPASS, + "ARM_CUSTOM_BYPASS", + ), + (DEFAULT_CONFIG_REMOTE_CODE, SERVICE_ALARM_DISARM, "DISARM"), + (DEFAULT_CONFIG_REMOTE_CODE, SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_with_remote_code( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, service, payload, ) -> None: """Test publishing of MQTT messages when remode code is configured.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, - DEFAULT_CONFIG_REMOTE_CODE, - ) - await hass.async_block_till_done() - mqtt_mock = await mqtt_mock_entry_with_yaml_config() + mqtt_mock = await mqtt_mock_entry_no_yaml_config() call_count = mqtt_mock.async_publish.call_count # No code provided, should not publish @@ -365,31 +346,29 @@ async def test_publish_mqtt_with_remote_code( @pytest.mark.parametrize( - ("service", "payload"), + ("hass_config", "service", "payload"), [ - (SERVICE_ALARM_ARM_HOME, "ARM_HOME"), - (SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), - (SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), - (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), - (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS"), - (SERVICE_ALARM_DISARM, "DISARM"), - (SERVICE_ALARM_TRIGGER, "TRIGGER"), + (DEFAULT_CONFIG_REMOTE_CODE_TEXT, SERVICE_ALARM_ARM_HOME, "ARM_HOME"), + (DEFAULT_CONFIG_REMOTE_CODE_TEXT, SERVICE_ALARM_ARM_AWAY, "ARM_AWAY"), + (DEFAULT_CONFIG_REMOTE_CODE_TEXT, SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT"), + (DEFAULT_CONFIG_REMOTE_CODE_TEXT, SERVICE_ALARM_ARM_VACATION, "ARM_VACATION"), + ( + DEFAULT_CONFIG_REMOTE_CODE_TEXT, + SERVICE_ALARM_ARM_CUSTOM_BYPASS, + "ARM_CUSTOM_BYPASS", + ), + (DEFAULT_CONFIG_REMOTE_CODE_TEXT, SERVICE_ALARM_DISARM, "DISARM"), + (DEFAULT_CONFIG_REMOTE_CODE_TEXT, SERVICE_ALARM_TRIGGER, "TRIGGER"), ], ) async def test_publish_mqtt_with_remote_code_text( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - service, - payload, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + service: str, + payload: str, ) -> None: """Test publishing of MQTT messages when remote text code is configured.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, - DEFAULT_CONFIG_REMOTE_CODE_TEXT, - ) - await hass.async_block_till_done() - mqtt_mock = await mqtt_mock_entry_with_yaml_config() + mqtt_mock = await mqtt_mock_entry_no_yaml_config() call_count = mqtt_mock.async_publish.call_count # No code provided, should not publish @@ -412,38 +391,85 @@ async def test_publish_mqtt_with_remote_code_text( @pytest.mark.parametrize( - ("service", "payload", "disable_code"), + ("hass_config", "service", "payload"), [ - (SERVICE_ALARM_ARM_HOME, "ARM_HOME", "code_arm_required"), - (SERVICE_ALARM_ARM_AWAY, "ARM_AWAY", "code_arm_required"), - (SERVICE_ALARM_ARM_NIGHT, "ARM_NIGHT", "code_arm_required"), - (SERVICE_ALARM_ARM_VACATION, "ARM_VACATION", "code_arm_required"), - (SERVICE_ALARM_ARM_CUSTOM_BYPASS, "ARM_CUSTOM_BYPASS", "code_arm_required"), - (SERVICE_ALARM_DISARM, "DISARM", "code_disarm_required"), - (SERVICE_ALARM_TRIGGER, "TRIGGER", "code_trigger_required"), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_arm_required": False},), + ), + SERVICE_ALARM_ARM_HOME, + "ARM_HOME", + ), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_arm_required": False},), + ), + SERVICE_ALARM_ARM_AWAY, + "ARM_AWAY", + ), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_arm_required": False},), + ), + SERVICE_ALARM_ARM_NIGHT, + "ARM_NIGHT", + ), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_arm_required": False},), + ), + SERVICE_ALARM_ARM_VACATION, + "ARM_VACATION", + ), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_arm_required": False},), + ), + SERVICE_ALARM_ARM_CUSTOM_BYPASS, + "ARM_CUSTOM_BYPASS", + ), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_disarm_required": False},), + ), + SERVICE_ALARM_DISARM, + "DISARM", + ), + ( + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ({"code_trigger_required": False},), + ), + SERVICE_ALARM_TRIGGER, + "TRIGGER", + ), ], ) async def test_publish_mqtt_with_code_required_false( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - service, - payload, - disable_code, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + service: str, + payload: str, ) -> None: """Test publishing of MQTT messages when code is configured. code_arm_required = False / code_disarm_required = False / code_trigger_required = False """ - config = copy.deepcopy(DEFAULT_CONFIG_CODE) - config[mqtt.DOMAIN][alarm_control_panel.DOMAIN][disable_code] = False - assert await async_setup_component( - hass, - mqtt.DOMAIN, - config, - ) - await hass.async_block_till_done() - mqtt_mock = await mqtt_mock_entry_with_yaml_config() + mqtt_mock = await mqtt_mock_entry_no_yaml_config() # No code provided, should publish await hass.services.async_call( @@ -476,25 +502,29 @@ async def test_publish_mqtt_with_code_required_false( mqtt_mock.reset_mock() +@pytest.mark.parametrize( + "hass_config", + [ + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_CODE, + ( + { + "code": "0123", + "command_template": '{"action":"{{ action }}","code":"{{ code }}"}', + }, + ), + ) + ], +) async def test_disarm_publishes_mqtt_with_template( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator ) -> None: """Test publishing of MQTT messages while disarmed. When command_template set to output json """ - config = copy.deepcopy(DEFAULT_CONFIG_CODE) - config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = "0123" - config[mqtt.DOMAIN][alarm_control_panel.DOMAIN][ - "command_template" - ] = '{"action":"{{ action }}","code":"{{ code }}"}' - assert await async_setup_component( - hass, - mqtt.DOMAIN, - config, - ) - await hass.async_block_till_done() - mqtt_mock = await mqtt_mock_entry_with_yaml_config() + mqtt_mock = await mqtt_mock_entry_no_yaml_config() await common.async_alarm_disarm(hass, "0123") mqtt_mock.async_publish.assert_called_once_with( @@ -502,13 +532,9 @@ async def test_disarm_publishes_mqtt_with_template( ) -async def test_update_state_via_state_topic_template( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test updating with template_value via state topic.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { alarm_control_panel.DOMAIN: { @@ -523,10 +549,14 @@ async def test_update_state_via_state_topic_template( {% endif %}", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_update_state_via_state_topic_template( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test updating with template_value via state topic.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("alarm_control_panel.test") assert state.state == STATE_UNKNOWN @@ -537,16 +567,19 @@ async def test_update_state_via_state_topic_template( assert state.state == STATE_ALARM_ARMED_AWAY +@pytest.mark.parametrize( + "hass_config", + [ + help_custom_config( + alarm_control_panel.DOMAIN, DEFAULT_CONFIG, ({"code": CODE_NUMBER},) + ) + ], +) async def test_attributes_code_number( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator ) -> None: """Test attributes which are not supported by the vacuum.""" - config = copy.deepcopy(DEFAULT_CONFIG) - config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = CODE_NUMBER - - assert await async_setup_component(hass, mqtt.DOMAIN, config) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("alarm_control_panel.test") assert ( @@ -555,16 +588,21 @@ async def test_attributes_code_number( ) +@pytest.mark.parametrize( + "hass_config", + [ + help_custom_config( + alarm_control_panel.DOMAIN, + DEFAULT_CONFIG_REMOTE_CODE, + ({"code": "REMOTE_CODE"},), + ) + ], +) async def test_attributes_remote_code_number( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator ) -> None: """Test attributes which are not supported by the vacuum.""" - config = copy.deepcopy(DEFAULT_CONFIG_REMOTE_CODE) - config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = "REMOTE_CODE" - - assert await async_setup_component(hass, mqtt.DOMAIN, config) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("alarm_control_panel.test") assert ( @@ -573,16 +611,19 @@ async def test_attributes_remote_code_number( ) +@pytest.mark.parametrize( + "hass_config", + [ + help_custom_config( + alarm_control_panel.DOMAIN, DEFAULT_CONFIG, ({"code": CODE_TEXT},) + ) + ], +) async def test_attributes_code_text( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator ) -> None: """Test attributes which are not supported by the vacuum.""" - config = copy.deepcopy(DEFAULT_CONFIG) - config[mqtt.DOMAIN][alarm_control_panel.DOMAIN]["code"] = CODE_TEXT - - assert await async_setup_component(hass, mqtt.DOMAIN, config) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("alarm_control_panel.test") assert ( diff --git a/tests/components/mqtt/test_binary_sensor.py b/tests/components/mqtt/test_binary_sensor.py index 3e224a4136a..0d3cd695490 100644 --- a/tests/components/mqtt/test_binary_sensor.py +++ b/tests/components/mqtt/test_binary_sensor.py @@ -19,10 +19,11 @@ from homeassistant.const import ( Platform, ) from homeassistant.core import HomeAssistant, State, callback -from homeassistant.setup import async_setup_component +from homeassistant.helpers.typing import ConfigType import homeassistant.util.dt as dt_util from .test_common import ( + help_custom_config, help_test_availability_when_connection_lost, help_test_availability_without_topic, help_test_custom_availability_payload, @@ -74,15 +75,9 @@ def binary_sensor_platform_only(): yield -async def test_setting_sensor_value_expires_availability_topic( - hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test the expiration of the value.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -93,10 +88,16 @@ async def test_setting_sensor_value_expires_availability_topic( "availability_topic": "availability-topic", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_setting_sensor_value_expires_availability_topic( + hass: HomeAssistant, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test the expiration of the value.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") assert state.state == STATE_UNAVAILABLE @@ -110,15 +111,9 @@ async def test_setting_sensor_value_expires_availability_topic( await expires_helper(hass) -async def test_setting_sensor_value_expires( - hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test the expiration of the value.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -128,10 +123,16 @@ async def test_setting_sensor_value_expires( "force_update": True, } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_setting_sensor_value_expires( + hass: HomeAssistant, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test the expiration of the value.""" + await mqtt_mock_entry_no_yaml_config() # State should be unavailable since expire_after is defined and > 0 state = hass.states.get("binary_sensor.test") @@ -274,13 +275,9 @@ async def test_expiration_on_discovery_and_discovery_update_of_binary_sensor( assert state.state == STATE_UNAVAILABLE -async def test_setting_sensor_value_via_mqtt_message( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test the setting of the value via MQTT.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -290,10 +287,14 @@ async def test_setting_sensor_value_via_mqtt_message( "payload_off": "OFF", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_setting_sensor_value_via_mqtt_message( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test the setting of the value via MQTT.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") @@ -312,15 +313,9 @@ async def test_setting_sensor_value_via_mqtt_message( assert state.state == STATE_UNKNOWN -async def test_invalid_sensor_value_via_mqtt_message( - hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test the setting of the value via MQTT.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -330,10 +325,16 @@ async def test_invalid_sensor_value_via_mqtt_message( "payload_off": "OFF", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_invalid_sensor_value_via_mqtt_message( + hass: HomeAssistant, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test the setting of the value via MQTT.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") @@ -356,13 +357,9 @@ async def test_invalid_sensor_value_via_mqtt_message( assert "No matching payload found for entity" in caplog.text -async def test_setting_sensor_value_via_mqtt_message_and_template( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test the setting of the value via MQTT.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -374,10 +371,14 @@ async def test_setting_sensor_value_via_mqtt_message_and_template( "{%-else-%}ON{%-endif%}", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_setting_sensor_value_via_mqtt_message_and_template( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test the setting of the value via MQTT.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") assert state.state == STATE_UNKNOWN @@ -391,15 +392,9 @@ async def test_setting_sensor_value_via_mqtt_message_and_template( assert state.state == STATE_OFF -async def test_setting_sensor_value_via_mqtt_message_and_template2( - hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test the setting of the value via MQTT.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -411,9 +406,15 @@ async def test_setting_sensor_value_via_mqtt_message_and_template2( } } }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + ], +) +async def test_setting_sensor_value_via_mqtt_message_and_template2( + hass: HomeAssistant, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test the setting of the value via MQTT.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") assert state.state == STATE_UNKNOWN @@ -432,15 +433,9 @@ async def test_setting_sensor_value_via_mqtt_message_and_template2( assert "template output: 'ILLEGAL'" in caplog.text -async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_encoding( - hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, - caplog: pytest.LogCaptureFixture, -) -> None: - """Test processing a raw value via MQTT.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -452,10 +447,16 @@ async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_ "value_template": "{%if value|unpack('b')-%}ON{%else%}OFF{%-endif-%}", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_encoding( + hass: HomeAssistant, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test processing a raw value via MQTT.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") assert state.state == STATE_UNKNOWN @@ -469,13 +470,9 @@ async def test_setting_sensor_value_via_mqtt_message_and_template_and_raw_state_ assert state.state == STATE_OFF -async def test_setting_sensor_value_via_mqtt_message_empty_template( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test the setting of the value via MQTT.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -486,10 +483,14 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template( "value_template": '{%if value == "ABC"%}ON{%endif%}', } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_setting_sensor_value_via_mqtt_message_empty_template( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test the setting of the value via MQTT.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") assert state.state == STATE_UNKNOWN @@ -503,13 +504,9 @@ async def test_setting_sensor_value_via_mqtt_message_empty_template( assert state.state == STATE_ON -async def test_valid_device_class( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test the setting of a valid sensor class.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -518,22 +515,22 @@ async def test_valid_device_class( "state_topic": "test-topic", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_valid_device_class( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test the setting of a valid sensor class.""" + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test") assert state.attributes.get("device_class") == "motion" -async def test_invalid_device_class( - hass: HomeAssistant, caplog: pytest.LogCaptureFixture -) -> None: - """Test the setting of an invalid sensor class.""" - assert not await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -542,8 +539,17 @@ async def test_invalid_device_class( "state_topic": "test-topic", } } - }, - ) + } + ], +) +async def test_invalid_device_class( + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, +) -> None: + """Test the setting of an invalid sensor class.""" + with pytest.raises(AssertionError): + await mqtt_mock_entry_no_yaml_config() assert "Invalid config for [mqtt]: expected BinarySensorDeviceClass" in caplog.text @@ -585,13 +591,9 @@ async def test_custom_availability_payload( ) -async def test_force_update_disabled( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test force update option.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -601,10 +603,14 @@ async def test_force_update_disabled( "payload_off": "OFF", } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_force_update_disabled( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test force update option.""" + await mqtt_mock_entry_no_yaml_config() events = [] @@ -624,13 +630,9 @@ async def test_force_update_disabled( assert len(events) == 1 -async def test_force_update_enabled( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test force update option.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -641,10 +643,14 @@ async def test_force_update_enabled( "force_update": True, } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_force_update_enabled( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test force update option.""" + await mqtt_mock_entry_no_yaml_config() events = [] @@ -664,13 +670,9 @@ async def test_force_update_enabled( assert len(events) == 2 -async def test_off_delay( - hass: HomeAssistant, mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator -) -> None: - """Test off_delay option.""" - assert await async_setup_component( - hass, - mqtt.DOMAIN, +@pytest.mark.parametrize( + "hass_config", + [ { mqtt.DOMAIN: { binary_sensor.DOMAIN: { @@ -682,10 +684,14 @@ async def test_off_delay( "force_update": True, } } - }, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + } + ], +) +async def test_off_delay( + hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator +) -> None: + """Test off_delay option.""" + await mqtt_mock_entry_no_yaml_config() events = [] @@ -1068,40 +1074,54 @@ async def test_reloadable( @pytest.mark.parametrize( - ("payload1", "state1", "payload2", "state2"), - [("ON", "on", "OFF", "off"), ("OFF", "off", "ON", "on")], + ("hass_config", "payload1", "state1", "payload2", "state2"), + [ + ( + help_custom_config( + binary_sensor.DOMAIN, + DEFAULT_CONFIG, + ( + {"name": "test1", "expire_after": 30, "state_topic": "test-topic1"}, + {"name": "test2", "expire_after": 5, "state_topic": "test-topic2"}, + ), + ), + "ON", + "on", + "OFF", + "off", + ), + ( + help_custom_config( + binary_sensor.DOMAIN, + DEFAULT_CONFIG, + ( + {"name": "test1", "expire_after": 30, "state_topic": "test-topic1"}, + {"name": "test2", "expire_after": 5, "state_topic": "test-topic2"}, + ), + ), + "OFF", + "off", + "ON", + "on", + ), + ], ) async def test_cleanup_triggers_and_restoring_state( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, caplog: pytest.LogCaptureFixture, tmp_path: Path, freezer: FrozenDateTimeFactory, + hass_config: ConfigType, payload1, state1, payload2, state2, ) -> None: """Test cleanup old triggers at reloading and restoring the state.""" - domain = binary_sensor.DOMAIN - config1 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][domain]) - config1["name"] = "test1" - config1["expire_after"] = 30 - config1["state_topic"] = "test-topic1" - config2 = copy.deepcopy(DEFAULT_CONFIG[mqtt.DOMAIN][domain]) - config2["name"] = "test2" - config2["expire_after"] = 5 - config2["state_topic"] = "test-topic2" - freezer.move_to("2022-02-02 12:01:00+01:00") - assert await async_setup_component( - hass, - mqtt.DOMAIN, - {mqtt.DOMAIN: {binary_sensor.DOMAIN: [config1, config2]}}, - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + await mqtt_mock_entry_no_yaml_config() async_fire_mqtt_message(hass, "test-topic1", payload1) state = hass.states.get("binary_sensor.test1") @@ -1114,7 +1134,7 @@ async def test_cleanup_triggers_and_restoring_state( freezer.move_to("2022-02-02 12:01:10+01:00") await help_test_reload_with_config( - hass, caplog, tmp_path, {mqtt.DOMAIN: {domain: [config1, config2]}} + hass, caplog, tmp_path, {mqtt.DOMAIN: hass_config} ) state = hass.states.get("binary_sensor.test1") @@ -1132,9 +1152,19 @@ async def test_cleanup_triggers_and_restoring_state( assert state.state == state2 +@pytest.mark.parametrize( + "hass_config", + [ + help_custom_config( + binary_sensor.DOMAIN, + DEFAULT_CONFIG, + ({"name": "test3", "expire_after": 10, "state_topic": "test-topic3"},), + ) + ], +) async def test_skip_restoring_state_with_over_due_expire_trigger( hass: HomeAssistant, - mqtt_mock_entry_with_yaml_config: MqttMockHAClientGenerator, + mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator, freezer: FrozenDateTimeFactory, ) -> None: """Test restoring a state with over due expire timer.""" @@ -1153,11 +1183,7 @@ async def test_skip_restoring_state_with_over_due_expire_trigger( ) mock_restore_cache(hass, (fake_state,)) - assert await async_setup_component( - hass, mqtt.DOMAIN, {mqtt.DOMAIN: {domain: config3}} - ) - await hass.async_block_till_done() - await mqtt_mock_entry_with_yaml_config() + await mqtt_mock_entry_no_yaml_config() state = hass.states.get("binary_sensor.test3") assert state.state == STATE_UNAVAILABLE diff --git a/tests/components/mqtt/test_common.py b/tests/components/mqtt/test_common.py index f5a4648e34c..6d238a63f43 100644 --- a/tests/components/mqtt/test_common.py +++ b/tests/components/mqtt/test_common.py @@ -1,4 +1,5 @@ """Common test objects.""" +from collections.abc import Iterable from contextlib import suppress import copy from datetime import datetime @@ -119,6 +120,29 @@ async def help_setup_component( return mqtt_mock +def help_custom_config( + mqtt_entity_domain: str, + mqtt_base_config: ConfigType, + mqtt_entity_configs: Iterable[ConfigType,], +) -> ConfigType: + """Tweak a default config for parametrization. + + Returns a custom config to be used as parametrization for with hass_config, + based on the supplied mqtt_base_config and updated with mqtt_entity_configs. + For each item in mqtt_entity_configs an entity instance is added to the config. + """ + config: ConfigType = copy.deepcopy(mqtt_base_config) + entity_instances: list[ConfigType] = [] + for instance in mqtt_entity_configs: + base: ConfigType = copy.deepcopy( + mqtt_base_config[mqtt.DOMAIN][mqtt_entity_domain] + ) + base.update(instance) + entity_instances.append(base) + config[mqtt.DOMAIN][mqtt_entity_domain]: list[ConfigType] = entity_instances + return config + + async def help_test_availability_when_connection_lost( hass: HomeAssistant, mqtt_mock_entry_no_yaml_config: MqttMockHAClientGenerator,