Non-dispatch gateways no longer open per-board kanban DBs for notifier polling. Mirrors the existing dispatcher gate (config kanban.dispatch_in_gateway, default True; env override HERMES_KANBAN_DISPATCH_IN_GATEWAY) so multi-gateway setups collapse to a single process holding kanban.db file descriptors. Salvaged from PR #31964 by @steveonjava; tests and docs trimmed during salvage.
75 lines
2.8 KiB
Python
75 lines
2.8 KiB
Python
"""Tests for the dispatch_in_gateway gate on _kanban_notifier_watcher.
|
|
|
|
- Non-dispatch gateways (dispatch_in_gateway=false) exit before opening any DB.
|
|
- HERMES_KANBAN_DISPATCH_IN_GATEWAY env var disables without loading config.
|
|
- Dispatch-owning gateways (dispatch_in_gateway=true) proceed past the gate.
|
|
"""
|
|
|
|
import asyncio
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from gateway.config import Platform
|
|
from gateway.run import GatewayRunner
|
|
|
|
|
|
def _make_runner(with_adapter=False):
|
|
runner = GatewayRunner.__new__(GatewayRunner)
|
|
runner._running = True
|
|
runner.adapters = {Platform.TELEGRAM: MagicMock()} if with_adapter else {}
|
|
runner._kanban_sub_fail_counts = {}
|
|
return runner
|
|
|
|
|
|
def _fake_config(dispatch_in_gateway):
|
|
return {"kanban": {"dispatch_in_gateway": dispatch_in_gateway}}
|
|
|
|
|
|
def test_notifier_watcher_skips_when_dispatch_disabled():
|
|
"""dispatch_in_gateway=false returns before opening any board DB."""
|
|
runner = _make_runner()
|
|
with patch("hermes_cli.config.load_config", return_value=_fake_config(False)):
|
|
with patch("hermes_cli.kanban_db.connect") as mock_connect:
|
|
asyncio.run(runner._kanban_notifier_watcher())
|
|
mock_connect.assert_not_called()
|
|
|
|
|
|
def test_notifier_watcher_env_override_disables(monkeypatch):
|
|
"""HERMES_KANBAN_DISPATCH_IN_GATEWAY=false skips config load entirely."""
|
|
runner = _make_runner()
|
|
monkeypatch.setenv("HERMES_KANBAN_DISPATCH_IN_GATEWAY", "false")
|
|
with patch("hermes_cli.config.load_config") as mock_load_config:
|
|
with patch("hermes_cli.kanban_db.connect") as mock_connect:
|
|
asyncio.run(runner._kanban_notifier_watcher())
|
|
mock_load_config.assert_not_called()
|
|
mock_connect.assert_not_called()
|
|
|
|
|
|
def test_notifier_watcher_runs_when_dispatch_enabled():
|
|
"""dispatch_in_gateway=true proceeds past the gate to the board fan-out."""
|
|
runner = _make_runner(with_adapter=True)
|
|
past_gate = []
|
|
sleep_calls = []
|
|
|
|
async def fake_sleep(delay):
|
|
sleep_calls.append(delay)
|
|
# Stop after the initial delay + first per-interval sleep so the loop
|
|
# body runs exactly once.
|
|
if len(sleep_calls) >= 2:
|
|
runner._running = False
|
|
|
|
async def fake_to_thread(fn, *args, **kwargs):
|
|
return fn(*args, **kwargs)
|
|
|
|
import hermes_cli.kanban_db as _kb
|
|
|
|
with patch("hermes_cli.config.load_config", return_value=_fake_config(True)):
|
|
with patch.object(
|
|
_kb, "list_boards",
|
|
side_effect=lambda *a, **kw: past_gate.append(True) or [],
|
|
):
|
|
with patch("asyncio.sleep", side_effect=fake_sleep):
|
|
with patch("asyncio.to_thread", side_effect=fake_to_thread):
|
|
asyncio.run(runner._kanban_notifier_watcher())
|
|
|
|
assert past_gate, "list_boards should be called when dispatch_in_gateway=true"
|