#!/usr/bin/env python3 """ H.1.6: Tests for Capability-Based Agent Discovery
Tests the capability extraction, matching, and recommendation engine. """
import json import pytest import sys from pathlib import Path from unittest.mock import MagicMock, patch
Add parent to path
sys.path.insert(0, str(Path(file).parent.parent.parent))
from scripts.core.capability_discovery import ( CapabilityMatch, AgentRecommendation, extract_capabilities_from_query, extract_keywords_from_query, CAPABILITY_KEYWORDS, DOMAIN_KEYWORDS, )
=============================================================================
Capability Extraction Tests
=============================================================================
class TestCapabilityExtraction: """Tests for capability extraction from queries."""
def test_extract_action_keyword_exact(self):
"""Test extraction of exact action keywords."""
matches = extract_capabilities_from_query("review this code")
actions = [m.capability for m in matches if m.capability_type == "action"]
assert "review" in actions
def test_extract_action_keyword_synonym(self):
"""Test extraction of action keyword synonyms."""
matches = extract_capabilities_from_query("audit the security")
actions = [m.capability for m in matches if m.capability_type == "action"]
assert "review" in actions # "audit" maps to "review"
def test_extract_multiple_actions(self):
"""Test extraction of multiple actions from query."""
matches = extract_capabilities_from_query("create tests and deploy to production")
actions = [m.capability for m in matches if m.capability_type == "action"]
assert "create" in actions
assert "test" in actions
assert "deploy" in actions
def test_extract_domain_keywords(self):
"""Test extraction of domain keywords."""
matches = extract_capabilities_from_query("fix security vulnerability")
domains = [m.capability for m in matches if m.capability_type == "domain"]
assert "security" in domains
def test_extract_multiple_domains(self):
"""Test extraction of multiple domains."""
matches = extract_capabilities_from_query("deploy database to kubernetes")
domains = [m.capability for m in matches if m.capability_type == "domain"]
assert "database" in domains
assert "devops" in domains
def test_extract_combined_capabilities(self):
"""Test extraction of both actions and domains."""
matches = extract_capabilities_from_query("review backend API security")
actions = [m.capability for m in matches if m.capability_type == "action"]
domains = [m.capability for m in matches if m.capability_type == "domain"]
assert "review" in actions
assert "security" in domains
assert "backend" in domains
def test_empty_query(self):
"""Test empty query returns no matches."""
matches = extract_capabilities_from_query("")
assert len(matches) == 0
def test_irrelevant_query(self):
"""Test query with no capability keywords."""
matches = extract_capabilities_from_query("hello world")
assert len(matches) == 0
def test_case_insensitivity(self):
"""Test case-insensitive matching."""
matches = extract_capabilities_from_query("REVIEW Security DEPLOY")
actions = [m.capability for m in matches if m.capability_type == "action"]
domains = [m.capability for m in matches if m.capability_type == "domain"]
assert "review" in actions
assert "deploy" in actions
assert "security" in domains
class TestKeywordExtraction: """Tests for keyword extraction from queries."""
def test_extract_keywords_basic(self):
"""Test basic keyword extraction."""
keywords = extract_keywords_from_query("deploy docker container")
assert "deploy" in keywords
assert "docker" in keywords
assert "container" in keywords
def test_stopword_removal(self):
"""Test that stopwords are removed."""
keywords = extract_keywords_from_query("the code is in the file")
assert "the" not in keywords
assert "code" in keywords
assert "file" in keywords
def test_short_word_removal(self):
"""Test that short words (<3 chars) are removed."""
keywords = extract_keywords_from_query("go to api")
assert "go" not in keywords
assert "to" not in keywords
assert "api" in keywords
def test_deduplication(self):
"""Test that duplicate keywords are removed."""
keywords = extract_keywords_from_query("test test test code")
assert keywords.count("test") == 1
def test_order_preservation(self):
"""Test that keyword order is preserved."""
keywords = extract_keywords_from_query("first second third")
assert keywords.index("first") < keywords.index("second")
assert keywords.index("second") < keywords.index("third")
=============================================================================
Data Class Tests
=============================================================================
class TestCapabilityMatch: """Tests for CapabilityMatch dataclass."""
def test_capability_match_creation(self):
"""Test CapabilityMatch creation."""
match = CapabilityMatch(
capability="review",
capability_type="action",
confidence=0.9,
source="keyword"
)
assert match.capability == "review"
assert match.capability_type == "action"
assert match.confidence == 0.9
assert match.source == "keyword"
def test_capability_match_confidence_range(self):
"""Test confidence values."""
high = CapabilityMatch("test", "action", 1.0, "test")
low = CapabilityMatch("test", "action", 0.0, "test")
mid = CapabilityMatch("test", "action", 0.5, "test")
assert high.confidence == 1.0
assert low.confidence == 0.0
assert mid.confidence == 0.5
class TestAgentRecommendation: """Tests for AgentRecommendation dataclass."""
def test_recommendation_creation(self):
"""Test AgentRecommendation creation."""
rec = AgentRecommendation(
component_id="agent/orchestrator",
name="orchestrator",
component_type="agent",
description="Multi-agent orchestration",
confidence=0.85,
matched_capabilities=[],
path="agents/orchestrator.md",
llm_model="sonnet"
)
assert rec.component_id == "agent/orchestrator"
assert rec.name == "orchestrator"
assert rec.confidence == 0.85
assert rec.llm_model == "sonnet"
def test_recommendation_to_dict(self):
"""Test AgentRecommendation serialization."""
cap_match = CapabilityMatch("review", "action", 0.8, "keyword")
rec = AgentRecommendation(
component_id="agent/code-reviewer",
name="code-reviewer",
component_type="agent",
description="Reviews code",
confidence=0.9,
matched_capabilities=[cap_match],
path="agents/code-reviewer.md"
)
data = rec.to_dict()
assert data["component_id"] == "agent/code-reviewer"
assert data["confidence"] == 0.9
assert len(data["matched_capabilities"]) == 1
assert data["matched_capabilities"][0]["capability"] == "review"
def test_recommendation_empty_capabilities(self):
"""Test recommendation with no matched capabilities."""
rec = AgentRecommendation(
component_id="agent/generic",
name="generic",
component_type="agent",
description="Generic agent",
confidence=0.5,
matched_capabilities=[],
path="agents/generic.md"
)
data = rec.to_dict()
assert data["matched_capabilities"] == []
=============================================================================
Keyword Configuration Tests
=============================================================================
class TestKeywordConfigurations: """Tests for keyword configuration dictionaries."""
def test_all_capability_keywords_have_list(self):
"""Test all capability keywords have a list of synonyms."""
for action, keywords in CAPABILITY_KEYWORDS.items():
assert isinstance(keywords, list), f"{action} should have list of keywords"
assert len(keywords) > 0, f"{action} should have at least one keyword"
def test_all_domain_keywords_have_list(self):
"""Test all domain keywords have a list of synonyms."""
for domain, keywords in DOMAIN_KEYWORDS.items():
assert isinstance(keywords, list), f"{domain} should have list of keywords"
assert len(keywords) > 0, f"{domain} should have at least one keyword"
def test_no_overlapping_primary_keywords(self):
"""Test primary keywords don't overlap between categories."""
all_actions = set(CAPABILITY_KEYWORDS.keys())
all_domains = set(DOMAIN_KEYWORDS.keys())
overlap = all_actions & all_domains
assert len(overlap) == 0, f"Overlapping keywords: {overlap}"
def test_required_actions_present(self):
"""Test that essential actions are defined."""
required = ["review", "create", "deploy", "test", "document"]
for action in required:
assert action in CAPABILITY_KEYWORDS, f"Missing required action: {action}"
def test_required_domains_present(self):
"""Test that essential domains are defined."""
required = ["security", "testing", "backend", "frontend", "devops"]
for domain in required:
assert domain in DOMAIN_KEYWORDS, f"Missing required domain: {domain}"
=============================================================================
Integration Pattern Tests (Mock DB)
=============================================================================
class TestIntegrationPatterns: """Tests for integration patterns with mocked database."""
def test_capability_to_recommendation_flow(self):
"""Test the flow from capability extraction to recommendation."""
# Extract capabilities from a realistic query
query = "I need to review and fix security issues in the API"
caps = extract_capabilities_from_query(query)
# Verify expected capabilities
cap_names = {c.capability for c in caps}
assert "review" in cap_names # Action
assert "security" in cap_names # Domain
assert "backend" in cap_names or "api" in cap_names or len(cap_names) >= 2
# Verify we could build a recommendation from these
for cap in caps:
assert cap.confidence > 0
assert cap.capability_type in ["action", "domain"]
def test_query_complexity_handling(self):
"""Test handling of complex multi-part queries."""
complex_query = (
"Create comprehensive documentation for the authentication system, "
"including API reference, security considerations, and deployment guides"
)
caps = extract_capabilities_from_query(complex_query)
keywords = extract_keywords_from_query(complex_query)
# Should extract multiple capabilities
assert len(caps) >= 2
# Should extract meaningful keywords
assert len(keywords) >= 3
# Check for expected extractions
cap_names = {c.capability for c in caps}
assert "create" in cap_names or "document" in cap_names
assert "security" in cap_names
=============================================================================
Edge Case Tests
=============================================================================
class TestEdgeCases: """Tests for edge cases and boundary conditions."""
def test_very_long_query(self):
"""Test handling of very long queries."""
long_query = " ".join(["deploy"] * 100)
caps = extract_capabilities_from_query(long_query)
# Should still work and not crash
assert len(caps) >= 1
def test_special_characters_in_query(self):
"""Test handling of special characters."""
query = "review code! @security #testing $important"
caps = extract_capabilities_from_query(query)
# Should extract valid capabilities despite special chars
cap_names = {c.capability for c in caps}
assert "review" in cap_names
assert "security" in cap_names
assert "testing" in cap_names
def test_numbers_in_query(self):
"""Test handling of numbers in query."""
query = "deploy version 2.0 to production"
caps = extract_capabilities_from_query(query)
cap_names = {c.capability for c in caps}
assert "deploy" in cap_names
def test_unicode_in_query(self):
"""Test handling of unicode characters."""
query = "review security \u2192 deploy"
caps = extract_capabilities_from_query(query)
cap_names = {c.capability for c in caps}
assert "review" in cap_names
assert "security" in cap_names
assert "deploy" in cap_names
=============================================================================
Run Tests
=============================================================================
if name == "main": pytest.main([file, "-v", "--tb=short"])