#!/bin/bash
# Test script for verifying proxy routing behavior
# Ensures /dashboard and /api/stats are always handled internally
PORT=8080
TEST_UPSTREAM_PORT=3000
echo "=== Proxy Routing Test Suite ==="
echo "================================"
# Start a simple upstream server that logs all requests
echo "Starting test upstream server on port $TEST_UPSTREAM_PORT..."
cat > test_upstream.py << 'EOF'
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import datetime
class TestHandler(BaseHTTPRequestHandler):
def do_GET(self):
print(f"[{datetime.datetime.now()}] UPSTREAM RECEIVED: {self.command} {self.path}")
if self.path == "/dashboard" or self.path == "/api/stats":
print("ERROR: Internal route leaked to upstream!")
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
response = {"upstream": "response", "path": self.path}
self.wfile.write(json.dumps(response).encode())
def do_POST(self):
self.do_GET()
def log_message(self, format, *args):
return # Suppress default logging
if __name__ == "__main__":
server = HTTPServer(('localhost', 3000), TestHandler)
print("Test upstream server running on port 3000")
server.serve_forever()
EOF
python3 test_upstream.py &
UPSTREAM_PID=$!
sleep 2
# Start the proxy with debug mode
echo "Starting proxy server..."
DEBUG=1 ./rproxy proxy_config.json &
PROXY_PID=$!
sleep 3
echo ""
echo "=== Test 1: Direct dashboard access ==="
echo "Request: GET /dashboard"
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/dashboard)
if [ "$response" = "200" ]; then
echo "✓ Dashboard served correctly (HTTP $response)"
else
echo "✗ Dashboard failed (HTTP $response)"
fi
echo ""
echo "=== Test 2: Direct API stats access ==="
echo "Request: GET /api/stats"
response=$(curl -s http://localhost:$PORT/api/stats | jq -r '.current' 2>/dev/null)
if [ ! -z "$response" ]; then
echo "✓ API stats served correctly"
else
echo "✗ API stats failed"
fi
echo ""
echo "=== Test 3: Multiple requests on same connection (keep-alive) ==="
echo "Testing pipeline: /api/stats -> /test -> /dashboard -> /another"
cat > test_requests.txt << 'EOF'
GET /api/stats HTTP/1.1
Host: localhost
Connection: keep-alive
GET /test HTTP/1.1
Host: localhost
Connection: keep-alive
GET /dashboard HTTP/1.1
Host: localhost
Connection: keep-alive
GET /another HTTP/1.1
Host: localhost
Connection: close
EOF
# Send pipelined requests
(cat test_requests.txt; sleep 1) | nc localhost $PORT > test_response.txt 2>&1
# Check if internal routes were handled correctly
if grep -q "cpu_percent" test_response.txt && grep -q "Reverse Proxy Monitor" test_response.txt; then
echo "✓ Internal routes handled correctly in pipeline"
else
echo "✗ Internal routes not handled correctly in pipeline"
fi
echo ""
echo "=== Test 4: Concurrent connections ==="
echo "Sending 10 concurrent requests to different endpoints..."
# Background requests
for i in {1..3}; do
curl -s http://localhost:$PORT/dashboard > /dev/null &
done
for i in {1..3}; do
curl -s http://localhost:$PORT/api/stats > /dev/null &
done
for i in {1..4}; do
curl -s http://localhost:$PORT/test$i > /dev/null &
done
wait
echo "✓ Concurrent requests completed"
echo ""
echo "=== Test 5: Rapid sequential requests ==="
echo "Sending rapid requests to verify state management..."
success=0
failed=0
for i in {1..20}; do
# Alternate between internal and forwarded routes
if [ $((i % 3)) -eq 0 ]; then
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/dashboard)
if [ "$response" = "200" ]; then
((success++))
else
((failed++))
echo " ✗ Dashboard request $i failed (HTTP $response)"
fi
elif [ $((i % 3)) -eq 1 ]; then
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/api/stats)
if [ "$response" = "200" ]; then
((success++))
else
((failed++))
echo " ✗ API stats request $i failed (HTTP $response)"
fi
else
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/test$i)
if [ "$response" = "200" ]; then
((success++))
else
((failed++))
fi
fi
done
echo "Results: $success successful, $failed failed"
if [ $failed -eq 0 ]; then
echo "✓ All rapid requests handled correctly"
else
echo "✗ Some requests failed"
fi
echo ""
echo "=== Test 6: WebSocket upgrade after regular request ==="
echo "Testing state reset after WebSocket..."
# First a normal request
curl -s http://localhost:$PORT/api/stats > /dev/null
echo "✓ Normal request sent"
# Then attempt WebSocket (will fail but tests state handling)
curl -s -H "Upgrade: websocket" -H "Connection: upgrade" http://localhost:$PORT/ws 2>/dev/null
echo "✓ WebSocket attempt sent"
# Then another normal request to internal route
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/dashboard)
if [ "$response" = "200" ]; then
echo "✓ Dashboard works after WebSocket attempt"
else
echo "✗ Dashboard failed after WebSocket attempt (HTTP $response)"
fi
echo ""
echo "=== Checking upstream server logs ==="
echo "Verifying no internal routes leaked to upstream..."
sleep 1
# The upstream server prints errors if it receives internal routes
# Check proxy debug logs for routing decisions
echo ""
echo "Recent routing decisions from proxy logs:"
echo "(Last 10 routing log entries)"
echo "----------------------------------------"
# Kill the servers
kill $PROXY_PID 2>/dev/null
kill $UPSTREAM_PID 2>/dev/null
# Clean up
rm -f test_upstream.py test_requests.txt test_response.txt
echo ""
echo "=== Test Complete ==="
echo "If you see any 'ERROR: Internal route leaked to upstream!' messages above,"
echo "the routing issue is NOT fixed. Otherwise, the fix is working correctly."