ailixir-drug-repurposing / test_integration.py
AILIXIR Bot
Auto-sync: ea9a2035cd92f6b1521e3c5f9d31e8c453a93d43
4a8b134
Raw
History Blame Contribute Delete
12.5 kB
#!/usr/bin/env python
"""
Integration Test Suite for Drug Repurposing API
Tests all endpoints and verifies the entire pipeline works with real APIs
Run with: python test_integration.py
"""
import requests
import json
import time
from typing import Dict, Any, Tuple, Optional, List
import sys
# Configuration
API_BASE_URL = "http://localhost:8000"
TIMEOUT = 120 # 2 minutes timeout for screening
class Colors:
"""Terminal colors"""
GREEN = '\033[92m'
RED = '\033[91m'
YELLOW = '\033[93m'
BLUE = '\033[94m'
RESET = '\033[0m'
def print_header(text: str):
"""Print a formatted header"""
print(f"\n{Colors.BLUE}{'='*70}")
print(f" {text}")
print(f"{'='*70}{Colors.RESET}\n")
def print_success(text: str):
"""Print success message"""
print(f"{Colors.GREEN}βœ… {text}{Colors.RESET}")
def print_error(text: str):
"""Print error message"""
print(f"{Colors.RED}❌ {text}{Colors.RESET}")
def print_info(text: str):
"""Print info message"""
print(f"{Colors.YELLOW}ℹ️ {text}{Colors.RESET}")
def test_health_check() -> bool:
"""Test health check endpoint"""
print_header("Test 1: Health Check")
try:
response = requests.get(f"{API_BASE_URL}/health", timeout=10)
if response.status_code == 200:
data = response.json()
print_success(f"API is healthy: {data['status']}")
print(f" Version: {data['version']}")
print(f" Service: {data['service']}")
return True
else:
print_error(f"Health check failed with status {response.status_code}")
return False
except requests.exceptions.ConnectionError:
print_error("Cannot connect to API. Is the server running on port 8000?")
print_info("Start the server with: python -m uvicorn app.main:app --reload")
return False
except Exception as e:
print_error(f"Health check error: {str(e)}")
return False
def test_model_status() -> bool:
"""Test model status endpoint"""
print_header("Test 2: Model Status")
try:
response = requests.get(f"{API_BASE_URL}/api/v1/model-status", timeout=10)
if response.status_code == 200:
data = response.json()
print_success("Model status retrieved:")
print(f" Model: {data.get('model', 'N/A')}")
print(f" Device: {data.get('device', 'N/A')}")
print(f" GPU Available: {data.get('gpu_available', False)}")
print(f" Model Loaded: {data.get('model_loaded', False)}")
print(f" Using Mock: {data.get('using_mock_mode', False)}")
print(f" Batch Size: {data.get('batch_size', 'N/A')}")
print(f" Max Drugs: {data.get('max_drugs_per_screening', 'N/A')}")
if not data.get('model_loaded') and data.get('using_mock_mode'):
print_error("WARNING: DeepPurpose not loaded - using mock predictions")
print_info("Install DeepPurpose for real predictions:")
print_info(" pip install git+https://github.com/kexinhuang12345/DeepPurpose.git")
return True
else:
print_error(f"Model status failed with status {response.status_code}")
return False
except Exception as e:
print_error(f"Model status error: {str(e)}")
return False
def test_disease_targets() -> Tuple[bool, Optional[List[Dict]]]:
"""Test disease targets endpoint (Stage 1)"""
print_header("Test 3: Disease Target Identification (OpenTargets)")
disease = "Type 2 Diabetes"
payload = {
"disease_name": disease,
"top_n": 5
}
try:
print_info(f"Searching for targets associated with: {disease}")
response = requests.post(
f"{API_BASE_URL}/api/v1/disease-targets",
json=payload,
timeout=30
)
if response.status_code == 200:
data = response.json()
print_success(f"Found {data['total_targets']} target proteins:")
for i, target in enumerate(data['targets'][:3], 1):
print(f" {i}. {target['symbol']} ({target['name']}) - Score: {target['score']}")
if len(data['targets']) > 3:
print(f" ... and {len(data['targets']) - 3} more")
return True, data['targets']
else:
print_error(f"Disease target search failed: {response.status_code}")
print_error(f"Response: {response.text}")
return False, None
except requests.exceptions.Timeout:
print_error(f"Request timeout - OpenTargets API slow or unavailable")
return False, None
except Exception as e:
print_error(f"Disease targets error: {str(e)}")
return False, None
def test_protein_sequences(targets: Optional[List[Dict]]) -> Tuple[bool, Optional[List[Dict]]]:
"""Test protein sequences endpoint (Stage 2)"""
print_header("Test 4: Protein Sequence Retrieval (UniProt)")
if not targets or len(targets) == 0:
print_error("No targets to test (skipping)")
return False, None
payload = targets[:3] # Test with first 3 targets
try:
print_info(f"Fetching sequences for {len(payload)} targets...")
response = requests.post(
f"{API_BASE_URL}/api/v1/protein-sequences",
json=payload,
timeout=30
)
if response.status_code == 200:
data = response.json()
print_success(f"Successfully fetched {data['total_found']} sequences:")
for target in data['targets'][:2]:
seq_len = len(target.get('sequence', ''))
print(f" {target['symbol']}: {seq_len} amino acids")
return True, data['targets']
else:
print_error(f"Protein sequence fetch failed: {response.status_code}")
return False, None
except Exception as e:
print_error(f"Protein sequences error: {str(e)}")
return False, None
def test_drug_library() -> Tuple[bool, Optional[List[Dict]]]:
"""Test drug library endpoint (Stage 3)"""
print_header("Test 5: Drug Library Loading (TDC)")
try:
print_info("Loading drug library...")
response = requests.get(
f"{API_BASE_URL}/api/v1/drug-library",
timeout=30
)
if response.status_code == 200:
data = response.json()
print_success(f"Loaded {data['total_drugs']} FDA-approved drugs:")
for i, drug in enumerate(data['drugs'][:3], 1):
print(f" {i}. {drug['name']} (ID: {drug.get('drug_id', 'N/A')})")
print(f" SMILES: {drug['smiles'][:30]}...")
if len(data['drugs']) > 3:
print(f" ... and {len(data['drugs']) - 3} more")
return True, data['drugs']
else:
print_error(f"Drug library load failed: {response.status_code}")
return False, None
except Exception as e:
print_error(f"Drug library error: {str(e)}")
return False, None
def test_virtual_screening() -> bool:
"""Test full virtual screening endpoint (All stages)"""
print_header("Test 6: FULL VIRTUAL SCREENING PIPELINE")
payload = {
"disease_name": "Type 2 Diabetes",
"min_score": 0.5,
"top_n_targets": 5,
"known_drugs": ["Metformin", "Insulin"]
}
print_info("This is the REAL END-TO-END PIPELINE:")
print_info(" Stage 1: Disease targets (OpenTargets)")
print_info(" Stage 2: Protein sequences (UniProt)")
print_info(" Stage 3: Drug library (TDC)")
print_info(" Stage 4: AI predictions (DeepPurpose)")
print_info(" Stage 5: Result processing")
print_info("")
print_info(f"Request: {json.dumps(payload, indent=2)}")
print_info("")
print_info("⏳ Running screening... (this may take 1-2 minutes)")
start_time = time.time()
try:
response = requests.post(
f"{API_BASE_URL}/api/v1/screen",
json=payload,
timeout=TIMEOUT
)
elapsed = time.time() - start_time
if response.status_code == 200:
data = response.json()
print_success(f"βœ… SCREENING COMPLETE in {elapsed:.1f} seconds")
print("")
print(f"Disease Targeted: {data['disease']}")
print(f"Targets Used: {data['total_targets_found']}")
print(f"Drugs Screened: {data['total_drugs_screened']}")
print(f"Total Predictions: {data['total_pairs_evaluated']}")
print("")
if data['top_candidates']:
print_success(f"Top {len(data['top_candidates'])} candidates:")
for i, result in enumerate(data['top_candidates'], 1):
print(f" {i}. {result['drug_name']} β†’ {result['target_symbol']}")
print(f" Binding Score: {result['binding_score']:.3f} | {result['status']}")
else:
print_error("No results found")
return True
else:
print_error(f"Screening failed: {response.status_code}")
print_error(f"Response: {response.text}")
return False
except requests.exceptions.Timeout:
elapsed = time.time() - start_time
print_error(f"Request timeout after {elapsed:.1f} seconds")
print_info("The screening took too long. This could be:")
print_info(" 1. OpenTargets/UniProt APIs are slow")
print_info(" 2. DeepPurpose is running on CPU (try GPU)")
print_info(" 3. Network connection is slow")
return False
except Exception as e:
print_error(f"Screening error: {str(e)}")
return False
def run_all_tests():
"""Run all tests"""
print(f"\n{Colors.BLUE}")
print("╔══════════════════════════════════════════════════════════════════╗")
print("β•‘ 🧬 DRUG REPURPOSING API - COMPREHENSIVE TEST SUITE β•‘")
print("β•‘ Testing Production-Ready End-to-End Pipeline β•‘")
print("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•")
print(f"{Colors.RESET}\n")
results = []
# Test 1: Health
results.append(("Health Check", test_health_check()))
if not results[-1][1]:
print_error("API is not responding. Make sure the server is running.")
print_info("Start with: python -m uvicorn app.main:app --reload")
return
# Test 2: Model Status
results.append(("Model Status", test_model_status()))
# Test 3: Disease Targets
success, targets = test_disease_targets()
results.append(("Disease Targets", success))
# Test 4: Protein Sequences (requires targets)
if targets:
success, sequences = test_protein_sequences(targets)
results.append(("Protein Sequences", success))
else:
results.append(("Protein Sequences", False))
# Test 5: Drug Library
success, drugs = test_drug_library()
results.append(("Drug Library", success))
# Test 6: Full Pipeline
results.append(("Full Virtual Screening", test_virtual_screening()))
# Print summary
print_header("TEST SUMMARY")
passed = sum(1 for _, success in results if success)
total = len(results)
for test_name, success in results:
status = f"{Colors.GREEN}βœ… PASSED{Colors.RESET}" if success else f"{Colors.RED}❌ FAILED{Colors.RESET}"
print(f"{test_name:.<50} {status}")
print("")
print_success(f"TOTAL: {passed}/{total} tests passed")
if passed == total:
print_success("πŸŽ‰ ALL TESTS PASSED! System is production-ready.")
else:
print_error(f"⚠️ {total - passed} test(s) failed. See details above.")
print("")
if __name__ == "__main__":
try:
run_all_tests()
except KeyboardInterrupt:
print_error("\nTests interrupted by user")
sys.exit(1)
except Exception as e:
print_error(f"Test suite error: {str(e)}")
sys.exit(1)