#!/usr/bin/env node import { RingNode } from '../src/ring-node.js'; import { OracleNode } from '../src/oracle-node.js'; import chalk from 'chalk'; console.log(chalk.blue.bold('๐Ÿงช Ring Network Test Suite\n')); class NetworkTester { constructor() { this.nodes = []; this.testResults = []; } async delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } log(message, type = 'info') { const colors = { info: chalk.blue, success: chalk.green, error: chalk.red, warning: chalk.yellow }; console.log(`${colors[type]}${message}`); } async runTest(name, testFn) { this.log(`\n๐Ÿ”ฌ Running test: ${name}`, 'info'); try { const startTime = Date.now(); await testFn(); const duration = Date.now() - startTime; this.log(`โœ… Test passed: ${name} (${duration}ms)`, 'success'); this.testResults.push({ name, status: 'passed', duration }); } catch (error) { this.log(`โŒ Test failed: ${name} - ${error.message}`, 'error'); this.testResults.push({ name, status: 'failed', error: error.message }); } } async setupBasicNetwork() { this.log('๐Ÿ—๏ธ Setting up basic network with 1 Oracle and 2 regular nodes', 'info'); // Create Oracle node const oracle = new OracleNode({ id: 'oracle-1', port: 8080 }); this.nodes.push(oracle); // Create regular nodes const node1 = new RingNode({ id: 'node-1', port: 8081 }); this.nodes.push(node1); const node2 = new RingNode({ id: 'node-2', port: 8082 }); this.nodes.push(node2); // Allow nodes to initialize await this.delay(2000); return { oracle, node1, node2 }; } async testNodeInitialization() { const { oracle, node1, node2 } = await this.setupBasicNetwork(); // Verify nodes are properly initialized if (!oracle.id || !oracle.isOracle) { throw new Error('Oracle node not properly initialized'); } if (!node1.id || node1.isOracle) { throw new Error('Regular node 1 not properly initialized'); } if (!node2.id || node2.isOracle) { throw new Error('Regular node 2 not properly initialized'); } this.log(`Oracle ID: ${oracle.id}`, 'info'); this.log(`Node 1 ID: ${node1.id}`, 'info'); this.log(`Node 2 ID: ${node2.id}`, 'info'); } async testPeerConnections() { const { oracle, node1, node2 } = this.nodes.length > 0 ? { oracle: this.nodes[0], node1: this.nodes[1], node2: this.nodes[2] } : await this.setupBasicNetwork(); // Simulate peer connections // In a real test, we would actually establish WebRTC connections // For this test, we'll simulate the connection state oracle.knownNodes.set(node1.id, { port: node1.port }); oracle.knownNodes.set(node2.id, { port: node2.port }); node1.knownNodes.set(oracle.id, { port: oracle.port, isOracle: true }); node1.knownNodes.set(node2.id, { port: node2.port }); node2.knownNodes.set(oracle.id, { port: oracle.port, isOracle: true }); node2.knownNodes.set(node1.id, { port: node1.port }); // Update oracle nodes list node1.oracleNodes.add(oracle.id); node2.oracleNodes.add(oracle.id); this.log(`Oracle knows ${oracle.knownNodes.size} nodes`, 'info'); this.log(`Node 1 knows ${node1.knownNodes.size} nodes`, 'info'); this.log(`Node 2 knows ${node2.knownNodes.size} nodes`, 'info'); } async testRingTopology() { const { oracle, node1, node2 } = this.nodes.length > 0 ? { oracle: this.nodes[0], node1: this.nodes[1], node2: this.nodes[2] } : await this.setupBasicNetwork(); // Simulate ring topology setup // Oracle -> Node1 -> Node2 -> Oracle (inner ring) oracle.rings.inner.right = node1.id; oracle.rings.inner.left = node2.id; node1.rings.inner.left = oracle.id; node1.rings.inner.right = node2.id; node2.rings.inner.left = node1.id; node2.rings.inner.right = oracle.id; // Oracle -> Node2 -> Node1 -> Oracle (outer ring - reversed) oracle.rings.outer.right = node2.id; oracle.rings.outer.left = node1.id; node1.rings.outer.left = node2.id; node1.rings.outer.right = oracle.id; node2.rings.outer.left = oracle.id; node2.rings.outer.right = node1.id; // Verify ring integrity const oracleHasValidRings = oracle.rings.inner.left && oracle.rings.inner.right && oracle.rings.outer.left && oracle.rings.outer.right; if (!oracleHasValidRings) { throw new Error('Oracle rings not properly configured'); } this.log('Ring topology established successfully', 'success'); } async testOracleServices() { const oracle = this.nodes[0]; if (!oracle.isOracle) { throw new Error('First node is not an Oracle'); } // Test network analysis const analysis = oracle.analyzeNetwork(); if (!analysis.networkSize || !analysis.ringTopology) { throw new Error('Network analysis failed'); } this.log(`Network analysis: ${analysis.networkSize} nodes`, 'info'); // Test data storage const storeResult = oracle.handleDataStorage({ operation: 'set', key: 'test-key', value: 'test-value' }); if (!storeResult.success) { throw new Error('Data storage (set) failed'); } const getResult = oracle.handleDataStorage({ operation: 'get', key: 'test-key' }); if (!getResult.success || getResult.value !== 'test-value') { throw new Error('Data storage (get) failed'); } this.log('Oracle data storage working correctly', 'success'); // Test consensus const proposalId = 'test-proposal-' + Date.now(); const consensusResult = oracle.handleConsensus({ proposalId, proposal: 'Test proposal for network upgrade' }); if (!consensusResult.success) { throw new Error('Consensus proposal creation failed'); } this.log('Oracle consensus mechanism working', 'success'); // Test health check const health = oracle.performHealthCheck(); if (!health.checks) { throw new Error('Health check failed'); } this.log(`Health check: ${health.healthy ? 'Healthy' : 'Issues detected'}`, health.healthy ? 'success' : 'warning'); } async testMessageRouting() { // This test simulates message routing through the ring // In a real implementation, this would test actual WebRTC communication const oracle = this.nodes[0]; let messageReceived = false; // Set up message handler oracle.on('ringMessage', ({ from, payload }) => { if (payload.type === 'test-message') { messageReceived = true; } }); // Simulate sending a message oracle.emit('ringMessage', { from: 'test-sender', payload: { type: 'test-message', content: 'Hello Ring!' } }); await this.delay(100); if (!messageReceived) { throw new Error('Message routing failed'); } this.log('Message routing test passed', 'success'); } async testNetworkResilience() { const { oracle, node1, node2 } = this.nodes.length > 0 ? { oracle: this.nodes[0], node1: this.nodes[1], node2: this.nodes[2] } : await this.setupBasicNetwork(); // Simulate node disconnection const originalPeerCount = oracle.knownNodes.size; // Remove node2 from network oracle.handlePeerDisconnection(node2.id); node1.handlePeerDisconnection(node2.id); if (oracle.knownNodes.has(node2.id)) { throw new Error('Node not properly removed from network'); } // Verify network adapted to disconnection const newPeerCount = oracle.knownNodes.size; if (newPeerCount >= originalPeerCount) { throw new Error('Network did not adapt to peer disconnection'); } this.log(`Network adapted to disconnection: ${originalPeerCount} -> ${newPeerCount} nodes`, 'success'); } async cleanup() { this.log('\n๐Ÿงน Cleaning up test environment', 'info'); for (const node of this.nodes) { try { await node.destroy(); } catch (error) { this.log(`Warning: Error cleaning up node ${node.id}: ${error.message}`, 'warning'); } } this.nodes = []; } printResults() { this.log('\n๐Ÿ“Š Test Results Summary:', 'info'); const passed = this.testResults.filter(r => r.status === 'passed').length; const failed = this.testResults.filter(r => r.status === 'failed').length; this.log(`โœ… Passed: ${passed}`, 'success'); this.log(`โŒ Failed: ${failed}`, failed > 0 ? 'error' : 'info'); if (failed > 0) { this.log('\nFailed tests:', 'error'); this.testResults .filter(r => r.status === 'failed') .forEach(r => { this.log(` - ${r.name}: ${r.error}`, 'error'); }); } const totalDuration = this.testResults.reduce((sum, r) => sum + (r.duration || 0), 0); this.log(`\nTotal test duration: ${totalDuration}ms`, 'info'); return failed === 0; } async runAllTests() { try { await this.runTest('Node Initialization', () => this.testNodeInitialization()); await this.runTest('Peer Connections', () => this.testPeerConnections()); await this.runTest('Ring Topology', () => this.testRingTopology()); await this.runTest('Oracle Services', () => this.testOracleServices()); await this.runTest('Message Routing', () => this.testMessageRouting()); await this.runTest('Network Resilience', () => this.testNetworkResilience()); } finally { await this.cleanup(); } return this.printResults(); } } // Run tests if this file is executed directly if (import.meta.url === `file://${process.argv[1]}`) { const tester = new NetworkTester(); tester.runAllTests() .then(success => { console.log(chalk.blue.bold('\n๐Ÿ Test suite completed')); process.exit(success ? 0 : 1); }) .catch(error => { console.error(chalk.red.bold(`\n๐Ÿ’ฅ Test suite crashed: ${error.message}`)); process.exit(1); }); } export { NetworkTester };