fbmc-chronos2 / test_runner.py
Evgueni Poloukarov
feat: add automated notebook test runner
6ab2f4a
#!/usr/bin/env python3
"""
Test runner for FBMC notebooks on HuggingFace Space
Executes notebooks and reports results
"""
import subprocess
import sys
import os
from pathlib import Path
from datetime import datetime
def run_notebook(notebook_path, timeout=600):
"""Execute a Jupyter notebook and return success status"""
print(f"\n{'='*60}")
print(f"Running: {notebook_path.name}")
print(f"Started: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*60}\n")
cmd = [
"jupyter", "nbconvert",
"--to", "notebook",
"--execute",
"--inplace",
f"--ExecutePreprocessor.timeout={timeout}",
str(notebook_path)
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout+60)
if result.returncode == 0:
print(f"\n✅ SUCCESS: {notebook_path.name}")
return True
else:
print(f"\n❌ FAILED: {notebook_path.name}")
print(f"Error: {result.stderr}")
return False
except subprocess.TimeoutExpired:
print(f"\n❌ TIMEOUT: {notebook_path.name} exceeded {timeout}s")
return False
except Exception as e:
print(f"\n❌ ERROR: {str(e)}")
return False
def main():
# Check environment
if "HF_TOKEN" not in os.environ:
print("⚠️ Warning: HF_TOKEN not set!")
print(" Set with: export HF_TOKEN='your_token'\n")
# Check GPU
try:
import torch
print(f"GPU Available: {torch.cuda.is_available()}")
if torch.cuda.is_available():
print(f"GPU Name: {torch.cuda.get_device_name(0)}")
print(f"GPU Memory: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f} GB")
except ImportError:
print("⚠️ PyTorch not installed")
print("\n")
# Define test sequence
tests = [
("/data/inference_smoke_test.ipynb", 300), # 5 min
# Uncomment to run full tests:
# ("/data/inference_full_14day.ipynb", 900), # 15 min
# ("/data/evaluation.ipynb", 300), # 5 min
]
results = {}
for notebook_path, timeout in tests:
nb_path = Path(notebook_path)
if not nb_path.exists():
print(f"❌ Not found: {notebook_path}")
results[nb_path.name] = False
continue
success = run_notebook(nb_path, timeout)
results[nb_path.name] = success
# Summary
print(f"\n{'='*60}")
print("SUMMARY")
print(f"{'='*60}")
for name, success in results.items():
status = "✅ PASS" if success else "❌ FAIL"
print(f"{status}: {name}")
total = len(results)
passed = sum(results.values())
print(f"\nResults: {passed}/{total} passed")
return 0 if all(results.values()) else 1
if __name__ == "__main__":
sys.exit(main())