Skip to main content
Glama
test_config.pyโ€ข14.2 kB
"""Tests for configuration module.""" import pytest from pathlib import Path import tempfile from delegation_mcp.config import ( DelegationConfig, DelegationRule, OrchestratorConfig, ConfigValidationError, ) def test_delegation_rule_creation(): """Test creating a delegation rule.""" rule = DelegationRule( pattern="security|audit", delegate_to="gemini", priority=5, requires_approval=False, description="Security tasks", ) assert rule.pattern == "security|audit" assert rule.delegate_to == "gemini" assert rule.priority == 5 def test_orchestrator_config_creation(): """Test creating orchestrator configuration.""" config = OrchestratorConfig( name="claude", command="claude", enabled=True, ) assert config.name == "claude" assert config.command == "claude" assert config.enabled is True assert config.timeout == 300 # default def test_delegation_config_find_rule(): """Test finding matching delegation rule.""" config = DelegationConfig( orchestrator="claude", rules=[ DelegationRule( pattern="security|audit", delegate_to="gemini", priority=5, ), DelegationRule( pattern="refactor", delegate_to="aider", priority=3, ), ], ) # Should match security rule rule = config.find_delegation_rule("Run a security audit") assert rule is not None assert rule.delegate_to == "gemini" # Should match refactor rule rule = config.find_delegation_rule("Refactor the code") assert rule is not None assert rule.delegate_to == "aider" # Should not match any rule rule = config.find_delegation_rule("Explain Python") assert rule is None def test_config_save_and_load(): """Test saving and loading configuration.""" with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "test_config.yaml" # Create and save config config = DelegationConfig( orchestrator="claude", rules=[ DelegationRule( pattern="test", delegate_to="gemini", priority=1, ), ], ) config.to_yaml(config_path) # Load config loaded_config = DelegationConfig.from_yaml(config_path, validate=False) assert loaded_config.orchestrator == "claude" assert len(loaded_config.rules) == 1 assert loaded_config.rules[0].pattern == "test" # ============================================================================ # Validation Tests # ============================================================================ def test_validate_minimum_agents_success(): """Test validation passes with 2 or more enabled agents.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), "aider": OrchestratorConfig(name="aider", command="aider", enabled=False), }, rules=[], ) # Should not raise exception config.validate() def test_validate_minimum_agents_failure_zero(): """Test validation fails with no enabled agents.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=False), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=False), }, rules=[], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() assert "At least 2 agents must be enabled" in str(exc_info.value) assert "only 0 are enabled" in str(exc_info.value) def test_validate_minimum_agents_failure_one(): """Test validation fails with only one enabled agent.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=False), }, rules=[], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() assert "At least 2 agents must be enabled" in str(exc_info.value) assert "only 1 is enabled" in str(exc_info.value) def test_validate_regex_patterns_success(): """Test validation passes with valid regex patterns.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), }, rules=[ DelegationRule(pattern="security|audit", delegate_to="gemini", priority=5), DelegationRule(pattern="refactor.*code", delegate_to="claude", priority=3), DelegationRule(pattern="^test", delegate_to="gemini", priority=2), ], ) # Should not raise exception config.validate() def test_validate_regex_patterns_failure(): """Test validation fails with invalid regex patterns.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), }, rules=[ DelegationRule( pattern="valid_pattern", delegate_to="gemini", priority=5 ), DelegationRule( pattern="[invalid(regex", delegate_to="claude", priority=3 ), # Invalid regex DelegationRule( pattern="(?P<incomplete", delegate_to="gemini", priority=2 ), # Invalid regex ], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() error_msg = str(exc_info.value) assert "Invalid regex pattern" in error_msg assert "[invalid(regex" in error_msg or "(?P<incomplete" in error_msg def test_validate_agent_references_success(): """Test validation passes when all referenced agents exist.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), "aider": OrchestratorConfig(name="aider", command="aider", enabled=True), }, rules=[ DelegationRule(pattern="security", delegate_to="gemini", priority=5), DelegationRule(pattern="refactor", delegate_to="claude", priority=3), DelegationRule(pattern="git", delegate_to="aider", priority=4), ], ) # Should not raise exception config.validate() def test_validate_agent_references_failure_rule_target(): """Test validation fails when rule references non-existent agent.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), }, rules=[ DelegationRule(pattern="security", delegate_to="gemini", priority=5), DelegationRule( pattern="git", delegate_to="nonexistent_agent", priority=3 ), # Invalid reference ], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() error_msg = str(exc_info.value) assert "Target orchestrator 'nonexistent_agent' is not defined" in error_msg assert "pattern: 'git'" in error_msg def test_validate_no_circular_delegation_success(): """Test validation passes with normal delegation rules.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), "aider": OrchestratorConfig(name="aider", command="aider", enabled=True), }, rules=[ DelegationRule(pattern="security", delegate_to="gemini", priority=5), DelegationRule(pattern="refactor", delegate_to="claude", priority=3), DelegationRule(pattern="git", delegate_to="aider", priority=4), ], ) # Should not raise exception - multiple different patterns to different targets is fine config.validate() def test_validate_no_ambiguous_delegation(): """Test validation detects ambiguous delegation patterns.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), "aider": OrchestratorConfig(name="aider", command="aider", enabled=True), }, rules=[ # Same pattern, same priority, different targets - ambiguous! DelegationRule(pattern="security", delegate_to="claude", priority=5), DelegationRule(pattern="security", delegate_to="gemini", priority=5), ], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() error_msg = str(exc_info.value) assert "ambiguous delegation" in error_msg.lower() assert "security" in error_msg.lower() def test_validate_same_pattern_different_priority_ok(): """Test validation allows same pattern with different priorities.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), "aider": OrchestratorConfig(name="aider", command="aider", enabled=True), }, rules=[ # Same pattern but different priorities - OK (higher priority wins) DelegationRule(pattern="security", delegate_to="gemini", priority=5), DelegationRule(pattern="security", delegate_to="claude", priority=3), ], ) # Should not raise exception - different priorities resolve ambiguity config.validate() def test_validate_multiple_errors(): """Test validation reports multiple errors at once.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=False), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=False), # Error 1: less than 2 enabled agents }, rules=[ DelegationRule( pattern="[invalid(", delegate_to="claude", priority=5 ), # Error 2: invalid regex DelegationRule( pattern="test", delegate_to="missing_agent", priority=3 ), # Error 3: invalid reference ], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() error_msg = str(exc_info.value) # Should contain multiple errors assert "At least 2 agents must be enabled" in error_msg assert "Invalid regex pattern" in error_msg assert "Target orchestrator 'missing_agent' is not defined" in error_msg def test_from_yaml_with_validation(): """Test loading config from YAML with validation enabled.""" with tempfile.TemporaryDirectory() as tmpdir: config_path = Path(tmpdir) / "test_config.yaml" # Create invalid config config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig( name="claude", command="claude", enabled=False ), "gemini": OrchestratorConfig( name="gemini", command="gemini", enabled=False ), }, rules=[], ) config.to_yaml(config_path) # Try to load with validation - should fail with pytest.raises(ConfigValidationError): DelegationConfig.from_yaml(config_path, validate=True) # Load without validation - should succeed loaded = DelegationConfig.from_yaml(config_path, validate=False) assert loaded.orchestrator == "claude" def test_validate_empty_orchestrators(): """Test validation fails with no orchestrators defined.""" config = DelegationConfig( orchestrator="claude", orchestrators={}, # Empty orchestrators rules=[], ) with pytest.raises(ConfigValidationError) as exc_info: config.validate() error_msg = str(exc_info.value) assert "At least 2 agents must be enabled" in error_msg assert "Primary orchestrator 'claude' is not defined" in error_msg def test_validate_with_three_enabled_agents(): """Test validation passes with more than minimum enabled agents.""" config = DelegationConfig( orchestrator="claude", orchestrators={ "claude": OrchestratorConfig(name="claude", command="claude", enabled=True), "gemini": OrchestratorConfig(name="gemini", command="gemini", enabled=True), "aider": OrchestratorConfig(name="aider", command="aider", enabled=True), "copilot": OrchestratorConfig( name="copilot", command="copilot", enabled=False ), }, rules=[ DelegationRule(pattern="security", delegate_to="gemini", priority=5), ], ) # Should not raise exception config.validate()

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/carlosduplar/multi-agent-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server