anderson-ufrj
commited on
Commit
·
de52c4a
1
Parent(s):
d5b36b2
test(agents): update tests for refactored agents
Browse files- Update test_zumbi.py to use InvestigatorAgent with new interface
- Update test_anita.py to use AnalystAgent with new interface
- Create test_tiradentes_reporter.py for ReporterAgent
- Fix all agent initialization parameters to match new pattern
- Update all message actions to use new naming convention
- Add tests for initialize() and shutdown() methods
- Update assertions to match new agent properties
This ensures test compatibility with the refactored agent architecture
tests/unit/agents/test_anita.py
CHANGED
|
@@ -10,10 +10,10 @@ from unittest.mock import Mock, AsyncMock, patch, MagicMock
|
|
| 10 |
from uuid import uuid4
|
| 11 |
|
| 12 |
from src.agents.anita import (
|
| 13 |
-
|
| 14 |
PatternResult,
|
| 15 |
CorrelationResult,
|
| 16 |
-
|
| 17 |
)
|
| 18 |
from src.agents.deodoro import (
|
| 19 |
AgentContext,
|
|
@@ -170,11 +170,10 @@ def anita_agent(mock_transparency_api, mock_spectral_analyzer):
|
|
| 170 |
with patch("src.agents.anita.TransparencyAPIClient", return_value=mock_transparency_api), \
|
| 171 |
patch("src.agents.anita.SpectralAnalyzer", return_value=mock_spectral_analyzer):
|
| 172 |
|
| 173 |
-
agent =
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
semantic_similarity_threshold=0.8
|
| 178 |
)
|
| 179 |
return agent
|
| 180 |
|
|
@@ -186,10 +185,9 @@ class TestAnitaAgent:
|
|
| 186 |
def test_agent_initialization(self, anita_agent):
|
| 187 |
"""Test Anita agent initialization."""
|
| 188 |
assert anita_agent.name == "Anita"
|
| 189 |
-
assert anita_agent.
|
| 190 |
-
assert anita_agent.
|
| 191 |
-
assert anita_agent.
|
| 192 |
-
assert anita_agent.semantic_similarity_threshold == 0.8
|
| 193 |
|
| 194 |
# Check capabilities
|
| 195 |
expected_capabilities = [
|
|
@@ -210,7 +208,7 @@ class TestAnitaAgent:
|
|
| 210 |
message = AgentMessage(
|
| 211 |
sender="investigator_agent",
|
| 212 |
recipient="Anita",
|
| 213 |
-
action="
|
| 214 |
payload={
|
| 215 |
"data_type": "expenses",
|
| 216 |
"time_window": "2024-01-01:2024-06-30",
|
|
@@ -241,7 +239,7 @@ class TestAnitaAgent:
|
|
| 241 |
message = AgentMessage(
|
| 242 |
sender="analyst_agent",
|
| 243 |
recipient="Anita",
|
| 244 |
-
action="
|
| 245 |
payload={
|
| 246 |
"variables": ["contract_values", "expense_amounts", "supplier_count"],
|
| 247 |
"correlation_methods": ["pearson", "spearman", "mutual_information"],
|
|
@@ -278,7 +276,7 @@ class TestAnitaAgent:
|
|
| 278 |
message = AgentMessage(
|
| 279 |
sender="master_agent",
|
| 280 |
recipient="Anita",
|
| 281 |
-
action="
|
| 282 |
payload={
|
| 283 |
"queries": queries,
|
| 284 |
"route_to_specialists": True,
|
|
@@ -305,7 +303,7 @@ class TestAnitaAgent:
|
|
| 305 |
message = AgentMessage(
|
| 306 |
sender="tiradentes_agent",
|
| 307 |
recipient="Anita",
|
| 308 |
-
action="
|
| 309 |
payload={
|
| 310 |
"analysis_scope": "ministry_level",
|
| 311 |
"include_geographic_analysis": True,
|
|
@@ -335,7 +333,7 @@ class TestAnitaAgent:
|
|
| 335 |
message = AgentMessage(
|
| 336 |
sender="machado_agent",
|
| 337 |
recipient="Anita",
|
| 338 |
-
action="
|
| 339 |
payload={
|
| 340 |
"network_type": "supplier_ministry_relationships",
|
| 341 |
"include_centrality_measures": True,
|
|
@@ -366,7 +364,7 @@ class TestAnitaAgent:
|
|
| 366 |
message = AgentMessage(
|
| 367 |
sender="investigator_agent",
|
| 368 |
recipient="Anita",
|
| 369 |
-
action="
|
| 370 |
payload={
|
| 371 |
"data_points": [
|
| 372 |
{"value": 1000000, "date": "2024-01-01", "entity": "supplier_a"},
|
|
@@ -398,7 +396,7 @@ class TestAnitaAgent:
|
|
| 398 |
message = AgentMessage(
|
| 399 |
sender="analyst_agent",
|
| 400 |
recipient="Anita",
|
| 401 |
-
action="
|
| 402 |
payload={
|
| 403 |
"historical_data": {
|
| 404 |
"2024-01": 1000000,
|
|
@@ -438,7 +436,7 @@ class TestAnitaAgent:
|
|
| 438 |
message = AgentMessage(
|
| 439 |
sender="quality_agent",
|
| 440 |
recipient="Anita",
|
| 441 |
-
action="
|
| 442 |
payload={
|
| 443 |
"data_type": "contracts",
|
| 444 |
"significance_filter": True
|
|
@@ -460,7 +458,7 @@ class TestAnitaAgent:
|
|
| 460 |
message = AgentMessage(
|
| 461 |
sender="comprehensive_analyst",
|
| 462 |
recipient="Anita",
|
| 463 |
-
action="
|
| 464 |
payload={
|
| 465 |
"dimensions": ["temporal", "geographic", "categorical", "financial"],
|
| 466 |
"interaction_analysis": True,
|
|
@@ -498,7 +496,7 @@ class TestAnitaAgent:
|
|
| 498 |
message = AgentMessage(
|
| 499 |
sender="test_agent",
|
| 500 |
recipient="Anita",
|
| 501 |
-
action="
|
| 502 |
payload={"data_type": "contracts"}
|
| 503 |
)
|
| 504 |
|
|
@@ -519,7 +517,7 @@ class TestAnitaAgent:
|
|
| 519 |
AgentMessage(
|
| 520 |
sender="concurrent_tester",
|
| 521 |
recipient="Anita",
|
| 522 |
-
action="
|
| 523 |
payload={"data_type": f"data_stream_{i}"}
|
| 524 |
)
|
| 525 |
for i in range(3)
|
|
@@ -542,7 +540,7 @@ class TestAnitaAgent:
|
|
| 542 |
message = AgentMessage(
|
| 543 |
sender="cache_tester",
|
| 544 |
recipient="Anita",
|
| 545 |
-
action="
|
| 546 |
payload={
|
| 547 |
"data_type": "expenses",
|
| 548 |
"cache_results": True,
|
|
|
|
| 10 |
from uuid import uuid4
|
| 11 |
|
| 12 |
from src.agents.anita import (
|
| 13 |
+
AnalystAgent,
|
| 14 |
PatternResult,
|
| 15 |
CorrelationResult,
|
| 16 |
+
AnalysisRequest,
|
| 17 |
)
|
| 18 |
from src.agents.deodoro import (
|
| 19 |
AgentContext,
|
|
|
|
| 170 |
with patch("src.agents.anita.TransparencyAPIClient", return_value=mock_transparency_api), \
|
| 171 |
patch("src.agents.anita.SpectralAnalyzer", return_value=mock_spectral_analyzer):
|
| 172 |
|
| 173 |
+
agent = AnalystAgent(
|
| 174 |
+
min_correlation_threshold=0.3,
|
| 175 |
+
significance_threshold=0.05,
|
| 176 |
+
trend_detection_window=6
|
|
|
|
| 177 |
)
|
| 178 |
return agent
|
| 179 |
|
|
|
|
| 185 |
def test_agent_initialization(self, anita_agent):
|
| 186 |
"""Test Anita agent initialization."""
|
| 187 |
assert anita_agent.name == "Anita"
|
| 188 |
+
assert anita_agent.correlation_threshold == 0.3
|
| 189 |
+
assert anita_agent.significance_threshold == 0.05
|
| 190 |
+
assert anita_agent.trend_window == 6
|
|
|
|
| 191 |
|
| 192 |
# Check capabilities
|
| 193 |
expected_capabilities = [
|
|
|
|
| 208 |
message = AgentMessage(
|
| 209 |
sender="investigator_agent",
|
| 210 |
recipient="Anita",
|
| 211 |
+
action="analyze",
|
| 212 |
payload={
|
| 213 |
"data_type": "expenses",
|
| 214 |
"time_window": "2024-01-01:2024-06-30",
|
|
|
|
| 239 |
message = AgentMessage(
|
| 240 |
sender="analyst_agent",
|
| 241 |
recipient="Anita",
|
| 242 |
+
action="analyze",
|
| 243 |
payload={
|
| 244 |
"variables": ["contract_values", "expense_amounts", "supplier_count"],
|
| 245 |
"correlation_methods": ["pearson", "spearman", "mutual_information"],
|
|
|
|
| 276 |
message = AgentMessage(
|
| 277 |
sender="master_agent",
|
| 278 |
recipient="Anita",
|
| 279 |
+
action="analyze",
|
| 280 |
payload={
|
| 281 |
"queries": queries,
|
| 282 |
"route_to_specialists": True,
|
|
|
|
| 303 |
message = AgentMessage(
|
| 304 |
sender="tiradentes_agent",
|
| 305 |
recipient="Anita",
|
| 306 |
+
action="analyze",
|
| 307 |
payload={
|
| 308 |
"analysis_scope": "ministry_level",
|
| 309 |
"include_geographic_analysis": True,
|
|
|
|
| 333 |
message = AgentMessage(
|
| 334 |
sender="machado_agent",
|
| 335 |
recipient="Anita",
|
| 336 |
+
action="analyze",
|
| 337 |
payload={
|
| 338 |
"network_type": "supplier_ministry_relationships",
|
| 339 |
"include_centrality_measures": True,
|
|
|
|
| 364 |
message = AgentMessage(
|
| 365 |
sender="investigator_agent",
|
| 366 |
recipient="Anita",
|
| 367 |
+
action="analyze",
|
| 368 |
payload={
|
| 369 |
"data_points": [
|
| 370 |
{"value": 1000000, "date": "2024-01-01", "entity": "supplier_a"},
|
|
|
|
| 396 |
message = AgentMessage(
|
| 397 |
sender="analyst_agent",
|
| 398 |
recipient="Anita",
|
| 399 |
+
action="analyze",
|
| 400 |
payload={
|
| 401 |
"historical_data": {
|
| 402 |
"2024-01": 1000000,
|
|
|
|
| 436 |
message = AgentMessage(
|
| 437 |
sender="quality_agent",
|
| 438 |
recipient="Anita",
|
| 439 |
+
action="analyze",
|
| 440 |
payload={
|
| 441 |
"data_type": "contracts",
|
| 442 |
"significance_filter": True
|
|
|
|
| 458 |
message = AgentMessage(
|
| 459 |
sender="comprehensive_analyst",
|
| 460 |
recipient="Anita",
|
| 461 |
+
action="analyze",
|
| 462 |
payload={
|
| 463 |
"dimensions": ["temporal", "geographic", "categorical", "financial"],
|
| 464 |
"interaction_analysis": True,
|
|
|
|
| 496 |
message = AgentMessage(
|
| 497 |
sender="test_agent",
|
| 498 |
recipient="Anita",
|
| 499 |
+
action="analyze",
|
| 500 |
payload={"data_type": "contracts"}
|
| 501 |
)
|
| 502 |
|
|
|
|
| 517 |
AgentMessage(
|
| 518 |
sender="concurrent_tester",
|
| 519 |
recipient="Anita",
|
| 520 |
+
action="analyze",
|
| 521 |
payload={"data_type": f"data_stream_{i}"}
|
| 522 |
)
|
| 523 |
for i in range(3)
|
|
|
|
| 540 |
message = AgentMessage(
|
| 541 |
sender="cache_tester",
|
| 542 |
recipient="Anita",
|
| 543 |
+
action="analyze",
|
| 544 |
payload={
|
| 545 |
"data_type": "expenses",
|
| 546 |
"cache_results": True,
|
tests/unit/agents/test_tiradentes.py
CHANGED
|
@@ -9,10 +9,10 @@ from unittest.mock import Mock, AsyncMock, patch, MagicMock
|
|
| 9 |
from uuid import uuid4
|
| 10 |
|
| 11 |
from src.agents.tiradentes import (
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
)
|
| 17 |
from src.agents.deodoro import (
|
| 18 |
AgentContext,
|
|
@@ -138,33 +138,31 @@ def agent_context():
|
|
| 138 |
|
| 139 |
|
| 140 |
@pytest.fixture
|
| 141 |
-
def tiradentes_agent(
|
| 142 |
-
"""Create Tiradentes agent
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
correlation_threshold=0.8,
|
| 149 |
-
max_investigation_depth=3
|
| 150 |
-
)
|
| 151 |
-
return agent
|
| 152 |
|
| 153 |
|
| 154 |
class TestTiradentesAgent:
|
| 155 |
-
"""Test suite for Tiradentes (
|
| 156 |
|
| 157 |
@pytest.mark.unit
|
| 158 |
def test_agent_initialization(self, tiradentes_agent):
|
| 159 |
"""Test Tiradentes agent initialization."""
|
| 160 |
assert tiradentes_agent.name == "Tiradentes"
|
| 161 |
-
assert tiradentes_agent.
|
| 162 |
-
assert tiradentes_agent.
|
| 163 |
-
assert tiradentes_agent.max_investigation_depth == 3
|
| 164 |
|
| 165 |
# Check capabilities
|
| 166 |
expected_capabilities = [
|
| 167 |
-
"
|
|
|
|
|
|
|
|
|
|
| 168 |
"corruption_analysis",
|
| 169 |
"investigation_planning",
|
| 170 |
"pattern_recognition",
|
|
|
|
| 9 |
from uuid import uuid4
|
| 10 |
|
| 11 |
from src.agents.tiradentes import (
|
| 12 |
+
ReporterAgent,
|
| 13 |
+
ReportRequest,
|
| 14 |
+
ReportType,
|
| 15 |
+
ReportFormat,
|
| 16 |
)
|
| 17 |
from src.agents.deodoro import (
|
| 18 |
AgentContext,
|
|
|
|
| 138 |
|
| 139 |
|
| 140 |
@pytest.fixture
|
| 141 |
+
def tiradentes_agent():
|
| 142 |
+
"""Create Tiradentes agent (ReporterAgent)."""
|
| 143 |
+
agent = ReporterAgent(
|
| 144 |
+
default_language="pt",
|
| 145 |
+
max_report_length=10000
|
| 146 |
+
)
|
| 147 |
+
return agent
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
|
| 149 |
|
| 150 |
class TestTiradentesAgent:
|
| 151 |
+
"""Test suite for Tiradentes (Reporter Agent)."""
|
| 152 |
|
| 153 |
@pytest.mark.unit
|
| 154 |
def test_agent_initialization(self, tiradentes_agent):
|
| 155 |
"""Test Tiradentes agent initialization."""
|
| 156 |
assert tiradentes_agent.name == "Tiradentes"
|
| 157 |
+
assert tiradentes_agent.default_language == "pt"
|
| 158 |
+
assert tiradentes_agent.max_length == 10000
|
|
|
|
| 159 |
|
| 160 |
# Check capabilities
|
| 161 |
expected_capabilities = [
|
| 162 |
+
"investigation_report_generation",
|
| 163 |
+
"pattern_analysis_reporting",
|
| 164 |
+
"executive_summary_creation",
|
| 165 |
+
"multi_format_rendering",
|
| 166 |
"corruption_analysis",
|
| 167 |
"investigation_planning",
|
| 168 |
"pattern_recognition",
|
tests/unit/agents/test_tiradentes_reporter.py
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Unit tests for Tiradentes Agent (ReporterAgent) - Report generation specialist.
|
| 3 |
+
Tests report generation, formatting, and multi-language support.
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import pytest
|
| 7 |
+
from datetime import datetime
|
| 8 |
+
from unittest.mock import Mock, AsyncMock, patch, MagicMock
|
| 9 |
+
|
| 10 |
+
from src.agents.tiradentes import (
|
| 11 |
+
ReporterAgent,
|
| 12 |
+
ReportRequest,
|
| 13 |
+
ReportType,
|
| 14 |
+
ReportFormat,
|
| 15 |
+
)
|
| 16 |
+
from src.agents.deodoro import (
|
| 17 |
+
AgentContext,
|
| 18 |
+
AgentMessage,
|
| 19 |
+
AgentResponse,
|
| 20 |
+
AgentStatus,
|
| 21 |
+
)
|
| 22 |
+
from src.core.exceptions import AgentExecutionError
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
@pytest.fixture
|
| 26 |
+
def investigation_results():
|
| 27 |
+
"""Sample investigation results from Zumbi agent."""
|
| 28 |
+
return {
|
| 29 |
+
"anomalies": [
|
| 30 |
+
{
|
| 31 |
+
"anomaly_type": "price_anomaly",
|
| 32 |
+
"severity": 0.85,
|
| 33 |
+
"confidence": 0.92,
|
| 34 |
+
"description": "Contract value 3.5x above market average",
|
| 35 |
+
"explanation": "Significant price deviation detected",
|
| 36 |
+
"evidence": {
|
| 37 |
+
"contract_id": "123/2024",
|
| 38 |
+
"value": 5000000.0,
|
| 39 |
+
"market_average": 1428571.0
|
| 40 |
+
},
|
| 41 |
+
"recommendations": [
|
| 42 |
+
"Review pricing justification",
|
| 43 |
+
"Compare with similar contracts"
|
| 44 |
+
]
|
| 45 |
+
}
|
| 46 |
+
],
|
| 47 |
+
"summary": {
|
| 48 |
+
"total_records": 100,
|
| 49 |
+
"anomalies_found": 3,
|
| 50 |
+
"investigation_id": "inv-123"
|
| 51 |
+
}
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
@pytest.fixture
|
| 56 |
+
def analysis_results():
|
| 57 |
+
"""Sample analysis results from Anita agent."""
|
| 58 |
+
return {
|
| 59 |
+
"patterns": [
|
| 60 |
+
{
|
| 61 |
+
"pattern_type": "temporal",
|
| 62 |
+
"description": "End-of-year spending spike",
|
| 63 |
+
"significance": 0.78,
|
| 64 |
+
"confidence": 0.85,
|
| 65 |
+
"insights": ["Budget execution rush", "Possible inefficiency"],
|
| 66 |
+
"evidence": {
|
| 67 |
+
"period": "Q4 2023",
|
| 68 |
+
"increase_percentage": 145
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
],
|
| 72 |
+
"correlations": [
|
| 73 |
+
{
|
| 74 |
+
"correlation_type": "vendor_concentration",
|
| 75 |
+
"variables": ["vendor_id", "contract_count"],
|
| 76 |
+
"correlation_coefficient": 0.82,
|
| 77 |
+
"significance_level": "high"
|
| 78 |
+
}
|
| 79 |
+
]
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
@pytest.fixture
|
| 84 |
+
def agent_context():
|
| 85 |
+
"""Create agent context for testing."""
|
| 86 |
+
return AgentContext(
|
| 87 |
+
investigation_id="test-report-123",
|
| 88 |
+
user_id="test_user",
|
| 89 |
+
session_id="test_session",
|
| 90 |
+
metadata={"purpose": "testing"}
|
| 91 |
+
)
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
@pytest.fixture
|
| 95 |
+
def tiradentes_agent():
|
| 96 |
+
"""Create Tiradentes agent (ReporterAgent)."""
|
| 97 |
+
return ReporterAgent(
|
| 98 |
+
default_language="pt",
|
| 99 |
+
max_report_length=10000
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
class TestTiradentesReporterAgent:
|
| 104 |
+
"""Test suite for Tiradentes (Reporter Agent)."""
|
| 105 |
+
|
| 106 |
+
@pytest.mark.unit
|
| 107 |
+
def test_agent_initialization(self, tiradentes_agent):
|
| 108 |
+
"""Test Tiradentes agent initialization."""
|
| 109 |
+
assert tiradentes_agent.name == "Tiradentes"
|
| 110 |
+
assert tiradentes_agent.default_language == "pt"
|
| 111 |
+
assert tiradentes_agent.max_length == 10000
|
| 112 |
+
|
| 113 |
+
# Check capabilities
|
| 114 |
+
expected_capabilities = [
|
| 115 |
+
"investigation_report_generation",
|
| 116 |
+
"pattern_analysis_reporting",
|
| 117 |
+
"executive_summary_creation",
|
| 118 |
+
"multi_format_rendering"
|
| 119 |
+
]
|
| 120 |
+
|
| 121 |
+
for capability in expected_capabilities:
|
| 122 |
+
assert capability in tiradentes_agent.capabilities
|
| 123 |
+
|
| 124 |
+
@pytest.mark.unit
|
| 125 |
+
async def test_initialize_and_shutdown(self, tiradentes_agent):
|
| 126 |
+
"""Test agent lifecycle methods."""
|
| 127 |
+
await tiradentes_agent.initialize()
|
| 128 |
+
await tiradentes_agent.shutdown()
|
| 129 |
+
# Should complete without errors
|
| 130 |
+
|
| 131 |
+
@pytest.mark.unit
|
| 132 |
+
async def test_generate_investigation_report(
|
| 133 |
+
self, tiradentes_agent, agent_context, investigation_results
|
| 134 |
+
):
|
| 135 |
+
"""Test generation of investigation report."""
|
| 136 |
+
message = AgentMessage(
|
| 137 |
+
sender="test",
|
| 138 |
+
recipient="Tiradentes",
|
| 139 |
+
action="generate_report",
|
| 140 |
+
payload={
|
| 141 |
+
"report_type": "investigation_report",
|
| 142 |
+
"format": "markdown",
|
| 143 |
+
"investigation_results": investigation_results,
|
| 144 |
+
"target_audience": "technical",
|
| 145 |
+
"include_visualizations": True
|
| 146 |
+
}
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 150 |
+
|
| 151 |
+
assert isinstance(response, AgentResponse)
|
| 152 |
+
assert response.agent_name == "Tiradentes"
|
| 153 |
+
assert response.status == AgentStatus.COMPLETED
|
| 154 |
+
assert "content" in response.result
|
| 155 |
+
assert "anomalies" in response.result["content"].lower()
|
| 156 |
+
|
| 157 |
+
@pytest.mark.unit
|
| 158 |
+
async def test_generate_analysis_report(
|
| 159 |
+
self, tiradentes_agent, agent_context, analysis_results
|
| 160 |
+
):
|
| 161 |
+
"""Test generation of analysis report."""
|
| 162 |
+
message = AgentMessage(
|
| 163 |
+
sender="test",
|
| 164 |
+
recipient="Tiradentes",
|
| 165 |
+
action="generate_report",
|
| 166 |
+
payload={
|
| 167 |
+
"report_type": "analysis_report",
|
| 168 |
+
"format": "markdown",
|
| 169 |
+
"analysis_results": analysis_results,
|
| 170 |
+
"language": "pt",
|
| 171 |
+
"detailed_findings": True
|
| 172 |
+
}
|
| 173 |
+
)
|
| 174 |
+
|
| 175 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 176 |
+
|
| 177 |
+
assert response.status == AgentStatus.COMPLETED
|
| 178 |
+
assert "patterns" in response.result["content"].lower()
|
| 179 |
+
|
| 180 |
+
@pytest.mark.unit
|
| 181 |
+
async def test_generate_executive_summary(
|
| 182 |
+
self, tiradentes_agent, agent_context, investigation_results, analysis_results
|
| 183 |
+
):
|
| 184 |
+
"""Test generation of executive summary."""
|
| 185 |
+
message = AgentMessage(
|
| 186 |
+
sender="test",
|
| 187 |
+
recipient="Tiradentes",
|
| 188 |
+
action="generate_report",
|
| 189 |
+
payload={
|
| 190 |
+
"report_type": "executive_summary",
|
| 191 |
+
"format": "executive_summary",
|
| 192 |
+
"investigation_results": investigation_results,
|
| 193 |
+
"analysis_results": analysis_results,
|
| 194 |
+
"target_audience": "executive"
|
| 195 |
+
}
|
| 196 |
+
)
|
| 197 |
+
|
| 198 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 199 |
+
|
| 200 |
+
assert response.status == AgentStatus.COMPLETED
|
| 201 |
+
# Executive summary should be concise
|
| 202 |
+
assert len(response.result["content"]) < 5000
|
| 203 |
+
|
| 204 |
+
@pytest.mark.unit
|
| 205 |
+
async def test_invalid_action(self, tiradentes_agent, agent_context):
|
| 206 |
+
"""Test handling of invalid action."""
|
| 207 |
+
message = AgentMessage(
|
| 208 |
+
sender="test",
|
| 209 |
+
recipient="Tiradentes",
|
| 210 |
+
action="invalid_action",
|
| 211 |
+
payload={}
|
| 212 |
+
)
|
| 213 |
+
|
| 214 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 215 |
+
|
| 216 |
+
assert response.status == AgentStatus.ERROR
|
| 217 |
+
assert "Unsupported action" in response.error
|
| 218 |
+
|
| 219 |
+
@pytest.mark.unit
|
| 220 |
+
async def test_missing_data_error(self, tiradentes_agent, agent_context):
|
| 221 |
+
"""Test error when no data provided."""
|
| 222 |
+
message = AgentMessage(
|
| 223 |
+
sender="test",
|
| 224 |
+
recipient="Tiradentes",
|
| 225 |
+
action="generate_report",
|
| 226 |
+
payload={
|
| 227 |
+
"report_type": "investigation_report",
|
| 228 |
+
"format": "markdown"
|
| 229 |
+
# Missing investigation_results and analysis_results
|
| 230 |
+
}
|
| 231 |
+
)
|
| 232 |
+
|
| 233 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 234 |
+
|
| 235 |
+
assert response.status == AgentStatus.ERROR
|
| 236 |
+
assert "No data provided" in response.error
|
| 237 |
+
|
| 238 |
+
@pytest.mark.unit
|
| 239 |
+
async def test_multi_language_support(
|
| 240 |
+
self, tiradentes_agent, agent_context, investigation_results
|
| 241 |
+
):
|
| 242 |
+
"""Test report generation in different languages."""
|
| 243 |
+
languages = ["pt", "en"]
|
| 244 |
+
|
| 245 |
+
for lang in languages:
|
| 246 |
+
message = AgentMessage(
|
| 247 |
+
sender="test",
|
| 248 |
+
recipient="Tiradentes",
|
| 249 |
+
action="generate_report",
|
| 250 |
+
payload={
|
| 251 |
+
"report_type": "investigation_report",
|
| 252 |
+
"format": "markdown",
|
| 253 |
+
"investigation_results": investigation_results,
|
| 254 |
+
"language": lang
|
| 255 |
+
}
|
| 256 |
+
)
|
| 257 |
+
|
| 258 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 259 |
+
|
| 260 |
+
assert response.status == AgentStatus.COMPLETED
|
| 261 |
+
assert response.result["metadata"]["language"] == lang
|
| 262 |
+
|
| 263 |
+
@pytest.mark.unit
|
| 264 |
+
async def test_report_format_rendering(
|
| 265 |
+
self, tiradentes_agent, agent_context, investigation_results
|
| 266 |
+
):
|
| 267 |
+
"""Test different report format rendering."""
|
| 268 |
+
formats = ["markdown", "html", "json"]
|
| 269 |
+
|
| 270 |
+
for fmt in formats:
|
| 271 |
+
message = AgentMessage(
|
| 272 |
+
sender="test",
|
| 273 |
+
recipient="Tiradentes",
|
| 274 |
+
action="generate_report",
|
| 275 |
+
payload={
|
| 276 |
+
"report_type": "investigation_report",
|
| 277 |
+
"format": fmt,
|
| 278 |
+
"investigation_results": investigation_results
|
| 279 |
+
}
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
response = await tiradentes_agent.process(message, agent_context)
|
| 283 |
+
|
| 284 |
+
assert response.status == AgentStatus.COMPLETED
|
| 285 |
+
assert response.result["metadata"]["format"] == fmt
|
tests/unit/agents/test_zumbi.py
CHANGED
|
@@ -1,28 +1,92 @@
|
|
| 1 |
"""
|
| 2 |
-
Unit tests for Zumbi Agent -
|
| 3 |
"""
|
| 4 |
|
| 5 |
import pytest
|
| 6 |
-
from unittest.mock import AsyncMock
|
| 7 |
-
from src.agents.zumbi import
|
| 8 |
-
from src.agents.deodoro import AgentContext, AgentMessage, AgentStatus
|
| 9 |
|
| 10 |
@pytest.fixture
|
| 11 |
def zumbi_agent():
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
class TestZumbiAgent:
|
| 15 |
@pytest.mark.unit
|
| 16 |
def test_agent_initialization(self, zumbi_agent):
|
|
|
|
| 17 |
assert zumbi_agent.name == "Zumbi"
|
| 18 |
-
assert "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
@pytest.mark.unit
|
| 21 |
-
async def
|
| 22 |
-
|
|
|
|
| 23 |
message = AgentMessage(
|
| 24 |
-
sender="test",
|
| 25 |
-
|
|
|
|
|
|
|
| 26 |
)
|
|
|
|
| 27 |
response = await zumbi_agent.process(message, context)
|
| 28 |
-
|
|
|
|
|
|
|
|
|
| 1 |
"""
|
| 2 |
+
Unit tests for Zumbi Agent (InvestigatorAgent) - Anomaly detection specialist.
|
| 3 |
"""
|
| 4 |
|
| 5 |
import pytest
|
| 6 |
+
from unittest.mock import AsyncMock, patch, MagicMock
|
| 7 |
+
from src.agents.zumbi import InvestigatorAgent
|
| 8 |
+
from src.agents.deodoro import AgentContext, AgentMessage, AgentResponse, AgentStatus
|
| 9 |
|
| 10 |
@pytest.fixture
|
| 11 |
def zumbi_agent():
|
| 12 |
+
"""Create an InvestigatorAgent instance for testing."""
|
| 13 |
+
return InvestigatorAgent(
|
| 14 |
+
price_anomaly_threshold=2.5,
|
| 15 |
+
concentration_threshold=0.7,
|
| 16 |
+
duplicate_similarity_threshold=0.85
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
@pytest.fixture
|
| 20 |
+
def mock_transparency_client():
|
| 21 |
+
"""Mock TransparencyAPIClient."""
|
| 22 |
+
client = AsyncMock()
|
| 23 |
+
client.search_contracts.return_value = [
|
| 24 |
+
{
|
| 25 |
+
"numeroContratoCompra": "123/2024",
|
| 26 |
+
"valorTotalCompra": 100000.0,
|
| 27 |
+
"dataPublicacaoContrato": "01/01/2024",
|
| 28 |
+
"orgaoEntidade": {"nome": "Ministério Teste"},
|
| 29 |
+
"fornecedor": {"nome": "Empresa ABC", "cnpj": "12345678901234"}
|
| 30 |
+
}
|
| 31 |
+
]
|
| 32 |
+
return client
|
| 33 |
|
| 34 |
class TestZumbiAgent:
|
| 35 |
@pytest.mark.unit
|
| 36 |
def test_agent_initialization(self, zumbi_agent):
|
| 37 |
+
"""Test that the agent is properly initialized."""
|
| 38 |
assert zumbi_agent.name == "Zumbi"
|
| 39 |
+
assert "price_anomaly_detection" in zumbi_agent.capabilities
|
| 40 |
+
assert "spectral_analysis" in zumbi_agent.capabilities
|
| 41 |
+
assert zumbi_agent.price_threshold == 2.5
|
| 42 |
+
assert zumbi_agent.concentration_threshold == 0.7
|
| 43 |
+
|
| 44 |
+
@pytest.mark.unit
|
| 45 |
+
async def test_initialize(self, zumbi_agent):
|
| 46 |
+
"""Test agent initialization method."""
|
| 47 |
+
await zumbi_agent.initialize()
|
| 48 |
+
# Should complete without errors
|
| 49 |
+
|
| 50 |
+
@pytest.mark.unit
|
| 51 |
+
async def test_shutdown(self, zumbi_agent):
|
| 52 |
+
"""Test agent shutdown method."""
|
| 53 |
+
await zumbi_agent.shutdown()
|
| 54 |
+
# Should complete without errors
|
| 55 |
+
|
| 56 |
+
@pytest.mark.unit
|
| 57 |
+
async def test_process_investigation(self, zumbi_agent, mock_transparency_client):
|
| 58 |
+
"""Test processing an investigation request."""
|
| 59 |
+
with patch('src.agents.zumbi.TransparencyAPIClient', return_value=mock_transparency_client):
|
| 60 |
+
context = AgentContext(investigation_id="test-123")
|
| 61 |
+
message = AgentMessage(
|
| 62 |
+
sender="test",
|
| 63 |
+
recipient="Zumbi",
|
| 64 |
+
action="investigate",
|
| 65 |
+
payload={
|
| 66 |
+
"query": "contratos suspeitos",
|
| 67 |
+
"max_records": 10
|
| 68 |
+
}
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
response = await zumbi_agent.process(message, context)
|
| 72 |
+
|
| 73 |
+
assert isinstance(response, AgentResponse)
|
| 74 |
+
assert response.agent_name == "Zumbi"
|
| 75 |
+
assert response.status == AgentStatus.COMPLETED
|
| 76 |
+
assert "anomalies" in response.result
|
| 77 |
|
| 78 |
@pytest.mark.unit
|
| 79 |
+
async def test_process_invalid_action(self, zumbi_agent):
|
| 80 |
+
"""Test processing with invalid action."""
|
| 81 |
+
context = AgentContext(investigation_id="test-123")
|
| 82 |
message = AgentMessage(
|
| 83 |
+
sender="test",
|
| 84 |
+
recipient="Zumbi",
|
| 85 |
+
action="invalid_action",
|
| 86 |
+
payload={}
|
| 87 |
)
|
| 88 |
+
|
| 89 |
response = await zumbi_agent.process(message, context)
|
| 90 |
+
|
| 91 |
+
assert response.status == AgentStatus.ERROR
|
| 92 |
+
assert "Unsupported action" in response.error
|