File size: 12,540 Bytes
4a8b134 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 | #!/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)
|