Stop script if sub-script stops or aborts (#71195)
This commit is contained in:
parent
3f7c6a1ba7
commit
f6c2fb088c
2 changed files with 68 additions and 3 deletions
|
@ -395,8 +395,14 @@ class _ScriptRun:
|
||||||
script_execution_set("finished")
|
script_execution_set("finished")
|
||||||
except _StopScript:
|
except _StopScript:
|
||||||
script_execution_set("finished")
|
script_execution_set("finished")
|
||||||
|
# Let the _StopScript bubble up if this is a sub-script
|
||||||
|
if not self._script.top_level:
|
||||||
|
raise
|
||||||
except _AbortScript:
|
except _AbortScript:
|
||||||
script_execution_set("aborted")
|
script_execution_set("aborted")
|
||||||
|
# Let the _AbortScript bubble up if this is a sub-script
|
||||||
|
if not self._script.top_level:
|
||||||
|
raise
|
||||||
except Exception:
|
except Exception:
|
||||||
script_execution_set("error")
|
script_execution_set("error")
|
||||||
raise
|
raise
|
||||||
|
@ -1143,7 +1149,7 @@ class Script:
|
||||||
hass.bus.async_listen_once(
|
hass.bus.async_listen_once(
|
||||||
EVENT_HOMEASSISTANT_STOP, partial(_async_stop_scripts_at_shutdown, hass)
|
EVENT_HOMEASSISTANT_STOP, partial(_async_stop_scripts_at_shutdown, hass)
|
||||||
)
|
)
|
||||||
self._top_level = top_level
|
self.top_level = top_level
|
||||||
if top_level:
|
if top_level:
|
||||||
all_scripts.append(
|
all_scripts.append(
|
||||||
{"instance": self, "started_before_shutdown": not hass.is_stopping}
|
{"instance": self, "started_before_shutdown": not hass.is_stopping}
|
||||||
|
@ -1431,7 +1437,7 @@ class Script:
|
||||||
# If this is a top level Script then make a copy of the variables in case they
|
# If this is a top level Script then make a copy of the variables in case they
|
||||||
# are read-only, but more importantly, so as not to leak any variables created
|
# are read-only, but more importantly, so as not to leak any variables created
|
||||||
# during the run back to the caller.
|
# during the run back to the caller.
|
||||||
if self._top_level:
|
if self.top_level:
|
||||||
if self.variables:
|
if self.variables:
|
||||||
try:
|
try:
|
||||||
variables = self.variables.async_render(
|
variables = self.variables.async_render(
|
||||||
|
|
|
@ -94,7 +94,7 @@ def assert_element(trace_element, expected_element, path):
|
||||||
# Check for unexpected items in trace_element
|
# Check for unexpected items in trace_element
|
||||||
assert not set(trace_element._result or {}) - set(expected_result)
|
assert not set(trace_element._result or {}) - set(expected_result)
|
||||||
|
|
||||||
if "error_type" in expected_element:
|
if "error_type" in expected_element and expected_element["error_type"] is not None:
|
||||||
assert isinstance(trace_element._error, expected_element["error_type"])
|
assert isinstance(trace_element._error, expected_element["error_type"])
|
||||||
else:
|
else:
|
||||||
assert trace_element._error is None
|
assert trace_element._error is None
|
||||||
|
@ -4485,6 +4485,65 @@ async def test_stop_action(hass, caplog):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"error,error_type,logmsg,script_execution",
|
||||||
|
(
|
||||||
|
(True, script._AbortScript, "Error", "aborted"),
|
||||||
|
(False, None, "Stop", "finished"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def test_stop_action_subscript(
|
||||||
|
hass, caplog, error, error_type, logmsg, script_execution
|
||||||
|
):
|
||||||
|
"""Test if automation stops on calling the stop action from a sub-script."""
|
||||||
|
event = "test_event"
|
||||||
|
events = async_capture_events(hass, event)
|
||||||
|
|
||||||
|
alias = "stop step"
|
||||||
|
sequence = cv.SCRIPT_SCHEMA(
|
||||||
|
[
|
||||||
|
{"event": event},
|
||||||
|
{
|
||||||
|
"if": {
|
||||||
|
"alias": "if condition",
|
||||||
|
"condition": "template",
|
||||||
|
"value_template": "{{ 1 == 1 }}",
|
||||||
|
},
|
||||||
|
"then": {
|
||||||
|
"alias": alias,
|
||||||
|
"stop": "In the name of love",
|
||||||
|
"error": error,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{"event": event},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
script_obj = script.Script(hass, sequence, "Test Name", "test_domain")
|
||||||
|
|
||||||
|
await script_obj.async_run(context=Context())
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert f"{logmsg} script sequence: In the name of love" in caplog.text
|
||||||
|
caplog.clear()
|
||||||
|
assert len(events) == 1
|
||||||
|
|
||||||
|
assert_action_trace(
|
||||||
|
{
|
||||||
|
"0": [{"result": {"event": "test_event", "event_data": {}}}],
|
||||||
|
"1": [{"error_type": error_type, "result": {"choice": "then"}}],
|
||||||
|
"1/if": [{"result": {"result": True}}],
|
||||||
|
"1/if/condition/0": [{"result": {"result": True, "entities": []}}],
|
||||||
|
"1/then/0": [
|
||||||
|
{
|
||||||
|
"error_type": error_type,
|
||||||
|
"result": {"stop": "In the name of love", "error": error},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
expected_script_execution=script_execution,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_stop_action_with_error(hass, caplog):
|
async def test_stop_action_with_error(hass, caplog):
|
||||||
"""Test if automation fails on calling the error action."""
|
"""Test if automation fails on calling the error action."""
|
||||||
event = "test_event"
|
event = "test_event"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue