185 lines
5.9 KiB
Python
185 lines
5.9 KiB
Python
"""
|
|
Tests for Triage Agent.
|
|
|
|
Tests entity extraction and classification logic.
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock, patch, AsyncMock
|
|
|
|
from src.agents.triage_agent import (
|
|
TriageAgent,
|
|
TriageResult,
|
|
ExtractedEntities,
|
|
Priority,
|
|
Category,
|
|
get_triage_agent
|
|
)
|
|
|
|
|
|
class TestExtractedEntities:
|
|
"""Tests for ExtractedEntities dataclass."""
|
|
|
|
def test_default_values(self):
|
|
"""Test default entity values."""
|
|
entities = ExtractedEntities()
|
|
|
|
assert entities.problem_summary == ""
|
|
assert entities.hostname is None
|
|
assert entities.category == Category.OTHER
|
|
assert entities.priority == Priority.MEDIUM
|
|
assert entities.is_urgent is False
|
|
|
|
def test_with_values(self):
|
|
"""Test entity with values."""
|
|
entities = ExtractedEntities(
|
|
hostname="srv-app01",
|
|
ip_address="192.168.1.10",
|
|
category=Category.INFRASTRUCTURE,
|
|
priority=Priority.HIGH,
|
|
is_urgent=True
|
|
)
|
|
|
|
assert entities.hostname == "srv-app01"
|
|
assert entities.priority == Priority.HIGH
|
|
assert entities.is_urgent is True
|
|
|
|
|
|
class TestTriageAgent:
|
|
"""Tests for TriageAgent class."""
|
|
|
|
@pytest.fixture
|
|
def agent(self):
|
|
"""Create a triage agent with mocked dependencies."""
|
|
# Patch at module level before creating agent
|
|
patcher1 = patch('src.agents.triage_agent.get_ollama_client')
|
|
patcher2 = patch('src.agents.triage_agent.get_financial_client')
|
|
|
|
mock_ollama = patcher1.start()
|
|
mock_financial = patcher2.start()
|
|
|
|
mock_ollama.return_value = Mock()
|
|
mock_financial.return_value = Mock()
|
|
|
|
agent = TriageAgent()
|
|
|
|
yield agent
|
|
|
|
patcher1.stop()
|
|
patcher2.stop()
|
|
|
|
def test_fallback_hostname_extraction(self, agent):
|
|
"""Test regex fallback for hostname extraction."""
|
|
content = "O servidor srv-app01 está com problema de memória"
|
|
entities = ExtractedEntities()
|
|
|
|
result = agent._fallback_extraction(content, entities)
|
|
|
|
assert result.hostname == "srv-app01"
|
|
|
|
def test_fallback_ip_extraction(self, agent):
|
|
"""Test regex fallback for IP extraction."""
|
|
content = "O servidor 192.168.1.50 não está respondendo"
|
|
entities = ExtractedEntities()
|
|
|
|
result = agent._fallback_extraction(content, entities)
|
|
|
|
assert result.ip_address == "192.168.1.50"
|
|
|
|
def test_fallback_service_extraction(self, agent):
|
|
"""Test regex fallback for service extraction."""
|
|
content = "O serviço nginx está retornando erro 502"
|
|
entities = ExtractedEntities()
|
|
|
|
result = agent._fallback_extraction(content, entities)
|
|
|
|
assert result.service_name.lower() == "nginx"
|
|
|
|
def test_urgency_detection(self, agent):
|
|
"""Test urgency keyword detection."""
|
|
content = "URGENTE: Sistema caiu e precisa de atenção imediata"
|
|
entities = ExtractedEntities(priority=Priority.MEDIUM)
|
|
|
|
result = agent._fallback_extraction(content, entities)
|
|
|
|
assert result.is_urgent is True
|
|
assert result.priority == Priority.HIGH
|
|
|
|
def test_production_detection(self, agent):
|
|
"""Test production keyword detection."""
|
|
content = "Servidor de produção com clientes afetados"
|
|
entities = ExtractedEntities(priority=Priority.MEDIUM)
|
|
|
|
result = agent._fallback_extraction(content, entities)
|
|
|
|
assert result.affects_production is True
|
|
assert result.priority == Priority.HIGH
|
|
|
|
def test_recommend_tools_with_host(self, agent):
|
|
"""Test tool recommendation with hostname."""
|
|
entities = ExtractedEntities(
|
|
hostname="srv-db01",
|
|
category=Category.DATABASE
|
|
)
|
|
tenant = Mock()
|
|
tenant.id = "tenant-001"
|
|
|
|
tools = agent._recommend_tools(entities, tenant)
|
|
|
|
assert "zabbix_get_host_status" in tools
|
|
assert "zabbix_get_problems" in tools
|
|
assert "rag_search_manuals" in tools
|
|
|
|
def test_build_reasoning(self, agent):
|
|
"""Test reasoning generation."""
|
|
entities = ExtractedEntities(
|
|
hostname="srv-app01",
|
|
category=Category.INFRASTRUCTURE,
|
|
priority=Priority.HIGH,
|
|
is_urgent=True,
|
|
affects_production=True,
|
|
problem_summary="Servidor não responde"
|
|
)
|
|
tenant = Mock()
|
|
tenant.name = "OESTEPAN"
|
|
|
|
reasoning = agent._build_reasoning(entities, tenant)
|
|
|
|
assert "OESTEPAN" in reasoning
|
|
assert "infrastructure" in reasoning
|
|
assert "high" in reasoning
|
|
assert "URGÊNCIA" in reasoning
|
|
assert "PRODUÇÃO" in reasoning
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_process_ticket_without_tenant(self, agent):
|
|
"""Test ticket processing when tenant cannot be resolved."""
|
|
agent._financial.get_tenant_by_email = AsyncMock(return_value=None)
|
|
|
|
result = await agent.process_ticket(
|
|
ticket_id="TKT-001",
|
|
sender_email="unknown@unknowndomain.com",
|
|
subject="Problema",
|
|
body="Teste"
|
|
)
|
|
|
|
assert result.success is False
|
|
assert "Tenant não identificado" in result.error
|
|
|
|
|
|
class TestTriageAgentSingleton:
|
|
"""Tests for singleton."""
|
|
|
|
def test_singleton(self):
|
|
"""Test singleton returns same instance."""
|
|
import src.agents.triage_agent as module
|
|
module._triage_agent = None
|
|
|
|
with patch('src.agents.triage_agent.get_ollama_client'), \
|
|
patch('src.agents.triage_agent.get_financial_client'):
|
|
|
|
agent1 = get_triage_agent()
|
|
agent2 = get_triage_agent()
|
|
|
|
assert agent1 is agent2
|