187 lines
6.3 KiB
Python
187 lines
6.3 KiB
Python
"""Unit tests for AgentRegistry."""
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
from agent_service.agents.registry import AgentRegistry
|
|
|
|
|
|
def _make_registry():
|
|
return AgentRegistry()
|
|
|
|
|
|
def _make_agent(name='test_agent'):
|
|
agent = MagicMock()
|
|
agent.name = name
|
|
return agent
|
|
|
|
|
|
# ── register / get_agent_instance ───────────────────────────────────────────
|
|
|
|
def test_register_stores_instance():
|
|
reg = _make_registry()
|
|
agent = _make_agent()
|
|
reg.register('test_agent', agent)
|
|
assert reg.get_agent_instance('test_agent') is agent
|
|
|
|
|
|
def test_register_missing_returns_none():
|
|
reg = _make_registry()
|
|
assert reg.get_agent_instance('nonexistent') is None
|
|
|
|
|
|
def test_register_activates_agent():
|
|
reg = _make_registry()
|
|
reg.register('test_agent', _make_agent())
|
|
assert 'test_agent' in reg._active
|
|
|
|
|
|
def test_register_assigns_default_capability():
|
|
reg = _make_registry()
|
|
reg.register('test_agent', _make_agent())
|
|
assert reg._capabilities.get('test_agent')
|
|
|
|
|
|
def test_register_known_agent_uses_default_description():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent('crm_agent'))
|
|
assert 'crm' in reg._capabilities['crm_agent'].lower() or \
|
|
'lead' in reg._capabilities['crm_agent'].lower()
|
|
|
|
|
|
def test_register_multiple_agents():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent('crm_agent'))
|
|
reg.register('sales_agent', _make_agent('sales_agent'))
|
|
assert len(reg._agents) == 2
|
|
|
|
|
|
# ── is_active ────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_is_active_after_register():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
assert await reg.is_active('crm_agent') is True
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_is_active_unknown_agent():
|
|
reg = _make_registry()
|
|
assert await reg.is_active('ghost_agent') is False
|
|
|
|
|
|
# ── get_active_agents ────────────────────────────────────────────────────────
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_active_agents_returns_only_registered():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
reg._active.add('ghost_agent') # active but no instance
|
|
result = await reg.get_active_agents()
|
|
keys = {r['agent_key'] for r in result}
|
|
assert 'crm_agent' in keys
|
|
assert 'ghost_agent' not in keys
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_active_agents_includes_capabilities():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
result = await reg.get_active_agents()
|
|
assert any('capabilities_summary' in r for r in result)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_active_agents_empty_registry():
|
|
reg = _make_registry()
|
|
result = await reg.get_active_agents()
|
|
assert result == []
|
|
|
|
|
|
# ── get_all ──────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_all_includes_all_registered():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
reg.register('sales_agent', _make_agent())
|
|
result = await reg.get_all()
|
|
names = {r['name'] for r in result}
|
|
assert 'crm_agent' in names
|
|
assert 'sales_agent' in names
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_all_marks_active_flag():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
result = await reg.get_all()
|
|
crm = next(r for r in result if r['name'] == 'crm_agent')
|
|
assert crm['active'] is True
|
|
assert crm['has_instance'] is True
|
|
|
|
|
|
# ── sync ─────────────────────────────────────────────────────────────────────
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_sync_replaces_active_set():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
reg.register('sales_agent', _make_agent())
|
|
await reg.sync(['sales_agent'])
|
|
assert await reg.is_active('sales_agent') is True
|
|
assert await reg.is_active('crm_agent') is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_sync_with_empty_list_deactivates_all():
|
|
reg = _make_registry()
|
|
reg.register('crm_agent', _make_agent())
|
|
await reg.sync([])
|
|
assert await reg.is_active('crm_agent') is False
|
|
|
|
|
|
# ── load_from_odoo ───────────────────────────────────────────────────────────
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_from_odoo_sets_active_agents():
|
|
reg = _make_registry()
|
|
odoo = MagicMock()
|
|
odoo.search_read = AsyncMock(return_value=[
|
|
{'agent_name': 'crm_agent', 'domain': 'CRM leads', 'backend': 'local'},
|
|
{'agent_name': 'sales_agent', 'domain': '', 'backend': 'cloud'},
|
|
])
|
|
await reg.load_from_odoo(odoo)
|
|
assert 'crm_agent' in reg._active
|
|
assert 'sales_agent' in reg._active
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_from_odoo_uses_domain_when_present():
|
|
reg = _make_registry()
|
|
odoo = MagicMock()
|
|
odoo.search_read = AsyncMock(return_value=[
|
|
{'agent_name': 'crm_agent', 'domain': 'Custom CRM description', 'backend': 'local'},
|
|
])
|
|
await reg.load_from_odoo(odoo)
|
|
assert reg._capabilities['crm_agent'] == 'Custom CRM description'
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_from_odoo_falls_back_to_default_when_no_domain():
|
|
reg = _make_registry()
|
|
odoo = MagicMock()
|
|
odoo.search_read = AsyncMock(return_value=[
|
|
{'agent_name': 'crm_agent', 'domain': '', 'backend': 'local'},
|
|
])
|
|
await reg.load_from_odoo(odoo)
|
|
assert reg._capabilities.get('crm_agent')
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_from_odoo_handles_exception_gracefully():
|
|
reg = _make_registry()
|
|
odoo = MagicMock()
|
|
odoo.search_read = AsyncMock(side_effect=Exception('DB error'))
|
|
await reg.load_from_odoo(odoo)
|
|
assert reg._active == set()
|