mirror of
https://github.com/esphome/esphome.git
synced 2026-08-27 16:29:29 +00:00
44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
"""Helpers for asserting on log output in integration tests."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
|
|
class LineWaiter:
|
|
"""Collects log lines and lets a test await one containing all needles.
|
|
|
|
Pass ``callback`` as ``run_compiled``'s ``line_callback``; the callback runs
|
|
on the test's own event loop, so futures are resolved directly. Only one
|
|
``wait_for`` may be outstanding at a time (tests await sequentially).
|
|
"""
|
|
|
|
def __init__(self) -> None:
|
|
self.lines: list[str] = []
|
|
self._needles: tuple[str, ...] = ()
|
|
self._future: asyncio.Future | None = None
|
|
|
|
def callback(self, line: str) -> None:
|
|
self.lines.append(line)
|
|
if (
|
|
self._future is not None
|
|
and not self._future.done()
|
|
and all(n in line for n in self._needles)
|
|
):
|
|
self._future.set_result(line)
|
|
self._future = None
|
|
|
|
async def wait_for(self, *needles: str, timeout: float = 10.0) -> str:
|
|
"""Return the first line, past or future, containing every needle."""
|
|
for line in self.lines:
|
|
if all(n in line for n in needles):
|
|
return line
|
|
assert self._future is None or self._future.done(), "concurrent wait_for"
|
|
self._needles = needles
|
|
self._future = asyncio.get_running_loop().create_future()
|
|
try:
|
|
return await asyncio.wait_for(self._future, timeout)
|
|
finally:
|
|
self._future = None
|
|
self._needles = ()
|