450 lines
17 KiB
Bash
Executable File
450 lines
17 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# NIP-45 COUNT Message Test - Test counting functionality
|
|
# Tests COUNT messages with various filters to verify correct event counting
|
|
|
|
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="ws://127.0.0.1:8888"
|
|
TEST_PRIVATE_KEY="nsec1j4c6269y9w0q2er2xjw8sv2ehyrtfxq3jwgdlxj6qfn8z4gjsq5qfvfk99"
|
|
|
|
# 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"
|
|
}
|
|
|
|
# Global arrays to store event IDs for counting tests
|
|
declare -a REGULAR_EVENT_IDS=()
|
|
declare -a REPLACEABLE_EVENT_IDS=()
|
|
declare -a EPHEMERAL_EVENT_IDS=()
|
|
declare -a ADDRESSABLE_EVENT_IDS=()
|
|
|
|
# Baseline counts from existing events in relay
|
|
BASELINE_TOTAL=0
|
|
BASELINE_KIND1=0
|
|
BASELINE_KIND0=0
|
|
BASELINE_KIND30001=0
|
|
BASELINE_AUTHOR=0
|
|
BASELINE_TYPE_REGULAR=0
|
|
BASELINE_TEST_NIP45=0
|
|
BASELINE_KINDS_01=0
|
|
BASELINE_COMBINED=0
|
|
|
|
# Helper function to publish event and extract ID
|
|
publish_event() {
|
|
local event_json="$1"
|
|
local event_type="$2"
|
|
local description="$3"
|
|
|
|
# Extract event ID
|
|
local event_id=$(echo "$event_json" | jq -r '.id' 2>/dev/null)
|
|
if [[ "$event_id" == "null" || -z "$event_id" ]]; then
|
|
print_error "Could not extract event ID from $description"
|
|
return 1
|
|
fi
|
|
|
|
print_info "Publishing $description..."
|
|
|
|
# Create EVENT message in Nostr format
|
|
local event_message="[\"EVENT\",$event_json]"
|
|
|
|
# Publish to relay
|
|
local response=""
|
|
if command -v websocat &> /dev/null; then
|
|
response=$(echo "$event_message" | timeout 5s websocat "$RELAY_URL" 2>&1 || echo "Connection failed")
|
|
else
|
|
print_error "websocat not found - required for testing"
|
|
return 1
|
|
fi
|
|
|
|
# Check response
|
|
if [[ "$response" == *"Connection failed"* ]]; then
|
|
print_error "Failed to connect to relay for $description"
|
|
return 1
|
|
elif [[ "$response" == *"true"* ]]; then
|
|
print_success "$description uploaded (ID: ${event_id:0:16}...)"
|
|
|
|
# Store event ID in appropriate array
|
|
case "$event_type" in
|
|
"regular") REGULAR_EVENT_IDS+=("$event_id") ;;
|
|
"replaceable") REPLACEABLE_EVENT_IDS+=("$event_id") ;;
|
|
"ephemeral") EPHEMERAL_EVENT_IDS+=("$event_id") ;;
|
|
"addressable") ADDRESSABLE_EVENT_IDS+=("$event_id") ;;
|
|
esac
|
|
echo # Add blank line for readability
|
|
return 0
|
|
else
|
|
print_warning "$description might have failed: $response"
|
|
echo # Add blank line for readability
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Helper function to get baseline count for a filter (before publishing test events)
|
|
get_baseline_count() {
|
|
local filter="$1"
|
|
|
|
# Create COUNT message
|
|
local count_message="[\"COUNT\",\"baseline\",$filter]"
|
|
|
|
# Send COUNT message and get response
|
|
local response=""
|
|
if command -v websocat &> /dev/null; then
|
|
response=$(echo "$count_message" | timeout 3s websocat "$RELAY_URL" 2>/dev/null || echo "")
|
|
fi
|
|
|
|
# Parse COUNT response
|
|
if [[ -n "$response" ]]; then
|
|
local count_result=$(echo "$response" | grep '"COUNT"' | head -1)
|
|
if [[ -n "$count_result" ]]; then
|
|
local count=$(echo "$count_result" | jq -r '.[2].count' 2>/dev/null)
|
|
if [[ "$count" =~ ^[0-9]+$ ]]; then
|
|
echo "$count"
|
|
return 0
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
echo "0" # Default to 0 if we can't get the count
|
|
}
|
|
|
|
# Helper function to send COUNT message and check response
|
|
test_count() {
|
|
local sub_id="$1"
|
|
local filter="$2"
|
|
local description="$3"
|
|
local expected_count="$4"
|
|
|
|
print_step "Testing COUNT: $description"
|
|
|
|
# Create COUNT message
|
|
local count_message="[\"COUNT\",\"$sub_id\",$filter]"
|
|
|
|
print_info "Sending filter: $filter"
|
|
|
|
# Send COUNT message and get response
|
|
local response=""
|
|
if command -v websocat &> /dev/null; then
|
|
response=$(echo "$count_message" | timeout 3s websocat "$RELAY_URL" 2>/dev/null || echo "")
|
|
fi
|
|
|
|
# Parse COUNT response
|
|
local count_result=""
|
|
if [[ -n "$response" ]]; then
|
|
# Look for COUNT response: ["COUNT","sub_id",{"count":N}]
|
|
count_result=$(echo "$response" | grep '"COUNT"' | head -1)
|
|
if [[ -n "$count_result" ]]; then
|
|
local actual_count=$(echo "$count_result" | jq -r '.[2].count' 2>/dev/null)
|
|
if [[ "$actual_count" =~ ^[0-9]+$ ]]; then
|
|
print_info "Received count: $actual_count"
|
|
|
|
# Check if count matches expected
|
|
if [[ "$expected_count" == "any" ]]; then
|
|
print_success "$description - Count: $actual_count"
|
|
return 0
|
|
elif [[ "$actual_count" -eq "$expected_count" ]]; then
|
|
print_success "$description - Expected: $expected_count, Got: $actual_count"
|
|
return 0
|
|
else
|
|
print_error "$description - Expected: $expected_count, Got: $actual_count"
|
|
return 1
|
|
fi
|
|
else
|
|
print_error "$description - Invalid count response: $count_result"
|
|
return 1
|
|
fi
|
|
else
|
|
print_error "$description - No COUNT response received"
|
|
print_error "Raw response: $response"
|
|
return 1
|
|
fi
|
|
else
|
|
print_error "$description - No response from relay"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Main test function
|
|
run_count_test() {
|
|
print_header "NIP-45 COUNT Message Test"
|
|
|
|
# Check dependencies
|
|
print_step "Checking dependencies..."
|
|
if ! command -v nak &> /dev/null; then
|
|
print_error "nak command not found"
|
|
print_info "Please install nak: go install github.com/fiatjaf/nak@latest"
|
|
return 1
|
|
fi
|
|
if ! command -v websocat &> /dev/null; then
|
|
print_error "websocat command not found"
|
|
print_info "Please install websocat for testing"
|
|
return 1
|
|
fi
|
|
if ! command -v jq &> /dev/null; then
|
|
print_error "jq command not found"
|
|
print_info "Please install jq for JSON processing"
|
|
return 1
|
|
fi
|
|
print_success "All dependencies found"
|
|
|
|
print_header "PHASE 0: Establishing Baseline Counts"
|
|
|
|
# Get baseline counts BEFORE publishing any test events
|
|
print_step "Getting baseline counts from existing events in relay..."
|
|
|
|
BASELINE_TOTAL=$(get_baseline_count '{}' "total events")
|
|
BASELINE_KIND1=$(get_baseline_count '{"kinds":[1]}' "kind 1 events")
|
|
BASELINE_KIND0=$(get_baseline_count '{"kinds":[0]}' "kind 0 events")
|
|
BASELINE_KIND30001=$(get_baseline_count '{"kinds":[30001]}' "kind 30001 events")
|
|
|
|
# We can't get the author baseline yet since we don't have the pubkey
|
|
BASELINE_AUTHOR=0 # Will be set after first event is created
|
|
BASELINE_TYPE_REGULAR=$(get_baseline_count '{"#type":["regular"]}' "events with type=regular tag")
|
|
BASELINE_TEST_NIP45=$(get_baseline_count '{"#test":["nip45"]}' "events with test=nip45 tag")
|
|
BASELINE_KINDS_01=$(get_baseline_count '{"kinds":[0,1]}' "events with kinds 0 or 1")
|
|
BASELINE_COMBINED=$(get_baseline_count '{"kinds":[1],"#type":["regular"],"#test":["nip45"]}' "combined filter (kind 1 + type=regular + test=nip45)")
|
|
|
|
print_info "Initial baseline counts established:"
|
|
print_info " Total events: $BASELINE_TOTAL"
|
|
print_info " Kind 1: $BASELINE_KIND1"
|
|
print_info " Kind 0: $BASELINE_KIND0"
|
|
print_info " Kind 30001: $BASELINE_KIND30001"
|
|
print_info " Type=regular: $BASELINE_TYPE_REGULAR"
|
|
print_info " Test=nip45: $BASELINE_TEST_NIP45"
|
|
print_info " Kinds 0+1: $BASELINE_KINDS_01"
|
|
print_info " Combined filter: $BASELINE_COMBINED"
|
|
|
|
print_header "PHASE 1: Publishing Test Events"
|
|
|
|
# Test 1: Regular Events (kind 1)
|
|
print_step "Creating regular events (kind 1)..."
|
|
local regular1=$(nak event --sec "$TEST_PRIVATE_KEY" -c "Regular event #1 for counting" -k 1 --ts $(($(date +%s) - 100)) -t "type=regular" -t "test=nip45" 2>/dev/null)
|
|
local regular2=$(nak event --sec "$TEST_PRIVATE_KEY" -c "Regular event #2 for counting" -k 1 --ts $(($(date +%s) - 90)) -t "type=regular" -t "test=nip45" 2>/dev/null)
|
|
local regular3=$(nak event --sec "$TEST_PRIVATE_KEY" -c "Regular event #3 for counting" -k 1 --ts $(($(date +%s) - 80)) -t "type=regular" -t "test=nip45" 2>/dev/null)
|
|
|
|
publish_event "$regular1" "regular" "Regular event #1"
|
|
|
|
# Now that we have the pubkey, get the author baseline
|
|
local test_pubkey=$(echo "$regular1" | jq -r '.pubkey' 2>/dev/null)
|
|
BASELINE_AUTHOR=$(get_baseline_count "{\"authors\":[\"$test_pubkey\"]}" "events by test author")
|
|
|
|
publish_event "$regular2" "regular" "Regular event #2"
|
|
publish_event "$regular3" "regular" "Regular event #3"
|
|
|
|
# Test 2: Replaceable Events (kind 0 - metadata)
|
|
print_step "Creating replaceable events (kind 0)..."
|
|
local replaceable1=$(nak event --sec "$TEST_PRIVATE_KEY" -c '{"name":"Test User","about":"Testing NIP-45 COUNT"}' -k 0 --ts $(($(date +%s) - 70)) -t "type=replaceable" 2>/dev/null)
|
|
local replaceable2=$(nak event --sec "$TEST_PRIVATE_KEY" -c '{"name":"Test User Updated","about":"Updated for NIP-45"}' -k 0 --ts $(($(date +%s) - 60)) -t "type=replaceable" 2>/dev/null)
|
|
|
|
publish_event "$replaceable1" "replaceable" "Replaceable event #1 (metadata)"
|
|
publish_event "$replaceable2" "replaceable" "Replaceable event #2 (metadata update)"
|
|
|
|
# Test 3: Ephemeral Events (kind 20000+) - should NOT be counted
|
|
print_step "Creating ephemeral events (kind 20001)..."
|
|
local ephemeral1=$(nak event --sec "$TEST_PRIVATE_KEY" -c "Ephemeral event - should not be counted" -k 20001 --ts $(date +%s) -t "type=ephemeral" 2>/dev/null)
|
|
|
|
publish_event "$ephemeral1" "ephemeral" "Ephemeral event (should not be counted)"
|
|
|
|
# Test 4: Addressable Events (kind 30000+)
|
|
print_step "Creating addressable events (kind 30001)..."
|
|
local addressable1=$(nak event --sec "$TEST_PRIVATE_KEY" -c "Addressable event #1" -k 30001 --ts $(($(date +%s) - 50)) -t "d=test-article" -t "type=addressable" 2>/dev/null)
|
|
local addressable2=$(nak event --sec "$TEST_PRIVATE_KEY" -c "Addressable event #2" -k 30001 --ts $(($(date +%s) - 40)) -t "d=test-article" -t "type=addressable" 2>/dev/null)
|
|
|
|
publish_event "$addressable1" "addressable" "Addressable event #1"
|
|
publish_event "$addressable2" "addressable" "Addressable event #2"
|
|
|
|
# Brief pause to let events settle
|
|
sleep 2
|
|
|
|
print_header "PHASE 2: Testing COUNT Messages"
|
|
|
|
local test_failures=0
|
|
|
|
# Test 1: Count all events
|
|
if ! test_count "count_all" '{}' "Count all events" "any"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 2: Count events by kind
|
|
# Regular events (kind 1): no replacement, all 3 should remain
|
|
local expected_kind1=$((3 + BASELINE_KIND1))
|
|
if ! test_count "count_kind1" '{"kinds":[1]}' "Count kind 1 events" "$expected_kind1"; then
|
|
((test_failures++))
|
|
fi
|
|
# Replaceable events (kind 0): only 1 should remain (newer replaces older of same kind+pubkey)
|
|
# Since we publish 2 with same pubkey, they replace to 1, which replaces any existing
|
|
local expected_kind0=$((1)) # Always 1 for this pubkey+kind after replacement
|
|
if ! test_count "count_kind0" '{"kinds":[0]}' "Count kind 0 events" "$expected_kind0"; then
|
|
((test_failures++))
|
|
fi
|
|
# Addressable events (kind 30001): only 1 should remain (same d-tag replaces)
|
|
# Since we publish 2 with same pubkey+kind+d-tag, they replace to 1
|
|
local expected_kind30001=$((1)) # Always 1 for this pubkey+kind+d-tag after replacement
|
|
if ! test_count "count_kind30001" '{"kinds":[30001]}' "Count kind 30001 events" "$expected_kind30001"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 3: Count events by author (pubkey)
|
|
# BASELINE_AUTHOR includes the first regular event, we add 2 more regular
|
|
# Replaceable and addressable replace existing events from this author
|
|
local test_pubkey=$(echo "$regular1" | jq -r '.pubkey' 2>/dev/null)
|
|
local expected_author=$((2 + BASELINE_AUTHOR))
|
|
if ! test_count "count_author" "{\"authors\":[\"$test_pubkey\"]}" "Count events by specific author" "$expected_author"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 4: Count recent events (time-based)
|
|
local recent_timestamp=$(($(date +%s) - 200))
|
|
if ! test_count "count_recent" "{\"since\":$recent_timestamp}" "Count recent events" "any"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 5: Count events with specific tags
|
|
# NOTE: Tag filtering is currently not working in the relay - should return the tagged events
|
|
local expected_type_regular=$((0 + BASELINE_TYPE_REGULAR)) # Currently returns 0 due to tag filtering bug
|
|
if ! test_count "count_tag_type" '{"#type":["regular"]}' "Count events with type=regular tag" "$expected_type_regular"; then
|
|
((test_failures++))
|
|
fi
|
|
local expected_test_nip45=$((0 + BASELINE_TEST_NIP45)) # Currently returns 0 due to tag filtering bug
|
|
if ! test_count "count_tag_test" '{"#test":["nip45"]}' "Count events with test=nip45 tag" "$expected_test_nip45"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 6: Count multiple kinds
|
|
# BASELINE_KINDS_01 + 3 regular events = total for kinds 0+1
|
|
local expected_kinds_01=$((3 + BASELINE_KINDS_01))
|
|
if ! test_count "count_multi_kinds" '{"kinds":[0,1]}' "Count multiple kinds (0,1)" "$expected_kinds_01"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 7: Count with time range
|
|
local start_time=$(($(date +%s) - 120))
|
|
local end_time=$(($(date +%s) - 60))
|
|
if ! test_count "count_time_range" "{\"since\":$start_time,\"until\":$end_time}" "Count events in time range" "any"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 8: Count specific event IDs
|
|
if [[ ${#REGULAR_EVENT_IDS[@]} -gt 0 ]]; then
|
|
local test_event_id="${REGULAR_EVENT_IDS[0]}"
|
|
if ! test_count "count_specific_id" "{\"ids\":[\"$test_event_id\"]}" "Count specific event ID" "1"; then
|
|
((test_failures++))
|
|
fi
|
|
fi
|
|
|
|
# Test 9: Count with multiple filters combined
|
|
# NOTE: Combined tag filtering is currently not working in the relay
|
|
local expected_combined=$((0 + BASELINE_COMBINED)) # Currently returns 0 due to tag filtering bug
|
|
if ! test_count "count_combined" '{"kinds":[1],"#type":["regular"],"#test":["nip45"]}' "Count with combined filters" "$expected_combined"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 10: Count ephemeral events (should be 0 since they're not stored)
|
|
if ! test_count "count_ephemeral" '{"kinds":[20001]}' "Count ephemeral events (should be 0)" "0"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 11: Count with limit (should still count all matching, ignore limit)
|
|
local expected_with_limit=$((3 + BASELINE_KIND1))
|
|
if ! test_count "count_with_limit" '{"kinds":[1],"limit":1}' "Count with limit (should ignore limit)" "$expected_with_limit"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 12: Count non-existent kind
|
|
if ! test_count "count_nonexistent" '{"kinds":[99999]}' "Count non-existent kind" "0"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Test 13: Count with empty filter
|
|
if ! test_count "count_empty_filter" '{}' "Count with empty filter" "any"; then
|
|
((test_failures++))
|
|
fi
|
|
|
|
# Report test results
|
|
if [[ $test_failures -gt 0 ]]; then
|
|
print_error "COUNT TESTS FAILED: $test_failures test(s) failed"
|
|
return 1
|
|
else
|
|
print_success "All COUNT tests passed"
|
|
fi
|
|
|
|
print_header "PHASE 3: Database Verification"
|
|
|
|
# Check what's actually stored in the database
|
|
print_step "Verifying database contents..."
|
|
|
|
if command -v sqlite3 &> /dev/null; then
|
|
# Find the database file (should be in build/ directory with relay pubkey as filename)
|
|
local db_file=""
|
|
if [[ -d "../build" ]]; then
|
|
db_file=$(find ../build -name "*.db" -type f | head -1)
|
|
fi
|
|
|
|
if [[ -n "$db_file" && -f "$db_file" ]]; then
|
|
print_info "Events by type in database ($db_file):"
|
|
sqlite3 "$db_file" "SELECT event_type, COUNT(*) as count FROM events GROUP BY event_type;" 2>/dev/null | while read line; do
|
|
echo " $line"
|
|
done
|
|
|
|
print_info "Total events in database:"
|
|
sqlite3 "$db_file" "SELECT COUNT(*) FROM events;" 2>/dev/null
|
|
|
|
print_success "Database verification complete"
|
|
else
|
|
print_warning "Database file not found in build/ directory"
|
|
print_info "Expected database files: build/*.db (named after relay pubkey)"
|
|
fi
|
|
else
|
|
print_warning "sqlite3 not available for database verification"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Run the COUNT test
|
|
print_header "Starting NIP-45 COUNT Message Test Suite"
|
|
echo
|
|
|
|
if run_count_test; then
|
|
echo
|
|
print_success "All NIP-45 COUNT tests completed successfully!"
|
|
print_info "The C-Relay COUNT functionality is working correctly"
|
|
print_info "✅ COUNT messages are processed and return correct event counts"
|
|
echo
|
|
exit 0
|
|
else
|
|
echo
|
|
print_error "❌ NIP-45 COUNT TESTS FAILED!"
|
|
print_error "The COUNT functionality has issues that need to be fixed"
|
|
echo
|
|
exit 1
|
|
fi |