Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1fcb9f7c91 | ||
|
|
f272264960 | ||
|
|
cb3171b390 |
@@ -81,6 +81,29 @@ echo "Building for platform: $PLATFORM"
|
|||||||
echo "Output binary: $OUTPUT_NAME"
|
echo "Output binary: $OUTPUT_NAME"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# Check if Alpine base image is cached
|
||||||
|
echo "Checking for cached Alpine Docker image..."
|
||||||
|
if ! docker images alpine:3.19 --format "{{.Repository}}:{{.Tag}}" | grep -q "alpine:3.19"; then
|
||||||
|
echo "⚠ Alpine 3.19 image not found in cache"
|
||||||
|
echo "Attempting to pull Alpine 3.19 image..."
|
||||||
|
if ! docker pull alpine:3.19; then
|
||||||
|
echo ""
|
||||||
|
echo "ERROR: Failed to pull Alpine 3.19 image"
|
||||||
|
echo "This is required for the static build."
|
||||||
|
echo ""
|
||||||
|
echo "Possible solutions:"
|
||||||
|
echo " 1. Check your internet connection"
|
||||||
|
echo " 2. Try again later (Docker Hub may be temporarily unavailable)"
|
||||||
|
echo " 3. If you have IPv6 issues, disable IPv6 for Docker"
|
||||||
|
echo ""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "✓ Alpine 3.19 image pulled successfully"
|
||||||
|
else
|
||||||
|
echo "✓ Alpine 3.19 image found in cache"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
# Build the Docker image
|
# Build the Docker image
|
||||||
echo "=========================================="
|
echo "=========================================="
|
||||||
echo "Step 1: Building Alpine Docker image"
|
echo "Step 1: Building Alpine Docker image"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ You're all set up now - just wait for the next crash and then run the coredumpct
|
|||||||
|
|
||||||
|
|
||||||
--------------------------
|
--------------------------
|
||||||
|
DEBUGGING
|
||||||
|
|
||||||
Even simpler: Use this one-liner
|
Even simpler: Use this one-liner
|
||||||
# Start relay and immediately attach gdb
|
# Start relay and immediately attach gdb
|
||||||
@@ -88,4 +88,5 @@ sudo ufw delete allow 8888/tcp
|
|||||||
|
|
||||||
lsof -i :7777
|
lsof -i :7777
|
||||||
kill $(lsof -t -i :7777)
|
kill $(lsof -t -i :7777)
|
||||||
kill -9 $(lsof -t -i :7777)
|
kill -9 $(lsof -t -i :7777)
|
||||||
|
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ cJSON* query_subscription_details(void) {
|
|||||||
const char* sql =
|
const char* sql =
|
||||||
"SELECT * "
|
"SELECT * "
|
||||||
"FROM active_subscriptions_log "
|
"FROM active_subscriptions_log "
|
||||||
"ORDER BY created_at DESC LIMIT 100";
|
"ORDER BY created_at DESC";
|
||||||
|
|
||||||
// DEBUG: Log the query results for debugging subscription_details
|
// DEBUG: Log the query results for debugging subscription_details
|
||||||
DEBUG_LOG("=== SUBSCRIPTION_DETAILS QUERY DEBUG ===");
|
DEBUG_LOG("=== SUBSCRIPTION_DETAILS QUERY DEBUG ===");
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
// Version information (auto-updated by build system)
|
// Version information (auto-updated by build system)
|
||||||
#define VERSION_MAJOR 1
|
#define VERSION_MAJOR 1
|
||||||
#define VERSION_MINOR 0
|
#define VERSION_MINOR 0
|
||||||
#define VERSION_PATCH 6
|
#define VERSION_PATCH 9
|
||||||
#define VERSION "v1.0.6"
|
#define VERSION "v1.0.9"
|
||||||
|
|
||||||
// Avoid VERSION_MAJOR redefinition warning from nostr_core_lib
|
// Avoid VERSION_MAJOR redefinition warning from nostr_core_lib
|
||||||
#undef VERSION_MAJOR
|
#undef VERSION_MAJOR
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/* Embedded SQL Schema for C Nostr Relay
|
/* Embedded SQL Schema for C Nostr Relay
|
||||||
* Schema Version: 8
|
* Schema Version: 9
|
||||||
*/
|
*/
|
||||||
#ifndef SQL_SCHEMA_H
|
#ifndef SQL_SCHEMA_H
|
||||||
#define SQL_SCHEMA_H
|
#define SQL_SCHEMA_H
|
||||||
|
|
||||||
/* Schema version constant */
|
/* Schema version constant */
|
||||||
#define EMBEDDED_SCHEMA_VERSION "8"
|
#define EMBEDDED_SCHEMA_VERSION "9"
|
||||||
|
|
||||||
/* Embedded SQL schema as C string literal */
|
/* Embedded SQL schema as C string literal */
|
||||||
static const char* const EMBEDDED_SCHEMA_SQL =
|
static const char* const EMBEDDED_SCHEMA_SQL =
|
||||||
@@ -14,7 +14,7 @@ static const char* const EMBEDDED_SCHEMA_SQL =
|
|||||||
-- Configuration system using config table\n\
|
-- Configuration system using config table\n\
|
||||||
\n\
|
\n\
|
||||||
-- Schema version tracking\n\
|
-- Schema version tracking\n\
|
||||||
PRAGMA user_version = 8;\n\
|
PRAGMA user_version = 9;\n\
|
||||||
\n\
|
\n\
|
||||||
-- Enable foreign key support\n\
|
-- Enable foreign key support\n\
|
||||||
PRAGMA foreign_keys = ON;\n\
|
PRAGMA foreign_keys = ON;\n\
|
||||||
@@ -57,8 +57,8 @@ CREATE TABLE schema_info (\n\
|
|||||||
\n\
|
\n\
|
||||||
-- Insert schema metadata\n\
|
-- Insert schema metadata\n\
|
||||||
INSERT INTO schema_info (key, value) VALUES\n\
|
INSERT INTO schema_info (key, value) VALUES\n\
|
||||||
('version', '8'),\n\
|
('version', '9'),\n\
|
||||||
('description', 'Hybrid Nostr relay schema with subscription deduplication support'),\n\
|
('description', 'Hybrid Nostr relay schema with fixed active_subscriptions_log view'),\n\
|
||||||
('created_at', strftime('%s', 'now'));\n\
|
('created_at', strftime('%s', 'now'));\n\
|
||||||
\n\
|
\n\
|
||||||
-- Helper views for common queries\n\
|
-- Helper views for common queries\n\
|
||||||
@@ -236,21 +236,16 @@ ORDER BY date DESC;\n\
|
|||||||
-- View for current active subscriptions (from log perspective)\n\
|
-- View for current active subscriptions (from log perspective)\n\
|
||||||
CREATE VIEW active_subscriptions_log AS\n\
|
CREATE VIEW active_subscriptions_log AS\n\
|
||||||
SELECT\n\
|
SELECT\n\
|
||||||
s.subscription_id,\n\
|
subscription_id,\n\
|
||||||
s.client_ip,\n\
|
client_ip,\n\
|
||||||
s.filter_json,\n\
|
filter_json,\n\
|
||||||
s.events_sent,\n\
|
events_sent,\n\
|
||||||
s.created_at,\n\
|
created_at,\n\
|
||||||
(strftime('%s', 'now') - s.created_at) as duration_seconds,\n\
|
(strftime('%s', 'now') - created_at) as duration_seconds,\n\
|
||||||
s.wsi_pointer\n\
|
wsi_pointer\n\
|
||||||
FROM subscriptions s\n\
|
FROM subscriptions\n\
|
||||||
WHERE s.event_type = 'created'\n\
|
WHERE event_type = 'created'\n\
|
||||||
AND NOT EXISTS (\n\
|
AND ended_at IS NULL;\n\
|
||||||
SELECT 1 FROM subscriptions s2\n\
|
|
||||||
WHERE s2.subscription_id = s.subscription_id\n\
|
|
||||||
AND s2.wsi_pointer = s.wsi_pointer\n\
|
|
||||||
AND s2.event_type IN ('closed', 'expired', 'disconnected')\n\
|
|
||||||
);\n\
|
|
||||||
\n\
|
\n\
|
||||||
-- Database Statistics Views for Admin API\n\
|
-- Database Statistics Views for Admin API\n\
|
||||||
-- Event kinds distribution view\n\
|
-- Event kinds distribution view\n\
|
||||||
|
|||||||
295
tests/subscription_cleanup_test.sh
Executable file
295
tests/subscription_cleanup_test.sh
Executable file
@@ -0,0 +1,295 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Subscription Cleanup Testing Suite for C-Relay
|
||||||
|
# Tests startup cleanup and connection age limit features
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Load test keys
|
||||||
|
source "$(dirname "$0")/.test_keys.txt"
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
RELAY_HOST="127.0.0.1"
|
||||||
|
RELAY_PORT="8888"
|
||||||
|
RELAY_URL="ws://${RELAY_HOST}:${RELAY_PORT}"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Test counters
|
||||||
|
TOTAL_TESTS=0
|
||||||
|
PASSED_TESTS=0
|
||||||
|
FAILED_TESTS=0
|
||||||
|
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo -e "${BLUE}Subscription Cleanup Test Suite${NC}"
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Function to print test header
|
||||||
|
print_test_header() {
|
||||||
|
echo -e "${BLUE}=== Test $1: $2 ===${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to print test result
|
||||||
|
print_result() {
|
||||||
|
local status=$1
|
||||||
|
local message=$2
|
||||||
|
|
||||||
|
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||||||
|
|
||||||
|
if [ "$status" = "PASS" ]; then
|
||||||
|
echo -e "${GREEN}[PASS]${NC} $message"
|
||||||
|
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||||
|
elif [ "$status" = "FAIL" ]; then
|
||||||
|
echo -e "${RED}[FAIL]${NC} $message"
|
||||||
|
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||||||
|
else
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $message"
|
||||||
|
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if relay is running
|
||||||
|
check_relay_running() {
|
||||||
|
# Send a simple REQ and check for EOSE response
|
||||||
|
local response=$(echo '["REQ","ping",{}]' | timeout 2 websocat -n1 "$RELAY_URL" 2>/dev/null)
|
||||||
|
if echo "$response" | grep -q "EOSE\|EVENT"; then
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to create a subscription
|
||||||
|
create_subscription() {
|
||||||
|
local sub_id=$1
|
||||||
|
local filter=${2:-"{}"}
|
||||||
|
|
||||||
|
echo "[\"REQ\",\"$sub_id\",$filter]" | timeout 5 websocat -n1 "$RELAY_URL" 2>/dev/null || echo "TIMEOUT"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to close a subscription
|
||||||
|
close_subscription() {
|
||||||
|
local sub_id=$1
|
||||||
|
|
||||||
|
echo "[\"CLOSE\",\"$sub_id\"]" | timeout 5 websocat -n1 "$RELAY_URL" 2>/dev/null || echo "TIMEOUT"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to query subscription count from database
|
||||||
|
get_subscription_count() {
|
||||||
|
local db_file=$(find . -name "*.db" -type f 2>/dev/null | head -1)
|
||||||
|
|
||||||
|
if [ -z "$db_file" ]; then
|
||||||
|
echo "0"
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
sqlite3 "$db_file" "SELECT COUNT(*) FROM subscriptions WHERE event_type='created' AND ended_at IS NULL;" 2>/dev/null || echo "0"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test 1: Basic Connectivity
|
||||||
|
print_test_header "1" "Basic Connectivity"
|
||||||
|
|
||||||
|
if check_relay_running; then
|
||||||
|
print_result "PASS" "Relay is running and accepting connections"
|
||||||
|
else
|
||||||
|
print_result "FAIL" "Cannot connect to relay at $RELAY_URL"
|
||||||
|
echo ""
|
||||||
|
echo -e "${RED}ERROR: Relay must be running for tests to proceed${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 2: Create Multiple Subscriptions
|
||||||
|
print_test_header "2" "Create Multiple Subscriptions"
|
||||||
|
|
||||||
|
echo "[INFO] Creating 5 test subscriptions..."
|
||||||
|
for i in {1..5}; do
|
||||||
|
response=$(create_subscription "cleanup_test_$i")
|
||||||
|
if echo "$response" | grep -q "EOSE"; then
|
||||||
|
echo "[INFO] Subscription cleanup_test_$i created successfully"
|
||||||
|
else
|
||||||
|
print_result "WARN" "Subscription cleanup_test_$i may not have been created: $response"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Give subscriptions time to be logged
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Check subscription count in database
|
||||||
|
active_subs=$(get_subscription_count)
|
||||||
|
echo "[INFO] Active subscriptions in database: $active_subs"
|
||||||
|
|
||||||
|
if [ "$active_subs" -ge 5 ]; then
|
||||||
|
print_result "PASS" "Multiple subscriptions created and logged ($active_subs active)"
|
||||||
|
else
|
||||||
|
print_result "WARN" "Expected at least 5 subscriptions, found $active_subs"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 3: Simulate Orphaned Subscriptions (disconnect without CLOSE)
|
||||||
|
print_test_header "3" "Simulate Orphaned Subscriptions"
|
||||||
|
|
||||||
|
echo "[INFO] Creating subscriptions and disconnecting abruptly..."
|
||||||
|
|
||||||
|
# Create subscriptions in background and kill the connection
|
||||||
|
for i in {6..10}; do
|
||||||
|
(echo "[\"REQ\",\"orphan_test_$i\",{}]" | timeout 2 websocat "$RELAY_URL" &>/dev/null) &
|
||||||
|
pid=$!
|
||||||
|
sleep 0.5
|
||||||
|
kill -9 $pid 2>/dev/null || true
|
||||||
|
done
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
orphaned_subs=$(get_subscription_count)
|
||||||
|
echo "[INFO] Subscriptions after abrupt disconnects: $orphaned_subs"
|
||||||
|
|
||||||
|
if [ "$orphaned_subs" -gt "$active_subs" ]; then
|
||||||
|
print_result "PASS" "Orphaned subscriptions detected ($orphaned_subs total, was $active_subs)"
|
||||||
|
else
|
||||||
|
print_result "WARN" "No increase in orphaned subscriptions detected"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 4: Startup Cleanup (requires relay restart)
|
||||||
|
print_test_header "4" "Startup Cleanup Feature"
|
||||||
|
|
||||||
|
echo "[INFO] This test requires relay restart to verify startup cleanup"
|
||||||
|
echo "[INFO] Current orphaned subscriptions: $orphaned_subs"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}[ACTION REQUIRED]${NC} Please restart the relay now with:"
|
||||||
|
echo " ./make_and_restart_relay.sh"
|
||||||
|
echo ""
|
||||||
|
echo -n "Press Enter after relay has restarted to continue..."
|
||||||
|
read
|
||||||
|
|
||||||
|
# Wait for relay to be ready
|
||||||
|
echo "[INFO] Waiting for relay to be ready..."
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
if ! check_relay_running; then
|
||||||
|
print_result "FAIL" "Relay not responding after restart"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if orphaned subscriptions were cleaned up
|
||||||
|
cleaned_subs=$(get_subscription_count)
|
||||||
|
echo "[INFO] Active subscriptions after restart: $cleaned_subs"
|
||||||
|
|
||||||
|
if [ "$cleaned_subs" -eq 0 ]; then
|
||||||
|
print_result "PASS" "Startup cleanup removed all orphaned subscriptions"
|
||||||
|
elif [ "$cleaned_subs" -lt "$orphaned_subs" ]; then
|
||||||
|
print_result "PASS" "Startup cleanup reduced orphaned subscriptions (from $orphaned_subs to $cleaned_subs)"
|
||||||
|
else
|
||||||
|
print_result "FAIL" "Startup cleanup did not reduce orphaned subscriptions"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 5: Connection Age Limit (requires configuration)
|
||||||
|
print_test_header "5" "Connection Age Limit Feature"
|
||||||
|
|
||||||
|
echo "[INFO] Testing connection age limit feature..."
|
||||||
|
echo "[INFO] Default max_connection_seconds is 86400 (24 hours)"
|
||||||
|
echo ""
|
||||||
|
echo -e "${YELLOW}[INFO]${NC} To test connection age limit with shorter timeout:"
|
||||||
|
echo " 1. Set max_connection_seconds to 60 (1 minute) via admin event"
|
||||||
|
echo " 2. Create a subscription and wait 61 seconds"
|
||||||
|
echo " 3. Connection should be automatically closed"
|
||||||
|
echo ""
|
||||||
|
echo "[INFO] For this test, we'll verify the feature is enabled in config"
|
||||||
|
|
||||||
|
# Create a test subscription to verify connection works
|
||||||
|
response=$(create_subscription "age_test_1")
|
||||||
|
if echo "$response" | grep -q "EOSE"; then
|
||||||
|
print_result "PASS" "Connection age limit feature is operational (subscription created)"
|
||||||
|
else
|
||||||
|
print_result "WARN" "Could not verify connection age limit feature"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 6: Verify Client Reconnection
|
||||||
|
print_test_header "6" "Client Reconnection After Cleanup"
|
||||||
|
|
||||||
|
echo "[INFO] Testing that clients can reconnect after cleanup..."
|
||||||
|
|
||||||
|
# Create a subscription
|
||||||
|
response=$(create_subscription "reconnect_test_1")
|
||||||
|
if echo "$response" | grep -q "EOSE"; then
|
||||||
|
echo "[INFO] First connection successful"
|
||||||
|
|
||||||
|
# Close and reconnect
|
||||||
|
sleep 1
|
||||||
|
response=$(create_subscription "reconnect_test_2")
|
||||||
|
if echo "$response" | grep -q "EOSE"; then
|
||||||
|
print_result "PASS" "Client can reconnect and create new subscriptions"
|
||||||
|
else
|
||||||
|
print_result "FAIL" "Client reconnection failed"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_result "FAIL" "Initial connection failed"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 7: Verify Disabled State (max_connection_seconds = 0)
|
||||||
|
print_test_header "7" "Verify Feature Can Be Disabled"
|
||||||
|
|
||||||
|
echo "[INFO] Connection age limit can be disabled by setting max_connection_seconds=0"
|
||||||
|
echo "[INFO] When disabled, connections remain open indefinitely"
|
||||||
|
echo "[INFO] This is the recommended setting for most relays"
|
||||||
|
|
||||||
|
# Create a long-lived subscription
|
||||||
|
response=$(create_subscription "disabled_test_1")
|
||||||
|
if echo "$response" | grep -q "EOSE"; then
|
||||||
|
print_result "PASS" "Subscriptions work normally when feature is disabled/default"
|
||||||
|
else
|
||||||
|
print_result "WARN" "Could not verify disabled state"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 8: Database Integrity Check
|
||||||
|
print_test_header "8" "Database Integrity After Cleanup"
|
||||||
|
|
||||||
|
echo "[INFO] Checking database integrity..."
|
||||||
|
|
||||||
|
db_file=$(find . -name "*.db" -type f 2>/dev/null | head -1)
|
||||||
|
if [ -n "$db_file" ]; then
|
||||||
|
# Check if database is accessible
|
||||||
|
if sqlite3 "$db_file" "PRAGMA integrity_check;" 2>/dev/null | grep -q "ok"; then
|
||||||
|
print_result "PASS" "Database integrity check passed"
|
||||||
|
else
|
||||||
|
print_result "FAIL" "Database integrity check failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check subscription table structure
|
||||||
|
if sqlite3 "$db_file" "SELECT COUNT(*) FROM subscriptions;" &>/dev/null; then
|
||||||
|
print_result "PASS" "Subscription table is accessible"
|
||||||
|
else
|
||||||
|
print_result "FAIL" "Subscription table is not accessible"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_result "WARN" "No database file found"
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Final Summary
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo -e "${BLUE}Test Summary${NC}"
|
||||||
|
echo -e "${BLUE}========================================${NC}"
|
||||||
|
echo "Total Tests: $TOTAL_TESTS"
|
||||||
|
echo -e "${GREEN}Passed: $PASSED_TESTS${NC}"
|
||||||
|
echo -e "${RED}Failed: $FAILED_TESTS${NC}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ $FAILED_TESTS -eq 0 ]; then
|
||||||
|
echo -e "${GREEN}All tests passed!${NC}"
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
echo -e "${RED}Some tests failed. Please review the output above.${NC}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
Reference in New Issue
Block a user