Newer
Older
cortex-hub / ai-hub / integration_tests / test_agents.py
import pytest
import httpx
import os
import uuid
from conftest import BASE_URL

def _headers():
    uid = os.getenv("SYNC_TEST_USER_ID", "")
    return {"X-User-ID": uid}

def test_agent_lifecycle_and_api_coverage():
    """
    Test suite covering Agent API endpoints:
    1. Register Node
    2. Register Template
    3. Register Instance
    4. Register Trigger
    5. List Agents
    6. Stop Agent
    7. Remove Agent
    """
    node_id = f"test-agent-node-{uuid.uuid4().hex[:8]}"
    admin_id = os.getenv("SYNC_TEST_USER_ID", "")
    
    with httpx.Client(timeout=10.0) as client:
        # 1. Register a test node specifically for this agent testing
        node_payload = {
            "node_id": node_id,
            "display_name": "Agent Test Node",
            "is_active": True,
            "skill_config": {"shell": {"enabled": True}}
        }
        r_node = client.post(f"{BASE_URL}/nodes/admin", params={"admin_id": admin_id}, json=node_payload)
        # If conflicts, clear first
        if r_node.status_code in (400, 409):
            client.delete(f"{BASE_URL}/nodes/admin/{node_id}", params={"admin_id": admin_id})
            r_node = client.post(f"{BASE_URL}/nodes/admin", params={"admin_id": admin_id}, json=node_payload)
        assert r_node.status_code == 200, f"Node registration failed: {r_node.text}"

        # 2. Register a basic Agent Template
        tmpl_payload = {
            "name": "Cron Print Agent",
            "description": "Periodically prints to the node console",
            "system_prompt_path": "You are a cron agent. Run shell tasks periodically.",
            "max_loop_iterations": 1
        }
        r_tmpl = client.post(f"{BASE_URL}/agents/templates", json=tmpl_payload, headers=_headers())
        assert r_tmpl.status_code == 200, f"Template registration failed: {r_tmpl.text}"
        template_id = r_tmpl.json()["id"]

        # 3. Register a simple Agent Instance
        inst_payload = {
            "template_id": template_id,
            "mesh_node_id": node_id,
            "status": "active"
        }
        r_inst = client.post(f"{BASE_URL}/agents/instances", json=inst_payload, headers=_headers())
        assert r_inst.status_code == 200, f"Instance registration failed: {r_inst.text}"
        instance_id = r_inst.json()["id"]

        # 4. Choose a basic trigger method (interval/cron)
        trig_payload = {
            "trigger_type": "interval",
            "interval_seconds": 10,
            "default_prompt": "Run the task now"
        }
        r_trig = client.post(f"{BASE_URL}/agents/{instance_id}/triggers", json=trig_payload, headers=_headers())
        assert r_trig.status_code == 200, f"Trigger logic failed: {r_trig.text}"
        trigger_id = r_trig.json()["id"]
        
        # 5. Test if agent is in the active list
        r_list = client.get(f"{BASE_URL}/agents", headers=_headers())
        assert r_list.status_code == 200
        agents = r_list.json()
        assert any(a["id"] == instance_id for a in agents), "Instance not found in active list"
        
        # Fetch triggers back
        r_trig_get = client.get(f"{BASE_URL}/agents/{instance_id}/triggers", headers=_headers())
        assert r_trig_get.status_code == 200
        assert any(t["id"] == trigger_id for t in r_trig_get.json()), "Trigger not found on instance"
        
        # 6. Test Stop Update / Config Update
        r_stop = client.patch(f"{BASE_URL}/agents/{instance_id}/status", json={"status": "stopped"}, headers=_headers())
        assert r_stop.status_code == 200
        assert r_stop.json()["status"] == "stopped"

        r_cfg = client.patch(f"{BASE_URL}/agents/{instance_id}/config", json={"name": "Updated Cron Agent", "mesh_node_id": node_id}, headers=_headers())
        assert r_cfg.status_code == 200
        
        # 7. Test Remove (delete trigger first, then agent)
        r_del_trig = client.delete(f"{BASE_URL}/agents/triggers/{trigger_id}", headers=_headers())
        assert r_del_trig.status_code == 200

        r_del_agent = client.delete(f"{BASE_URL}/agents/{instance_id}", headers=_headers())
        assert r_del_agent.status_code == 200
        
        # Cleanup Node
        client.delete(f"{BASE_URL}/nodes/admin/{node_id}", params={"admin_id": admin_id})