Skip to main content
Glama
test_unified_biothings.py13.7 kB
"""Tests for unified search/fetch with BioThings domains.""" import json import pytest from biomcp.router import fetch, search class TestUnifiedBioThingsSearch: """Test unified search with BioThings domains.""" @pytest.mark.asyncio async def test_search_gene_domain(self, monkeypatch): """Test searching genes through unified search.""" # Mock the BioThingsClient mock_gene_query = [{"_id": "673", "symbol": "BRAF"}] mock_gene_details = { "_id": "673", "symbol": "BRAF", "name": "B-Raf proto-oncogene, serine/threonine kinase", "summary": "This gene encodes a protein belonging to the RAF family...", "entrezgene": 673, } class MockBioThingsClient: async def _query_gene(self, query): return mock_gene_query async def _get_gene_by_id(self, gene_id): from biomcp.integrations.biothings_client import GeneInfo return GeneInfo(**mock_gene_details) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test gene search results = await search(query="", domain="gene", keywords=["BRAF"]) assert "results" in results # Skip thinking reminder if present actual_results = [ r for r in results["results"] if r["id"] != "thinking-reminder" ] assert len(actual_results) == 1 assert actual_results[0]["id"] == "673" assert "BRAF" in actual_results[0]["title"] @pytest.mark.asyncio async def test_search_drug_domain(self, monkeypatch): """Test searching drugs through unified search.""" # Mock the BioThingsClient mock_drug_query = [{"_id": "CHEMBL941"}] mock_drug_details = { "_id": "CHEMBL941", "name": "Imatinib", "drugbank_id": "DB00619", "description": "Imatinib is a tyrosine kinase inhibitor...", "indication": "Treatment of chronic myeloid leukemia...", } class MockBioThingsClient: async def _query_drug(self, query): return mock_drug_query async def _get_drug_by_id(self, drug_id): from biomcp.integrations.biothings_client import DrugInfo return DrugInfo(**mock_drug_details) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test drug search results = await search(query="", domain="drug", keywords=["imatinib"]) assert "results" in results # Skip thinking reminder if present actual_results = [ r for r in results["results"] if r["id"] != "thinking-reminder" ] assert len(actual_results) == 1 assert actual_results[0]["id"] == "CHEMBL941" assert "Imatinib" in actual_results[0]["title"] @pytest.mark.asyncio async def test_search_disease_domain(self, monkeypatch): """Test searching diseases through unified search.""" # Mock the BioThingsClient mock_disease_query = [{"_id": "MONDO:0005105"}] mock_disease_details = { "_id": "MONDO:0005105", "name": "melanoma", "definition": "A malignant neoplasm composed of melanocytes.", "mondo": {"id": "MONDO:0005105"}, "phenotypes": [], } class MockBioThingsClient: async def _query_disease(self, query): return mock_disease_query async def _get_disease_by_id(self, disease_id): from biomcp.integrations.biothings_client import DiseaseInfo return DiseaseInfo(**mock_disease_details) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test disease search results = await search( query="", domain="disease", keywords=["melanoma"] ) assert "results" in results # Skip thinking reminder if present actual_results = [ r for r in results["results"] if r["id"] != "thinking-reminder" ] assert len(actual_results) == 1 assert actual_results[0]["id"] == "MONDO:0005105" assert "melanoma" in actual_results[0]["title"] class TestUnifiedBioThingsFetch: """Test unified fetch with BioThings domains.""" @pytest.mark.asyncio async def test_fetch_gene(self, monkeypatch): """Test fetching gene information.""" mock_gene_info = { "_id": "673", "symbol": "BRAF", "name": "B-Raf proto-oncogene, serine/threonine kinase", "summary": "This gene encodes a protein belonging to the RAF family...", "entrezgene": 673, "type_of_gene": "protein-coding", "alias": ["BRAF1", "B-RAF1"], } class MockBioThingsClient: async def get_gene_info(self, gene_id): from biomcp.integrations.biothings_client import GeneInfo return GeneInfo(**mock_gene_info) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test gene fetch result = await fetch(id="BRAF", domain="gene") assert result["id"] == "673" assert "BRAF" in result["title"] assert "B-Raf proto-oncogene" in result["title"] assert "Entrez ID: 673" in result["text"] assert "Type: protein-coding" in result["text"] @pytest.mark.asyncio async def test_fetch_drug(self, monkeypatch): """Test fetching drug information.""" mock_drug_info = { "_id": "CHEMBL941", "name": "Imatinib", "drugbank_id": "DB00619", "description": "Imatinib is a tyrosine kinase inhibitor...", "indication": "Treatment of chronic myeloid leukemia...", "mechanism_of_action": "Inhibits BCR-ABL tyrosine kinase...", "tradename": ["Gleevec", "Glivec"], "formula": "C29H31N7O", } class MockBioThingsClient: async def get_drug_info(self, drug_id): from biomcp.integrations.biothings_client import DrugInfo return DrugInfo(**mock_drug_info) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test drug fetch result = await fetch(id="imatinib", domain="drug") assert result["id"] == "CHEMBL941" assert "Imatinib" in result["title"] assert "DrugBank ID: DB00619" in result["text"] assert "Formula: C29H31N7O" in result["text"] assert "Trade Names: Gleevec, Glivec" in result["text"] @pytest.mark.asyncio async def test_fetch_disease(self, monkeypatch): """Test fetching disease information.""" mock_disease_info = { "_id": "MONDO:0005105", "name": "melanoma", "definition": "A malignant neoplasm composed of melanocytes.", "mondo": {"id": "MONDO:0005105"}, "synonyms": [ "malignant melanoma", "melanoma, malignant", "melanosarcoma", ], "phenotypes": [{"hp": "HP:0002861"}], } class MockBioThingsClient: async def get_disease_info(self, disease_id): from biomcp.integrations.biothings_client import DiseaseInfo return DiseaseInfo(**mock_disease_info) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test disease fetch result = await fetch(id="melanoma", domain="disease") assert result["id"] == "MONDO:0005105" assert "melanoma" in result["title"] assert "MONDO ID: MONDO:0005105" in result["text"] assert "Definition:" in result["text"] assert "Synonyms:" in result["text"] assert "Associated Phenotypes: 1" in result["text"] class TestUnifiedQueryLanguage: """Test unified query language with BioThings domains.""" @pytest.mark.asyncio async def test_cross_domain_gene_search(self, monkeypatch): """Test that gene searches include gene domain.""" # Mock multiple domain searches searched_domains = [] async def mock_execute_routing_plan(plan, output_json=True): searched_domains.extend(plan.tools_to_call) return { "articles": json.dumps([]), "variants": json.dumps([]), "genes": json.dumps([]), "trials": json.dumps([]), } monkeypatch.setattr( "biomcp.router.execute_routing_plan", mock_execute_routing_plan ) # Test cross-domain gene search await search(query="gene:BRAF") assert "gene_searcher" in searched_domains assert "article_searcher" in searched_domains assert "variant_searcher" in searched_domains @pytest.mark.asyncio async def test_cross_domain_disease_search(self, monkeypatch): """Test that disease searches include disease domain.""" # Mock multiple domain searches searched_domains = [] async def mock_execute_routing_plan(plan, output_json=True): searched_domains.extend(plan.tools_to_call) return { "articles": json.dumps([]), "trials": json.dumps([]), "diseases": json.dumps([]), } monkeypatch.setattr( "biomcp.router.execute_routing_plan", mock_execute_routing_plan ) # Test cross-domain disease search await search(query="disease:melanoma") assert "disease_searcher" in searched_domains assert "article_searcher" in searched_domains assert "trial_searcher" in searched_domains @pytest.mark.asyncio async def test_domain_specific_query(self, monkeypatch): """Test domain-specific query language.""" # Mock execute routing plan searched_domains = [] async def mock_execute_routing_plan(plan, output_json=True): searched_domains.extend(plan.tools_to_call) return {"genes": json.dumps([])} monkeypatch.setattr( "biomcp.router.execute_routing_plan", mock_execute_routing_plan ) # Test gene-specific search await search(query="genes.symbol:BRAF") assert "gene_searcher" in searched_domains assert len(searched_domains) == 1 # Only gene domain searched class TestBioThingsErrorCases: """Test error handling for BioThings integration.""" @pytest.mark.asyncio async def test_gene_api_failure(self, monkeypatch): """Test handling of API failures for gene search.""" class MockBioThingsClient: async def _query_gene(self, query): raise Exception("API connection failed") monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) # Test that search handles the error gracefully with pytest.raises(Exception) as exc_info: await search(query="", domain="gene", keywords=["BRAF"]) assert "API connection failed" in str(exc_info.value) @pytest.mark.asyncio async def test_drug_not_found(self, monkeypatch): """Test handling when drug is not found.""" class MockBioThingsClient: async def _query_drug(self, query): return [] # No results monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) results = await search( query="", domain="drug", keywords=["nonexistent"] ) assert "results" in results actual_results = [ r for r in results["results"] if r["id"] != "thinking-reminder" ] assert len(actual_results) == 0 @pytest.mark.asyncio async def test_disease_invalid_id(self, monkeypatch): """Test handling of invalid disease ID in fetch.""" class MockBioThingsClient: async def get_disease_info(self, disease_id): return None # Not found monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) result = await fetch(id="INVALID:12345", domain="disease") assert "error" in result assert "not found" in result["error"].lower() @pytest.mark.asyncio async def test_gene_partial_data(self, monkeypatch): """Test handling of incomplete gene data.""" mock_gene_query = [{"_id": "673"}] # Missing symbol mock_gene_details = { "_id": "673", # Missing symbol, name, summary "entrezgene": 673, } class MockBioThingsClient: async def _query_gene(self, query): return mock_gene_query async def _get_gene_by_id(self, gene_id): from biomcp.integrations.biothings_client import GeneInfo return GeneInfo(**mock_gene_details) monkeypatch.setattr( "biomcp.router.BioThingsClient", MockBioThingsClient ) results = await search(query="", domain="gene", keywords=["673"]) assert "results" in results actual_results = [ r for r in results["results"] if r["id"] != "thinking-reminder" ] assert len(actual_results) == 1 # Should handle missing data gracefully assert actual_results[0]["id"] == "673"

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/genomoncology/biomcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server