374 lines
12 KiB
Bash
Executable File
374 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# End-to-End Test for explorer.d-bis.org
|
||
# Comprehensive testing of all explorer functionality
|
||
|
||
set -uo pipefail
|
||
|
||
EXPLORER_URL="https://explorer.d-bis.org"
|
||
BASE_URL="http://192.168.11.140"
|
||
TEST_RESULTS=()
|
||
PASSED=0
|
||
FAILED=0
|
||
WARNINGS=0
|
||
|
||
# Colors
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
NC='\033[0m'
|
||
|
||
log_test() {
|
||
local status=$1
|
||
local message=$2
|
||
if [ "$status" = "PASS" ]; then
|
||
echo -e "${GREEN}✅ PASS${NC}: $message"
|
||
((PASSED++))
|
||
TEST_RESULTS+=("PASS: $message")
|
||
elif [ "$status" = "FAIL" ]; then
|
||
echo -e "${RED}❌ FAIL${NC}: $message"
|
||
((FAILED++))
|
||
TEST_RESULTS+=("FAIL: $message")
|
||
elif [ "$status" = "WARN" ]; then
|
||
echo -e "${YELLOW}⚠️ WARN${NC}: $message"
|
||
((WARNINGS++))
|
||
TEST_RESULTS+=("WARN: $message")
|
||
else
|
||
echo -e "${BLUE}ℹ️ INFO${NC}: $message"
|
||
fi
|
||
}
|
||
|
||
test_http_response() {
|
||
local url=$1
|
||
local expected_code=$2
|
||
local description=$3
|
||
|
||
local response_code=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 --max-time 30 "$url" 2>/dev/null || echo "000")
|
||
|
||
if [ "$response_code" = "$expected_code" ]; then
|
||
log_test "PASS" "$description (HTTP $response_code)"
|
||
return 0
|
||
elif [ "$response_code" = "000" ]; then
|
||
log_test "FAIL" "$description (Connection failed/timeout)"
|
||
return 1
|
||
else
|
||
log_test "FAIL" "$description (Expected HTTP $expected_code, got $response_code)"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
test_content() {
|
||
local url=$1
|
||
local search_term=$2
|
||
local description=$3
|
||
|
||
local content=$(curl -s -L --connect-timeout 10 --max-time 30 "$url" 2>/dev/null || echo "")
|
||
|
||
if [ -z "$content" ]; then
|
||
log_test "FAIL" "$description (Empty response)"
|
||
return 1
|
||
elif echo "$content" | grep -qi "$search_term"; then
|
||
log_test "PASS" "$description (Found: $search_term)"
|
||
return 0
|
||
else
|
||
# Show first 100 chars for debugging
|
||
PREVIEW=$(echo "$content" | head -c 100 | tr -d '\n')
|
||
log_test "FAIL" "$description (Not found: $search_term, got: $PREVIEW...)"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
test_json_response() {
|
||
local url=$1
|
||
local description=$2
|
||
|
||
local response=$(curl -s -L --connect-timeout 10 --max-time 30 "$url" 2>/dev/null || echo "")
|
||
|
||
if echo "$response" | jq . >/dev/null 2>&1; then
|
||
log_test "PASS" "$description (Valid JSON)"
|
||
return 0
|
||
else
|
||
log_test "FAIL" "$description (Invalid JSON or empty response)"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
echo "=========================================="
|
||
echo "End-to-End Test: explorer.d-bis.org"
|
||
echo "=========================================="
|
||
echo "Test URL: $EXPLORER_URL"
|
||
echo "Base URL: $BASE_URL"
|
||
echo "Date: $(date)"
|
||
echo "=========================================="
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 1. Basic Connectivity Tests
|
||
# ============================================
|
||
echo "=== 1. Basic Connectivity Tests ==="
|
||
|
||
# Test HTTPS accessibility (may fail if Cloudflare tunnel not running)
|
||
HTTPS_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 5 --max-time 10 "$EXPLORER_URL" 2>/dev/null || echo "000")
|
||
if [ "$HTTPS_CODE" = "200" ] || [ "$HTTPS_CODE" = "301" ] || [ "$HTTPS_CODE" = "302" ]; then
|
||
log_test "PASS" "HTTPS homepage accessibility (HTTP $HTTPS_CODE)"
|
||
elif [ "$HTTPS_CODE" = "000" ]; then
|
||
log_test "WARN" "HTTPS homepage not accessible externally (Cloudflare tunnel may be down - testing internal access instead)"
|
||
else
|
||
log_test "WARN" "HTTPS homepage returned HTTP $HTTPS_CODE"
|
||
fi
|
||
|
||
# Test HTTP redirect
|
||
test_http_response "http://explorer.d-bis.org" "301\|302" "HTTP to HTTPS redirect"
|
||
|
||
# Test direct IP access (internal)
|
||
test_http_response "$BASE_URL:80/" "200" "Direct IP access (port 80)"
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 2. Frontend Content Tests
|
||
# ============================================
|
||
echo "=== 2. Frontend Content Tests ==="
|
||
|
||
# Use internal URL for content tests since HTTPS may not be accessible
|
||
CONTENT_URL="$BASE_URL:80"
|
||
|
||
# Test homepage content
|
||
test_content "$CONTENT_URL" "SolaceScanScout" "Homepage contains SolaceScanScout title"
|
||
|
||
# Test explorer branding
|
||
test_content "$CONTENT_URL" "Explorer" "Homepage contains explorer branding"
|
||
|
||
# Test HTML structure
|
||
test_content "$CONTENT_URL" "<!DOCTYPE html" "Valid HTML document structure"
|
||
|
||
# Test JavaScript loading
|
||
test_content "$CONTENT_URL" "ethers" "JavaScript libraries present"
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 3. API Endpoint Tests
|
||
# ============================================
|
||
echo "=== 3. API Endpoint Tests ==="
|
||
|
||
# Test Blockscout API stats (via internal nginx)
|
||
test_json_response "$BASE_URL:80/api/v2/stats" "Blockscout API /api/v2/stats endpoint (via nginx)"
|
||
|
||
# Test Blockscout API blocks (via internal nginx)
|
||
test_json_response "$BASE_URL:80/api/v2/blocks" "Blockscout API /api/v2/blocks endpoint (via nginx)"
|
||
|
||
# Test Blockscout API transactions (via internal nginx)
|
||
test_json_response "$BASE_URL:80/api/v2/transactions" "Blockscout API /api/v2/transactions endpoint (via nginx)"
|
||
|
||
# Test direct API access (internal)
|
||
test_json_response "$BASE_URL:4000/api/v2/stats" "Direct Blockscout API access (port 4000)"
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 4. Security & Headers Tests
|
||
# ============================================
|
||
echo "=== 4. Security & Headers Tests ==="
|
||
|
||
# Test headers from internal nginx
|
||
HEADERS=$(curl -s -I -L --connect-timeout 10 --max-time 30 "$BASE_URL:80/" 2>/dev/null || echo "")
|
||
|
||
if echo "$HEADERS" | grep -qi "strict-transport-security\|HSTS"; then
|
||
log_test "PASS" "HSTS header present"
|
||
else
|
||
log_test "WARN" "HSTS header not found"
|
||
fi
|
||
|
||
if echo "$HEADERS" | grep -qi "x-frame-options"; then
|
||
log_test "PASS" "X-Frame-Options header present"
|
||
else
|
||
log_test "WARN" "X-Frame-Options header not found"
|
||
fi
|
||
|
||
if echo "$HEADERS" | grep -qi "x-content-type-options"; then
|
||
log_test "PASS" "X-Content-Type-Options header present"
|
||
else
|
||
log_test "WARN" "X-Content-Type-Options header not found"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 5. Performance Tests
|
||
# ============================================
|
||
echo "=== 5. Performance Tests ==="
|
||
|
||
# Test performance on internal URL
|
||
START_TIME=$(date +%s%N)
|
||
curl -s -o /dev/null -w '%{time_total}' --connect-timeout 10 --max-time 30 "$BASE_URL:80/" >/dev/null 2>&1
|
||
END_TIME=$(date +%s%N)
|
||
RESPONSE_TIME=$(echo "scale=3; ($END_TIME - $START_TIME) / 1000000000" | bc 2>/dev/null || echo "N/A")
|
||
|
||
if [ "$RESPONSE_TIME" != "N/A" ]; then
|
||
if (( $(echo "$RESPONSE_TIME < 3.0" | bc -l 2>/dev/null || echo 0) )); then
|
||
log_test "PASS" "Response time acceptable (${RESPONSE_TIME}s)"
|
||
else
|
||
log_test "WARN" "Response time slow (${RESPONSE_TIME}s)"
|
||
fi
|
||
else
|
||
log_test "WARN" "Could not measure response time"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 6. Service Status Tests
|
||
# ============================================
|
||
echo "=== 6. Service Status Tests ==="
|
||
|
||
# Test nginx on VMID 5000
|
||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.11.10 "ssh -o ConnectTimeout=5 root@r630-02 'pct exec 5000 -- systemctl is-active nginx 2>/dev/null'" 2>/dev/null | grep -q "active"; then
|
||
log_test "PASS" "Nginx service running on VMID 5000"
|
||
else
|
||
log_test "FAIL" "Nginx service not running on VMID 5000"
|
||
fi
|
||
|
||
# Test Blockscout service
|
||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.11.10 "ssh -o ConnectTimeout=5 root@r630-02 'pct exec 5000 -- systemctl is-active blockscout 2>/dev/null || pct exec 5000 -- docker ps | grep -q blockscout'" 2>/dev/null | grep -qE "active|blockscout"; then
|
||
log_test "PASS" "Blockscout service running on VMID 5000"
|
||
else
|
||
log_test "WARN" "Blockscout service status unknown"
|
||
fi
|
||
|
||
# Test port 80 listening
|
||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.11.10 "ssh -o ConnectTimeout=5 root@r630-02 'pct exec 5000 -- ss -tlnp | grep -q :80'" 2>/dev/null; then
|
||
log_test "PASS" "Port 80 listening on VMID 5000"
|
||
else
|
||
log_test "FAIL" "Port 80 not listening on VMID 5000"
|
||
fi
|
||
|
||
# Test port 4000 listening
|
||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.11.10 "ssh -o ConnectTimeout=5 root@r630-02 'pct exec 5000 -- ss -tlnp | grep -q :4000'" 2>/dev/null; then
|
||
log_test "PASS" "Port 4000 listening on VMID 5000"
|
||
else
|
||
log_test "WARN" "Port 4000 not listening on VMID 5000"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 7. Frontend Functionality Tests
|
||
# ============================================
|
||
echo "=== 7. Frontend Functionality Tests ==="
|
||
|
||
# Check if frontend file exists
|
||
if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.11.10 "ssh -o ConnectTimeout=5 root@r630-02 'pct exec 5000 -- test -f /var/www/html/index.html'" 2>/dev/null; then
|
||
log_test "PASS" "Frontend HTML file exists"
|
||
else
|
||
log_test "FAIL" "Frontend HTML file not found"
|
||
fi
|
||
|
||
# Check frontend file size (should be substantial)
|
||
FRONTEND_SIZE=$(ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.11.10 "ssh -o ConnectTimeout=5 root@r630-02 'pct exec 5000 -- stat -c%s /var/www/html/index.html 2>/dev/null'" 2>/dev/null || echo "0")
|
||
if [ "$FRONTEND_SIZE" -gt 10000 ]; then
|
||
log_test "PASS" "Frontend file size reasonable (${FRONTEND_SIZE} bytes)"
|
||
else
|
||
log_test "WARN" "Frontend file size suspiciously small (${FRONTEND_SIZE} bytes)"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 8. Network Routing Tests
|
||
# ============================================
|
||
echo "=== 8. Network Routing Tests ==="
|
||
|
||
# Test NPMplus routing (may fail if Cloudflare tunnel down)
|
||
NPMPLUS_CHECK=$(curl -s -I --connect-timeout 5 --max-time 10 "https://explorer.d-bis.org" 2>/dev/null | head -1 || echo "")
|
||
if echo "$NPMPLUS_CHECK" | grep -qE "200|301|302"; then
|
||
log_test "PASS" "NPMplus routing working"
|
||
elif echo "$NPMPLUS_CHECK" | grep -qE "000|timeout"; then
|
||
log_test "WARN" "NPMplus routing timeout (Cloudflare tunnel may be down)"
|
||
else
|
||
log_test "WARN" "NPMplus routing returned: $NPMPLUS_CHECK"
|
||
fi
|
||
|
||
# Test DNS resolution
|
||
if host explorer.d-bis.org 2>/dev/null | grep -q "has address"; then
|
||
log_test "PASS" "DNS resolution working"
|
||
else
|
||
log_test "WARN" "DNS resolution check failed (may be local DNS issue)"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 9. API Data Validation
|
||
# ============================================
|
||
echo "=== 9. API Data Validation ==="
|
||
|
||
# Get stats and validate structure (use internal URL)
|
||
STATS_JSON=$(curl -s -L --connect-timeout 10 --max-time 30 "$BASE_URL:80/api/v2/stats" 2>/dev/null || echo "{}")
|
||
|
||
if echo "$STATS_JSON" | jq -e '.total_blocks' >/dev/null 2>&1; then
|
||
TOTAL_BLOCKS=$(echo "$STATS_JSON" | jq -r '.total_blocks // 0')
|
||
if [ "$TOTAL_BLOCKS" -gt 0 ]; then
|
||
log_test "PASS" "API returns valid block count ($TOTAL_BLOCKS blocks)"
|
||
else
|
||
log_test "WARN" "API returns zero blocks (may be indexing)"
|
||
fi
|
||
else
|
||
log_test "FAIL" "API stats structure invalid"
|
||
fi
|
||
|
||
# Check for chain ID
|
||
if echo "$STATS_JSON" | jq -e '.chain_id' >/dev/null 2>&1; then
|
||
CHAIN_ID=$(echo "$STATS_JSON" | jq -r '.chain_id // "unknown"')
|
||
log_test "PASS" "API returns chain ID ($CHAIN_ID)"
|
||
else
|
||
log_test "WARN" "API does not return chain ID"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# 10. Error Handling Tests
|
||
# ============================================
|
||
echo "=== 10. Error Handling Tests ==="
|
||
|
||
# Test 404 handling (use internal URL)
|
||
test_http_response "$BASE_URL:80/nonexistent-page" "404" "404 error handling"
|
||
|
||
# Test API error handling (use internal URL)
|
||
API_ERROR=$(curl -s -L --connect-timeout 10 --max-time 30 "$BASE_URL:80/api/v2/invalid-endpoint" 2>/dev/null || echo "")
|
||
if echo "$API_ERROR" | grep -qiE "error|404|not found"; then
|
||
log_test "PASS" "API error handling works"
|
||
else
|
||
log_test "WARN" "API error handling unclear"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# ============================================
|
||
# Summary
|
||
# ============================================
|
||
echo "=========================================="
|
||
echo "Test Summary"
|
||
echo "=========================================="
|
||
echo -e "${GREEN}Passed: $PASSED${NC}"
|
||
echo -e "${RED}Failed: $FAILED${NC}"
|
||
echo -e "${YELLOW}Warnings: $WARNINGS${NC}"
|
||
echo ""
|
||
|
||
TOTAL=$((PASSED + FAILED + WARNINGS))
|
||
if [ $TOTAL -gt 0 ]; then
|
||
PASS_PERCENT=$(echo "scale=1; $PASSED * 100 / $TOTAL" | bc 2>/dev/null || echo "0")
|
||
echo "Pass Rate: ${PASS_PERCENT}%"
|
||
fi
|
||
|
||
echo ""
|
||
if [ $FAILED -eq 0 ]; then
|
||
echo -e "${GREEN}✅ All critical tests passed!${NC}"
|
||
exit 0
|
||
else
|
||
echo -e "${RED}❌ Some tests failed. Review results above.${NC}"
|
||
exit 1
|
||
fi
|