"""Tests for :mod:`decnet.bus.publish`. The whole point of ``publish_safely`` is that it never raises back at the caller. These tests pin that contract: ``None`` bus is a no-op, a real bus publishes, and a raising bus is swallowed + logged. """ from __future__ import annotations import logging import pytest from decnet.bus.base import BaseBus, Event, Subscription from decnet.bus.fake import FakeBus from decnet.bus.publish import publish_safely class _ExplodingBus(BaseBus): """Minimal bus whose ``publish`` always raises.""" async def connect(self) -> None: # pragma: no cover - trivial return None async def publish(self, topic, payload, *, event_type=""): raise RuntimeError("transport exploded") def subscribe(self, pattern: str) -> Subscription: # pragma: no cover raise NotImplementedError async def close(self) -> None: # pragma: no cover - trivial return None @pytest.mark.asyncio async def test_publish_safely_none_bus_is_noop() -> None: # Must not raise. A worker that couldn't connect at startup passes # bus=None and expects every call to silently no-op. await publish_safely(None, "system.log", {"msg": "hi"}) @pytest.mark.asyncio async def test_publish_safely_delivers_on_live_bus() -> None: bus = FakeBus() await bus.connect() try: sub = bus.subscribe("system.log") async with sub: await publish_safely(bus, "system.log", {"msg": "hi"}, event_type="log") event = await sub.__anext__() assert isinstance(event, Event) assert event.topic == "system.log" assert event.type == "log" assert event.payload == {"msg": "hi"} finally: await bus.close() @pytest.mark.asyncio async def test_publish_safely_swallows_transport_errors(caplog: pytest.LogCaptureFixture) -> None: caplog.set_level(logging.WARNING, logger="bus.publish") # The exploding bus would crash the caller without publish_safely. # After wrapping, the caller sees nothing but a log line. await publish_safely(_ExplodingBus(), "system.log", {"msg": "hi"}) assert any("bus publish failed" in rec.message for rec in caplog.records)