385 lines
15 KiB
Python
385 lines
15 KiB
Python
# ================================================================
|
||
# validate_local.py - Script completo con todos los imports
|
||
# ================================================================
|
||
|
||
import asyncio
|
||
import httpx
|
||
import json
|
||
import sys
|
||
import traceback
|
||
from datetime import datetime
|
||
from typing import Optional, Dict, Any
|
||
|
||
# Configuración
|
||
AUTH_URL = "http://localhost:8001"
|
||
DATA_URL = "http://localhost:8004"
|
||
GATEWAY_URL = "http://localhost:8000" # Si usas gateway
|
||
|
||
class DataServiceValidator:
|
||
"""Validador completo para el Data Service"""
|
||
|
||
def __init__(self, use_gateway: bool = False):
|
||
self.auth_token: Optional[str] = None
|
||
self.use_gateway = use_gateway
|
||
self.base_url = GATEWAY_URL if use_gateway else DATA_URL
|
||
self.auth_base_url = GATEWAY_URL if use_gateway else AUTH_URL
|
||
|
||
async def test_service_health(self) -> bool:
|
||
"""Verificar que los servicios estén funcionando"""
|
||
print("🔍 Checking service health...")
|
||
|
||
try:
|
||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||
# Test auth service
|
||
auth_response = await client.get(f"{AUTH_URL}/health")
|
||
if auth_response.status_code == 200:
|
||
print("✅ Auth service is healthy")
|
||
else:
|
||
print(f"❌ Auth service unhealthy: {auth_response.status_code}")
|
||
return False
|
||
|
||
# Test data service
|
||
data_response = await client.get(f"{DATA_URL}/health")
|
||
if data_response.status_code == 200:
|
||
print("✅ Data service is healthy")
|
||
else:
|
||
print(f"❌ Data service unhealthy: {data_response.status_code}")
|
||
return False
|
||
|
||
return True
|
||
|
||
except httpx.ConnectError as e:
|
||
print(f"❌ Connection error: {e}")
|
||
print("💡 Make sure services are running with: docker-compose up -d")
|
||
return False
|
||
except Exception as e:
|
||
print(f"❌ Health check failed: {e}")
|
||
return False
|
||
|
||
async def authenticate(self) -> bool:
|
||
"""Autenticar y obtener token"""
|
||
print("🔐 Authenticating...")
|
||
|
||
try:
|
||
async with httpx.AsyncClient(timeout=15.0) as client:
|
||
# Datos de usuario de prueba
|
||
user_data = {
|
||
"email": "test@bakery.es",
|
||
"password": "TestPass123",
|
||
"full_name": "Test User",
|
||
"language": "es"
|
||
}
|
||
|
||
# Intentar registrar usuario (puede fallar si ya existe)
|
||
register_endpoint = f"{self.auth_base_url}/api/v1/auth/register"
|
||
register_response = await client.post(register_endpoint, json=user_data)
|
||
|
||
if register_response.status_code == 200:
|
||
print("✅ User registered successfully")
|
||
elif register_response.status_code == 409:
|
||
print("ℹ️ User already exists, proceeding with login")
|
||
else:
|
||
print(f"⚠️ Registration response: {register_response.status_code}")
|
||
|
||
# Login
|
||
login_data = {
|
||
"email": user_data["email"],
|
||
"password": user_data["password"]
|
||
}
|
||
|
||
login_endpoint = f"{self.auth_base_url}/api/v1/auth/login"
|
||
login_response = await client.post(login_endpoint, json=login_data)
|
||
|
||
if login_response.status_code == 200:
|
||
response_data = login_response.json()
|
||
self.auth_token = response_data["access_token"]
|
||
print("✅ Authentication successful")
|
||
return True
|
||
else:
|
||
print(f"❌ Login failed: {login_response.status_code}")
|
||
print(f"Response: {login_response.text}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ Authentication failed: {e}")
|
||
return False
|
||
|
||
def get_headers(self) -> Dict[str, str]:
|
||
"""Obtener headers con token de autenticación"""
|
||
if not self.auth_token:
|
||
raise ValueError("No authentication token available")
|
||
return {"Authorization": f"Bearer {self.auth_token}"}
|
||
|
||
async def test_weather_endpoints(self) -> bool:
|
||
"""Probar endpoints de clima"""
|
||
print("🌤️ Testing weather endpoints...")
|
||
|
||
try:
|
||
headers = self.get_headers()
|
||
madrid_coords = {"latitude": 40.4168, "longitude": -3.7038}
|
||
|
||
async with httpx.AsyncClient(timeout=20.0) as client:
|
||
# Current weather
|
||
current_endpoint = f"{self.base_url}/api/v1/weather/current" if not self.use_gateway else f"{self.base_url}/api/v1/data/weather/current"
|
||
current_response = await client.get(
|
||
current_endpoint,
|
||
params=madrid_coords,
|
||
headers=headers
|
||
)
|
||
|
||
if current_response.status_code == 200:
|
||
weather = current_response.json()
|
||
print(f"✅ Current weather: {weather.get('temperature')}°C, {weather.get('description')}")
|
||
else:
|
||
print(f"❌ Current weather failed: {current_response.status_code}")
|
||
print(f"Response: {current_response.text}")
|
||
return False
|
||
|
||
# Weather forecast
|
||
forecast_endpoint = f"{self.base_url}/api/v1/weather/forecast" if not self.use_gateway else f"{self.base_url}/api/v1/data/weather/forecast"
|
||
forecast_response = await client.get(
|
||
forecast_endpoint,
|
||
params={**madrid_coords, "days": 3},
|
||
headers=headers
|
||
)
|
||
|
||
if forecast_response.status_code == 200:
|
||
forecast = forecast_response.json()
|
||
print(f"✅ Weather forecast: {len(forecast)} days")
|
||
else:
|
||
print(f"❌ Weather forecast failed: {forecast_response.status_code}")
|
||
return False
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"❌ Weather tests failed: {e}")
|
||
return False
|
||
|
||
async def test_traffic_endpoints(self) -> bool:
|
||
"""Probar endpoints de tráfico"""
|
||
print("🚦 Testing traffic endpoints...")
|
||
|
||
try:
|
||
headers = self.get_headers()
|
||
madrid_coords = {"latitude": 40.4168, "longitude": -3.7038}
|
||
|
||
async with httpx.AsyncClient(timeout=20.0) as client:
|
||
# Current traffic
|
||
current_endpoint = f"{self.base_url}/api/v1/traffic/current" if not self.use_gateway else f"{self.base_url}/api/v1/data/traffic/current"
|
||
current_response = await client.get(
|
||
current_endpoint,
|
||
params=madrid_coords,
|
||
headers=headers
|
||
)
|
||
|
||
if current_response.status_code == 200:
|
||
traffic = current_response.json()
|
||
print(f"✅ Current traffic: {traffic.get('traffic_volume')} vehicles, {traffic.get('congestion_level')} congestion")
|
||
return True
|
||
else:
|
||
print(f"❌ Current traffic failed: {current_response.status_code}")
|
||
print(f"Response: {current_response.text}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ Traffic tests failed: {e}")
|
||
return False
|
||
|
||
async def test_sales_endpoints(self) -> bool:
|
||
"""Probar endpoints de ventas"""
|
||
print("📊 Testing sales endpoints...")
|
||
|
||
try:
|
||
headers = self.get_headers()
|
||
|
||
# Datos de prueba
|
||
sales_data = {
|
||
"tenant_id": "123e4567-e89b-12d3-a456-426614174000",
|
||
"date": datetime.now().isoformat(),
|
||
"product_name": "Pan Integral Test",
|
||
"quantity_sold": 25,
|
||
"revenue": 37.50,
|
||
"location_id": "madrid_centro",
|
||
"source": "test"
|
||
}
|
||
|
||
async with httpx.AsyncClient(timeout=20.0) as client:
|
||
# Create sales record
|
||
create_endpoint = f"{self.base_url}/api/v1/sales/" if not self.use_gateway else f"{self.base_url}/api/v1/data/sales/"
|
||
create_response = await client.post(
|
||
create_endpoint,
|
||
json=sales_data,
|
||
headers=headers
|
||
)
|
||
|
||
if create_response.status_code == 200:
|
||
record = create_response.json()
|
||
print(f"✅ Sales record created: ID {record.get('id')}")
|
||
else:
|
||
print(f"❌ Sales creation failed: {create_response.status_code}")
|
||
print(f"Response: {create_response.text}")
|
||
return False
|
||
|
||
# Test import template
|
||
template_endpoint = f"{self.base_url}/api/v1/sales/import/template/csv" if not self.use_gateway else f"{self.base_url}/api/v1/data/sales/import/template/csv"
|
||
template_response = await client.get(
|
||
template_endpoint,
|
||
headers=headers
|
||
)
|
||
|
||
if template_response.status_code == 200:
|
||
print("✅ Import template generated successfully")
|
||
else:
|
||
print(f"❌ Template generation failed: {template_response.status_code}")
|
||
return False
|
||
|
||
return True
|
||
|
||
except Exception as e:
|
||
print(f"❌ Sales tests failed: {e}")
|
||
return False
|
||
|
||
async def test_import_functionality(self) -> bool:
|
||
"""Probar funcionalidad de importación"""
|
||
print("📄 Testing import functionality...")
|
||
|
||
try:
|
||
headers = self.get_headers()
|
||
|
||
# Crear CSV de prueba
|
||
csv_content = """fecha,producto,cantidad,ingresos
|
||
15/01/2024,Pan Integral,25,37.50
|
||
15/01/2024,Croissant,15,22.50
|
||
15/01/2024,Café con Leche,10,20.00"""
|
||
|
||
# Test CSV import
|
||
import_data = {
|
||
"tenant_id": "123e4567-e89b-12d3-a456-426614174000",
|
||
"data_format": "csv",
|
||
"data": csv_content
|
||
}
|
||
|
||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||
import_endpoint = f"{self.base_url}/api/v1/sales/import/json" if not self.use_gateway else f"{self.base_url}/api/v1/data/sales/import/json"
|
||
import_response = await client.post(
|
||
import_endpoint,
|
||
json=import_data,
|
||
headers=headers
|
||
)
|
||
|
||
if import_response.status_code == 200:
|
||
result = import_response.json()
|
||
if result.get("success"):
|
||
print(f"✅ CSV import successful: {result.get('records_created')} records created")
|
||
return True
|
||
else:
|
||
print(f"❌ CSV import failed: {result.get('error')}")
|
||
return False
|
||
else:
|
||
print(f"❌ Import request failed: {import_response.status_code}")
|
||
print(f"Response: {import_response.text}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
print(f"❌ Import tests failed: {e}")
|
||
return False
|
||
|
||
async def main():
|
||
"""Función principal de validación"""
|
||
print("🚀 Starting Data Service Validation")
|
||
print("=" * 50)
|
||
|
||
# Preguntar si usar gateway
|
||
use_gateway_input = input("Use API Gateway? (y/N): ").lower()
|
||
use_gateway = use_gateway_input == 'y'
|
||
|
||
if use_gateway:
|
||
print("📡 Testing via API Gateway")
|
||
else:
|
||
print("🔗 Testing direct service connections")
|
||
|
||
validator = DataServiceValidator(use_gateway=use_gateway)
|
||
|
||
try:
|
||
# 1. Health checks
|
||
if not await validator.test_service_health():
|
||
print("\n❌ Health checks failed. Ensure services are running.")
|
||
return False
|
||
|
||
# 2. Authentication
|
||
if not await validator.authenticate():
|
||
print("\n❌ Authentication failed.")
|
||
return False
|
||
|
||
# 3. Weather tests
|
||
if not await validator.test_weather_endpoints():
|
||
print("\n❌ Weather endpoint tests failed.")
|
||
return False
|
||
|
||
# 4. Traffic tests
|
||
if not await validator.test_traffic_endpoints():
|
||
print("\n❌ Traffic endpoint tests failed.")
|
||
return False
|
||
|
||
# 5. Sales tests
|
||
if not await validator.test_sales_endpoints():
|
||
print("\n❌ Sales endpoint tests failed.")
|
||
return False
|
||
|
||
# 6. Import tests
|
||
if not await validator.test_import_functionality():
|
||
print("\n❌ Import functionality tests failed.")
|
||
return False
|
||
|
||
print("\n" + "=" * 50)
|
||
print("🎉 ALL TESTS PASSED! Data Service is working correctly!")
|
||
print("=" * 50)
|
||
return True
|
||
|
||
except KeyboardInterrupt:
|
||
print("\n⚠️ Tests interrupted by user")
|
||
return False
|
||
except Exception as e:
|
||
print(f"\n❌ Unexpected error: {e}")
|
||
print("Traceback:")
|
||
traceback.print_exc()
|
||
return False
|
||
|
||
def check_dependencies():
|
||
"""Verificar que las dependencias estén instaladas"""
|
||
try:
|
||
import httpx
|
||
print("✅ httpx is available")
|
||
except ImportError:
|
||
print("❌ httpx not found. Install with: pip install httpx")
|
||
return False
|
||
|
||
return True
|
||
|
||
if __name__ == "__main__":
|
||
print("🔧 Checking dependencies...")
|
||
|
||
if not check_dependencies():
|
||
print("\n💡 Install dependencies with:")
|
||
print("pip install httpx")
|
||
sys.exit(1)
|
||
|
||
print("✅ All dependencies available")
|
||
print()
|
||
|
||
# Ejecutar validación
|
||
success = asyncio.run(main())
|
||
|
||
if success:
|
||
print("\n🎯 Next steps:")
|
||
print("1. Check logs: docker-compose logs -f data-service")
|
||
print("2. Connect to DB: docker-compose exec data-db psql -U data_user -d data_db")
|
||
print("3. Test with real data imports")
|
||
sys.exit(0)
|
||
else:
|
||
print("\n🔧 Troubleshooting:")
|
||
print("1. Check services: docker-compose ps")
|
||
print("2. Restart services: docker-compose restart")
|
||
print("3. Check logs: docker-compose logs data-service")
|
||
sys.exit(1) |