from __future__ import annotations from unittest.mock import AsyncMock, MagicMock, patch import pytest from yuxi.channel.container import ChannelContainer, _InfraBundle, _WorkerBundle from yuxi.channel.domain.service.pipeline import Pipeline class TestChannelContainer: @pytest.fixture def mock_pipeline(self): pipeline = MagicMock(spec=Pipeline) pipeline.middlewares = [] return pipeline @pytest.fixture def mock_container(self, mock_pipeline): return ChannelContainer( pipeline=mock_pipeline, inbound_service=MagicMock(), dispatch_service=MagicMock(), delivery_service=MagicMock(), session_resolver=MagicMock(), binding_service=MagicMock(), config_service=MagicMock(), auth_service=MagicMock(), channel_config=MagicMock(), worker_pool=MagicMock(), outbox_worker=MagicMock(), session_factory=MagicMock(), ) @pytest.mark.asyncio async def test_shutdown_with_none_services(self, mock_pipeline): container = ChannelContainer(pipeline=mock_pipeline) await container.shutdown() @pytest.mark.asyncio async def test_shutdown_closes_adapters(self, mock_container): adapter = AsyncMock() mock_container.adapters = {"web": adapter} await mock_container.shutdown() adapter.close.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_stops_worker_pool(self, mock_container): await mock_container.shutdown() mock_container.worker_pool.stop.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_stops_outbox_worker(self, mock_container): await mock_container.shutdown() mock_container.outbox_worker.stop.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_stops_sse_endpoint(self, mock_container): sse = AsyncMock() mock_container.sse_endpoint = sse await mock_container.shutdown() sse.stop.assert_awaited_once() sse.broadcast_shutdown.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_stops_ws_manager(self, mock_container): ws = AsyncMock() mock_container.ws_manager = ws await mock_container.shutdown() ws.stop_all.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_closes_redis(self, mock_container): redis = AsyncMock() mock_container.redis = redis await mock_container.shutdown() redis.aclose.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_publishes_gateway_shutdown(self, mock_container): publisher = AsyncMock() mock_container.event_publisher = publisher await mock_container.shutdown() publisher.publish.assert_awaited_once() @pytest.mark.asyncio async def test_shutdown_safe_exception_handling(self, mock_container): mock_container.worker_pool.stop.side_effect = Exception("pool error") await mock_container.shutdown() @pytest.mark.asyncio async def test_shutdown_pubsub_subscriber(self, mock_container): pubsub = AsyncMock() mock_container.pubsub_subscriber = pubsub await mock_container.shutdown() pubsub.stop.assert_awaited_once() class TestInfraBundle: def test_creation(self): infra = _InfraBundle( queue_port=MagicMock(), event_publisher=MagicMock(), content_filter=MagicMock(), config_reload=MagicMock(), cache_port=MagicMock(), rate_limit_port=MagicMock(), bot_loop_guard=MagicMock(), circuit_breaker=MagicMock(), metrics=MagicMock(), signature_verifier=MagicMock(), ) assert infra.queue_port is not None class TestWorkerBundle: def test_creation(self): workers = _WorkerBundle( dispatch_service=MagicMock(), binding_service=MagicMock(), config_service=MagicMock(), worker_pool=MagicMock(), outbox_worker=MagicMock(), session_factory=MagicMock(), binding_repo=MagicMock(), session_repo=MagicMock(), outbox_repo=MagicMock(), message_repo=MagicMock(), message_log_repo=MagicMock(), ) assert workers.dispatch_service is not None