just why not
All checks were successful
AI Codebase Quality Review / ai-codebase-review (push) Successful in 39s
All checks were successful
AI Codebase Quality Review / ai-codebase-review (push) Successful in 39s
This commit is contained in:
296
tests/test_dispatcher.py
Normal file
296
tests/test_dispatcher.py
Normal file
@@ -0,0 +1,296 @@
|
||||
"""Test Suite for Dispatcher
|
||||
|
||||
Tests for event routing and agent execution.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "tools", "ai-review"))
|
||||
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
class TestDispatcherCreation:
|
||||
"""Test dispatcher initialization."""
|
||||
|
||||
def test_create_dispatcher(self):
|
||||
"""Test creating dispatcher."""
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
assert dispatcher is not None
|
||||
assert dispatcher.agents == []
|
||||
|
||||
def test_create_dispatcher_with_config(self):
|
||||
"""Test creating dispatcher with config."""
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
config = {"dispatcher": {"max_workers": 4}}
|
||||
dispatcher = Dispatcher(config=config)
|
||||
assert dispatcher.config == config
|
||||
|
||||
|
||||
class TestAgentRegistration:
|
||||
"""Test agent registration."""
|
||||
|
||||
def test_register_agent(self):
|
||||
"""Test registering an agent."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
class MockAgent(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "test"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="done")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
agent = MockAgent(config={}, gitea_client=None, llm_client=None)
|
||||
dispatcher.register_agent(agent)
|
||||
|
||||
assert len(dispatcher.agents) == 1
|
||||
assert dispatcher.agents[0] == agent
|
||||
|
||||
def test_register_multiple_agents(self):
|
||||
"""Test registering multiple agents."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
class MockAgent1(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "type1"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="agent1")
|
||||
|
||||
class MockAgent2(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "type2"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="agent2")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
dispatcher.register_agent(
|
||||
MockAgent1(config={}, gitea_client=None, llm_client=None)
|
||||
)
|
||||
dispatcher.register_agent(
|
||||
MockAgent2(config={}, gitea_client=None, llm_client=None)
|
||||
)
|
||||
|
||||
assert len(dispatcher.agents) == 2
|
||||
|
||||
|
||||
class TestEventRouting:
|
||||
"""Test event routing to agents."""
|
||||
|
||||
def test_route_to_matching_agent(self):
|
||||
"""Test that events are routed to matching agents."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
class MockAgent(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "issues"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="handled")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
agent = MockAgent(config={}, gitea_client=None, llm_client=None)
|
||||
dispatcher.register_agent(agent)
|
||||
|
||||
result = dispatcher.dispatch(
|
||||
event_type="issues",
|
||||
event_data={"action": "opened"},
|
||||
owner="test",
|
||||
repo="repo",
|
||||
)
|
||||
|
||||
assert len(result.agents_run) == 1
|
||||
assert result.results[0].success is True
|
||||
|
||||
def test_no_matching_agent(self):
|
||||
"""Test dispatch when no agent matches."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
class MockAgent(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "issues"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="handled")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
agent = MockAgent(config={}, gitea_client=None, llm_client=None)
|
||||
dispatcher.register_agent(agent)
|
||||
|
||||
result = dispatcher.dispatch(
|
||||
event_type="pull_request", # Different event type
|
||||
event_data={"action": "opened"},
|
||||
owner="test",
|
||||
repo="repo",
|
||||
)
|
||||
|
||||
assert len(result.agents_run) == 0
|
||||
|
||||
def test_multiple_matching_agents(self):
|
||||
"""Test dispatch when multiple agents match."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
class MockAgent1(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "issues"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="agent1")
|
||||
|
||||
class MockAgent2(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return event_type == "issues"
|
||||
|
||||
def execute(self, context):
|
||||
return AgentResult(success=True, message="agent2")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
dispatcher.register_agent(
|
||||
MockAgent1(config={}, gitea_client=None, llm_client=None)
|
||||
)
|
||||
dispatcher.register_agent(
|
||||
MockAgent2(config={}, gitea_client=None, llm_client=None)
|
||||
)
|
||||
|
||||
result = dispatcher.dispatch(
|
||||
event_type="issues",
|
||||
event_data={"action": "opened"},
|
||||
owner="test",
|
||||
repo="repo",
|
||||
)
|
||||
|
||||
assert len(result.agents_run) == 2
|
||||
|
||||
|
||||
class TestDispatchResult:
|
||||
"""Test dispatch result structure."""
|
||||
|
||||
def test_result_structure(self):
|
||||
"""Test DispatchResult has correct structure."""
|
||||
from dispatcher import DispatchResult
|
||||
|
||||
result = DispatchResult(
|
||||
agents_run=["Agent1", "Agent2"],
|
||||
results=[],
|
||||
errors=[],
|
||||
)
|
||||
|
||||
assert result.agents_run == ["Agent1", "Agent2"]
|
||||
assert result.results == []
|
||||
assert result.errors == []
|
||||
|
||||
def test_result_with_errors(self):
|
||||
"""Test DispatchResult with errors."""
|
||||
from dispatcher import DispatchResult
|
||||
|
||||
result = DispatchResult(
|
||||
agents_run=["Agent1"],
|
||||
results=[],
|
||||
errors=["Error 1", "Error 2"],
|
||||
)
|
||||
|
||||
assert len(result.errors) == 2
|
||||
|
||||
|
||||
class TestAgentExecution:
|
||||
"""Test agent execution through dispatcher."""
|
||||
|
||||
def test_agent_receives_context(self):
|
||||
"""Test that agents receive proper context."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
received_context = None
|
||||
|
||||
class MockAgent(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
nonlocal received_context
|
||||
received_context = context
|
||||
return AgentResult(success=True, message="done")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
dispatcher.register_agent(
|
||||
MockAgent(config={}, gitea_client=None, llm_client=None)
|
||||
)
|
||||
|
||||
dispatcher.dispatch(
|
||||
event_type="issues",
|
||||
event_data={"action": "opened", "issue": {"number": 123}},
|
||||
owner="testowner",
|
||||
repo="testrepo",
|
||||
)
|
||||
|
||||
assert received_context is not None
|
||||
assert received_context.owner == "testowner"
|
||||
assert received_context.repo == "testrepo"
|
||||
assert received_context.event_type == "issues"
|
||||
assert received_context.event_data["action"] == "opened"
|
||||
|
||||
def test_agent_failure_captured(self):
|
||||
"""Test that agent failures are captured in results."""
|
||||
from agents.base_agent import AgentContext, AgentResult, BaseAgent
|
||||
from dispatcher import Dispatcher
|
||||
|
||||
class FailingAgent(BaseAgent):
|
||||
def can_handle(self, event_type, event_data):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
raise Exception("Test error")
|
||||
|
||||
dispatcher = Dispatcher()
|
||||
dispatcher.register_agent(
|
||||
FailingAgent(config={}, gitea_client=None, llm_client=None)
|
||||
)
|
||||
|
||||
result = dispatcher.dispatch(
|
||||
event_type="issues",
|
||||
event_data={},
|
||||
owner="test",
|
||||
repo="repo",
|
||||
)
|
||||
|
||||
# Agent should still be in agents_run
|
||||
assert len(result.agents_run) == 1
|
||||
# Result should indicate failure
|
||||
assert result.results[0].success is False
|
||||
|
||||
|
||||
class TestGetDispatcher:
|
||||
"""Test get_dispatcher factory function."""
|
||||
|
||||
def test_get_dispatcher_returns_singleton(self):
|
||||
"""Test that get_dispatcher returns configured dispatcher."""
|
||||
from dispatcher import get_dispatcher
|
||||
|
||||
dispatcher = get_dispatcher()
|
||||
assert dispatcher is not None
|
||||
|
||||
def test_get_dispatcher_with_config(self):
|
||||
"""Test get_dispatcher with custom config."""
|
||||
from dispatcher import get_dispatcher
|
||||
|
||||
config = {"test": "value"}
|
||||
dispatcher = get_dispatcher(config=config)
|
||||
assert dispatcher.config.get("test") == "value"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__, "-v"])
|
||||
Reference in New Issue
Block a user