#!/bin/bash # Test runner script for Readur # This script orchestrates all tests in an isolated environment set -e # Exit on error # 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 COMPOSE_FILE="docker-compose.test.yml" COMPOSE_PROJECT_NAME="readur_test" TEST_TIMEOUT=600 # 10 minutes timeout for all tests # Function to print colored output print_status() { echo -e "${BLUE}[TEST]${NC} $1" } print_success() { echo -e "${GREEN}[✓]${NC} $1" } print_error() { echo -e "${RED}[✗]${NC} $1" } print_warning() { echo -e "${YELLOW}[!]${NC} $1" } # Function to cleanup test environment cleanup() { print_status "Cleaning up test environment..." docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME down -v --remove-orphans 2>/dev/null || true # Force remove any lingering containers with our test names docker rm -f readur_postgres_test readur_app_test readur_frontend_test 2>/dev/null || true # Force remove the test network if it exists docker network rm readur_test_network 2>/dev/null || true # Remove any test artifacts rm -rf /tmp/test_uploads /tmp/test_watch 2>/dev/null || true } # Function to wait for service to be healthy wait_for_service() { local service=$1 local max_attempts=30 local attempt=0 print_status "Waiting for $service to be healthy..." while [ $attempt -lt $max_attempts ]; do if docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME ps | grep -q "${service}.*healthy"; then print_success "$service is healthy" return 0 fi attempt=$((attempt + 1)) sleep 2 done print_error "$service failed to become healthy after $max_attempts attempts" return 1 } # Parse command line arguments TEST_TYPE="${1:-all}" KEEP_RUNNING="${2:-false}" # Trap to ensure cleanup on exit trap cleanup EXIT INT TERM # Main test execution main() { print_status "Starting Readur test suite (type: $TEST_TYPE)" # Force cleanup any existing test environment to avoid conflicts print_status "Ensuring clean test environment..." cleanup # Extra cleanup for stubborn resources print_status "Removing any conflicting resources..." docker ps -a | grep -E "readur_(postgres|app|frontend)_test" | awk '{print $1}' | xargs -r docker rm -f 2>/dev/null || true docker network ls | grep "readur_test_network" | awk '{print $1}' | xargs -r docker network rm 2>/dev/null || true # Load test environment variables if [ -f .env.test ]; then print_status "Loading test environment variables..." export $(grep -v '^#' .env.test | xargs) fi # Build test images print_status "Building test images..." docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME build # Start test infrastructure print_status "Starting test infrastructure..." docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME up -d postgres_test # Wait for PostgreSQL to be ready wait_for_service "postgres_test" # The application runs SQLx migrations automatically at startup print_status "Application will run database migrations on startup..." # Start the application print_status "Starting Readur test instance..." docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME up -d readur_test # Wait for application to be ready wait_for_service "readur_test" # Execute tests based on type case $TEST_TYPE in unit) run_unit_tests ;; integration) run_integration_tests ;; frontend) run_frontend_tests ;; e2e) run_e2e_tests ;; all) run_unit_tests run_integration_tests run_frontend_tests ;; *) print_error "Invalid test type: $TEST_TYPE" echo "Usage: $0 [unit|integration|frontend|e2e|all] [keep-running]" exit 1 ;; esac # Keep containers running if requested (useful for debugging) if [ "$KEEP_RUNNING" = "keep-running" ]; then print_warning "Keeping test containers running. Press Ctrl+C to stop and cleanup." print_status "Test services:" echo " - PostgreSQL: localhost:5433" echo " - Readur API: http://localhost:8001" echo " - Logs: docker compose -f $COMPOSE_FILE -p $COMPOSE_PROJECT_NAME logs -f" # Wait for user to press Ctrl+C read -r -d '' _