""" Agent Tests ============ Unit tests for the multi-agent system components. """ import pytest import sys import os # Add src to path for imports sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src')) from agents.research_agent import ResearchAgent from agents.summarizer_agent import SummarizerAgent from orchestrator import Orchestrator from ledger.merkle import compute_merkle_root, hash_leaf class TestResearchAgent: """Tests for ResearchAgent.""" @pytest.mark.asyncio async def test_research_agent_returns_results(self): """ Test that research agent returns results with expected structure. """ agent = ResearchAgent() result = await agent.run({"query": "diabetes AI"}) # Assert 'results' key exists and is a list assert "results" in result, "Result should contain 'results' key" assert isinstance(result["results"], list), "Results should be a list" assert len(result["results"]) > 0, "Results should not be empty" # Assert each result has expected structure for item in result["results"]: assert "title" in item, "Each result should have 'title'" assert "url" in item, "Each result should have 'url'" assert "snippet" in item, "Each result should have 'snippet'" @pytest.mark.asyncio async def test_research_agent_includes_query_in_response(self): """Test that response includes the original query.""" agent = ResearchAgent() query = "machine learning healthcare" result = await agent.run({"query": query}) assert result["query"] == query assert result["agent"] == "research" class TestSummarizerAgent: """Tests for SummarizerAgent.""" @pytest.mark.asyncio async def test_summarizer_agent_composes_summary(self): """ Test that summarizer agent creates a summary from documents. """ agent = SummarizerAgent() sample_docs = [ {"title": "Doc 1", "snippet": "This is the first document about AI."}, {"title": "Doc 2", "snippet": "This is the second document about healthcare."}, {"title": "Doc 3", "snippet": "This is the third document about research."} ] result = await agent.run({"documents": sample_docs}) # Assert 'summary' key exists and is a non-empty string assert "summary" in result, "Result should contain 'summary' key" assert isinstance(result["summary"], str), "Summary should be a string" assert len(result["summary"]) > 10, "Summary should be longer than 10 characters" @pytest.mark.asyncio async def test_summarizer_handles_empty_documents(self): """Test that summarizer handles empty document list gracefully.""" agent = SummarizerAgent() result = await agent.run({"documents": []}) assert "summary" in result assert result["document_count"] == 0 class TestOrchestrator: """Tests for Orchestrator.""" @pytest.mark.asyncio async def test_orchestrator_runs_pipeline(self): """ Test that orchestrator runs the full pipeline and returns expected structure. """ orchestrator = Orchestrator() task = {"query": "AI in medical diagnosis"} result = await orchestrator.run_task(task) # Assert steps list exists and has at least 2 steps assert "steps" in result, "Result should contain 'steps' key" assert isinstance(result["steps"], list), "Steps should be a list" assert len(result["steps"]) >= 2, "Pipeline should have at least 2 steps" # Assert each step has required fields for step in result["steps"]: assert "agent" in step, "Each step should have 'agent' field" assert "output" in step, "Each step should have 'output' field" assert "step" in step, "Each step should have 'step' number" assert "timestamp" in step, "Each step should have 'timestamp'" assert "hash" in step, "Each step should have 'hash'" @pytest.mark.asyncio async def test_orchestrator_produces_final_output(self): """Test that orchestrator produces a final output from summarizer.""" orchestrator = Orchestrator() result = await orchestrator.run_task({"query": "test query"}) assert "final_output" in result assert "summary" in result["final_output"] class TestMerkle: """Tests for Merkle tree functions.""" def test_merkle_root(self): """ Test that merkle root is computed correctly and has valid format. """ leaves = ["leaf1", "leaf2"] root = compute_merkle_root(leaves) # Assert root is 64 hex characters (SHA256) assert len(root) == 64, "Merkle root should be 64 hex characters" assert all(c in '0123456789abcdef' for c in root), "Root should be valid hex" def test_hash_leaf(self): """Test that hash_leaf produces valid SHA256 hash.""" result = hash_leaf("test data") assert len(result) == 64, "Hash should be 64 hex characters" assert all(c in '0123456789abcdef' for c in result), "Hash should be valid hex" def test_merkle_root_single_leaf(self): """Test merkle root with single leaf.""" root = compute_merkle_root(["single"]) assert len(root) == 64 def test_merkle_root_deterministic(self): """Test that merkle root is deterministic.""" leaves = ["a", "b", "c"] root1 = compute_merkle_root(leaves) root2 = compute_merkle_root(leaves) assert root1 == root2, "Merkle root should be deterministic" def test_merkle_root_empty_raises(self): """Test that empty leaves raises ValueError.""" with pytest.raises(ValueError): compute_merkle_root([]) if __name__ == "__main__": pytest.main([__file__, "-v"])