"""Tests for the extracted GatewayKanbanWatchersMixin (god-file Phase 3). The kanban watcher loops were lifted out of gateway/run.py into a mixin that GatewayRunner inherits. These tests confirm the mixin exposes the methods and that GatewayRunner picks them up via the MRO (behavior-neutral relocation). """ from __future__ import annotations import inspect from gateway.kanban_watchers import GatewayKanbanWatchersMixin KANBAN_METHODS = [ "_kanban_notifier_watcher", "_kanban_dispatcher_watcher", "_kanban_advance", "_kanban_unsub", "_kanban_rewind", "_deliver_kanban_artifacts", ] def test_mixin_defines_kanban_methods(): for m in KANBAN_METHODS: assert hasattr(GatewayKanbanWatchersMixin, m), f"mixin missing {m}" def test_gateway_runner_inherits_mixin(): # Import here so a heavy gateway import only happens if the first test passed. from gateway.run import GatewayRunner assert issubclass(GatewayRunner, GatewayKanbanWatchersMixin) # Each kanban method resolves to the mixin's implementation via the MRO. for m in KANBAN_METHODS: owner = next(c for c in GatewayRunner.__mro__ if m in c.__dict__) assert owner is GatewayKanbanWatchersMixin, ( f"{m} resolved to {owner.__name__}, expected the mixin" ) def test_watcher_loops_are_coroutines(): # The two long-running watchers are async loops. assert inspect.iscoroutinefunction(GatewayKanbanWatchersMixin._kanban_notifier_watcher) assert inspect.iscoroutinefunction(GatewayKanbanWatchersMixin._kanban_dispatcher_watcher)