#!/bin/bash # ================================================================================================ # Level 2 Rollback Test: Database Rollback (Target: ~5 minutes) # Agent R1 - Rollback & Disaster Recovery Specialist # ================================================================================================ # # SCENARIO: Rollback database migration 045 (regime detection tables) # EXPECTED: All Wave D tables removed, services restart with Wave C configuration # # ================================================================================================ set -e # Exit on error echo "====================================================================================================" echo "LEVEL 2 ROLLBACK TEST: Database Rollback" echo "====================================================================================================" echo "" # Start timer START_TIME=$(date +%s) # Step 1: Pre-rollback validation echo "Step 1: Pre-rollback validation" echo "------------------------------------------------------------------------------------" # Check current database state echo " ✓ Checking database for Wave D tables..." REGIME_TABLES=$(PGPASSWORD=foxhunt_dev_password psql -h localhost -U foxhunt -d foxhunt -tAc " SELECT COUNT(*) FROM information_schema.tables WHERE table_name IN ('regime_states', 'regime_transitions', 'adaptive_strategy_metrics'); " 2>/dev/null || echo "0") echo " ✓ Found $REGIME_TABLES Wave D tables before rollback" if [ "$REGIME_TABLES" -eq 0 ]; then echo " ⚠ WARNING: No Wave D tables found. Migration 045 may not be applied." echo " ⚠ Skipping Level 2 test (nothing to rollback)" exit 1 fi # Check for existing data echo " ✓ Checking for existing Wave D data..." REGIME_DATA=$(PGPASSWORD=foxhunt_dev_password psql -h localhost -U foxhunt -d foxhunt -tAc " SELECT COUNT(*) FROM regime_states; " 2>/dev/null || echo "0") echo " ✓ Found $REGIME_DATA regime_states records" # Backup database (safety measure) echo " ✓ Creating database backup..." BACKUP_FILE="/tmp/foxhunt_backup_$(date +%s).sql" PGPASSWORD=foxhunt_dev_password pg_dump -h localhost -U foxhunt -d foxhunt -f "$BACKUP_FILE" 2>/dev/null || { echo " ⚠ WARNING: Backup failed, continuing anyway" BACKUP_FILE="" } if [ -n "$BACKUP_FILE" ] && [ -f "$BACKUP_FILE" ]; then BACKUP_SIZE=$(du -h "$BACKUP_FILE" | cut -f1) echo " ✅ Backup created: $BACKUP_FILE ($BACKUP_SIZE)" fi echo "" # Step 2: Stop services (graceful shutdown) echo "Step 2: Stopping services (graceful shutdown)" echo "------------------------------------------------------------------------------------" SHUTDOWN_START=$(date +%s) # Find and stop Foxhunt services PIDS=$(pgrep -f "api_gateway|trading_service|backtesting_service|ml_training_service" || true) if [ -n "$PIDS" ]; then echo " ✓ Found service PIDs: $PIDS" echo " ✓ Sending SIGTERM for graceful shutdown..." kill -TERM $PIDS 2>/dev/null || true # Wait up to 30s for graceful shutdown for i in {1..30}; do REMAINING=$(pgrep -f "api_gateway|trading_service|backtesting_service|ml_training_service" | wc -l) if [ "$REMAINING" -eq 0 ]; then echo " ✅ All services stopped gracefully in ${i}s" break fi sleep 1 done # Force kill if still running REMAINING=$(pgrep -f "api_gateway|trading_service|backtesting_service|ml_training_service" | wc -l) if [ "$REMAINING" -gt 0 ]; then echo " ⚠ WARNING: Forcing shutdown of $REMAINING remaining processes" kill -9 $(pgrep -f "api_gateway|trading_service|backtesting_service|ml_training_service") 2>/dev/null || true fi else echo " ⚠ No services running" fi SHUTDOWN_END=$(date +%s) SHUTDOWN_TIME=$((SHUTDOWN_END - SHUTDOWN_START)) echo " ✓ Shutdown completed in ${SHUTDOWN_TIME}s" echo "" # Step 3: Apply rollback migration echo "Step 3: Rolling back database migration 045" echo "------------------------------------------------------------------------------------" MIGRATION_START=$(date +%s) # Method 1: Use sqlx migrate revert (if sqlx-cli is installed) if command -v sqlx &> /dev/null; then echo " ✓ Using sqlx migrate revert..." cd /home/jgrusewski/Work/foxhunt DATABASE_URL="postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt" \ sqlx migrate revert --database-url "postgresql://foxhunt:foxhunt_dev_password@localhost:5432/foxhunt" 2>&1 | grep -E "Applied|Reverted|error" || echo " ✓ Revert completed" else # Method 2: Direct SQL execution (fallback) echo " ✓ Using direct SQL execution (sqlx not found)..." PGPASSWORD=foxhunt_dev_password psql -h localhost -U foxhunt -d foxhunt -f /home/jgrusewski/Work/foxhunt/migrations/045_wave_d_regime_tracking.down.sql 2>&1 | grep -E "DROP|REVOKE|NOTICE|ERROR" || echo " ✓ Rollback SQL executed" fi MIGRATION_END=$(date +%s) MIGRATION_TIME=$((MIGRATION_END - MIGRATION_START)) echo " ✓ Migration rollback completed in ${MIGRATION_TIME}s" echo "" # Step 4: Validate rollback echo "Step 4: Validating database rollback" echo "------------------------------------------------------------------------------------" # Check tables removed REMAINING_TABLES=$(PGPASSWORD=foxhunt_dev_password psql -h localhost -U foxhunt -d foxhunt -tAc " SELECT COUNT(*) FROM information_schema.tables WHERE table_name IN ('regime_states', 'regime_transitions', 'adaptive_strategy_metrics'); " 2>/dev/null || echo "unknown") if [ "$REMAINING_TABLES" = "0" ]; then echo " ✅ VERIFIED: All Wave D tables removed" else echo " ❌ FAILED: $REMAINING_TABLES Wave D tables still exist" echo " ⚠ Rollback did not complete successfully" fi # Check functions removed REMAINING_FUNCTIONS=$(PGPASSWORD=foxhunt_dev_password psql -h localhost -U foxhunt -d foxhunt -tAc " SELECT COUNT(*) FROM information_schema.routines WHERE routine_name IN ('get_latest_regime', 'get_regime_transition_matrix', 'get_regime_performance'); " 2>/dev/null || echo "unknown") if [ "$REMAINING_FUNCTIONS" = "0" ]; then echo " ✅ VERIFIED: All Wave D functions removed" else echo " ❌ FAILED: $REMAINING_FUNCTIONS Wave D functions still exist" fi # Check migration history MIGRATION_VERSION=$(PGPASSWORD=foxhunt_dev_password psql -h localhost -U foxhunt -d foxhunt -tAc " SELECT version FROM _sqlx_migrations ORDER BY version DESC LIMIT 1; " 2>/dev/null || echo "unknown") echo " ✓ Latest migration version: $MIGRATION_VERSION (should be 44 after rollback)" echo "" # Step 5: Restart services with Wave C configuration echo "Step 5: Restarting services with Wave C configuration" echo "------------------------------------------------------------------------------------" RESTART_START=$(date +%s) # Ensure Wave C configuration is active (from Level 1 rollback) echo " ✓ Verifying Wave C configuration..." if grep -q "enable_wave_d_regime: false" /home/jgrusewski/Work/foxhunt/ml/src/features/config.rs 2>/dev/null; then echo " ✅ Wave C configuration active" else echo " ⚠ WARNING: Wave D features still enabled in code" echo " ⚠ Recommendation: Run Level 1 rollback first" fi # Rebuild services (if needed) echo " ✓ Rebuilding services..." cd /home/jgrusewski/Work/foxhunt cargo build --release --workspace 2>&1 | grep -E "Compiling|Finished|error" || echo " ✓ Build completed" echo " ⚠ NOTE: Manual service restart required for production" echo " ⚠ Services NOT started automatically by this test script" RESTART_END=$(date +%s) RESTART_TIME=$((RESTART_END - RESTART_START)) echo " ✓ Rebuild completed in ${RESTART_TIME}s" echo "" # Step 6: Calculate rollback time echo "Step 6: Rollback Performance Metrics" echo "------------------------------------------------------------------------------------" END_TIME=$(date +%s) TOTAL_TIME=$((END_TIME - START_TIME)) echo " • Total rollback time: ${TOTAL_TIME}s" echo " • Shutdown time: ${SHUTDOWN_TIME}s" echo " • Migration time: ${MIGRATION_TIME}s" echo " • Rebuild time: ${RESTART_TIME}s" echo " • Target time: <300s (5 minutes)" if [ $TOTAL_TIME -lt 300 ]; then echo " ✅ PASSED: Rollback completed within 5-minute target" else echo " ⚠ MISSED TARGET: Rollback took ${TOTAL_TIME}s (>300s)" fi echo "" # Summary echo "====================================================================================================" echo "LEVEL 2 ROLLBACK TEST: SUMMARY" echo "====================================================================================================" echo "" echo "Result:" echo " • Database tables removed: $REGIME_TABLES → $REMAINING_TABLES" echo " • Database functions removed: ✓ (get_latest_regime, get_regime_transition_matrix, get_regime_performance)" echo " • Migration version: $MIGRATION_VERSION" echo " • Services: STOPPED (manual restart required)" echo " • Rollback time: ${TOTAL_TIME}s (target: <300s)" echo "" echo "Data Loss:" echo " • regime_states: $REGIME_DATA records DELETED" echo " • regime_transitions: DELETED" echo " • adaptive_strategy_metrics: DELETED" if [ -n "$BACKUP_FILE" ] && [ -f "$BACKUP_FILE" ]; then echo " • Backup: $BACKUP_FILE ($BACKUP_SIZE)" fi echo "" echo "Recovery Path:" echo " To re-apply Wave D migration:" echo " 1. Restore database: psql < $BACKUP_FILE (if needed)" echo " 2. Re-apply migration: sqlx migrate run" echo " 3. Re-enable Wave D features (reverse Level 1 rollback)" echo " 4. Rebuild services: cargo build --workspace --release" echo " 5. Restart services" echo "" echo "====================================================================================================" exit 0