train-schedule-optimization / api /test_greedyoptim_api.py
Arpit-Bansal's picture
update synthetic generation
51de58f
#!/usr/bin/env python3
"""
Test script for GreedyOptim API
Tests all endpoints with sample data
"""
import requests
import json
from datetime import datetime, timedelta
BASE_URL = "http://localhost:7860"
def test_health():
"""Test health check endpoint"""
print("\n" + "="*70)
print("Testing Health Check")
print("="*70)
response = requests.get(f"{BASE_URL}/health")
print(f"Status: {response.status_code}")
print(f"Response: {json.dumps(response.json(), indent=2)}")
return response.status_code == 200
def test_methods():
"""Test methods listing endpoint"""
print("\n" + "="*70)
print("Testing Methods Listing")
print("="*70)
response = requests.get(f"{BASE_URL}/methods")
print(f"Status: {response.status_code}")
if response.status_code == 200:
methods = response.json()
print(f"\nAvailable Methods: {len(methods['available_methods'])}")
for method, info in methods['available_methods'].items():
print(f" {method}: {info['name']}")
return response.status_code == 200
def test_generate_synthetic():
"""Test synthetic data generation"""
print("\n" + "="*70)
print("Testing Synthetic Data Generation")
print("="*70)
payload = {
"num_trainsets": 25,
"maintenance_rate": 0.1,
"availability_rate": 0.8
}
response = requests.post(f"{BASE_URL}/generate-synthetic", json=payload)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
print(f"\nGenerated Data:")
print(f" Trainsets: {result['metadata']['num_trainsets']}")
print(f" Fitness Certificates: {result['metadata']['num_fitness_certificates']}")
print(f" Job Cards: {result['metadata']['num_job_cards']}")
print(f" Component Health: {result['metadata']['num_component_health']}")
return result['data'] # Return for use in other tests
return None
def test_validate(data):
"""Test data validation endpoint"""
print("\n" + "="*70)
print("Testing Data Validation")
print("="*70)
# Create request from synthetic data
request_data = {
"trainset_status": data['trainset_status'],
"fitness_certificates": data['fitness_certificates'],
"job_cards": data['job_cards'],
"component_health": data['component_health'],
"method": "ga"
}
response = requests.post(f"{BASE_URL}/validate", json=request_data)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
print(f"\nValidation Result:")
print(f" Valid: {result['valid']}")
if result['valid']:
print(f" Trainsets: {result['num_trainsets']}")
print(f" Certificates: {result['num_certificates']}")
print(f" Job Cards: {result['num_job_cards']}")
print(f" Component Health: {result['num_component_health']}")
else:
print(f" Errors: {len(result.get('validation_errors', []))}")
return response.status_code == 200
def test_optimize(data):
"""Test optimization endpoint"""
print("\n" + "="*70)
print("Testing Schedule Optimization")
print("="*70)
# Create optimization request
request_data = {
"trainset_status": data['trainset_status'],
"fitness_certificates": data['fitness_certificates'],
"job_cards": data['job_cards'],
"component_health": data['component_health'],
"method": "ga",
"config": {
"required_service_trains": 15,
"min_standby": 2,
"population_size": 30,
"generations": 50
}
}
print(f"Optimizing with method: {request_data['method']}")
print(f"Trainsets: {len(request_data['trainset_status'])}")
response = requests.post(f"{BASE_URL}/optimize", json=request_data)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
print(f"\nOptimization Results:")
print(f" Method: {result['method']}")
print(f" Fitness Score: {result['fitness_score']:.4f}")
print(f" Execution Time: {result['execution_time_seconds']:.3f}s")
print(f"\n Schedule Allocation:")
print(f" In Service: {result['num_service']} trains")
print(f" Standby: {result['num_standby']} trains")
print(f" Maintenance: {result['num_maintenance']} trains")
print(f" Unavailable: {result['num_unavailable']} trains")
print(f"\n Detailed Scores:")
print(f" Service: {result['service_score']:.4f}")
print(f" Standby: {result['standby_score']:.4f}")
print(f" Health: {result['health_score']:.4f}")
print(f" Certificate: {result['certificate_score']:.4f}")
print(f"\n Constraints Satisfied: {result['constraints_satisfied']}")
if result.get('warnings'):
print(f" Warnings: {len(result['warnings'])}")
for warning in result['warnings'][:3]:
print(f" - {warning}")
else:
print(f"Error: {response.text}")
return response.status_code == 200
def test_compare(data):
"""Test method comparison endpoint"""
print("\n" + "="*70)
print("Testing Method Comparison")
print("="*70)
# Create comparison request with all trainsets and all methods
request_data = {
"trainset_status": data['trainset_status'],
"fitness_certificates": data['fitness_certificates'],
"job_cards": data.get('job_cards', []),
"component_health": data['component_health'],
"methods": ["ga", "pso", "sa", "cmaes", "nsga2"],
"config": {
"required_service_trains": 15,
"min_standby": 2,
"population_size": 30,
"generations": 50
}
}
print(f"Comparing methods: {request_data['methods']}")
print(f"Trainsets: {len(request_data['trainset_status'])}")
response = requests.post(f"{BASE_URL}/compare", json=request_data)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
print(f"\nComparison Results:")
print(f" Total Execution Time: {result['summary']['total_execution_time']:.3f}s")
print(f" Best Method: {result['summary']['best_method']}")
print(f" Best Score: {result['summary']['best_score']:.4f}")
print(f"\n Individual Results:")
for method, method_result in result['methods'].items():
print(f" {method.upper()}:")
print(f" Fitness: {method_result['fitness_score']:.4f}")
print(f" Service: {method_result['num_service']} trains")
print(f" Time: {method_result.get('execution_time_seconds', 'N/A')}")
else:
print(f"Error: {response.text}")
return response.status_code == 200
def test_custom_data():
"""Test with minimal custom data"""
print("\n" + "="*70)
print("Testing with Custom Minimal Data")
print("="*70)
# Create minimal valid data with 25 trainsets
custom_data = {
"trainset_status": [
{"trainset_id": f"KMRL-{i:02d}", "operational_status": "Available", "total_mileage_km": 50000.0}
for i in range(1, 26)
],
"fitness_certificates": [
{
"trainset_id": f"KMRL-{i:02d}",
"department": "Safety",
"status": "Valid",
"expiry_date": (datetime.now() + timedelta(days=365)).isoformat()
}
for i in range(1, 26)
],
"job_cards": [], # No job cards
"component_health": [
{
"trainset_id": f"KMRL-{i:02d}",
"component": "Brakes",
"status": "Good",
"wear_level": 20.0
}
for i in range(1, 26)
],
"method": "ga",
"config": {
"required_service_trains": 15,
"min_standby": 2,
"population_size": 30,
"generations": 50
}
}
print(f"Testing with {len(custom_data['trainset_status'])} trainsets")
response = requests.post(f"{BASE_URL}/optimize", json=custom_data)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
print(f"\nOptimization successful!")
print(f" Fitness: {result['fitness_score']:.4f}")
print(f" In Service: {result['num_service']}")
print(f" Time: {result['execution_time_seconds']:.3f}s")
else:
print(f"Error: {response.text}")
return response.status_code == 200
def test_schedule(data):
"""Test full schedule generation endpoint"""
print("\n" + "="*70)
print("Testing Full Schedule Generation (/schedule)")
print("="*70)
# Create schedule request
request_data = {
"trainset_status": data['trainset_status'],
"fitness_certificates": data['fitness_certificates'],
"job_cards": data.get('job_cards', []),
"component_health": data['component_health'],
"method": "ga",
"config": {
"required_service_trains": 6,
"min_standby": 2,
"population_size": 30,
"generations": 50
}
}
print(f"Generating schedule with method: {request_data['method']}")
print(f"Trainsets: {len(request_data['trainset_status'])}")
response = requests.post(f"{BASE_URL}/schedule", json=request_data)
print(f"Status: {response.status_code}")
if response.status_code == 200:
result = response.json()
print(f"\nSchedule Generated:")
print(f" Schedule ID: {result['schedule_id']}")
print(f" Valid From: {result['valid_from']}")
print(f" Valid Until: {result['valid_until']}")
print(f" Depot: {result['depot']}")
print(f"\n Fleet Summary:")
fleet = result['fleet_summary']
print(f" Total Trainsets: {fleet['total_trainsets']}")
print(f" Revenue Service: {fleet['revenue_service']}")
print(f" Standby: {fleet['standby']}")
print(f" Maintenance: {fleet['maintenance']}")
print(f" Availability: {fleet['availability_percent']}%")
print(f"\n Optimization Metrics:")
metrics = result['optimization_metrics']
print(f" Fitness Score: {metrics['fitness_score']:.4f}")
print(f" Method: {metrics['method']}")
print(f" Total Planned KM: {metrics['total_planned_km']}")
print(f" Runtime: {metrics['optimization_runtime_ms']}ms")
# Show service trainsets with blocks
print(f"\n Service Trainsets with Blocks:")
service_count = 0
for ts in result['trainsets']:
if ts['status'] == 'REVENUE_SERVICE':
service_count += 1
blocks = ts.get('service_blocks', [])
print(f" {ts['trainset_id']}: {len(blocks)} blocks, {ts['daily_km_allocation']} km")
if blocks and service_count <= 2: # Show blocks for first 2 service trains
for block in blocks[:3]:
print(f" - {block['block_id']}: {block['departure_time']} {block['origin']}{block['destination']}")
if len(blocks) > 3:
print(f" ... and {len(blocks) - 3} more blocks")
# Show alerts
if result.get('alerts'):
print(f"\n Alerts: {len(result['alerts'])}")
for alert in result['alerts'][:3]:
print(f" [{alert['severity']}] {alert['trainset_id']}: {alert['message']}")
else:
print(f"Error: {response.text}")
return response.status_code == 200
def test_schedule_methods(data):
"""Test schedule generation with different optimization methods"""
print("\n" + "="*70)
print("Testing Schedule with Different Methods")
print("="*70)
methods = ['ga', 'pso', 'sa', 'nsga2']
results = {}
for method in methods:
request_data = {
"trainset_status": data['trainset_status'][:15],
"fitness_certificates": [fc for fc in data['fitness_certificates']
if fc['trainset_id'] in [ts['trainset_id'] for ts in data['trainset_status'][:15]]],
"job_cards": [],
"component_health": [ch for ch in data['component_health']
if ch['trainset_id'] in [ts['trainset_id'] for ts in data['trainset_status'][:15]]],
"method": method,
"config": {
"required_service_trains": 6,
"min_standby": 2,
"population_size": 20,
"generations": 30
}
}
response = requests.post(f"{BASE_URL}/schedule", json=request_data)
if response.status_code == 200:
result = response.json()
total_blocks = sum(
len(ts.get('service_blocks', []))
for ts in result['trainsets']
if ts['status'] == 'REVENUE_SERVICE'
)
results[method] = {
'success': True,
'blocks': total_blocks,
'fitness': result['optimization_metrics']['fitness_score'],
'service': result['fleet_summary']['revenue_service']
}
print(f" {method.upper()}: ✓ {total_blocks} blocks, {results[method]['service']} service trains")
else:
results[method] = {'success': False}
print(f" {method.upper()}: ✗ Failed")
return all(r['success'] for r in results.values())
def main():
"""Run all tests"""
print("=" * 70)
print("GREEDYOPTIM API TEST SUITE")
print("=" * 70)
print(f"Testing API at: {BASE_URL}")
print(f"Start Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
results = {}
# Run tests
results['health'] = test_health()
results['methods'] = test_methods()
# Generate synthetic data for remaining tests
synthetic_data = test_generate_synthetic()
if synthetic_data:
results['validate'] = test_validate(synthetic_data)
results['optimize'] = test_optimize(synthetic_data)
results['schedule'] = test_schedule(synthetic_data)
results['schedule_methods'] = test_schedule_methods(synthetic_data)
results['compare'] = test_compare(synthetic_data)
results['custom'] = test_custom_data()
# Summary
print("\n" + "="*70)
print("TEST SUMMARY")
print("="*70)
passed = sum(1 for v in results.values() if v)
total = len(results)
print(f"\nTests Passed: {passed}/{total}")
for test_name, passed in results.items():
status = "✓ PASS" if passed else "✗ FAIL"
print(f" {status} - {test_name}")
print("\n" + "="*70)
print(f"End Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*70)
if __name__ == "__main__":
try:
main()
except requests.exceptions.ConnectionError:
print("\n✗ ERROR: Could not connect to API")
print(" Make sure the API is running:")
print(" python api/greedyoptim_api.py")
except Exception as e:
print(f"\n✗ ERROR: {str(e)}")