Files
crewAI/lib/crewai/tests/utilities/events/test_async_event_bus.py
Greyson LaLonde c925d2d519
Some checks failed
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
chore: restructure test env, cassettes, and conftest; fix flaky tests
Consolidates pytest config, standardizes env handling, reorganizes cassette layout, removes outdated VCR configs, improves sync with threading.Condition, updates event-waiting logic, ensures cleanup, regenerates Gemini cassettes, and reverts unintended test changes.
2025-11-29 16:55:24 -05:00

212 lines
6.2 KiB
Python

"""Tests for async event handling in CrewAI event bus.
This module tests async handler registration, execution, and the aemit method.
"""
import asyncio
import pytest
from crewai.events.base_events import BaseEvent
from crewai.events.event_bus import crewai_event_bus
class AsyncTestEvent(BaseEvent):
pass
@pytest.mark.asyncio
async def test_async_handler_execution():
received_events = []
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def async_handler(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.01)
received_events.append(event)
event = AsyncTestEvent(type="async_test")
crewai_event_bus.emit("test_source", event)
await asyncio.sleep(0.1)
assert len(received_events) == 1
assert received_events[0] == event
@pytest.mark.asyncio
async def test_aemit_with_async_handlers():
received_events = []
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def async_handler(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.01)
received_events.append(event)
event = AsyncTestEvent(type="async_test")
await crewai_event_bus.aemit("test_source", event)
assert len(received_events) == 1
assert received_events[0] == event
@pytest.mark.asyncio
async def test_multiple_async_handlers():
received_events_1 = []
received_events_2 = []
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def handler_1(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.01)
received_events_1.append(event)
@crewai_event_bus.on(AsyncTestEvent)
async def handler_2(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.02)
received_events_2.append(event)
event = AsyncTestEvent(type="async_test")
await crewai_event_bus.aemit("test_source", event)
assert len(received_events_1) == 1
assert len(received_events_2) == 1
@pytest.mark.asyncio
async def test_mixed_sync_and_async_handlers():
sync_events = []
async_events = []
sync_done = asyncio.Event()
async_done = asyncio.Event()
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
def sync_handler(source: object, event: BaseEvent) -> None:
sync_events.append(event)
sync_done.set()
@crewai_event_bus.on(AsyncTestEvent)
async def async_handler(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.01)
async_events.append(event)
async_done.set()
event = AsyncTestEvent(type="mixed_test")
crewai_event_bus.emit("test_source", event)
await asyncio.wait_for(sync_done.wait(), timeout=5)
await asyncio.wait_for(async_done.wait(), timeout=5)
assert len(sync_events) == 1
assert len(async_events) == 1
@pytest.mark.asyncio
async def test_async_handler_error_handling():
successful_handler_called = []
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def failing_handler(source: object, event: BaseEvent) -> None:
raise ValueError("Async handler error")
@crewai_event_bus.on(AsyncTestEvent)
async def successful_handler(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.01)
successful_handler_called.append(True)
event = AsyncTestEvent(type="error_test")
await crewai_event_bus.aemit("test_source", event)
assert len(successful_handler_called) == 1
@pytest.mark.asyncio
async def test_aemit_with_no_handlers():
with crewai_event_bus.scoped_handlers():
event = AsyncTestEvent(type="no_handlers")
await crewai_event_bus.aemit("test_source", event)
@pytest.mark.asyncio
async def test_async_handler_registration_via_register_handler():
received_events = []
with crewai_event_bus.scoped_handlers():
async def custom_async_handler(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.01)
received_events.append(event)
crewai_event_bus.register_handler(AsyncTestEvent, custom_async_handler)
event = AsyncTestEvent(type="register_test")
await crewai_event_bus.aemit("test_source", event)
assert len(received_events) == 1
assert received_events[0] == event
@pytest.mark.asyncio
async def test_emit_async_handlers_fire_and_forget():
received_events = []
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def slow_async_handler(source: object, event: BaseEvent) -> None:
await asyncio.sleep(0.05)
received_events.append(event)
event = AsyncTestEvent(type="fire_forget_test")
crewai_event_bus.emit("test_source", event)
assert len(received_events) == 0
await asyncio.sleep(0.1)
assert len(received_events) == 1
@pytest.mark.asyncio
async def test_scoped_handlers_with_async():
received_before = []
received_during = []
received_after = []
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def before_handler(source: object, event: BaseEvent) -> None:
received_before.append(event)
with crewai_event_bus.scoped_handlers():
@crewai_event_bus.on(AsyncTestEvent)
async def scoped_handler(source: object, event: BaseEvent) -> None:
received_during.append(event)
event1 = AsyncTestEvent(type="during_scope")
await crewai_event_bus.aemit("test_source", event1)
assert len(received_before) == 0
assert len(received_during) == 1
@crewai_event_bus.on(AsyncTestEvent)
async def after_handler(source: object, event: BaseEvent) -> None:
received_after.append(event)
event2 = AsyncTestEvent(type="after_scope")
await crewai_event_bus.aemit("test_source", event2)
assert len(received_before) == 1
assert len(received_during) == 1
assert len(received_after) == 1