mirror of
https://github.com/esphome/esphome.git
synced 2026-05-22 01:42:49 +08:00
97 lines
3.7 KiB
Python
97 lines
3.7 KiB
Python
"""Test the self-keyed scheduler API.
|
|
|
|
Verifies that `Scheduler::set_timeout(const void *, ...)` /
|
|
`set_interval(const void *, ...)` and the matching `cancel_*(const void *)`
|
|
overloads behave correctly: callbacks fire, distinct keys don't collide,
|
|
self-keyed and component-keyed namespaces are independent, and re-registering
|
|
the same key replaces the existing timer.
|
|
"""
|
|
|
|
import asyncio
|
|
import re
|
|
|
|
import pytest
|
|
|
|
from .types import APIClientConnectedFactory, RunCompiledFunction
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_scheduler_self_keyed(
|
|
yaml_config: str,
|
|
run_compiled: RunCompiledFunction,
|
|
api_client_connected: APIClientConnectedFactory,
|
|
) -> None:
|
|
"""Test self-keyed scheduler API."""
|
|
self_a_fired = asyncio.Event()
|
|
self_b_error = asyncio.Event()
|
|
self_c_fired = asyncio.Event()
|
|
self_d_fired = asyncio.Event()
|
|
self_shared_fired = asyncio.Event()
|
|
component_7777_fired = asyncio.Event()
|
|
self_interval_done = asyncio.Event()
|
|
self_f_first_error = asyncio.Event()
|
|
self_f_replacement_fired = asyncio.Event()
|
|
all_tests_complete = asyncio.Event()
|
|
|
|
def on_log_line(line: str) -> None:
|
|
clean_line = re.sub(r"\x1b\[[0-9;]*m", "", line)
|
|
|
|
if "Self timeout A fired" in clean_line:
|
|
self_a_fired.set()
|
|
elif "ERROR: Self timeout B" in clean_line:
|
|
self_b_error.set()
|
|
elif "Self timeout C fired" in clean_line:
|
|
self_c_fired.set()
|
|
elif "Self timeout D fired" in clean_line:
|
|
self_d_fired.set()
|
|
elif "Self timeout shared fired" in clean_line:
|
|
self_shared_fired.set()
|
|
elif "Component timeout 7777 fired" in clean_line:
|
|
component_7777_fired.set()
|
|
elif "Self interval E fired twice" in clean_line:
|
|
self_interval_done.set()
|
|
elif "ERROR: Self timeout F first registration" in clean_line:
|
|
self_f_first_error.set()
|
|
elif "Self timeout F replacement fired" in clean_line:
|
|
self_f_replacement_fired.set()
|
|
elif "All self-keyed tests complete" in clean_line:
|
|
all_tests_complete.set()
|
|
|
|
async with (
|
|
run_compiled(yaml_config, line_callback=on_log_line),
|
|
api_client_connected() as client,
|
|
):
|
|
device_info = await client.device_info()
|
|
assert device_info is not None
|
|
assert device_info.name == "scheduler-self-keyed-test"
|
|
|
|
try:
|
|
await asyncio.wait_for(all_tests_complete.wait(), timeout=5.0)
|
|
except TimeoutError:
|
|
pytest.fail("Not all self-keyed tests completed within 5 seconds")
|
|
|
|
# Test 1: self-keyed timeout fires
|
|
assert self_a_fired.is_set(), "Self timeout A should have fired"
|
|
|
|
# Test 2: cancel_timeout(self) actually cancels
|
|
assert not self_b_error.is_set(), "Self timeout B should have been cancelled"
|
|
|
|
# Test 3: distinct self keys don't collide
|
|
assert self_c_fired.is_set(), "Self timeout C should have fired"
|
|
assert self_d_fired.is_set(), "Self timeout D should have fired"
|
|
|
|
# Test 4: self-keyed and component-keyed namespaces are independent
|
|
assert self_shared_fired.is_set(), "Self timeout shared should have fired"
|
|
assert component_7777_fired.is_set(), "Component timeout 7777 should have fired"
|
|
|
|
# Test 5: self-keyed interval fires repeatedly and cancels cleanly
|
|
assert self_interval_done.is_set(), "Self interval E should have fired twice"
|
|
|
|
# Test 6: re-registering same self-key replaces the previous timer
|
|
assert not self_f_first_error.is_set(), (
|
|
"Self timeout F first registration should have been replaced"
|
|
)
|
|
assert self_f_replacement_fired.is_set(), (
|
|
"Self timeout F replacement should have fired"
|
|
)
|