432 lines
13 KiB
Bash
Executable File
432 lines
13 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# NIP-11 Relay Information Document Test
|
|
# Tests HTTP endpoint for relay information according to NIP-11 specification
|
|
|
|
set -e # Exit on any error
|
|
|
|
# Color constants
|
|
RED='\033[31m'
|
|
GREEN='\033[32m'
|
|
YELLOW='\033[33m'
|
|
BLUE='\033[34m'
|
|
BOLD='\033[1m'
|
|
RESET='\033[0m'
|
|
|
|
# Test configuration
|
|
RELAY_URL="http://127.0.0.1:8888"
|
|
RELAY_WS_URL="ws://127.0.0.1:8888"
|
|
|
|
# Print functions
|
|
print_header() {
|
|
echo -e "${BLUE}${BOLD}=== $1 ===${RESET}"
|
|
}
|
|
|
|
print_step() {
|
|
echo -e "${YELLOW}[STEP]${RESET} $1"
|
|
}
|
|
|
|
print_success() {
|
|
echo -e "${GREEN}✓${RESET} $1"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}✗${RESET} $1"
|
|
}
|
|
|
|
print_info() {
|
|
echo -e "${BLUE}[INFO]${RESET} $1"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "${YELLOW}[WARNING]${RESET} $1"
|
|
}
|
|
|
|
# Test functions
|
|
test_http_with_correct_header() {
|
|
print_step "Testing HTTP request with correct Accept header"
|
|
|
|
local response=""
|
|
local http_code=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
# Use curl to test with proper Accept header
|
|
response=$(curl -s -H "Accept: application/nostr+json" "$RELAY_URL/" 2>/dev/null || echo "")
|
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" -H "Accept: application/nostr+json" "$RELAY_URL/" 2>/dev/null || echo "000")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$http_code" == "200" ]]; then
|
|
print_success "HTTP 200 OK received with correct Accept header"
|
|
|
|
# Validate JSON response
|
|
if echo "$response" | jq . >/dev/null 2>&1; then
|
|
print_success "Response is valid JSON"
|
|
return 0
|
|
else
|
|
print_error "Response is not valid JSON"
|
|
return 1
|
|
fi
|
|
else
|
|
print_error "Expected HTTP 200, got HTTP $http_code"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_http_without_header() {
|
|
print_step "Testing HTTP request without Accept header (should return 406)"
|
|
|
|
local http_code=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" "$RELAY_URL/" 2>/dev/null || echo "000")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$http_code" == "406" ]]; then
|
|
print_success "HTTP 406 Not Acceptable received without proper Accept header"
|
|
return 0
|
|
else
|
|
print_error "Expected HTTP 406, got HTTP $http_code"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_http_with_wrong_header() {
|
|
print_step "Testing HTTP request with wrong Accept header (should return 406)"
|
|
|
|
local http_code=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" -H "Accept: application/json" "$RELAY_URL/" 2>/dev/null || echo "000")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$http_code" == "406" ]]; then
|
|
print_success "HTTP 406 Not Acceptable received with wrong Accept header"
|
|
return 0
|
|
else
|
|
print_error "Expected HTTP 406, got HTTP $http_code"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_cors_headers() {
|
|
print_step "Testing CORS headers presence"
|
|
|
|
local headers=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
headers=$(curl -s -I -H "Accept: application/nostr+json" "$RELAY_URL/" 2>/dev/null || echo "")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
local cors_origin_found=false
|
|
local cors_headers_found=false
|
|
local cors_methods_found=false
|
|
|
|
if echo "$headers" | grep -qi "access-control-allow-origin"; then
|
|
cors_origin_found=true
|
|
print_success "Access-Control-Allow-Origin header found"
|
|
fi
|
|
|
|
if echo "$headers" | grep -qi "access-control-allow-headers"; then
|
|
cors_headers_found=true
|
|
print_success "Access-Control-Allow-Headers header found"
|
|
fi
|
|
|
|
if echo "$headers" | grep -qi "access-control-allow-methods"; then
|
|
cors_methods_found=true
|
|
print_success "Access-Control-Allow-Methods header found"
|
|
fi
|
|
|
|
if [[ "$cors_origin_found" == true && "$cors_headers_found" == true && "$cors_methods_found" == true ]]; then
|
|
print_success "All required CORS headers present"
|
|
return 0
|
|
else
|
|
print_error "Missing CORS headers"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_json_structure() {
|
|
print_step "Testing NIP-11 JSON structure and required fields"
|
|
|
|
local response=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
response=$(curl -s -H "Accept: application/nostr+json" "$RELAY_URL/" 2>/dev/null || echo "")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
if [[ -z "$response" ]]; then
|
|
print_error "Empty response received"
|
|
return 1
|
|
fi
|
|
|
|
# Validate JSON structure using jq
|
|
if ! echo "$response" | jq . >/dev/null 2>&1; then
|
|
print_error "Response is not valid JSON"
|
|
return 1
|
|
fi
|
|
|
|
print_success "Valid JSON structure confirmed"
|
|
|
|
# Check for required fields
|
|
local required_checks=0
|
|
local total_checks=0
|
|
|
|
# Test name field
|
|
((total_checks++))
|
|
if echo "$response" | jq -e '.name' >/dev/null 2>&1; then
|
|
local name=$(echo "$response" | jq -r '.name')
|
|
print_success "Name field present: $name"
|
|
((required_checks++))
|
|
else
|
|
print_warning "Name field missing (optional)"
|
|
fi
|
|
|
|
# Test supported_nips field (required)
|
|
((total_checks++))
|
|
if echo "$response" | jq -e '.supported_nips' >/dev/null 2>&1; then
|
|
local nips=$(echo "$response" | jq -r '.supported_nips | @json')
|
|
print_success "Supported NIPs field present: $nips"
|
|
((required_checks++))
|
|
|
|
# Verify NIP-11 is in the supported list
|
|
if echo "$response" | jq -e '.supported_nips | contains([11])' >/dev/null 2>&1; then
|
|
print_success "NIP-11 correctly listed in supported NIPs"
|
|
else
|
|
print_warning "NIP-11 not found in supported NIPs list"
|
|
fi
|
|
else
|
|
print_error "Supported NIPs field missing (should be present)"
|
|
fi
|
|
|
|
# Test software field
|
|
((total_checks++))
|
|
if echo "$response" | jq -e '.software' >/dev/null 2>&1; then
|
|
local software=$(echo "$response" | jq -r '.software')
|
|
print_success "Software field present: $software"
|
|
((required_checks++))
|
|
else
|
|
print_warning "Software field missing (optional)"
|
|
fi
|
|
|
|
# Test version field
|
|
((total_checks++))
|
|
if echo "$response" | jq -e '.version' >/dev/null 2>&1; then
|
|
local version=$(echo "$response" | jq -r '.version')
|
|
print_success "Version field present: $version"
|
|
((required_checks++))
|
|
else
|
|
print_warning "Version field missing (optional)"
|
|
fi
|
|
|
|
# Test limitation object
|
|
((total_checks++))
|
|
if echo "$response" | jq -e '.limitation' >/dev/null 2>&1; then
|
|
print_success "Limitation object present"
|
|
((required_checks++))
|
|
|
|
# Check some common limitation fields
|
|
if echo "$response" | jq -e '.limitation.max_message_length' >/dev/null 2>&1; then
|
|
local max_msg=$(echo "$response" | jq -r '.limitation.max_message_length')
|
|
print_info " max_message_length: $max_msg"
|
|
fi
|
|
|
|
if echo "$response" | jq -e '.limitation.max_subscriptions' >/dev/null 2>&1; then
|
|
local max_subs=$(echo "$response" | jq -r '.limitation.max_subscriptions')
|
|
print_info " max_subscriptions: $max_subs"
|
|
fi
|
|
else
|
|
print_warning "Limitation object missing (recommended)"
|
|
fi
|
|
|
|
# Test description field
|
|
if echo "$response" | jq -e '.description' >/dev/null 2>&1; then
|
|
local description=$(echo "$response" | jq -r '.description')
|
|
print_success "Description field present: ${description:0:50}..."
|
|
else
|
|
print_warning "Description field missing (optional)"
|
|
fi
|
|
|
|
print_info "JSON structure validation: $required_checks/$total_checks core fields present"
|
|
return 0
|
|
}
|
|
|
|
test_content_type_header() {
|
|
print_step "Testing Content-Type header"
|
|
|
|
local headers=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
headers=$(curl -s -I -H "Accept: application/nostr+json" "$RELAY_URL/" 2>/dev/null || echo "")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
if echo "$headers" | grep -qi "content-type.*application/nostr+json"; then
|
|
print_success "Correct Content-Type header: application/nostr+json"
|
|
return 0
|
|
else
|
|
print_warning "Content-Type header not exactly 'application/nostr+json'"
|
|
echo "$headers" | grep -i "content-type" | head -1
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_non_root_path() {
|
|
print_step "Testing non-root path (should return 404)"
|
|
|
|
local http_code=""
|
|
|
|
if command -v curl &> /dev/null; then
|
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" -H "Accept: application/nostr+json" "$RELAY_URL/nonexistent" 2>/dev/null || echo "000")
|
|
else
|
|
print_error "curl command not found - required for NIP-11 testing"
|
|
return 1
|
|
fi
|
|
|
|
if [[ "$http_code" == "404" ]]; then
|
|
print_success "HTTP 404 Not Found received for non-root path"
|
|
return 0
|
|
else
|
|
print_error "Expected HTTP 404 for non-root path, got HTTP $http_code"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
test_websocket_still_works() {
|
|
print_step "Testing that WebSocket functionality still works on same port"
|
|
|
|
if ! command -v websocat &> /dev/null; then
|
|
print_warning "websocat not available - skipping WebSocket test"
|
|
return 0
|
|
fi
|
|
|
|
# Try to connect to WebSocket and send a simple REQ
|
|
local response=""
|
|
response=$(echo '["REQ","test_ws_nip11",{}]' | timeout 3s websocat "$RELAY_WS_URL" 2>/dev/null || echo "Connection failed")
|
|
|
|
if [[ "$response" == *"Connection failed"* ]]; then
|
|
print_error "WebSocket connection failed"
|
|
return 1
|
|
elif [[ "$response" == *"EOSE"* ]]; then
|
|
print_success "WebSocket still functional - received EOSE response"
|
|
return 0
|
|
else
|
|
print_warning "WebSocket response unclear, but connection succeeded"
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
# Main test function
|
|
run_nip11_tests() {
|
|
print_header "NIP-11 Relay Information Document Tests"
|
|
|
|
# Check dependencies
|
|
print_step "Checking dependencies..."
|
|
if ! command -v curl &> /dev/null; then
|
|
print_error "curl command not found - required for NIP-11 HTTP testing"
|
|
return 1
|
|
fi
|
|
if ! command -v jq &> /dev/null; then
|
|
print_error "jq command not found - required for JSON validation"
|
|
return 1
|
|
fi
|
|
print_success "All dependencies found"
|
|
|
|
print_header "PHASE 1: Basic HTTP Functionality"
|
|
|
|
# Test 1: Correct Accept header
|
|
if ! test_http_with_correct_header; then
|
|
return 1
|
|
fi
|
|
|
|
# Test 2: Missing Accept header
|
|
if ! test_http_without_header; then
|
|
return 1
|
|
fi
|
|
|
|
# Test 3: Wrong Accept header
|
|
if ! test_http_with_wrong_header; then
|
|
return 1
|
|
fi
|
|
|
|
print_header "PHASE 2: HTTP Headers Validation"
|
|
|
|
# Test 4: CORS headers
|
|
if ! test_cors_headers; then
|
|
return 1
|
|
fi
|
|
|
|
# Test 5: Content-Type header
|
|
if ! test_content_type_header; then
|
|
return 1
|
|
fi
|
|
|
|
print_header "PHASE 3: JSON Structure Validation"
|
|
|
|
# Test 6: JSON structure and required fields
|
|
if ! test_json_structure; then
|
|
return 1
|
|
fi
|
|
|
|
print_header "PHASE 4: Additional Endpoint Behavior"
|
|
|
|
# Test 7: Non-root paths
|
|
if ! test_non_root_path; then
|
|
return 1
|
|
fi
|
|
|
|
# Test 8: WebSocket compatibility
|
|
if ! test_websocket_still_works; then
|
|
return 1
|
|
fi
|
|
|
|
print_header "PHASE 5: NIP-11 Compliance Summary"
|
|
|
|
# Final validation - get the actual response and display it
|
|
print_step "Displaying complete NIP-11 response..."
|
|
local response=""
|
|
if command -v curl &> /dev/null; then
|
|
response=$(curl -s -H "Accept: application/nostr+json" "$RELAY_URL/" 2>/dev/null || echo "")
|
|
if [[ -n "$response" ]] && echo "$response" | jq . >/dev/null 2>&1; then
|
|
echo "$response" | jq .
|
|
else
|
|
print_error "Failed to retrieve or parse final response"
|
|
fi
|
|
fi
|
|
|
|
print_success "All NIP-11 tests passed!"
|
|
return 0
|
|
}
|
|
|
|
# Main execution
|
|
print_header "Starting NIP-11 Relay Information Document Test Suite"
|
|
echo
|
|
|
|
if run_nip11_tests; then
|
|
echo
|
|
print_success "All NIP-11 tests completed successfully!"
|
|
print_info "The C-Relay NIP-11 implementation is fully compliant"
|
|
print_info "✅ HTTP endpoint, Accept header validation, CORS, and JSON structure all working"
|
|
echo
|
|
exit 0
|
|
else
|
|
echo
|
|
print_error "Some NIP-11 tests failed"
|
|
exit 1
|
|
fi |