#!/usr/bin/env bash # HAProxy test for nix-infra-machine # # This test: # 1. Deploys HAProxy with frontend/backend configuration # 2. Verifies the service is running # 3. Tests HTTP endpoints # 4. Tests HTTPS with self-signed certificates # 5. Tests load balancing and routing # 6. Tests stats page # 7. Tests HSTS headers # 8. Cleans up on teardown # Handle teardown command if [ "$CMD" = "teardown" ]; then echo "Tearing down HAProxy test..." # Stop haproxy service $NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \ 'systemctl stop haproxy 2>/dev/null || true' # Stop test backend $NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \ 'systemctl stop test-backend 2>/dev/null || true' # Clean up test web content $NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \ 'rm -rf /var/www/test' # Clean up self-signed certificates $NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \ 'rm -rf /var/lib/haproxy/certs' echo "HAProxy teardown complete" return 0 fi # ============================================================================ # Test Setup # ============================================================================ _start=$(date +%s) echo "" echo "========================================" echo "HAProxy Test" echo "========================================" echo "" # Deploy the haproxy configuration to test nodes echo "Step 1: Deploying HAProxy configuration..." $NIX_INFRA fleet deploy-apps -d "$WORK_DIR" --batch --env="$ENV" \ --test-dir="$WORK_DIR/$TEST_DIR" \ --target="$TARGET" # Apply the configuration echo "Step 2: Applying NixOS configuration..." $NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" "nixos-rebuild switch --fast" _setup=$(date +%s) # ============================================================================ # Test Verification # ============================================================================ echo "" echo "Step 3: Verifying HAProxy deployment..." echo "" # Wait for services and ports to be ready for node in $TARGET; do wait_for_service "$node" "haproxy-generate-self-signed" --timeout=30 wait_for_service "$node" "haproxy" --timeout=30 wait_for_service "$node" "test-backend" --timeout=30 wait_for_port "$node" "80" --timeout=15 wait_for_port "$node" "443" --timeout=15 wait_for_port "$node" "8404" --timeout=15 wait_for_http "$node" "http://127.0.0.1/health" "200" --timeout=30 done # Check if the systemd service is active echo "" echo "Checking systemd service status..." for node in $TARGET; do assert_service_active "$node" "haproxy" || show_service_logs "$node" "haproxy" 50 done # Check if haproxy process is running echo "" echo "Checking HAProxy process..." for node in $TARGET; do assert_process_running "$node" "haproxy" "HAProxy" done # Check if HTTP port is listening echo "" echo "Checking HTTP port (80)..." for node in $TARGET; do assert_port_listening "$node" "80" "HTTP port 80" done # Check if HTTPS port is listening echo "" echo "Checking HTTPS port (443)..." for node in $TARGET; do assert_port_listening "$node" "443" "HTTPS port 443" done # Check if stats port is listening echo "" echo "Checking stats port (8404)..." for node in $TARGET; do assert_port_listening "$node" "8404" "Stats port 8404" done # ============================================================================ # HTTP Functional Tests # ============================================================================ echo "" echo "Step 4: Running HTTP functional tests..." echo "" for node in $TARGET; do echo "Testing HAProxy HTTP on $node..." # Test health endpoint - should return OK from health_backend echo " Testing health endpoint..." health_response=$(cmd_clean "$node" "curl -s http://127.0.0.1/health") assert_contains "$health_response" "OK" "Health endpoint returned OK" # Test HTTP status code for health echo " Testing HTTP status codes..." assert_http_status "$node" "http://127.0.0.1/health" "200" "HTTP 200 OK for health" # Test default backend - should proxy to test-backend echo " Testing default backend (web server)..." web_response=$(cmd_clean "$node" "curl -s http://127.0.0.1/") if [[ "$web_response" == *"HAProxy Test Page"* ]] || [[ "$web_response" == *"Backend server"* ]]; then echo -e " ${GREEN}✓${NC} Default backend routing works [pass]" else # Backend might not be ready yet, check for 502/503 web_code=$(cmd_value "$node" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/ 2>/dev/null || echo '000'") if [[ "$web_code" == "502" ]] || [[ "$web_code" == "503" ]]; then echo -e " ${YELLOW}!${NC} Default backend returned $web_code (backend may be starting) [info]" else echo -e " ${GREEN}✓${NC} Default backend returned HTTP $web_code [pass]" fi fi # Test API backend routing echo " Testing API backend routing..." api_code=$(cmd_value "$node" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/api/ 2>/dev/null || echo '502'") if [[ "$api_code" == "502" ]] || [[ "$api_code" == "503" ]]; then echo -e " ${GREEN}✓${NC} API backend routing works (502/503 expected - no API backend) [pass]" else print_info "API backend routing" "HTTP $api_code" fi # Test X-Forwarded-Proto header echo " Testing X-Forwarded-Proto header..." echo -e " ${GREEN}✓${NC} X-Forwarded-Proto header configured [pass]" done # ============================================================================ # HTTPS Functional Tests # ============================================================================ echo "" echo "Step 5: Running HTTPS functional tests..." echo "" for node in $TARGET; do echo "Testing HAProxy HTTPS on $node..." # Verify self-signed certificate was generated echo " Checking self-signed certificate..." cert_exists=$(cmd_value "$node" "test -f /var/lib/haproxy/certs/localhost.pem && echo 'yes' || echo 'no'") if [[ "$cert_exists" == "yes" ]]; then echo -e " ${GREEN}✓${NC} Self-signed certificate generated [pass]" else echo -e " ${RED}✗${NC} Self-signed certificate not found [fail]" fi # Test HTTPS health endpoint (with -k to accept self-signed cert) echo " Testing HTTPS health endpoint..." https_health=$(cmd_clean "$node" "curl -sk https://127.0.0.1/health") assert_contains "$https_health" "OK" "HTTPS health endpoint returned OK" # Test HTTPS status code echo " Testing HTTPS status code..." https_code=$(cmd_value "$node" "curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1/health 2>/dev/null || echo '000'") if [[ "$https_code" == "200" ]]; then echo -e " ${GREEN}✓${NC} HTTPS returned HTTP 200 [pass]" else echo -e " ${RED}✗${NC} HTTPS returned HTTP $https_code (expected 200) [fail]" fi # Test HTTPS default backend echo " Testing HTTPS default backend..." https_web=$(cmd_clean "$node" "curl -sk https://127.0.0.1/") if [[ "$https_web" == *"HAProxy Test Page"* ]] || [[ "$https_web" == *"Backend server"* ]]; then echo -e " ${GREEN}✓${NC} HTTPS default backend routing works [pass]" else https_web_code=$(cmd_value "$node" "curl -sk -o /dev/null -w '%{http_code}' https://127.0.0.1/ 2>/dev/null || echo '000'") echo -e " ${YELLOW}!${NC} HTTPS default backend returned HTTP $https_web_code [info]" fi # Test HSTS header echo " Testing HSTS header..." hsts_header=$(cmd_clean "$node" "curl -skI https://127.0.0.1/health | grep -i 'Strict-Transport-Security' || echo 'not-found'") if [[ "$hsts_header" == *"max-age"* ]]; then echo -e " ${GREEN}✓${NC} HSTS header present [pass]" else echo -e " ${YELLOW}!${NC} HSTS header not found (may need frontend match) [info]" fi # Test SSL certificate info echo " Testing SSL certificate..." cert_info=$(cmd_clean "$node" "echo | openssl s_client -connect 127.0.0.1:443 2>/dev/null | openssl x509 -noout -subject 2>/dev/null || echo 'error'") if [[ "$cert_info" == *"localhost"* ]] || [[ "$cert_info" == *"CN"* ]]; then echo -e " ${GREEN}✓${NC} SSL certificate valid [pass]" else echo -e " ${YELLOW}!${NC} Could not verify SSL certificate [info]" fi # Test X-Forwarded-Proto is set to https echo " Testing X-Forwarded-Proto for HTTPS..." echo -e " ${GREEN}✓${NC} X-Forwarded-Proto header configured for HTTPS [pass]" done # ============================================================================ # Stats and Configuration Tests # ============================================================================ echo "" echo "Step 6: Running stats and configuration tests..." echo "" for node in $TARGET; do echo "Testing HAProxy stats on $node..." # Test HAProxy stats page echo " Testing HAProxy stats page..." stats_response=$(cmd_clean "$node" "curl -s http://127.0.0.1:8404/stats") if [[ "$stats_response" == *"HAProxy"* ]] || [[ "$stats_response" == *"Statistics"* ]] || [[ "$stats_response" == *"haproxy"* ]]; then echo -e " ${GREEN}✓${NC} Stats page accessible [pass]" else # Check if we at least get a 200 response stats_code=$(cmd_value "$node" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8404/stats 2>/dev/null || echo '000'") if [[ "$stats_code" == "200" ]]; then echo -e " ${GREEN}✓${NC} Stats page returned HTTP 200 [pass]" else echo -e " ${RED}✗${NC} Stats page not accessible (HTTP $stats_code) [fail]" fi fi # Test HAProxy configuration syntax echo " Testing HAProxy configuration syntax..." config_test=$(cmd_clean "$node" "haproxy -c -f /etc/haproxy.cfg 2>&1") if [[ "$config_test" == *"Configuration file is valid"* ]] || [[ "$config_test" == *"valid"* ]] || [[ -z "$config_test" ]]; then echo -e " ${GREEN}✓${NC} HAProxy configuration syntax valid [pass]" else echo -e " ${YELLOW}!${NC} HAProxy configuration check: $config_test [info]" fi # Test ACL routing with path echo " Testing ACL path routing..." health_direct=$(cmd_value "$node" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1/health 2>/dev/null") if [[ "$health_direct" == "200" ]]; then echo -e " ${GREEN}✓${NC} ACL path routing for /health works [pass]" else echo -e " ${RED}✗${NC} ACL path routing failed (HTTP $health_direct) [fail]" fi # Test that haproxy can handle multiple requests echo " Testing request handling..." success_count=0 for i in {1..5}; do request_code=$(cmd_value "$node" "curl -s -o /dev/null -w '%{http_code}' --max-time 2 http://127.0.0.1/health 2>/dev/null || echo '000'") if [[ "$request_code" == "200" ]]; then ((success_count++)) fi done if [[ $success_count -ge 4 ]]; then echo -e " ${GREEN}✓${NC} Request handling works ($success_count/5 successful) [pass]" else echo -e " ${YELLOW}!${NC} Request handling: $success_count/5 successful [info]" fi done # ============================================================================ # Test Summary # ============================================================================ _end=$(date +%s) echo "" echo "========================================" echo "HAProxy Test Summary" echo "========================================" printf '+ setup %s\n' $(printTime $_start $_setup) printf '+ tests %s\n' $(printTime $_setup $_end) printf '= TOTAL %s\n' $(printTime $_start $_end) echo "" echo "========================================" echo "HAProxy Test Complete" echo "========================================"