meldestelle/scripts/test/test_database_initialization.sh
2025-07-25 23:16:16 +02:00

651 lines
21 KiB
Bash
Executable File

#!/bin/bash
# =============================================================================
# Enhanced Database Initialization Test Script
# =============================================================================
# This script provides comprehensive testing of database initialization and
# configuration with actual connection testing, schema validation, performance
# testing, and cleanup capabilities.
# =============================================================================
# Load common utilities
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=../utils/common.sh
source "$SCRIPT_DIR/../utils/common.sh" || {
echo "Error: Could not load common utilities from $SCRIPT_DIR/../utils/common.sh"
exit 1
}
# =============================================================================
# Configuration
# =============================================================================
readonly COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}"
readonly DB_SERVICES=("postgres" "redis")
readonly BUILD_TIMEOUT=300
readonly DB_STARTUP_TIMEOUT=120
readonly CONNECTION_TIMEOUT=30
# Database configuration
readonly DB_HOST="${DB_HOST:-localhost}"
readonly DB_PORT="${DB_PORT:-5432}"
readonly DB_NAME="${DB_NAME:-meldestelle_test}"
readonly DB_USER="${DB_USER:-meldestelle_user}"
readonly DB_PASSWORD="${DB_PASSWORD:-meldestelle_password}"
# Redis configuration
readonly REDIS_HOST="${REDIS_HOST:-localhost}"
readonly REDIS_PORT="${REDIS_PORT:-6379}"
# Service modules
readonly SERVICE_MODULES=(
"infrastructure:gateway"
"horses:horses-service"
"events:events-service"
"masterdata:masterdata-service"
"members:members-service"
)
# Test database name
readonly TEST_DB_NAME="meldestelle_test_$(date +%s)"
# =============================================================================
# Cleanup Function
# =============================================================================
cleanup() {
log_info "Cleaning up test environment..."
# Drop test database if created
if [[ "${TEST_DB_CREATED:-false}" == "true" ]]; then
log_info "Dropping test database: $TEST_DB_NAME"
PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres \
-c "DROP DATABASE IF EXISTS $TEST_DB_NAME;" >/dev/null 2>&1 || true
fi
# Stop database services if started by this script
if [[ "${STARTED_DB_SERVICES:-false}" == "true" ]]; then
log_info "Stopping database services..."
docker-compose -f "$COMPOSE_FILE" stop "${DB_SERVICES[@]}" >/dev/null 2>&1 || true
fi
# Clean up temporary files
rm -f /tmp/db_test_*.sql /tmp/db_performance_*.log 2>/dev/null || true
log_info "Cleanup completed"
}
# =============================================================================
# Database Setup Functions
# =============================================================================
setup_database_services() {
log_section "Database Services Setup"
# Check Docker availability
check_docker || return 1
check_docker_compose || return 1
# Start database services
log_info "Starting database services: ${DB_SERVICES[*]}"
if run_with_timeout "$DB_STARTUP_TIMEOUT" "Start database services" \
docker-compose -f "$COMPOSE_FILE" up -d "${DB_SERVICES[@]}"; then
STARTED_DB_SERVICES=true
print_status "OK" "Database services started successfully"
else
print_status "ERROR" "Failed to start database services"
return 1
fi
# Wait for PostgreSQL to be ready
if wait_for_service "PGPASSWORD=$DB_PASSWORD pg_isready -h $DB_HOST -p $DB_PORT -U $DB_USER" \
"PostgreSQL" "$CONNECTION_TIMEOUT" 5; then
print_status "OK" "PostgreSQL is ready"
else
print_status "ERROR" "PostgreSQL failed to become ready"
return 1
fi
# Wait for Redis to be ready
if wait_for_service "redis-cli -h $REDIS_HOST -p $REDIS_PORT ping | grep -q PONG" \
"Redis" "$CONNECTION_TIMEOUT" 5; then
print_status "OK" "Redis is ready"
else
print_status "ERROR" "Redis failed to become ready"
return 1
fi
return 0
}
# =============================================================================
# Environment Validation Functions
# =============================================================================
validate_environment() {
log_section "Environment Validation"
# Load environment file
load_env_file
# Validate required environment variables
local required_vars=(
"DB_HOST" "DB_PORT" "DB_NAME" "DB_USER" "DB_PASSWORD"
"REDIS_HOST" "REDIS_PORT"
)
validate_env_vars "${required_vars[@]}" || return 1
# Check for required tools
local required_tools=("psql" "redis-cli")
for tool in "${required_tools[@]}"; do
if command_exists "$tool"; then
print_status "OK" "$tool is available"
else
print_status "WARNING" "$tool is not available - some tests may be skipped"
fi
done
return 0
}
# =============================================================================
# Build Testing Functions
# =============================================================================
test_service_builds() {
log_section "Service Build Testing"
local build_results=()
# Test each service module build
for module in "${SERVICE_MODULES[@]}"; do
log_info "Building module: $module"
if run_with_timeout "$BUILD_TIMEOUT" "Build $module" \
./gradlew ":${module}:build" -x test; then
print_status "OK" "$module builds successfully"
build_results+=("$module: PASS")
else
print_status "ERROR" "$module build failed"
build_results+=("$module: FAIL")
fi
done
# Summary of build results
log_info "Build Results Summary:"
for result in "${build_results[@]}"; do
if [[ "$result" == *"PASS" ]]; then
log_success "$result"
else
log_error "$result"
fi
done
# Check if any builds failed
if echo "${build_results[*]}" | grep -q "FAIL"; then
print_status "ERROR" "One or more service builds failed"
return 1
else
print_status "OK" "All service builds successful"
return 0
fi
}
# =============================================================================
# Database Connection Testing Functions
# =============================================================================
test_database_connections() {
log_section "Database Connection Testing"
# Test PostgreSQL connection
test_postgresql_connection || return 1
# Test Redis connection
test_redis_connection || return 1
return 0
}
test_postgresql_connection() {
log_info "Testing PostgreSQL connection..."
# Basic connection test
if PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres \
-c "SELECT version();" >/dev/null 2>&1; then
print_status "OK" "PostgreSQL connection successful"
else
print_status "ERROR" "PostgreSQL connection failed"
return 1
fi
# Test database creation
log_info "Testing database creation..."
if PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d postgres \
-c "CREATE DATABASE $TEST_DB_NAME;" >/dev/null 2>&1; then
TEST_DB_CREATED=true
print_status "OK" "Test database created successfully"
else
print_status "ERROR" "Failed to create test database"
return 1
fi
# Test connection to new database
if PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-c "SELECT current_database();" >/dev/null 2>&1; then
print_status "OK" "Connection to test database successful"
else
print_status "ERROR" "Failed to connect to test database"
return 1
fi
return 0
}
test_redis_connection() {
log_info "Testing Redis connection..."
# Basic connection test
if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" ping | grep -q "PONG"; then
print_status "OK" "Redis connection successful"
else
print_status "ERROR" "Redis connection failed"
return 1
fi
# Test basic operations
local test_key="test_key_$(date +%s)"
local test_value="test_value_$(date +%s)"
if redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" set "$test_key" "$test_value" >/dev/null 2>&1; then
print_status "OK" "Redis SET operation successful"
else
print_status "ERROR" "Redis SET operation failed"
return 1
fi
local retrieved_value
retrieved_value=$(redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" get "$test_key" 2>/dev/null)
if [[ "$retrieved_value" == "$test_value" ]]; then
print_status "OK" "Redis GET operation successful"
else
print_status "ERROR" "Redis GET operation failed"
return 1
fi
# Cleanup test key
redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" del "$test_key" >/dev/null 2>&1 || true
return 0
}
# =============================================================================
# Schema Validation Functions
# =============================================================================
test_schema_initialization() {
log_section "Schema Initialization Testing"
# Create test schema
create_test_schema || return 1
# Validate schema structure
validate_schema_structure || return 1
# Test schema constraints
test_schema_constraints || return 1
return 0
}
create_test_schema() {
log_info "Creating test schema..."
# Create a simple test table
local create_table_sql="
CREATE TABLE IF NOT EXISTS test_table (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
"
if PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-c "$create_table_sql" >/dev/null 2>&1; then
print_status "OK" "Test schema created successfully"
return 0
else
print_status "ERROR" "Failed to create test schema"
return 1
fi
}
validate_schema_structure() {
log_info "Validating schema structure..."
# Check if table exists
local table_exists
table_exists=$(PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-t -c "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'test_table';" 2>/dev/null | tr -d ' ')
if [[ "$table_exists" == "1" ]]; then
print_status "OK" "Test table exists in schema"
else
print_status "ERROR" "Test table not found in schema"
return 1
fi
# Check table columns
local column_count
column_count=$(PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-t -c "SELECT COUNT(*) FROM information_schema.columns WHERE table_name = 'test_table';" 2>/dev/null | tr -d ' ')
if [[ "$column_count" == "4" ]]; then
print_status "OK" "Test table has correct number of columns"
else
print_status "WARNING" "Test table column count unexpected: $column_count"
fi
return 0
}
test_schema_constraints() {
log_info "Testing schema constraints..."
# Test NOT NULL constraint
if ! PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-c "INSERT INTO test_table (name) VALUES (NULL);" >/dev/null 2>&1; then
print_status "OK" "NOT NULL constraint working correctly"
else
print_status "WARNING" "NOT NULL constraint may not be working"
fi
# Test UNIQUE constraint
PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-c "INSERT INTO test_table (name, email) VALUES ('Test User', 'test@example.com');" >/dev/null 2>&1
if ! PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-c "INSERT INTO test_table (name, email) VALUES ('Another User', 'test@example.com');" >/dev/null 2>&1; then
print_status "OK" "UNIQUE constraint working correctly"
else
print_status "WARNING" "UNIQUE constraint may not be working"
fi
return 0
}
# =============================================================================
# Performance Testing Functions
# =============================================================================
test_database_performance() {
log_section "Database Performance Testing"
# Test PostgreSQL performance
test_postgresql_performance || return 1
# Test Redis performance
test_redis_performance || return 1
return 0
}
test_postgresql_performance() {
log_info "Testing PostgreSQL performance..."
# Insert performance test
local start_time
local end_time
local duration
start_time=$(date +%s%N)
# Insert 1000 test records
for i in {1..1000}; do
PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-c "INSERT INTO test_table (name, email) VALUES ('User $i', 'user$i@example.com');" >/dev/null 2>&1
done
end_time=$(date +%s%N)
duration=$(( (end_time - start_time) / 1000000 )) # Convert to milliseconds
if [[ $duration -lt 10000 ]]; then # Less than 10 seconds
print_status "OK" "PostgreSQL insert performance is good (${duration}ms for 1000 records)"
else
print_status "WARNING" "PostgreSQL insert performance is slow (${duration}ms for 1000 records)"
fi
# Query performance test
start_time=$(date +%s%N)
local record_count
record_count=$(PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$TEST_DB_NAME" \
-t -c "SELECT COUNT(*) FROM test_table;" 2>/dev/null | tr -d ' ')
end_time=$(date +%s%N)
duration=$(( (end_time - start_time) / 1000000 ))
if [[ $duration -lt 1000 ]] && [[ "$record_count" -gt 0 ]]; then
print_status "OK" "PostgreSQL query performance is good (${duration}ms, $record_count records)"
else
print_status "WARNING" "PostgreSQL query performance may be suboptimal (${duration}ms)"
fi
return 0
}
test_redis_performance() {
log_info "Testing Redis performance..."
# Set performance test
local start_time
local end_time
local duration
start_time=$(date +%s%N)
# Set 1000 test keys
for i in {1..1000}; do
redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" set "perf_test_$i" "value_$i" >/dev/null 2>&1
done
end_time=$(date +%s%N)
duration=$(( (end_time - start_time) / 1000000 ))
if [[ $duration -lt 5000 ]]; then # Less than 5 seconds
print_status "OK" "Redis SET performance is good (${duration}ms for 1000 keys)"
else
print_status "WARNING" "Redis SET performance is slow (${duration}ms for 1000 keys)"
fi
# Get performance test
start_time=$(date +%s%N)
for i in {1..100}; do
redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" get "perf_test_$i" >/dev/null 2>&1
done
end_time=$(date +%s%N)
duration=$(( (end_time - start_time) / 1000000 ))
if [[ $duration -lt 1000 ]]; then # Less than 1 second
print_status "OK" "Redis GET performance is good (${duration}ms for 100 keys)"
else
print_status "WARNING" "Redis GET performance is slow (${duration}ms for 100 keys)"
fi
# Cleanup performance test keys
redis-cli -h "$REDIS_HOST" -p "$REDIS_PORT" eval "
for i=1,1000 do
redis.call('del', 'perf_test_' .. i)
end
" 0 >/dev/null 2>&1 || true
return 0
}
# =============================================================================
# Integration Testing Functions
# =============================================================================
test_database_integration() {
log_section "Database Integration Testing"
# Test DatabaseFactory usage
test_database_factory_integration || return 1
# Test service-specific database initialization
test_service_database_integration || return 1
return 0
}
test_database_factory_integration() {
log_info "Testing DatabaseFactory integration..."
# Check for direct Database.connect() calls in gateway
local direct_connects
direct_connects=$(find infrastructure/gateway/src -name "*.kt" -exec grep -l "Database\.connect(" {} \; 2>/dev/null || true)
if [[ -z "$direct_connects" ]]; then
print_status "OK" "No direct Database.connect() calls found in gateway"
else
print_status "ERROR" "Found direct Database.connect() calls in gateway: $direct_connects"
return 1
fi
# Check for DatabaseFactory usage in gateway
local factory_usage
factory_usage=$(find infrastructure/gateway/src -name "*.kt" -exec grep -l "DatabaseFactory" {} \; 2>/dev/null || true)
if [[ -n "$factory_usage" ]]; then
print_status "OK" "DatabaseFactory usage found in gateway"
else
print_status "WARNING" "No DatabaseFactory usage found in gateway"
fi
return 0
}
test_service_database_integration() {
log_info "Testing service database integration..."
# Check that services don't call DatabaseFactory.init()
local factory_inits
factory_inits=$(find . -path "*/service/config/*" -name "*.kt" -exec grep -l "DatabaseFactory\.init(" {} \; 2>/dev/null || true)
if [[ -z "$factory_inits" ]]; then
print_status "OK" "No DatabaseFactory.init() calls found in service configurations"
else
print_status "ERROR" "Found DatabaseFactory.init() calls in service configurations: $factory_inits"
return 1
fi
return 0
}
# =============================================================================
# Main Execution
# =============================================================================
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --skip-builds Skip service build testing"
echo " --skip-performance Skip performance testing"
echo " --keep-test-data Don't cleanup test data after testing"
echo " --help Show this help message"
echo ""
echo "Environment Variables:"
echo " DB_HOST Database host (default: localhost)"
echo " DB_PORT Database port (default: 5432)"
echo " DB_NAME Database name (default: meldestelle_test)"
echo " DB_USER Database user (default: meldestelle_user)"
echo " DB_PASSWORD Database password (default: meldestelle_password)"
echo " REDIS_HOST Redis host (default: localhost)"
echo " REDIS_PORT Redis port (default: 6379)"
}
main() {
local SKIP_BUILDS=false
local SKIP_PERFORMANCE=false
local KEEP_TEST_DATA=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--skip-builds)
SKIP_BUILDS=true
shift
;;
--skip-performance)
SKIP_PERFORMANCE=true
shift
;;
--keep-test-data)
KEEP_TEST_DATA=true
shift
;;
--help)
show_usage
exit 0
;;
*)
log_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
log_section "Enhanced Database Initialization Test"
log_info "Starting comprehensive database tests..."
log_info "Test database: $TEST_DB_NAME"
log_info "Test timestamp: $(date)"
# Run all tests
local test_results=()
validate_environment && test_results+=("Environment: PASS") || test_results+=("Environment: FAIL")
setup_database_services && test_results+=("Setup: PASS") || test_results+=("Setup: FAIL")
if [[ "$SKIP_BUILDS" != "true" ]]; then
test_service_builds && test_results+=("Builds: PASS") || test_results+=("Builds: FAIL")
else
test_results+=("Builds: SKIPPED")
fi
test_database_connections && test_results+=("Connections: PASS") || test_results+=("Connections: FAIL")
test_schema_initialization && test_results+=("Schema: PASS") || test_results+=("Schema: FAIL")
test_database_integration && test_results+=("Integration: PASS") || test_results+=("Integration: FAIL")
if [[ "$SKIP_PERFORMANCE" != "true" ]]; then
test_database_performance && test_results+=("Performance: PASS") || test_results+=("Performance: FAIL")
else
test_results+=("Performance: SKIPPED")
fi
# Print test results summary
log_section "Test Results Summary"
for result in "${test_results[@]}"; do
if [[ "$result" == *"PASS" ]]; then
log_success "$result"
elif [[ "$result" == *"SKIPPED" ]]; then
log_info "$result"
else
log_error "$result"
fi
done
# Print final summary
print_summary "Enhanced Database Initialization Test"
}
# Run main function
main "$@"