Source code for ralph.recovery.testing

"""Test helpers for recovery package: fake monitors and fakes for black-box tests."""

from __future__ import annotations

import asyncio
import contextlib
from datetime import UTC, datetime
from typing import TYPE_CHECKING

from ralph.recovery.connectivity import ConnectivityEvent, ConnectivityState

if TYPE_CHECKING:
    from collections.abc import Callable


[docs] class FakeConnectivityMonitor: """Deterministic connectivity monitor for tests. Allows injecting state transitions without real network probes. """ def __init__(self, initial_state: ConnectivityState = ConnectivityState.ONLINE) -> None: self._state: ConnectivityState = initial_state self._listeners: list[Callable[[ConnectivityEvent], None]] = [] self._online_event: asyncio.Event = asyncio.Event() if initial_state == ConnectivityState.ONLINE: self._online_event.set() @property def current_state(self) -> ConnectivityState: return self._state def add_listener(self, cb: Callable[[ConnectivityEvent], None]) -> Callable[[], None]: self._listeners.append(cb) def _unsub() -> None: with contextlib.suppress(ValueError): self._listeners.remove(cb) return _unsub async def start(self) -> None: pass async def stop(self) -> None: self._online_event.set() async def wait_online(self) -> None: await self._online_event.wait()
[docs] def go_offline(self, reason: str = "test offline") -> None: """Simulate going offline.""" if self._state != ConnectivityState.OFFLINE: self._state = ConnectivityState.OFFLINE self._online_event.clear() self._emit(ConnectivityState.OFFLINE, reason)
[docs] def go_online(self, reason: str = "test online") -> None: """Simulate coming back online.""" if self._state != ConnectivityState.ONLINE: self._state = ConnectivityState.ONLINE self._online_event.set() self._emit(ConnectivityState.ONLINE, reason)
def _emit(self, state: ConnectivityState, reason: str) -> None: evt = ConnectivityEvent(state=state, since=datetime.now(UTC), reason=reason) for listener in list(self._listeners): with contextlib.suppress(Exception): listener(evt)