219 lines
7.4 KiB
Python
219 lines
7.4 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Comprehensive test to verify all services can start correctly after database refactoring
|
|
"""
|
|
|
|
import subprocess
|
|
import time
|
|
import sys
|
|
from typing import Dict, List, Tuple
|
|
|
|
# Service configurations
|
|
SERVICES = {
|
|
"infrastructure": {
|
|
"services": ["redis", "rabbitmq", "auth-db", "data-db", "tenant-db",
|
|
"forecasting-db", "notification-db", "training-db", "prometheus"],
|
|
"wait_time": 60
|
|
},
|
|
"core": {
|
|
"services": ["auth-service", "data-service"],
|
|
"wait_time": 45,
|
|
"health_checks": [
|
|
("auth-service", "http://localhost:8001/health"),
|
|
("data-service", "http://localhost:8002/health"),
|
|
]
|
|
},
|
|
"business": {
|
|
"services": ["tenant-service", "training-service", "forecasting-service",
|
|
"notification-service"],
|
|
"wait_time": 45,
|
|
"health_checks": [
|
|
("tenant-service", "http://localhost:8003/health"),
|
|
("training-service", "http://localhost:8004/health"),
|
|
("forecasting-service", "http://localhost:8005/health"),
|
|
("notification-service", "http://localhost:8006/health"),
|
|
]
|
|
},
|
|
"ui": {
|
|
"services": ["gateway", "dashboard"],
|
|
"wait_time": 30,
|
|
"health_checks": [
|
|
("gateway", "http://localhost:8000/health"),
|
|
]
|
|
}
|
|
}
|
|
|
|
def run_command(command: str, description: str = None) -> Tuple[int, str]:
|
|
"""Run a shell command and return exit code and output"""
|
|
if description:
|
|
print(f"Running: {command}")
|
|
|
|
try:
|
|
result = subprocess.run(
|
|
command,
|
|
shell=True,
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=120
|
|
)
|
|
return result.returncode, result.stdout + result.stderr
|
|
except subprocess.TimeoutExpired:
|
|
return -1, f"Command timed out: {command}"
|
|
|
|
def check_container_status() -> Dict[str, str]:
|
|
"""Get status of all containers"""
|
|
exit_code, output = run_command("docker compose ps")
|
|
|
|
if exit_code != 0:
|
|
return {}
|
|
|
|
status_dict = {}
|
|
lines = output.strip().split('\n')[1:] # Skip header
|
|
|
|
for line in lines:
|
|
if line.strip():
|
|
parts = line.split()
|
|
if len(parts) >= 4:
|
|
name = parts[0].replace('bakery-', '')
|
|
status = ' '.join(parts[3:])
|
|
status_dict[name] = status
|
|
|
|
return status_dict
|
|
|
|
def check_health(service: str, url: str) -> bool:
|
|
"""Check if a service health endpoint is responding"""
|
|
try:
|
|
# Use curl for health checks instead of requests
|
|
exit_code, _ = run_command(f"curl -f {url}", None)
|
|
return exit_code == 0
|
|
except Exception as e:
|
|
print(f"❌ Health check failed for {service}: {str(e)}")
|
|
return False
|
|
|
|
def wait_for_healthy_containers(services: List[str], max_wait: int = 60) -> bool:
|
|
"""Wait for containers to become healthy"""
|
|
print(f"⏳ Waiting up to {max_wait} seconds for services to become healthy...")
|
|
|
|
for i in range(max_wait):
|
|
status = check_container_status()
|
|
healthy_count = 0
|
|
|
|
for service in services:
|
|
service_status = status.get(service, "not found")
|
|
if "healthy" in service_status.lower() or "up" in service_status.lower():
|
|
healthy_count += 1
|
|
|
|
if healthy_count == len(services):
|
|
print(f"✅ All {len(services)} services are healthy after {i+1} seconds")
|
|
return True
|
|
|
|
time.sleep(1)
|
|
|
|
print(f"⚠️ Only {healthy_count}/{len(services)} services became healthy")
|
|
return False
|
|
|
|
def test_service_group(group_name: str, config: Dict) -> bool:
|
|
"""Test a group of services"""
|
|
print(f"\n🧪 Testing {group_name} services...")
|
|
print(f"Services: {', '.join(config['services'])}")
|
|
|
|
# Start services
|
|
services_str = ' '.join(config['services'])
|
|
exit_code, output = run_command(f"docker compose up -d {services_str}")
|
|
|
|
if exit_code != 0:
|
|
print(f"❌ Failed to start {group_name} services")
|
|
print(output[-1000:]) # Last 1000 chars of output
|
|
return False
|
|
|
|
print(f"✅ {group_name.title()} services started")
|
|
|
|
# Wait for services to be healthy
|
|
if not wait_for_healthy_containers(config['services'], config['wait_time']):
|
|
print(f"⚠️ Some {group_name} services didn't become healthy")
|
|
|
|
# Show container status
|
|
status = check_container_status()
|
|
for service in config['services']:
|
|
service_status = status.get(service, "not found")
|
|
print(f" {service}: {service_status}")
|
|
|
|
# Show logs for failed services
|
|
for service in config['services']:
|
|
service_status = status.get(service, "")
|
|
if "unhealthy" in service_status.lower() or "restarting" in service_status.lower():
|
|
print(f"\n📋 Logs for failed service {service}:")
|
|
_, logs = run_command(f"docker compose logs --tail=10 {service}")
|
|
print(logs[-800:]) # Last 800 chars
|
|
|
|
return False
|
|
|
|
# Run health checks if defined
|
|
if "health_checks" in config:
|
|
print(f"🔍 Running health checks for {group_name} services...")
|
|
|
|
for service, url in config['health_checks']:
|
|
if check_health(service, url):
|
|
print(f"✅ {service} health check passed")
|
|
else:
|
|
print(f"❌ {service} health check failed")
|
|
return False
|
|
|
|
print(f"🎉 {group_name.title()} services test PASSED!")
|
|
return True
|
|
|
|
def main():
|
|
"""Main test function"""
|
|
print("🔧 COMPREHENSIVE SERVICES STARTUP TEST")
|
|
print("=" * 50)
|
|
|
|
# Clean up any existing containers
|
|
print("🧹 Cleaning up existing containers...")
|
|
run_command("docker compose down")
|
|
|
|
all_passed = True
|
|
|
|
# Test each service group in order
|
|
for group_name, config in SERVICES.items():
|
|
if not test_service_group(group_name, config):
|
|
all_passed = False
|
|
break
|
|
|
|
# Final status check
|
|
print("\n📊 Final container status:")
|
|
status = check_container_status()
|
|
|
|
healthy_count = 0
|
|
total_count = 0
|
|
|
|
for group_config in SERVICES.values():
|
|
for service in group_config['services']:
|
|
total_count += 1
|
|
service_status = status.get(service, "not found")
|
|
status_icon = "✅" if ("healthy" in service_status.lower() or "up" in service_status.lower()) else "❌"
|
|
|
|
if "healthy" in service_status.lower() or "up" in service_status.lower():
|
|
healthy_count += 1
|
|
|
|
print(f"{status_icon} {service}: {service_status}")
|
|
|
|
# Clean up
|
|
print("\n🧹 Cleaning up containers...")
|
|
run_command("docker compose down")
|
|
|
|
# Final result
|
|
print("=" * 50)
|
|
if all_passed and healthy_count == total_count:
|
|
print(f"🎉 ALL SERVICES TEST PASSED!")
|
|
print(f"✅ {healthy_count}/{total_count} services started successfully")
|
|
print("💡 Your docker-compose setup is working correctly")
|
|
print("🚀 You can now run: docker compose up -d")
|
|
return 0
|
|
else:
|
|
print(f"❌ SERVICES TEST FAILED")
|
|
print(f"⚠️ {healthy_count}/{total_count} services started successfully")
|
|
print("💡 Check the logs above for details")
|
|
return 1
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main()) |