#!/bin/bash # Comprehensive release testing script for Pulse # Tests actual deployments, not just unit tests set -e VERSION=${1:-$(cat VERSION)} PULSE_URL=${PULSE_URL:-http://localhost:7655} API_TOKEN=${API_TOKEN:-""} RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' echo "================================================" echo "Pulse Release Test Suite v${VERSION}" echo "================================================" # Detect if auth is disabled AUTH_DISABLED=false security_status=$(curl -s "$PULSE_URL/api/security/status" 2>/dev/null || echo "{}") if echo "$security_status" | grep -q '"disabled":true'; then AUTH_DISABLED=true echo "" echo -e "${YELLOW}Note: Authentication is DISABLED (DISABLE_AUTH mode)${NC}" fi # Track test results FAILED_TESTS=() PASSED_TESTS=() # Test function run_test() { local test_name="$1" local test_command="$2" echo -n "Testing: $test_name... " if eval "$test_command" > /dev/null 2>&1; then echo -e "${GREEN}✓${NC}" PASSED_TESTS+=("$test_name") else echo -e "${RED}✗${NC}" FAILED_TESTS+=("$test_name") fi } # Test function with output run_test_verbose() { local test_name="$1" local test_command="$2" echo "Testing: $test_name..." if eval "$test_command"; then echo -e "${GREEN}✓ $test_name passed${NC}" PASSED_TESTS+=("$test_name") else echo -e "${RED}✗ $test_name failed${NC}" FAILED_TESTS+=("$test_name") fi } echo "" echo "1. HTTP/ROUTING TESTS" echo "====================" # Critical: Test root without trailing slash (catches issue #334) run_test "Root path without trailing slash (no redirect)" \ "curl -s -I ${PULSE_URL} | grep -q 'HTTP/1.1 200'" run_test "Root path with trailing slash" \ "curl -s -I ${PULSE_URL}/ | grep -q 'HTTP/1.1 200'" # Check for unwanted redirects run_test "No relative path redirects" \ "! curl -s -I ${PULSE_URL} | grep -q 'Location: ./'" # Test static assets (get actual filenames from index.html) JS_FILE=$(curl -s ${PULSE_URL}/ | grep -o '/assets/index-[^"]*\.js' | head -1) CSS_FILE=$(curl -s ${PULSE_URL}/ | grep -o '/assets/index-[^"]*\.css' | head -1) if [ -n "$JS_FILE" ]; then run_test "JavaScript assets load" \ "curl -s -I ${PULSE_URL}${JS_FILE} | grep -q 'Content-Type: application/javascript'" else echo -e "${RED}✗ Could not find JS file${NC}" FAILED_TESTS+=("JavaScript assets load") fi if [ -n "$CSS_FILE" ]; then run_test "CSS assets load" \ "curl -s -I ${PULSE_URL}${CSS_FILE} | grep -q 'Content-Type: text/css'" else echo -e "${RED}✗ Could not find CSS file${NC}" FAILED_TESTS+=("CSS assets load") fi # Test various access patterns run_test "Empty path handling" \ "curl -s -o /dev/null -w '%{http_code}' ${PULSE_URL} | grep -q '200'" if [ "$AUTH_DISABLED" != true ]; then run_test "SPA routes require authentication" \ "curl -s ${PULSE_URL}/settings | grep -q 'Authentication required'" else run_test "SPA routes accessible (auth disabled)" \ "curl -s ${PULSE_URL}/settings | grep -q '
'" fi echo "" echo "2. API ENDPOINT TESTS" echo "====================" # Public endpoints (should work without auth) run_test "API health endpoint" \ "curl -s ${PULSE_URL}/api/health | grep -q 'healthy'" run_test "API version endpoint" \ "curl -s ${PULSE_URL}/api/version | grep -q 'version'" # If API token provided, test protected endpoints if [ -n "$API_TOKEN" ]; then echo "Testing with API token..." run_test "API state with token" \ "curl -s -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/state | grep -q 'nodes'" run_test "API config/nodes with token" \ "curl -s -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/config/nodes | jq -e '. | type == \"array\"'" run_test "API export requires passphrase" \ "curl -s -X POST -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/config/export -d '{}' | grep -q 'Passphrase is required'" else echo -e "${YELLOW}Skipping auth tests (no API_TOKEN provided)${NC}" fi echo "" echo "3. WEBSOCKET TESTS" echo "==================" # Test WebSocket endpoint availability run_test "WebSocket endpoint responds" \ "curl -s -I -H 'Upgrade: websocket' ${PULSE_URL}/ws | grep -q 'HTTP/1.1'" echo "" echo "4. REVERSE PROXY SIMULATION" echo "===========================" # Simulate reverse proxy headers run_test "Handles X-Forwarded headers" \ "curl -s -H 'X-Forwarded-For: 10.0.0.1' -H 'X-Forwarded-Proto: https' ${PULSE_URL}/api/health | grep -q 'healthy'" run_test "Handles proxy without trailing slash" \ "curl -s -H 'X-Forwarded-Host: proxy.example.com' ${PULSE_URL} | grep -q ''" echo "" echo "5. DOCKER DEPLOYMENT TEST (if Docker available)" echo "==============================================" if false && command -v docker &> /dev/null; then # Temporarily disabled - hanging echo "Testing Docker deployment..." # Stop any existing test container docker stop pulse-test 2>/dev/null || true docker rm pulse-test 2>/dev/null || true # Run test container echo "Starting Docker container..." docker run -d --name pulse-test \ -p 7656:7655 \ -e API_TOKEN=test123 \ rcourtman/pulse:v${VERSION} > /dev/null 2>&1 # Wait for container to start sleep 5 run_test "Docker container running" \ "docker ps | grep -q pulse-test" run_test "Docker health endpoint" \ "curl -s http://localhost:7656/api/health | grep -q 'healthy'" run_test "Docker UI loads" \ "curl -s http://localhost:7656 | grep -q '<title>Pulse'" # Cleanup docker stop pulse-test > /dev/null 2>&1 docker rm pulse-test > /dev/null 2>&1 else echo -e "${YELLOW}Docker not available, skipping Docker tests${NC}" fi echo "" echo "6. LXC DEPLOYMENT TEST (if on Proxmox)" echo "=====================================" if command -v pct &> /dev/null; then echo "Would test LXC deployment (implement based on environment)" # This would create a test container, install Pulse, and verify else echo -e "${YELLOW}Not on Proxmox, skipping LXC tests${NC}" fi echo "" echo "7. UPDATE MECHANISM TEST" echo "=======================" # Update check if [ "$AUTH_DISABLED" = true ]; then run_test "Update check endpoint (auth disabled)" \ "curl -s ${PULSE_URL}/api/updates/check | jq -e '.currentVersion'" elif [ -n "$API_TOKEN" ]; then run_test "Update check endpoint with auth" \ "curl -s -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/updates/check | jq -e '.currentVersion'" else run_test "Update check requires auth" \ "curl -s ${PULSE_URL}/api/updates/check | grep -q 'Authentication required'" fi echo "" echo "8. PERFORMANCE TESTS" echo "===================" # Test response times RESPONSE_TIME=$(curl -s -o /dev/null -w '%{time_total}' ${PULSE_URL}/api/health) if (( $(echo "$RESPONSE_TIME < 1" | bc -l) )); then echo -e "${GREEN}✓ API response time: ${RESPONSE_TIME}s${NC}" PASSED_TESTS+=("API response time") else echo -e "${RED}✗ API slow: ${RESPONSE_TIME}s${NC}" FAILED_TESTS+=("API response time") fi echo "" echo "9. ERROR HANDLING TESTS" echo "======================" # 401 is returned before 404 when not authenticated (auth checked first) if [ "$AUTH_DISABLED" = true ]; then run_test "404 for non-existent endpoint" \ "curl -s -o /dev/null -w '%{http_code}' ${PULSE_URL}/api/nonexistent | grep -q '404'" elif [ -n "$API_TOKEN" ]; then run_test "404 for non-existent API endpoint" \ "curl -s -o /dev/null -w '%{http_code}' -H 'X-API-Token: $API_TOKEN' ${PULSE_URL}/api/nonexistent | grep -q '404'" else run_test "401 for non-existent endpoint (auth first)" \ "curl -s -o /dev/null -w '%{http_code}' ${PULSE_URL}/api/nonexistent | grep -q '401'" fi run_test "405 for wrong method" \ "curl -s -X DELETE -o /dev/null -w '%{http_code}' ${PULSE_URL}/api/health | grep -q '405'" echo "" echo "================================================" echo "TEST RESULTS SUMMARY" echo "================================================" echo -e "${GREEN}Passed: ${#PASSED_TESTS[@]} tests${NC}" echo -e "${RED}Failed: ${#FAILED_TESTS[@]} tests${NC}" if [ ${#FAILED_TESTS[@]} -gt 0 ]; then echo "" echo "Failed tests:" for test in "${FAILED_TESTS[@]}"; do echo " - $test" done echo "" echo -e "${RED}⚠️ RELEASE TESTS FAILED - DO NOT RELEASE!${NC}" exit 1 else echo "" echo -e "${GREEN}✅ All tests passed! Safe to release.${NC}" fi echo "" echo "Additional manual tests recommended:" echo " 1. Test behind actual reverse proxy (nginx/traefik)" echo " 2. Test with Cloudflare tunnel" echo " 3. Test ProxmoxVE 'update' command" echo " 4. Test on different architectures (ARM)" echo " 5. Test upgrade from previous version"