Files
next.orly.dev/test-relay-connection.js
mleku 7906bb2295 Add WebSocket Connection Testing Scripts
- Introduced two new test scripts: `test-relay-connection.js` and `test-websocket-close.js` to verify WebSocket connection stability and closure behavior.
- `test-relay-connection.js` tests multiple connections, monitors their open/close events, and analyzes premature closures.
- `test-websocket-close.js` focuses on connection closure issues with concurrent connections and logs results for connected, closed, and error states.
- Both scripts utilize the NostrWebSocket from the @nostr-dev-kit/ndk package for testing purposes.
2025-10-28 18:42:18 +00:00

168 lines
5.0 KiB
JavaScript
Executable File

#!/usr/bin/env node
// Test script to verify websocket connections are not closed prematurely
// This is a Node.js test script that can be run with: node test-relay-connection.js
import { NostrWebSocket } from '@nostr-dev-kit/ndk';
const RELAY = process.env.RELAY || 'ws://localhost:8080';
const MAX_CONNECTIONS = 10;
const TEST_DURATION = 30000; // 30 seconds
let connectionsClosed = 0;
let connectionsOpened = 0;
let messagesReceived = 0;
let errors = 0;
const stats = {
premature: 0,
normal: 0,
errors: 0,
};
class TestConnection {
constructor(id) {
this.id = id;
this.ws = null;
this.closed = false;
this.openTime = null;
this.closeTime = null;
this.lastError = null;
}
connect() {
return new Promise((resolve, reject) => {
this.ws = new NostrWebSocket(RELAY);
this.ws.addEventListener('open', () => {
this.openTime = Date.now();
connectionsOpened++;
console.log(`[Connection ${this.id}] Opened`);
resolve();
});
this.ws.addEventListener('close', (event) => {
this.closeTime = Date.now();
this.closed = true;
connectionsClosed++;
const duration = this.closeTime - this.openTime;
console.log(`[Connection ${this.id}] Closed: code=${event.code}, reason="${event.reason || ''}", duration=${duration}ms`);
if (duration < 5000 && event.code !== 1000) {
stats.premature++;
console.log(`[Connection ${this.id}] PREMATURE CLOSE DETECTED: duration=${duration}ms < 5s`);
} else {
stats.normal++;
}
});
this.ws.addEventListener('error', (error) => {
this.lastError = error;
stats.errors++;
console.error(`[Connection ${this.id}] Error:`, error);
});
this.ws.addEventListener('message', (event) => {
messagesReceived++;
try {
const data = JSON.parse(event.data);
console.log(`[Connection ${this.id}] Message:`, data[0]);
} catch (e) {
console.log(`[Connection ${this.id}] Message (non-JSON):`, event.data);
}
});
setTimeout(reject, 5000); // Timeout after 5 seconds if not opened
});
}
sendReq() {
if (this.ws && !this.closed) {
this.ws.send(JSON.stringify(['REQ', `test-sub-${this.id}`, { kinds: [1], limit: 10 }]));
console.log(`[Connection ${this.id}] Sent REQ`);
}
}
close() {
if (this.ws && !this.closed) {
this.ws.close();
}
}
}
async function runTest() {
console.log('='.repeat(60));
console.log('Testing Relay Connection Stability');
console.log('='.repeat(60));
console.log(`Relay: ${RELAY}`);
console.log(`Duration: ${TEST_DURATION}ms`);
console.log(`Connections: ${MAX_CONNECTIONS}`);
console.log('='.repeat(60));
console.log();
const connections = [];
// Open connections
console.log('Opening connections...');
for (let i = 0; i < MAX_CONNECTIONS; i++) {
const conn = new TestConnection(i);
try {
await conn.connect();
connections.push(conn);
} catch (error) {
console.error(`Failed to open connection ${i}:`, error);
}
}
console.log(`Opened ${connections.length} connections`);
console.log();
// Send requests from each connection
console.log('Sending REQ messages...');
for (const conn of connections) {
conn.sendReq();
}
// Wait and let connections run
console.log(`Waiting ${TEST_DURATION / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, TEST_DURATION));
// Close all connections
console.log('Closing all connections...');
for (const conn of connections) {
conn.close();
}
// Wait for close events
await new Promise(resolve => setTimeout(resolve, 1000));
// Print results
console.log();
console.log('='.repeat(60));
console.log('Test Results:');
console.log('='.repeat(60));
console.log(`Connections Opened: ${connectionsOpened}`);
console.log(`Connections Closed: ${connectionsClosed}`);
console.log(`Messages Received: ${messagesReceived}`);
console.log();
console.log('Closure Analysis:');
console.log(`- Premature Closes: ${stats.premature}`);
console.log(`- Normal Closes: ${stats.normal}`);
console.log(`- Errors: ${stats.errors}`);
console.log('='.repeat(60));
if (stats.premature > 0) {
console.error('FAILED: Detected premature connection closures!');
process.exit(1);
} else {
console.log('PASSED: No premature connection closures detected.');
process.exit(0);
}
}
runTest().catch(error => {
console.error('Test failed:', error);
process.exit(1);
});