#!/bin/bash # Calejo Control Adapter - Comprehensive Test Runner # This script sets up a PostgreSQL database and runs all tests with detailed output set -e # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Configuration POSTGRES_IMAGE="postgres:15" CONTAINER_NAME="calejo-test-db" DB_NAME="calejo_test" DB_USER="test_user" DB_PASSWORD="test_password" DB_PORT=5433 # Use different port to avoid conflicts # Function to print colored output print_info() { echo -e "${BLUE}[INFO]${NC} $1" } print_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } print_warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } print_error() { echo -e "${RED}[ERROR]${NC} $1" } # Check if Docker is running if ! docker info > /dev/null 2>&1; then print_error "Docker is not running. Please start Docker and try again." exit 1 fi # Stop and remove existing container if it exists if docker ps -a | grep -q $CONTAINER_NAME; then print_info "Stopping existing test database container..." docker stop $CONTAINER_NAME > /dev/null docker rm $CONTAINER_NAME > /dev/null print_success "Existing container removed" fi # Start PostgreSQL container print_info "Starting PostgreSQL test database..." docker run -d \ --name $CONTAINER_NAME \ -e POSTGRES_DB=$DB_NAME \ -e POSTGRES_USER=$DB_USER \ -e POSTGRES_PASSWORD=$DB_PASSWORD \ -p $DB_PORT:5432 \ $POSTGRES_IMAGE # Wait for database to be ready print_info "Waiting for database to be ready..." for i in {1..30}; do if docker exec $CONTAINER_NAME pg_isready -U $DB_USER -d $DB_NAME > /dev/null 2>&1; then print_success "Database is ready!" break fi if [ $i -eq 30 ]; then print_error "Database failed to start within 30 seconds" docker logs $CONTAINER_NAME exit 1 fi sleep 1 echo -n "." done # Create test database schema print_info "Creating test database schema..." # Create the necessary tables SQL_FILE=$(mktemp) cat > $SQL_FILE << 'EOF' -- Create stations table CREATE TABLE IF NOT EXISTS stations ( station_id VARCHAR(50) PRIMARY KEY, station_name VARCHAR(100), location VARCHAR(200), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- Create pumps table CREATE TABLE IF NOT EXISTS pumps ( station_id VARCHAR(50), pump_id VARCHAR(50), pump_name VARCHAR(100), control_type VARCHAR(50), min_speed_hz DECIMAL(5,2) DEFAULT 20.0, max_speed_hz DECIMAL(5,2) DEFAULT 60.0, default_setpoint_hz DECIMAL(5,2) DEFAULT 35.0, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (station_id, pump_id), FOREIGN KEY (station_id) REFERENCES stations(station_id) ); -- Create pump_plans table CREATE TABLE IF NOT EXISTS pump_plans ( plan_id SERIAL PRIMARY KEY, station_id VARCHAR(50), pump_id VARCHAR(50), target_flow_m3h DECIMAL(8,2), target_power_kw DECIMAL(8,2), target_level_m DECIMAL(8,2), suggested_speed_hz DECIMAL(5,2), interval_start TIMESTAMP, interval_end TIMESTAMP, plan_version INTEGER, plan_status VARCHAR(20) DEFAULT 'ACTIVE', plan_created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, plan_updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, optimization_run_id VARCHAR(100), FOREIGN KEY (station_id, pump_id) REFERENCES pumps(station_id, pump_id) ); -- Create pump_feedback table CREATE TABLE IF NOT EXISTS pump_feedback ( feedback_id SERIAL PRIMARY KEY, station_id VARCHAR(50), pump_id VARCHAR(50), timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, actual_speed_hz DECIMAL(5,2), actual_power_kw DECIMAL(8,2), actual_flow_m3h DECIMAL(8,2), wet_well_level_m DECIMAL(8,2), pump_running BOOLEAN, alarm_active BOOLEAN, alarm_code VARCHAR(50), FOREIGN KEY (station_id, pump_id) REFERENCES pumps(station_id, pump_id) ); -- Create emergency_stop_events table CREATE TABLE IF NOT EXISTS emergency_stop_events ( event_id SERIAL PRIMARY KEY, triggered_by VARCHAR(100), reason TEXT, station_id VARCHAR(50), pump_id VARCHAR(50), event_timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, cleared_by VARCHAR(100), cleared_timestamp TIMESTAMP, cleared_notes TEXT, FOREIGN KEY (station_id, pump_id) REFERENCES pumps(station_id, pump_id) ); -- Insert test data INSERT INTO stations (station_id, station_name, location) VALUES ('STATION_001', 'Main Pump Station', 'Downtown Area'), ('STATION_002', 'Secondary Station', 'Industrial Zone'); INSERT INTO pumps (station_id, pump_id, pump_name, control_type, min_speed_hz, max_speed_hz, default_setpoint_hz) VALUES ('STATION_001', 'PUMP_001', 'Main Pump 1', 'DIRECT_SPEED', 20.0, 60.0, 35.0), ('STATION_001', 'PUMP_002', 'Main Pump 2', 'LEVEL_CONTROLLED', 20.0, 60.0, 35.0), ('STATION_002', 'PUMP_001', 'Secondary Pump 1', 'POWER_CONTROLLED', 20.0, 60.0, 35.0); INSERT INTO pump_plans ( station_id, pump_id, target_flow_m3h, target_power_kw, target_level_m, suggested_speed_hz, interval_start, interval_end, plan_version, optimization_run_id ) VALUES ('STATION_001', 'PUMP_001', 150.0, NULL, NULL, 42.5, NOW() - INTERVAL '1 hour', NOW() + INTERVAL '1 hour', 1, 'OPT_RUN_001'), ('STATION_001', 'PUMP_002', NULL, NULL, 2.5, 38.0, NOW() - INTERVAL '1 hour', NOW() + INTERVAL '1 hour', 1, 'OPT_RUN_001'), ('STATION_002', 'PUMP_001', NULL, 18.5, NULL, 40.0, NOW() - INTERVAL '1 hour', NOW() + INTERVAL '1 hour', 1, 'OPT_RUN_001'); INSERT INTO pump_feedback ( station_id, pump_id, actual_speed_hz, actual_power_kw, actual_flow_m3h, wet_well_level_m, pump_running, alarm_active ) VALUES ('STATION_001', 'PUMP_001', 42.5, 16.2, 148.5, 1.8, true, false), ('STATION_001', 'PUMP_002', 38.0, 14.8, 135.2, 2.3, true, false), ('STATION_002', 'PUMP_001', 40.0, 18.3, 142.1, 1.9, true, false); EOF docker exec -i $CONTAINER_NAME psql -U $DB_USER -d $DB_NAME < $SQL_FILE rm $SQL_FILE print_success "Test database schema created with sample data" # Set environment variables for tests export DATABASE_URL="postgresql://$DB_USER:$DB_PASSWORD@localhost:$DB_PORT/$DB_NAME" export TEST_DATABASE_URL="$DATABASE_URL" print_info "Environment variables set for testing" # Run tests with detailed output print_info "Running tests with detailed output..." echo "" # Run unit tests first print_info "=== RUNNING UNIT TESTS ===" python -m pytest tests/unit/ -v --tb=long --cov=src --cov-report=term-missing --cov-report=html:htmlcov_unit UNIT_EXIT_CODE=$? # Run integration tests print_info "=== RUNNING INTEGRATION TESTS ===" python -m pytest tests/integration/ -v --tb=long --cov=src --cov-append --cov-report=term-missing --cov-report=html:htmlcov_integration INTEGRATION_EXIT_CODE=$? # Generate combined coverage report print_info "=== GENERATING COMBINED COVERAGE REPORT ===" python -m pytest --cov=src --cov-report=html:htmlcov_combined --cov-report=term-missing tests/ # Clean up print_info "Cleaning up test database container..." docker stop $CONTAINER_NAME > /dev/null docker rm $CONTAINER_NAME > /dev/null print_success "Test database container cleaned up" # Report results echo "" print_info "=== TEST RESULTS SUMMARY ===" if [ $UNIT_EXIT_CODE -eq 0 ] && [ $INTEGRATION_EXIT_CODE -eq 0 ]; then print_success "All tests passed!" exit 0 else if [ $UNIT_EXIT_CODE -ne 0 ]; then print_error "Unit tests failed with exit code: $UNIT_EXIT_CODE" fi if [ $INTEGRATION_EXIT_CODE -ne 0 ]; then print_error "Integration tests failed with exit code: $INTEGRATION_EXIT_CODE" fi exit 1 fi