"""Pytest configuration and fixtures for otar_mcp tests."""
from unittest.mock import MagicMock, Mock
import pytest
from graphql import GraphQLSchema, build_schema
# ============================================================================
# Test Markers Configuration
# ============================================================================
def pytest_configure(config):
"""Register custom markers."""
config.addinivalue_line("markers", "integration: marks tests as integration tests (requires real API access)")
# ============================================================================
# API Endpoint Fixtures
# ============================================================================
@pytest.fixture
def mock_api_endpoint() -> str:
"""Mock Open Targets Platform API endpoint for testing."""
return "https://api.platform.opentargets.org/api/v4/graphql"
# ============================================================================
# GraphQL Query Fixtures
# ============================================================================
@pytest.fixture
def sample_query_string() -> str:
"""Sample GraphQL query string for testing."""
return """
query testQuery {
target(ensemblId: "ENSG00000141510") {
id
approvedSymbol
}
}
"""
@pytest.fixture
def sample_variables() -> dict:
"""Sample GraphQL query variables for testing."""
return {"ensemblId": "ENSG00000141510"}
@pytest.fixture
def sample_batch_variables() -> list[dict]:
"""Sample batch query variables for testing."""
return [
{"ensemblId": "ENSG00000141510"},
{"ensemblId": "ENSG00000012048"},
{"ensemblId": "ENSG00000139618"},
]
@pytest.fixture
def sample_search_query() -> str:
"""Sample search query GraphQL string."""
return """
query searchQuery($queryString: String!) {
search(queryString: $queryString) {
hits {
id
entity
name
}
}
}
"""
# ============================================================================
# GraphQL Response Fixtures
# ============================================================================
@pytest.fixture
def sample_graphql_response() -> dict:
"""Sample successful GraphQL response."""
return {"target": {"id": "ENSG00000141510", "approvedSymbol": "TP53"}}
@pytest.fixture
def sample_search_response() -> dict:
"""Sample search API response."""
return {
"search": {
"hits": [
{"id": "ENSG00000012048", "entity": "target", "name": "BRCA1"},
{"id": "EFO_0000305", "entity": "disease", "name": "breast carcinoma"},
{"id": "CHEMBL25", "entity": "drug", "name": "Aspirin"},
],
},
}
@pytest.fixture
def sample_error_response() -> dict:
"""Sample error response from GraphQL."""
return {"status": "error", "message": "Query execution failed"}
# ============================================================================
# GraphQL Client Mock Fixtures
# ============================================================================
@pytest.fixture
def mock_graphql_schema() -> GraphQLSchema:
"""Mock GraphQL schema for testing."""
schema_definition = """
type Query {
target(ensemblId: String!): Target
disease(efoId: String!): Disease
drug(chemblId: String!): Drug
search(queryString: String!): SearchResult
}
type Target {
id: String!
approvedSymbol: String
approvedName: String
}
type Disease {
id: String!
name: String
}
type Drug {
id: String!
name: String
}
type SearchResult {
hits: [SearchHit]
}
type SearchHit {
id: String!
entity: String!
name: String
}
"""
return build_schema(schema_definition)
@pytest.fixture
def mock_graphql_client(sample_graphql_response, mock_graphql_schema):
"""Mock GQL Client for testing."""
client = MagicMock()
client.execute.return_value = sample_graphql_response
client.schema = mock_graphql_schema
client.__enter__ = Mock(return_value=client)
client.__exit__ = Mock(return_value=False)
return client
# ============================================================================
# JQ Filter Fixtures
# ============================================================================
@pytest.fixture
def simple_jq_filter() -> str:
"""Simple jq filter for testing."""
return ".data.target"
@pytest.fixture
def complex_jq_filter() -> str:
"""Complex jq filter for testing."""
return ".data.target | {id, symbol: .approvedSymbol}"
# ============================================================================
# Environment Variable Fixtures
# ============================================================================
@pytest.fixture
def clean_env(monkeypatch):
"""Remove all Open Targets Platform environment variables."""
env_vars = [
"OTP_MCP_API_ENDPOINT",
"OTP_MCP_SERVER_NAME",
"OTP_MCP_HTTP_HOST",
"OTP_MCP_HTTP_PORT",
"OTP_MCP_API_CALL_TIMEOUT",
"OTP_MCP_JQ_ENABLED",
]
for var in env_vars:
monkeypatch.delenv(var, raising=False)
@pytest.fixture
def custom_env(monkeypatch):
"""Set custom environment variables for testing."""
monkeypatch.setenv("OTP_MCP_API_ENDPOINT", "https://custom.api.test/graphql")
monkeypatch.setenv("OTP_MCP_SERVER_NAME", "Test Server")
monkeypatch.setenv("OTP_MCP_HTTP_HOST", "0.0.0.0")
monkeypatch.setenv("OTP_MCP_HTTP_PORT", "9000")
monkeypatch.setenv("OTP_MCP_API_CALL_TIMEOUT", "60")
# ============================================================================
# File System Fixtures
# ============================================================================
@pytest.fixture
def sample_gql_file_content() -> str:
"""Sample .gql file content with metadata."""
return """# Query Name: GetTargetInfo
# Entity Type: target
# Description: Retrieve basic information about a target
# Variables: ensemblId (String!) - The ENSEMBL ID of the target
# Pagination Behavior: None - single target query
query GetTargetInfo($ensemblId: String!) {
target(ensemblId: $ensemblId) {
id
approvedSymbol
approvedName
}
}
"""
@pytest.fixture
def sample_category_descriptors() -> dict:
"""Sample category descriptors mapping."""
return {
"target": "Queries related to genes and protein targets",
"disease": "Queries for disease and phenotype information",
"drug": "Queries for drug and molecule information",
}
@pytest.fixture
def sample_category_query_mapper() -> dict:
"""Sample category to query mapping."""
return {
"target": ["GetTargetInfo", "GetTargetAssociations"],
"disease": ["GetDiseaseInfo", "GetDiseaseAssociations"],
"drug": ["GetDrugInfo", "GetDrugMechanisms"],
}
# ============================================================================
# Batch Query Fixtures
# ============================================================================
@pytest.fixture
def batch_query_string() -> str:
"""GraphQL query string for batch testing."""
return """
query GetTarget($ensemblId: String!) {
target(ensemblId: $ensemblId) {
id
approvedSymbol
}
}
"""
@pytest.fixture
def batch_variables_with_key() -> list[dict]:
"""Batch variables with consistent key field."""
return [
{"ensemblId": "ENSG00000141510", "name": "TP53"},
{"ensemblId": "ENSG00000012048", "name": "BRCA1"},
{"ensemblId": "ENSG00000139618", "name": "BRCA2"},
]
@pytest.fixture
def batch_expected_results() -> dict:
"""Expected batch query results."""
return {
"ENSG00000141510": {
"status": "success",
"data": {"target": {"id": "ENSG00000141510", "approvedSymbol": "TP53"}},
},
"ENSG00000012048": {
"status": "success",
"data": {"target": {"id": "ENSG00000012048", "approvedSymbol": "BRCA1"}},
},
"ENSG00000139618": {
"status": "success",
"data": {"target": {"id": "ENSG00000139618", "approvedSymbol": "BRCA2"}},
},
}