Files
esphome/tests/integration/test_scheduler_background_wake.py
T

85 lines
2.7 KiB
Python

"""A background scheduler insertion must interrupt the loop's current sleep.
Covers both set_timeout and defer: a zero-delay insert from another thread
takes the separate defer queue on multi-threaded builds.
"""
from __future__ import annotations
import asyncio
from pathlib import Path
import re
from aioesphomeapi import ButtonInfo
import pytest
from .state_utils import require_entity
from .types import APIClientConnectedFactory, RunCompiledFunction
@pytest.mark.asyncio
async def test_scheduler_background_wake(
yaml_config: str,
run_compiled: RunCompiledFunction,
api_client_connected: APIClientConnectedFactory,
) -> None:
external_components_path = str(
Path(__file__).parent / "fixtures" / "external_components"
)
yaml_config = yaml_config.replace(
"EXTERNAL_COMPONENT_PATH", external_components_path
)
loop = asyncio.get_running_loop()
results: dict[int, asyncio.Future[tuple[int, int]]] = {
100: loop.create_future(),
0: loop.create_future(),
}
def on_log_line(line: str) -> None:
match = re.search(
r"SCHEDULER_WAKE_RESULT delay=(\d+) elapsed=(\d+) loop_delta=(-?\d+)",
line,
)
if match is None:
return
result = results[int(match.group(1))]
if not result.done():
result.set_result((int(match.group(2)), int(match.group(3))))
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-background-wake"
entities, _ = await client.list_entities_services()
for object_id, delay in (
("start_scheduler_timeout", 100),
("start_scheduler_defer", 0),
):
start_button = require_entity(
entities,
object_id,
ButtonInfo,
description=f"{object_id} button",
)
client.button_command(start_button.key)
try:
elapsed, loop_delta = await asyncio.wait_for(
results[delay], timeout=10.0
)
except TimeoutError:
pytest.fail(f"background insert with delay={delay} did not fire")
assert elapsed < 1000, (
f"background insert with delay={delay} should interrupt the "
f"five-second sleep; it fired after {elapsed}ms"
)
assert loop_delta == 0, (
f"scheduler-only wake must not run component loops; observed "
f"loop_delta={loop_delta} for delay={delay}"
)