| |
| """Integration tests for the full ALS Research Agent workflow""" |
| import pytest |
| from unittest.mock import AsyncMock, patch, MagicMock |
| from mcp.types import TextContent |
|
|
|
|
| @pytest.mark.asyncio |
| @pytest.mark.integration |
| class TestIntegration: |
|
|
| async def test_multi_server_search_workflow( |
| self, |
| pubmed_session, |
| biorxiv_session, |
| clinicaltrials_session |
| ): |
| """Test searching across all three data sources""" |
|
|
| |
| pubmed_result = await pubmed_session.call_tool( |
| "search_pubmed", |
| {"query": "ALS SOD1", "max_results": 3} |
| ) |
| assert len(pubmed_result.content) > 0 |
|
|
| |
| biorxiv_result = await biorxiv_session.call_tool( |
| "search_preprints", |
| {"query": "ALS", "max_results": 3, "days_back": 90} |
| ) |
| assert len(biorxiv_result.content) > 0 |
|
|
| |
| trials_result = await clinicaltrials_session.call_tool( |
| "search_trials", |
| {"condition": "ALS", "status": "recruiting", "max_results": 3} |
| ) |
| assert len(trials_result.content) > 0 |
|
|
| |
| assert all([pubmed_result, biorxiv_result, trials_result]) |
|
|
| async def test_fetch_and_detail_workflow( |
| self, |
| pubmed_session, |
| clinicaltrials_session |
| ): |
| """Test fetching a result then getting its details""" |
|
|
| |
| search_result = await pubmed_session.call_tool( |
| "search_pubmed", |
| {"query": "ALS", "max_results": 1} |
| ) |
|
|
| |
| text = search_result.content[0].text |
|
|
| |
| assert "PMID" in text or "papers" in text.lower() |
|
|
| |
| trials_search = await clinicaltrials_session.call_tool( |
| "search_trials", |
| {"condition": "ALS", "max_results": 1} |
| ) |
|
|
| trials_text = trials_search.content[0].text |
| assert "NCT" in trials_text or "trial" in trials_text.lower() |
|
|
| async def test_error_recovery_across_servers(self, pubmed_session): |
| """Test that errors in one server don't crash the system""" |
|
|
| |
| with patch('httpx.AsyncClient') as mock_client: |
| mock_response = MagicMock() |
| mock_response.json.return_value = { |
| "esearchresult": {"idlist": []} |
| } |
|
|
| mock_client_instance = AsyncMock() |
| mock_client_instance.get = AsyncMock(return_value=mock_response) |
| mock_client.return_value.__aenter__.return_value = mock_client_instance |
|
|
| result = await pubmed_session.call_tool( |
| "search_pubmed", |
| {"query": "nonexistentquery12345xyz"} |
| ) |
|
|
| |
| assert len(result.content) > 0 |
| assert "no results" in result.content[0].text.lower() |
|
|
| async def test_concurrent_server_calls( |
| self, |
| pubmed_session, |
| biorxiv_session, |
| clinicaltrials_session |
| ): |
| """Test that multiple servers can be queried concurrently""" |
| import asyncio |
|
|
| |
| tasks = [ |
| pubmed_session.call_tool( |
| "search_pubmed", |
| {"query": "ALS", "max_results": 2} |
| ), |
| biorxiv_session.call_tool( |
| "search_preprints", |
| {"query": "ALS", "max_results": 2} |
| ), |
| clinicaltrials_session.call_tool( |
| "search_trials", |
| {"condition": "ALS", "max_results": 2} |
| ) |
| ] |
|
|
| |
| results = await asyncio.gather(*tasks, return_exceptions=True) |
|
|
| |
| assert len(results) == 3 |
|
|
| |
| for result in results: |
| assert not isinstance(result, Exception) |
| assert len(result.content) > 0 |
|
|
| async def test_server_initialization( |
| self, |
| pubmed_session, |
| biorxiv_session, |
| clinicaltrials_session, |
| fetch_session |
| ): |
| """Test that all servers initialize and list tools correctly""" |
|
|
| |
| pubmed_tools = await pubmed_session.list_tools() |
| biorxiv_tools = await biorxiv_session.list_tools() |
| trials_tools = await clinicaltrials_session.list_tools() |
| fetch_tools = await fetch_session.list_tools() |
|
|
| |
| assert len(pubmed_tools.tools) == 2 |
| assert len(biorxiv_tools.tools) == 2 |
| assert len(trials_tools.tools) == 2 |
| assert len(fetch_tools.tools) == 1 |
|
|
| |
| pubmed_tool_names = [t.name for t in pubmed_tools.tools] |
| assert "search_pubmed" in pubmed_tool_names |
| assert "get_paper_details" in pubmed_tool_names |
|
|