Día 69 - Probar Todo lo que Hicimos
🎯 Objetivo del Día
Validar que todo funciona correctamente con pruebas simples pero efectivas
📋 Plan de Testing Simple
⏰ Tiempo | 📋 Prueba | 🎯 Validar |
---|---|---|
40 min | 🚀 Tests de carga básicos | App aguanta tráfico |
35 min | 🔄 Probar backup y restore | Recuperación funciona |
30 min | 💥 Romper cosas (Chaos) | Sistema se recupera |
30 min | 🎯 End-to-end completo | Todo el flujo funciona |
15 min | 📊 Reportar resultados | Documentar hallazgos |
🚀 Paso 1: Tests de Carga Básicos (40 min)
1.1 Instalar herramienta simple para load testing
# Opción 1: Usar ApacheBench (viene con la mayoría de sistemas)
sudo apt install apache2-utils
# Opción 2: Usar hey (más moderno)
go install github.com/rakyll/hey@latest
# Opción 3: Usar curl en loop (si no tienes nada)
# Solo necesitas curl que ya tienes
1.2 Script de load testing simple
#!/bin/bash
# simple-load-test.sh - Pruebas de carga sin complicaciones
APP_URL="http://localhost:3000"
RESULTS_DIR="load-test-results"
mkdir -p $RESULTS_DIR
echo "🚀 Ejecutando pruebas de carga simples"
echo "====================================="
# Test 1: Verificar que la app responde
echo "📋 1. Verificación básica..."
response=$(curl -s -o /dev/null -w "%{http_code}" $APP_URL/health)
if [ "$response" != "200" ]; then
echo "❌ App no responde, cancelando tests"
exit 1
fi
echo "✅ App responde correctamente"
# Test 2: 100 requests en 10 segundos (carga ligera)
echo ""
echo "📈 2. Carga ligera (100 requests en 10s)..."
if command -v ab >/dev/null 2>&1; then
ab -n 100 -c 10 -g "${RESULTS_DIR}/light-load.data" $APP_URL/ > "${RESULTS_DIR}/light-load.txt"
# Extraer métricas importantes
avg_time=$(grep "Time per request:" "${RESULTS_DIR}/light-load.txt" | head -1 | awk '{print $4}')
req_per_sec=$(grep "Requests per second:" "${RESULTS_DIR}/light-load.txt" | awk '{print $4}')
echo " ⚡ Tiempo promedio: ${avg_time} ms"
echo " 🔥 Requests/seg: ${req_per_sec}"
# Evaluar resultados
if (( $(echo "$avg_time < 1000" | bc -l 2>/dev/null || echo 0) )); then
echo " ✅ Rendimiento bueno"
else
echo " ⚠️ Rendimiento lento"
fi
else
# Fallback con curl
echo " 🔄 Usando curl fallback..."
start_time=$(date +%s)
for i in {1..50}; do
curl -s $APP_URL/health >/dev/null &
done
wait
end_time=$(date +%s)
duration=$((end_time - start_time))
echo " ⏱️ 50 requests completadas en ${duration}s"
fi
# Test 3: Carga media (500 requests)
echo ""
echo "📊 3. Carga media (500 requests en 30s)..."
if command -v ab >/dev/null 2>&1; then
ab -n 500 -c 25 -t 30 $APP_URL/ > "${RESULTS_DIR}/medium-load.txt"
failed=$(grep "Failed requests:" "${RESULTS_DIR}/medium-load.txt" | awk '{print $3}')
avg_time=$(grep "Time per request:" "${RESULTS_DIR}/medium-load.txt" | head -1 | awk '{print $4}')
echo " ❌ Requests fallidos: $failed"
echo " ⚡ Tiempo promedio: ${avg_time} ms"
if [ "$failed" -eq 0 ]; then
echo " ✅ Sin fallos bajo carga media"
else
echo " ⚠️ Algunos fallos detectados"
fi
fi
# Test 4: Verificar métricas de sistema durante carga
echo ""
echo "💻 4. Verificando recursos del sistema..."
echo " CPU:" $(grep 'cpu ' /proc/stat | awk '{usage=($2+$4)*100/($2+$4+$5)} END {print usage "%"}')
echo " Memoria:" $(free | grep Mem | awk '{printf("%.1f%%", $3/$2 * 100.0)}')
echo " Conexiones TCP:" $(ss -s | grep TCP | awk '{print $2}')
echo ""
echo "📊 Resultados guardados en: $RESULTS_DIR/"
echo "💡 Para ver detalles: cat $RESULTS_DIR/*.txt"
1.3 Monitor simple durante pruebas
#!/usr/bin/env python3
# system-monitor.py - Monitorear sistema durante pruebas
import psutil
import time
import json
from datetime import datetime
class SimpleMonitor:
def __init__(self):
self.data = []
self.monitoring = False
def collect_metrics(self):
"""Recopilar métricas básicas"""
return {
"timestamp": datetime.now().isoformat(),
"cpu_percent": psutil.cpu_percent(interval=1),
"memory_percent": psutil.virtual_memory().percent,
"disk_io": psutil.disk_io_counters()._asdict() if psutil.disk_io_counters() else {},
"network_io": psutil.net_io_counters()._asdict() if psutil.net_io_counters() else {},
"connections": len(psutil.net_connections()),
"processes": len(psutil.pids())
}
def start_monitoring(self, duration=60):
"""Monitorear por X segundos"""
print(f"📊 Monitoreando sistema por {duration} segundos...")
end_time = time.time() + duration
while time.time() < end_time:
metrics = self.collect_metrics()
self.data.append(metrics)
# Mostrar en tiempo real
print(f" CPU: {metrics['cpu_percent']:5.1f}% | "
f"RAM: {metrics['memory_percent']:5.1f}% | "
f"Conexiones: {metrics['connections']:4d}")
time.sleep(5) # Cada 5 segundos
self.save_results()
def save_results(self):
"""Guardar resultados"""
filename = f"system-metrics-{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w') as f:
json.dump(self.data, f, indent=2)
# Generar resumen
if self.data:
cpu_avg = sum(d['cpu_percent'] for d in self.data) / len(self.data)
cpu_max = max(d['cpu_percent'] for d in self.data)
mem_avg = sum(d['memory_percent'] for d in self.data) / len(self.data)
mem_max = max(d['memory_percent'] for d in self.data)
print(f"\n📊 RESUMEN DE MONITOREO:")
print(f" 💻 CPU - Promedio: {cpu_avg:.1f}%, Máximo: {cpu_max:.1f}%")
print(f" 🧠 RAM - Promedio: {mem_avg:.1f}%, Máximo: {mem_max:.1f}%")
print(f" 📄 Datos guardados en: {filename}")
if __name__ == "__main__":
import sys
duration = int(sys.argv[1]) if len(sys.argv) > 1 else 60
monitor = SimpleMonitor()
try:
monitor.start_monitoring(duration)
except KeyboardInterrupt:
print("\n⏹️ Monitoreo detenido por usuario")
monitor.save_results()
1.4 Ejecutar pruebas de carga
# Ejecutar todo junto
chmod +x simple-load-test.sh
./simple-load-test.sh &
# Monitorear sistema mientras tanto
python3 system-monitor.py 120 &
# Esperar que terminen
wait
echo "🎉 Pruebas de carga completadas!"
🔄 Paso 2: Probar Backup y Restore (35 min)
2.1 Test completo de backup/restore
#!/bin/bash
# test-backup-restore.sh - Probar que backups realmente funcionan
echo "💾 Test de Backup y Restore"
echo "==========================="
# Variables
BACKUP_DIR="/tmp/test-backup-$(date +%Y%m%d_%H%M%S)"
TEST_DATA_FILE="test-data.txt"
DB_CONTAINER="database"
# 1. Crear datos de prueba
echo "📝 1. Creando datos de prueba..."
echo "Test data created at $(date)" > $TEST_DATA_FILE
# Si hay base de datos, crear datos de prueba ahí también
if docker-compose ps $DB_CONTAINER >/dev/null 2>&1; then
echo " 📊 Insertando datos de prueba en BD..."
docker-compose exec -T $DB_CONTAINER psql -U postgres -c "
CREATE TABLE IF NOT EXISTS test_backup (
id SERIAL PRIMARY KEY,
message TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO test_backup (message) VALUES ('Backup test data');
" 2>/dev/null || echo " ⚠️ No se pudo conectar a BD"
fi
# 2. Hacer backup
echo ""
echo "💾 2. Ejecutando backup..."
mkdir -p $BACKUP_DIR
# Backup de archivos
cp -r . $BACKUP_DIR/files/
echo " ✅ Backup de archivos completado"
# Backup de base de datos
if docker-compose ps $DB_CONTAINER >/dev/null 2>&1; then
docker-compose exec -T $DB_CONTAINER pg_dump -U postgres postgres > $BACKUP_DIR/database.sql
echo " ✅ Backup de BD completado"
fi
# Backup de configuración Docker
docker-compose config > $BACKUP_DIR/docker-compose-backup.yml
echo " ✅ Backup de configuración completado"
# 3. Simular desastre (¡cuidado!)
echo ""
echo "💥 3. Simulando desastre..."
echo " ⚠️ CUIDADO: Esto va a parar los servicios"
read -p " ¿Continuar? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
# Parar servicios
docker-compose down
# Eliminar datos de prueba
rm -f $TEST_DATA_FILE
# Limpiar datos de BD (eliminar volumen)
docker volume rm $(docker-compose config --volumes) 2>/dev/null || true
echo " 💥 Desastre simulado - datos eliminados"
else
echo " ⏭️ Saltando simulación de desastre"
exit 0
fi
# 4. Restaurar desde backup
echo ""
echo "🔄 4. Restaurando desde backup..."
# Restaurar archivos
if [ -f "$TEST_DATA_FILE" ]; then
echo " ⚠️ Archivo test aún existe (desastre incompleto)"
else
cp $BACKUP_DIR/files/$TEST_DATA_FILE .
echo " ✅ Archivos restaurados"
fi
# Levantar servicios
docker-compose up -d
echo " ✅ Servicios reiniciados"
# Esperar que BD esté lista
echo " ⏳ Esperando que BD esté lista..."
sleep 30
# Restaurar BD
if [ -f "$BACKUP_DIR/database.sql" ]; then
docker-compose exec -T $DB_CONTAINER psql -U postgres postgres < $BACKUP_DIR/database.sql
echo " ✅ BD restaurada"
fi
# 5. Verificar restauración
echo ""
echo "✅ 5. Verificando restauración..."
# Verificar archivo
if [ -f "$TEST_DATA_FILE" ]; then
echo " ✅ Archivo de prueba restaurado correctamente"
cat $TEST_DATA_FILE
else
echo " ❌ Archivo de prueba NO restaurado"
fi
# Verificar BD
if docker-compose ps $DB_CONTAINER >/dev/null 2>&1; then
test_count=$(docker-compose exec -T $DB_CONTAINER psql -U postgres -t -c "SELECT COUNT(*) FROM test_backup;" 2>/dev/null | tr -d ' \n')
if [ "$test_count" -gt 0 ]; then
echo " ✅ Datos de BD restaurados ($test_count registros)"
else
echo " ❌ Datos de BD NO restaurados"
fi
fi
# Verificar servicios
if curl -f http://localhost:3000/health >/dev/null 2>&1; then
echo " ✅ Aplicación funcional después de restore"
else
echo " ❌ Aplicación NO funcional después de restore"
fi
# Limpiar
echo ""
echo "🧹 Limpieza..."
rm -f $TEST_DATA_FILE
rm -rf $BACKUP_DIR
echo " ✅ Archivos de prueba eliminados"
echo ""
echo "🎯 RESULTADO: Test de backup/restore completado"
echo "💡 Si todo salió bien, tus backups funcionan correctamente"
2.2 Test de failover simple
#!/bin/bash
# test-failover.sh - Probar que el sistema se recupera de fallos
echo "🔄 Test de Failover"
echo "=================="
APP_URL="http://localhost:3000"
# 1. Verificar estado inicial
echo "📊 1. Estado inicial del sistema..."
if curl -f $APP_URL/health >/dev/null 2>&1; then
echo " ✅ App funcionando normalmente"
else
echo " ❌ App no está funcionando - cancelling test"
exit 1
fi
# 2. Simular fallo de app (matar container)
echo ""
echo "💥 2. Simulando fallo de aplicación..."
docker-compose kill app
echo " 💀 Aplicación eliminada"
# 3. Verificar que el sistema detecta el fallo
echo ""
echo "🔍 3. Verificando detección de fallo..."
sleep 5
if curl -f $APP_URL/health >/dev/null 2>&1; then
echo " ⚠️ App aún responde (Load balancer/cache?)"
else
echo " ✅ Fallo detectado correctamente"
fi
# 4. Auto-recovery (restart automático)
echo ""
echo "🔄 4. Probando auto-recovery..."
docker-compose up -d app
# Esperar recovery
echo " ⏳ Esperando recovery..."
max_attempts=12 # 60 segundos máximo
attempt=0
while [ $attempt -lt $max_attempts ]; do
if curl -f $APP_URL/health >/dev/null 2>&1; then
echo " ✅ App recuperada en $((attempt * 5)) segundos"
break
fi
sleep 5
attempt=$((attempt + 1))
echo " 🔄 Intento $attempt/$max_attempts..."
done
if [ $attempt -ge $max_attempts ]; then
echo " ❌ App NO se recuperó automáticamente"
exit 1
fi
# 5. Verificar funcionalidad completa
echo ""
echo "✅ 5. Verificando funcionalidad completa..."
# Test varios endpoints
endpoints=("/health" "/metrics")
for endpoint in "${endpoints[@]}"; do
if curl -f $APP_URL$endpoint >/dev/null 2>&1; then
echo " ✅ $endpoint - OK"
else
echo " ⚠️ $endpoint - No responde"
fi
done
echo ""
echo "🎉 Test de failover completado"
echo "💡 El sistema se recuperó automáticamente del fallo"