Files
explorer-monorepo/scripts/e2e-test-explorer.sh

419 lines
16 KiB
Bash
Raw Permalink Normal View History

#!/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 extra_opts="${4:-}"
local content=$(curl -s -L --max-redirs 3 $extra_opts --connect-timeout 10 --max-time 30 "$url" 2>/dev/null || echo "")
if [ -z "$content" ]; then
log_test "FAIL" "$description (Empty response)"
return 1
elif grep -qi "$search_term" <<< "$content"; then
log_test "PASS" "$description (Found: $search_term)"
return 0
else
# Show first 100 chars for debugging
PREVIEW=$(printf '%.100s' "$content" | 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 (301 or 302)
REDIRECT_CODE=$(curl -s -o /dev/null -w '%{http_code}' --connect-timeout 10 "http://explorer.d-bis.org" 2>/dev/null || echo "000")
if [ "$REDIRECT_CODE" = "301" ] || [ "$REDIRECT_CODE" = "302" ]; then
log_test "PASS" "HTTP to HTTPS redirect (HTTP $REDIRECT_CODE)"
else
log_test "FAIL" "HTTP to HTTPS redirect (Expected 301 or 302, got $REDIRECT_CODE)"
fi
# 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 (optional; Blockscout may use different field)
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)"
elif echo "$STATS_JSON" | jq -e '.total_blocks' >/dev/null 2>&1; then
log_test "PASS" "API returns stats (chain ID optional)"
else
log_test "WARN" "API does not return chain ID"
fi
echo ""
# ============================================
# 10. Path-Based URL & Link Tests (SPA routing)
# ============================================
echo "=== 10. Path-Based URL & Link Tests ==="
# Use BASE_URL:80 for path tests (HTTP SPA paths served by nginx)
PATH_TEST_BASE="$BASE_URL:80"
PATH_CURL_EXTRA=""
# SPA serves index.html for all paths - verify path-based routing is present
test_content "$PATH_TEST_BASE/address/0x99b3511a2d315a497c8112c1fdd8d508d4b1e506" "fromPath" "Path-based routing code present (address URL)" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/address/0x99b3511a2d315a497c8112c1fdd8d508d4b1e506" "SolaceScanScout" "Address path serves SPA shell" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/blocks" "SolaceScanScout" "Blocks path serves SPA" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/transactions" "SolaceScanScout" "Transactions path serves SPA" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/bridge" "SolaceScanScout" "Bridge path serves SPA" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/weth" "SolaceScanScout" "WETH path serves SPA" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/watchlist" "SolaceScanScout" "Watchlist path serves SPA" "$PATH_CURL_EXTRA"
# Verify nav links exist in HTML (use same base)
test_content "$PATH_TEST_BASE/" "#/home" "Home nav link present" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/" "#/blocks" "Blocks nav link present" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/" "#/transactions" "Transactions nav link present" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/" "#/bridge" "Bridge nav link present" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/" "#/weth" "WETH nav link present" "$PATH_CURL_EXTRA"
test_content "$PATH_TEST_BASE/" "/snap/" "MetaMask Snap nav link present" "$PATH_CURL_EXTRA"
# Verify applyHashRoute handles pathname
test_content "$PATH_TEST_BASE/" "location.pathname" "Path-based route detection present" "$PATH_CURL_EXTRA"
echo ""
# ============================================
# 11. Error Handling Tests
# ============================================
echo "=== 11. Error Handling Tests ==="
# SPA fallback: unknown paths return index.html (200) or redirect (301/302)
FALLBACK_CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-redirs 2 --connect-timeout 10 "$BASE_URL:80/nonexistent-page" 2>/dev/null || echo "000")
if [ "$FALLBACK_CODE" = "200" ] || [ "$FALLBACK_CODE" = "301" ] || [ "$FALLBACK_CODE" = "302" ]; then
log_test "PASS" "SPA fallback for unknown paths (HTTP $FALLBACK_CODE)"
else
log_test "WARN" "SPA fallback returned HTTP $FALLBACK_CODE (expected 200 or redirect)"
fi
# 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 "")
API_ERROR_CODE=$(curl -s -o /dev/null -w '%{http_code}' -L --connect-timeout 10 --max-time 30 "$BASE_URL:80/api/v2/invalid-endpoint" 2>/dev/null || echo "000")
if [ "$API_ERROR_CODE" = "404" ] || [ "$API_ERROR_CODE" = "400" ] || echo "$API_ERROR" | grep -qiE "error|404|not found"; then
log_test "PASS" "API error handling works (HTTP $API_ERROR_CODE)"
else
log_test "WARN" "API error handling unclear (HTTP $API_ERROR_CODE)"
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