1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
"""Conftest for XKNX."""
import asyncio
from unittest.mock import AsyncMock, Mock, patch
import pytest
from xknx import XKNX
class EventLoopClockAdvancer:
"""Allow advancing of loop time."""
# thanks to @dermotduffy for his asyncio.sleep mock
# https://github.com/dermotduffy/hyperion-py/blob/main/tests/client_test.py#L273
__slots__ = ("_base_time", "loop", "offset")
def __init__(self, loop: asyncio.AbstractEventLoop) -> None:
"""Initialize."""
self.offset = 0.0
self._base_time = loop.time
self.loop = loop
# incorporate offset timing into the event loop
self.loop.time = self.time # type: ignore[assignment]
def time(self) -> float:
"""Return loop time adjusted by offset."""
return self._base_time() + self.offset
async def _exhaust_callbacks(self) -> None:
"""Run the loop until all ready callbacks are executed."""
while self.loop._ready: # noqa: ASYNC110 # type: ignore[attr-defined]
await asyncio.sleep(0)
async def __call__(self, seconds: float) -> None:
"""Advance time by a given offset in seconds."""
# Exhaust all callbacks.
await self._exhaust_callbacks()
if seconds > 0:
# advance the clock by the given offset
self.offset += seconds
# Once the clock is adjusted, new tasks may have just been
# scheduled for running in the next pass through the event loop
await asyncio.sleep(0)
await self._exhaust_callbacks()
@pytest.fixture
def time_travel(event_loop: asyncio.AbstractEventLoop) -> EventLoopClockAdvancer:
"""Advance loop time and run callbacks."""
return EventLoopClockAdvancer(event_loop)
@pytest.fixture
def xknx_no_interface() -> XKNX:
"""Return XKNX instance without KNX/IP interface."""
def knx_ip_interface_mock() -> Mock:
"""Create a xknx knx ip interface mock."""
mock = Mock()
mock.start = AsyncMock()
mock.stop = AsyncMock()
mock.send_cemi = AsyncMock()
return mock
with patch("xknx.xknx.knx_interface_factory", return_value=knx_ip_interface_mock()):
return XKNX()
|