Fix wait_template incorrectly matching falsey values (#44938)
parent
c457ea854c
commit
7c93a11aba
|
@ -62,11 +62,7 @@ from homeassistant.core import (
|
|||
callback,
|
||||
)
|
||||
from homeassistant.helpers import condition, config_validation as cv, service, template
|
||||
from homeassistant.helpers.event import (
|
||||
TrackTemplate,
|
||||
async_call_later,
|
||||
async_track_template_result,
|
||||
)
|
||||
from homeassistant.helpers.event import async_call_later, async_track_template
|
||||
from homeassistant.helpers.script_variables import ScriptVariables
|
||||
from homeassistant.helpers.trigger import (
|
||||
async_initialize_triggers,
|
||||
|
@ -359,7 +355,7 @@ class _ScriptRun:
|
|||
return
|
||||
|
||||
@callback
|
||||
def _async_script_wait(event, updates):
|
||||
def async_script_wait(entity_id, from_s, to_s):
|
||||
"""Handle script after template condition is true."""
|
||||
self._variables["wait"] = {
|
||||
"remaining": to_context.remaining if to_context else delay,
|
||||
|
@ -368,12 +364,9 @@ class _ScriptRun:
|
|||
done.set()
|
||||
|
||||
to_context = None
|
||||
info = async_track_template_result(
|
||||
self._hass,
|
||||
[TrackTemplate(wait_template, self._variables)],
|
||||
_async_script_wait,
|
||||
unsub = async_track_template(
|
||||
self._hass, wait_template, async_script_wait, self._variables
|
||||
)
|
||||
unsub = info.async_remove
|
||||
|
||||
self._changed()
|
||||
done = asyncio.Event()
|
||||
|
|
|
@ -8,6 +8,7 @@ from types import MappingProxyType
|
|||
from unittest import mock
|
||||
from unittest.mock import patch
|
||||
|
||||
from async_timeout import timeout
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
|
||||
|
@ -544,6 +545,41 @@ async def test_wait_basic(hass, action_type):
|
|||
assert script_obj.last_action is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("action_type", ["template", "trigger"])
|
||||
async def test_wait_basic_times_out(hass, action_type):
|
||||
"""Test wait actions times out when the action does not happen."""
|
||||
wait_alias = "wait step"
|
||||
action = {"alias": wait_alias}
|
||||
if action_type == "template":
|
||||
action["wait_template"] = "{{ states.switch.test.state == 'off' }}"
|
||||
else:
|
||||
action["wait_for_trigger"] = {
|
||||
"platform": "state",
|
||||
"entity_id": "switch.test",
|
||||
"to": "off",
|
||||
}
|
||||
sequence = cv.SCRIPT_SCHEMA(action)
|
||||
script_obj = script.Script(hass, sequence, "Test Name", "test_domain")
|
||||
wait_started_flag = async_watch_for_action(script_obj, wait_alias)
|
||||
timed_out = False
|
||||
|
||||
try:
|
||||
hass.states.async_set("switch.test", "on")
|
||||
hass.async_create_task(script_obj.async_run(context=Context()))
|
||||
await asyncio.wait_for(wait_started_flag.wait(), 1)
|
||||
assert script_obj.is_running
|
||||
assert script_obj.last_action == wait_alias
|
||||
hass.states.async_set("switch.test", "not_on")
|
||||
|
||||
with timeout(0.1):
|
||||
await hass.async_block_till_done()
|
||||
except asyncio.TimeoutError:
|
||||
timed_out = True
|
||||
await script_obj.async_stop()
|
||||
|
||||
assert timed_out
|
||||
|
||||
|
||||
@pytest.mark.parametrize("action_type", ["template", "trigger"])
|
||||
async def test_multiple_runs_wait(hass, action_type):
|
||||
"""Test multiple runs with wait in script."""
|
||||
|
@ -782,30 +818,53 @@ async def test_wait_template_variables_in(hass):
|
|||
|
||||
async def test_wait_template_with_utcnow(hass):
|
||||
"""Test the wait template with utcnow."""
|
||||
sequence = cv.SCRIPT_SCHEMA({"wait_template": "{{ utcnow().hours == 12 }}"})
|
||||
sequence = cv.SCRIPT_SCHEMA({"wait_template": "{{ utcnow().hour == 12 }}"})
|
||||
script_obj = script.Script(hass, sequence, "Test Name", "test_domain")
|
||||
wait_started_flag = async_watch_for_action(script_obj, "wait")
|
||||
start_time = dt_util.utcnow() + timedelta(hours=24)
|
||||
start_time = dt_util.utcnow().replace(minute=1) + timedelta(hours=48)
|
||||
|
||||
try:
|
||||
hass.async_create_task(script_obj.async_run(context=Context()))
|
||||
async_fire_time_changed(hass, start_time.replace(hour=5))
|
||||
assert not script_obj.is_running
|
||||
async_fire_time_changed(hass, start_time.replace(hour=12))
|
||||
|
||||
await asyncio.wait_for(wait_started_flag.wait(), 1)
|
||||
|
||||
assert script_obj.is_running
|
||||
|
||||
match_time = start_time.replace(hour=12)
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=match_time):
|
||||
async_fire_time_changed(hass, match_time)
|
||||
except (AssertionError, asyncio.TimeoutError):
|
||||
await script_obj.async_stop()
|
||||
raise
|
||||
else:
|
||||
async_fire_time_changed(hass, start_time.replace(hour=3))
|
||||
await hass.async_block_till_done()
|
||||
|
||||
assert not script_obj.is_running
|
||||
|
||||
|
||||
async def test_wait_template_with_utcnow_no_match(hass):
|
||||
"""Test the wait template with utcnow that does not match."""
|
||||
sequence = cv.SCRIPT_SCHEMA({"wait_template": "{{ utcnow().hour == 12 }}"})
|
||||
script_obj = script.Script(hass, sequence, "Test Name", "test_domain")
|
||||
wait_started_flag = async_watch_for_action(script_obj, "wait")
|
||||
start_time = dt_util.utcnow().replace(minute=1) + timedelta(hours=48)
|
||||
timed_out = False
|
||||
|
||||
try:
|
||||
hass.async_create_task(script_obj.async_run(context=Context()))
|
||||
await asyncio.wait_for(wait_started_flag.wait(), 1)
|
||||
assert script_obj.is_running
|
||||
|
||||
non_maching_time = start_time.replace(hour=3)
|
||||
with patch("homeassistant.util.dt.utcnow", return_value=non_maching_time):
|
||||
async_fire_time_changed(hass, non_maching_time)
|
||||
|
||||
with timeout(0.1):
|
||||
await hass.async_block_till_done()
|
||||
except asyncio.TimeoutError:
|
||||
timed_out = True
|
||||
await script_obj.async_stop()
|
||||
|
||||
assert timed_out
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ["no_timeout", "timeout_finish", "timeout_not_finish"])
|
||||
@pytest.mark.parametrize("action_type", ["template", "trigger"])
|
||||
async def test_wait_variables_out(hass, mode, action_type):
|
||||
|
|
Loading…
Reference in New Issue