"""协作台账实时事件总线:revision、跨线程投递、队列满时保留最新事件。""" from __future__ import annotations import asyncio import threading from web.backend.services.huya_collab_events import CollabEventHub def test_publish_increments_revision_without_subscribers(): hub = CollabEventHub() first = hub.publish(scope="orders", action="order.create", actor_id=7) second = hub.publish(scope="shops", action="shop.create", actor_id=8) assert first["revision"] == 1 assert second["revision"] == 2 assert hub.ready_event() == {"type": "collab.ready", "revision": 2} assert hub.ping_event() == {"type": "collab.ping", "revision": 2} def test_publish_delivers_from_worker_thread(): async def scenario(): hub = CollabEventHub() queue = hub.subscribe() worker = threading.Thread( target=lambda: hub.publish( scope="orders", action="order.update", actor_id=9 ) ) worker.start() worker.join(timeout=2) event = await asyncio.wait_for(queue.get(), timeout=2) assert event["type"] == "collab.invalidate" assert event["scope"] == "orders" assert event["action"] == "order.update" assert event["actor_id"] == 9 assert event["revision"] == 1 asyncio.run(scenario()) def test_queue_overflow_keeps_latest_event(): async def scenario(): hub = CollabEventHub() queue = hub.subscribe() for _ in range(101): hub.publish(scope="orders", action="order.update", actor_id=1) await asyncio.sleep(0.05) assert queue.qsize() <= queue.maxsize latest = await asyncio.wait_for(queue.get(), timeout=2) # 队列满时丢掉旧事件,但最后一条一定是 revision 最大的 while not queue.empty(): latest = queue.get_nowait() assert latest["revision"] == 101 asyncio.run(scenario())