Fix execute device actions with WS execute_script (#95783)

This commit is contained in:
Erik Montnemery 2023-07-03 20:21:01 +02:00 committed by GitHub
parent 3f9d5a0192
commit 78880f0c9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 5 deletions

View File

@ -704,10 +704,12 @@ async def handle_execute_script(
"""Handle execute script command."""
# Circular dep
# pylint: disable-next=import-outside-toplevel
from homeassistant.helpers.script import Script
from homeassistant.helpers.script import Script, async_validate_actions_config
script_config = await async_validate_actions_config(hass, msg["sequence"])
context = connection.context(msg)
script_obj = Script(hass, msg["sequence"], f"{const.DOMAIN} script", const.DOMAIN)
script_obj = Script(hass, script_config, f"{const.DOMAIN} script", const.DOMAIN)
response = await script_obj.async_run(msg.get("variables"), context=context)
connection.send_result(
msg["id"],

View File

@ -1,12 +1,14 @@
"""Tests for WebSocket API commands."""
from copy import deepcopy
import datetime
from unittest.mock import ANY, patch
from unittest.mock import ANY, AsyncMock, Mock, patch
from async_timeout import timeout
import pytest
import voluptuous as vol
from homeassistant import config_entries, loader
from homeassistant.components.device_automation import toggle_entity
from homeassistant.components.websocket_api import const
from homeassistant.components.websocket_api.auth import (
TYPE_AUTH,
@ -17,13 +19,20 @@ from homeassistant.components.websocket_api.const import FEATURE_COALESCE_MESSAG
from homeassistant.const import SIGNAL_BOOTSTRAP_INTEGRATIONS
from homeassistant.core import Context, HomeAssistant, State, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import entity
from homeassistant.helpers import device_registry as dr, entity
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.loader import async_get_integration
from homeassistant.setup import DATA_SETUP_TIME, async_setup_component
from homeassistant.util.json import json_loads
from tests.common import MockEntity, MockEntityPlatform, MockUser, async_mock_service
from tests.common import (
MockConfigEntry,
MockEntity,
MockEntityPlatform,
MockUser,
async_mock_service,
mock_platform,
)
from tests.typing import (
ClientSessionGenerator,
WebSocketGenerator,
@ -40,6 +49,25 @@ STATE_KEY_SHORT_NAMES = {
STATE_KEY_LONG_NAMES = {v: k for k, v in STATE_KEY_SHORT_NAMES.items()}
@pytest.fixture
def fake_integration(hass: HomeAssistant):
"""Set up a mock integration with device automation support."""
DOMAIN = "fake_integration"
hass.config.components.add(DOMAIN)
mock_platform(
hass,
f"{DOMAIN}.device_action",
Mock(
ACTION_SCHEMA=toggle_entity.ACTION_SCHEMA.extend(
{vol.Required("domain"): DOMAIN}
),
spec=["ACTION_SCHEMA"],
),
)
def _apply_entities_changes(state_dict: dict, change_dict: dict) -> None:
"""Apply a diff set to a dict.
@ -1775,6 +1803,52 @@ async def test_execute_script_complex_response(
}
async def test_execute_script_with_dynamically_validated_action(
hass: HomeAssistant,
hass_ws_client: WebSocketGenerator,
device_registry: dr.DeviceRegistry,
fake_integration,
) -> None:
"""Test executing a script with an action which is dynamically validated."""
ws_client = await hass_ws_client(hass)
module_cache = hass.data.setdefault(loader.DATA_COMPONENTS, {})
module = module_cache["fake_integration.device_action"]
module.async_call_action_from_config = AsyncMock()
module.async_validate_action_config = AsyncMock(
side_effect=lambda hass, config: config
)
config_entry = MockConfigEntry(domain="fake_integration", data={})
config_entry.state = config_entries.ConfigEntryState.LOADED
config_entry.add_to_hass(hass)
device_entry = device_registry.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
)
await ws_client.send_json_auto_id(
{
"type": "execute_script",
"sequence": [
{
"device_id": device_entry.id,
"domain": "fake_integration",
},
],
}
)
msg_no_var = await ws_client.receive_json()
assert msg_no_var["type"] == const.TYPE_RESULT
assert msg_no_var["success"]
assert msg_no_var["result"]["response"] is None
module.async_validate_action_config.assert_awaited_once()
module.async_call_action_from_config.assert_awaited_once()
async def test_subscribe_unsubscribe_bootstrap_integrations(
hass: HomeAssistant, websocket_client, hass_admin_user: MockUser
) -> None: