diff --git a/homeassistant/components/template/helpers.py b/homeassistant/components/template/helpers.py index 66ca4eec45b5..491fbbff6e76 100644 --- a/homeassistant/components/template/helpers.py +++ b/homeassistant/components/template/helpers.py @@ -133,10 +133,10 @@ async def validate_template_scripts( hass: HomeAssistant, config: ConfigType, script_options: tuple[str, ...] | None = None, -) -> None: +) -> bool: """Validate template scripts.""" if not script_options: - return + return True def _humanize(err: Exception, data: Any) -> str: """Humanize vol.Invalid, stringify other exceptions.""" @@ -160,6 +160,9 @@ async def validate_template_scripts( breadcrumb, _humanize(err, script_config), ) + return False + + return True def async_create_platform_template_not_supported_issue( @@ -199,15 +202,12 @@ async def async_setup_template_platform( # Trigger Configuration if "coordinator" in discovery_info: if trigger_entity_cls: - entities = [] - for entity_config in discovery_info["entities"]: - await validate_template_scripts(hass, entity_config, script_options) - entities.append( - trigger_entity_cls( - hass, discovery_info["coordinator"], entity_config - ) - ) - async_add_entities(entities) + if trigger_entities := [ + trigger_entity_cls(hass, discovery_info["coordinator"], entity_config) + for entity_config in discovery_info["entities"] + if await validate_template_scripts(hass, entity_config, script_options) + ]: + async_add_entities(trigger_entities) else: raise PlatformNotReady( f"The template {domain} platform doesn't support trigger entities" @@ -215,16 +215,18 @@ async def async_setup_template_platform( return # Modern Configuration - for entity_config in discovery_info["entities"]: - await validate_template_scripts(hass, entity_config, script_options) - - async_create_template_tracking_entities( - state_entity_cls, - async_add_entities, - hass, - discovery_info["entities"], - discovery_info["unique_id"], - ) + if state_entities := [ + entity_config + for entity_config in discovery_info["entities"] + if await validate_template_scripts(hass, entity_config, script_options) + ]: + async_create_template_tracking_entities( + state_entity_cls, + async_add_entities, + hass, + state_entities, + discovery_info["unique_id"], + ) async def async_setup_template_entry( @@ -247,11 +249,10 @@ async def async_setup_template_entry( options[CONF_STATE] = options.pop(CONF_VALUE_TEMPLATE) validated_config = config_schema(options) - await validate_template_scripts(hass, validated_config, script_options) - - async_add_entities( - [state_entity_cls(hass, validated_config, config_entry.entry_id)] - ) + if await validate_template_scripts(hass, validated_config, script_options): + async_add_entities( + [state_entity_cls(hass, validated_config, config_entry.entry_id)] + ) def async_setup_template_preview[T: TemplateEntity]( diff --git a/tests/components/template/conftest.py b/tests/components/template/conftest.py index a9a0428d3c8e..82dd9f6bf543 100644 --- a/tests/components/template/conftest.py +++ b/tests/components/template/conftest.py @@ -15,6 +15,7 @@ from homeassistant.helpers.typing import ConfigType from homeassistant.setup import async_setup_component from tests.common import ( + MockConfigEntry, assert_setup_component, async_mock_service, mock_restore_cache, @@ -292,6 +293,74 @@ async def caplog_setup_text(caplog: pytest.LogCaptureFixture) -> str: return caplog.text +def _create_bad_action_config(action: str, config: ConfigType) -> ConfigType: + """Create a bad device action.""" + return { + action: { + "type": "turn_off", + "device_id": "70c5f67ec2f82f9ba128fe6e99eb7dfa", + "entity_id": "c7e6f3753cb18937f2147bbbdccdd949", + "domain": "light", + }, + **config, + } + + +async def assert_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + platform_setup: TemplatePlatformSetup, + style: ConfigurationStyle, + config: ConfigType, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Assert invalid yaml actions on entity services do not create entities.""" + + await setup_entity( + hass, + platform_setup, + style, + 1, + { + "default_entity_id": platform_setup.entity_id, + **_create_bad_action_config(action, config), + }, + ) + assert len(hass.states.async_all(platform_setup.domain)) == 0 + + error = f"The '{action}' actions for {platform_setup.object_id} failed to setup: Unknown device '70c5f67ec2f82f9ba128fe6e99eb7dfa'" + assert error in caplog.text + + +async def assert_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + platform_setup: TemplatePlatformSetup, + config: ConfigType, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Assert invalid config entry actions on entity services do not create entities.""" + + template_config_entry = MockConfigEntry( + data={}, + domain=template.DOMAIN, + options={ + "name": platform_setup.object_id, + "template_type": platform_setup.domain, + **_create_bad_action_config(action, config), + }, + title="My template", + ) + template_config_entry.add_to_hass(hass) + assert await hass.config_entries.async_setup(template_config_entry.entry_id) + await hass.async_block_till_done() + + assert len(hass.states.async_all(platform_setup.domain)) == 0 + + error = f"The '{action}' actions for {platform_setup.object_id} failed to setup: Unknown device '70c5f67ec2f82f9ba128fe6e99eb7dfa'" + assert error in caplog.text + + async def async_get_flow_preview_state( hass: HomeAssistant, hass_ws_client: WebSocketGenerator, diff --git a/tests/components/template/test_alarm_control_panel.py b/tests/components/template/test_alarm_control_panel.py index 856e2fff5b5c..5cf25419b25c 100644 --- a/tests/components/template/test_alarm_control_panel.py +++ b/tests/components/template/test_alarm_control_panel.py @@ -11,7 +11,10 @@ from homeassistant.components.alarm_control_panel import ( AlarmControlPanelEntityStateAttribute, AlarmControlPanelState, ) -from homeassistant.components.template.alarm_control_panel import DEFAULT_NAME +from homeassistant.components.template.alarm_control_panel import ( + DEFAULT_NAME, + SCRIPT_FIELDS, +) from homeassistant.const import STATE_OFF, STATE_ON, STATE_UNAVAILABLE, STATE_UNKNOWN from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.helpers import device_registry as dr, entity_registry as er @@ -24,6 +27,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -797,6 +802,34 @@ async def test_invalid_availability_template_keeps_component_available( assert error in caplog_setup_text or error in caplog.text +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize("action", SCRIPT_FIELDS) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_PANEL, style, {}, action, caplog + ) + + +@pytest.mark.parametrize("action", SCRIPT_FIELDS) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_PANEL, {}, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_button.py b/tests/components/template/test_button.py index cefbb2c9fc9d..6609d56ac860 100644 --- a/tests/components/template/test_button.py +++ b/tests/components/template/test_button.py @@ -8,7 +8,7 @@ from syrupy.assertion import SnapshotAssertion from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS from homeassistant.components.template import DOMAIN -from homeassistant.components.template.button import DEFAULT_NAME +from homeassistant.components.template.button import DEFAULT_NAME, SCRIPT_FIELDS from homeassistant.components.template.const import CONF_PICTURE from homeassistant.const import ( ATTR_ENTITY_PICTURE, @@ -31,6 +31,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, async_trigger, make_test_action, setup_and_test_nested_unique_id, @@ -385,6 +387,34 @@ async def test_invalid_availability_template_keeps_component_available( assert "UndefinedError: 'x' is undefined" in caplog_setup_text +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize("action", SCRIPT_FIELDS) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_BUTTON, style, {}, action, caplog + ) + + +@pytest.mark.parametrize("action", SCRIPT_FIELDS) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_BUTTON, {}, action, caplog + ) + + async def test_extra_template_attributes(hass: HomeAssistant) -> None: """Test extra attributes.""" await assert_extra_template_attributes( diff --git a/tests/components/template/test_cover.py b/tests/components/template/test_cover.py index 2d98f37ddc6b..d8aea41d2da1 100644 --- a/tests/components/template/test_cover.py +++ b/tests/components/template/test_cover.py @@ -38,6 +38,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -1291,6 +1293,54 @@ async def test_restore_state( assert state.attributes["current_tilt_position"] == 75 +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize( + ("action", "config"), + [ + ("open_cover", {"close_cover": []}), + ("close_cover", {"open_cover": []}), + ("set_cover_position", COVER_ACTIONS), + ("stop_cover", COVER_ACTIONS), + ("set_cover_tilt_position", COVER_ACTIONS), + ], +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_COVER, style, config, action, caplog + ) + + +@pytest.mark.parametrize( + ("action", "config"), + [ + ("open_cover", {"close_cover": []}), + ("close_cover", {"open_cover": []}), + ("set_cover_position", COVER_ACTIONS), + ("stop_cover", COVER_ACTIONS), + ("set_cover_tilt_position", COVER_ACTIONS), + ], +) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_COVER, config, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_fan.py b/tests/components/template/test_fan.py index 1490246db54e..71e477eefc55 100644 --- a/tests/components/template/test_fan.py +++ b/tests/components/template/test_fan.py @@ -31,6 +31,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -1618,6 +1620,56 @@ async def test_restore_state( assert state.attributes["direction"] == DIRECTION_REVERSE +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize( + ("action", "config"), + [ + ("turn_on", {"turn_off": []}), + ("turn_off", {"turn_on": []}), + ("set_direction", OPTIMISTIC_ON_OFF_ACTIONS), + ("set_oscillating", OPTIMISTIC_ON_OFF_ACTIONS), + ("set_percentage", OPTIMISTIC_ON_OFF_ACTIONS), + ("set_preset_mode", OPTIMISTIC_ON_OFF_ACTIONS), + ], +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_FAN, style, config, action, caplog + ) + + +@pytest.mark.parametrize( + ("action", "config"), + [ + ("turn_on", {"turn_off": []}), + ("turn_off", {"turn_on": []}), + ("set_direction", OPTIMISTIC_ON_OFF_ACTIONS), + ("set_oscillating", OPTIMISTIC_ON_OFF_ACTIONS), + ("set_percentage", OPTIMISTIC_ON_OFF_ACTIONS), + ("set_preset_mode", OPTIMISTIC_ON_OFF_ACTIONS), + ], +) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_FAN, config, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_light.py b/tests/components/template/test_light.py index fd819d564903..a2fa4fa5249c 100644 --- a/tests/components/template/test_light.py +++ b/tests/components/template/test_light.py @@ -43,6 +43,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -2238,6 +2240,78 @@ async def test_saving_state( } +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize( + ("action", "config"), + [ + ("turn_on", {"turn_off": []}), + ("turn_off", {"turn_on": []}), + ( + "set_effect", + { + "effect_list": "{{ ['Disco', 'Police'] }}", + "effect": "{{ None }}", + **ON_OFF_ACTIONS, + }, + ), + ("set_hs", ON_OFF_ACTIONS), + ("set_level", ON_OFF_ACTIONS), + ("set_rgb", ON_OFF_ACTIONS), + ("set_rgbw", ON_OFF_ACTIONS), + ("set_rgbww", ON_OFF_ACTIONS), + ("set_temperature", ON_OFF_ACTIONS), + ("set_xy", ON_OFF_ACTIONS), + ], +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_LIGHT, style, config, action, caplog + ) + + +@pytest.mark.parametrize( + ("action", "config"), + [ + ("turn_on", {"turn_off": []}), + ("turn_off", {"turn_on": []}), + ( + "set_effect", + { + "effect_list": "{{ ['Disco', 'Police'] }}", + "effect": "{{ None }}", + **ON_OFF_ACTIONS, + }, + ), + ("set_hs", ON_OFF_ACTIONS), + ("set_level", ON_OFF_ACTIONS), + ("set_rgb", ON_OFF_ACTIONS), + ("set_rgbw", ON_OFF_ACTIONS), + ("set_rgbww", ON_OFF_ACTIONS), + ("set_temperature", ON_OFF_ACTIONS), + ("set_xy", ON_OFF_ACTIONS), + ], +) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_LIGHT, config, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_lock.py b/tests/components/template/test_lock.py index 145ae4ed6c88..98c891c2bb35 100644 --- a/tests/components/template/test_lock.py +++ b/tests/components/template/test_lock.py @@ -30,6 +30,8 @@ from .conftest import ( ConfigurationStyle, TemplatePlatformSetup, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -1163,6 +1165,50 @@ async def test_restore_state( ) +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize( + ("action", "config"), + [ + ("lock", UNLOCK_ACTION), + ("unlock", LOCK_ACTION), + ("open", {**LOCK_ACTION, **UNLOCK_ACTION}), + ], +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_LOCK, style, config, action, caplog + ) + + +@pytest.mark.parametrize( + ("action", "config"), + [ + ("lock", UNLOCK_ACTION), + ("unlock", LOCK_ACTION), + ("open", {**LOCK_ACTION, **UNLOCK_ACTION}), + ], +) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_LOCK, config, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_number.py b/tests/components/template/test_number.py index bb46638d52ea..f61ada08c59e 100644 --- a/tests/components/template/test_number.py +++ b/tests/components/template/test_number.py @@ -37,6 +37,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -752,6 +754,45 @@ async def test_restore_state( ) +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, + TEST_NUMBER, + style, + { + "state": "0", + "step": "1", + }, + "set_value", + caplog, + ) + + +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, + TEST_NUMBER, + { + "state": "0", + "step": 1, + }, + "set_value", + caplog, + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_select.py b/tests/components/template/test_select.py index be2045d1ce2e..bbf1bc92d1bb 100644 --- a/tests/components/template/test_select.py +++ b/tests/components/template/test_select.py @@ -35,6 +35,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -690,6 +692,39 @@ async def test_restore_state( ) +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, + TEST_SELECT, + style, + {"options": "{{ ['test', 'yes', 'no'] }}"}, + "select_option", + caplog, + ) + + +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, + TEST_SELECT, + {"options": "{{ ['test', 'yes', 'no'] }}"}, + "select_option", + caplog, + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_switch.py b/tests/components/template/test_switch.py index cc1732b499ff..04879981984e 100644 --- a/tests/components/template/test_switch.py +++ b/tests/components/template/test_switch.py @@ -27,6 +27,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, async_get_flow_preview_state, async_trigger, make_test_action, @@ -830,6 +832,48 @@ async def test_not_optimistic(hass: HomeAssistant, expected: str) -> None: assert state.state == expected +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize( + ("action", "config"), + [ + ("turn_on", {"turn_off": []}), + ("turn_off", {"turn_on": []}), + ], +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_SWITCH, style, config, action, caplog + ) + + +@pytest.mark.parametrize( + ("action", "config"), + [ + ("turn_on", {"turn_off": []}), + ("turn_off", {"turn_on": []}), + ], +) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_SWITCH, config, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_update.py b/tests/components/template/test_update.py index f75c177c5c42..906c2f99562a 100644 --- a/tests/components/template/test_update.py +++ b/tests/components/template/test_update.py @@ -6,7 +6,7 @@ import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.components import template, update -from homeassistant.components.template.update import DEFAULT_NAME +from homeassistant.components.template.update import DEFAULT_NAME, SCRIPT_FIELDS from homeassistant.const import ( ATTR_ENTITY_PICTURE, ATTR_ICON, @@ -26,6 +26,8 @@ from .conftest import ( TemplatePlatformSetup, assert_action, assert_extra_template_attributes, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, async_get_flow_preview_state, make_test_action, make_test_trigger, @@ -984,6 +986,34 @@ async def test_flow_preview( assert state["attributes"]["latest_version"] == "2.0" +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize("action", SCRIPT_FIELDS) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_UPDATE, style, TEST_UPDATE_CONFIG, action, caplog + ) + + +@pytest.mark.parametrize("action", SCRIPT_FIELDS) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_UPDATE, TEST_UPDATE_CONFIG, action, caplog + ) + + @pytest.mark.parametrize( "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] ) diff --git a/tests/components/template/test_vacuum.py b/tests/components/template/test_vacuum.py index 1dc35e33ecd0..11cd43814d0c 100644 --- a/tests/components/template/test_vacuum.py +++ b/tests/components/template/test_vacuum.py @@ -32,6 +32,8 @@ from .conftest import ( ConfigurationStyle, TemplatePlatformSetup, assert_action, + assert_invalid_config_entry_actions_do_not_create_entities, + assert_invalid_yaml_actions_do_not_create_entities, assert_state_and_attributes, async_get_flow_preview_state, async_trigger, @@ -1471,3 +1473,70 @@ async def test_saving_state( "activity": "docked", "fan_speed": "high", } + + +@pytest.mark.parametrize( + "style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER] +) +@pytest.mark.parametrize( + ("action", "config"), + [ + ( + "clean_segments", + { + "segments": "{{ [{'id': '1', 'name': 'Kitchen'}] }}", + **START_ACTION, + "unique_id": "5adfasdffsfsdafad", + }, + ), + ("clean_spot", START_ACTION), + ("locate", START_ACTION), + ("pause", START_ACTION), + ("return_to_base", START_ACTION), + ("set_fan_speed", START_ACTION), + ("start", {}), + ("stop", START_ACTION), + ], +) +async def test_invalid_yaml_actions_do_not_create_entities( + hass: HomeAssistant, + style: ConfigurationStyle, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid yaml actions do not create entities.""" + await assert_invalid_yaml_actions_do_not_create_entities( + hass, TEST_VACUUM, style, config, action, caplog + ) + + +@pytest.mark.parametrize( + ("action", "config"), + [ + ( + "clean_segments", + { + "segments": "{{ [{'id': '1', 'name': 'Kitchen'}] }}", + **START_ACTION, + }, + ), + ("clean_spot", START_ACTION), + ("locate", START_ACTION), + ("pause", START_ACTION), + ("return_to_base", START_ACTION), + ("set_fan_speed", START_ACTION), + ("start", {}), + ("stop", START_ACTION), + ], +) +async def test_invalid_config_entry_actions_do_not_create_entities( + hass: HomeAssistant, + action: str, + config: ConfigType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test invalid config entry actions do not create entities.""" + await assert_invalid_config_entry_actions_do_not_create_entities( + hass, TEST_VACUUM, config, action, caplog + )