From 66ea8d2ddf0d19d6df2aa584f60ce12a16ac7f25 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Thu, 15 Jan 2026 22:20:44 +0100 Subject: [PATCH] chore: drop unused integration tests --- AGENTS.md | 1 - CLAUDE.md | 7 - dash-spv/CLAUDE.md | 16 +- dash-spv/run_integration_tests.md | 192 ------ dash-spv/tests/integration_real_node_test.rs | 614 ------------------- dash-spv/tests/simple_header_test.rs | 121 ---- dash-spv/tests/test_plan.md | 89 --- 7 files changed, 1 insertion(+), 1039 deletions(-) delete mode 100644 dash-spv/run_integration_tests.md delete mode 100644 dash-spv/tests/integration_real_node_test.rs delete mode 100644 dash-spv/tests/simple_header_test.rs diff --git a/AGENTS.md b/AGENTS.md index 3efc92b8d..474639074 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,6 @@ - MSRV: 1.89. Build all: `cargo build --workspace --all-features` - Test all: `cargo test --workspace --all-features` or `./contrib/test.sh` (set `DO_COV=true`, `DO_LINT=true`, `DO_FMT=true` as needed) - Targeted tests: `cargo test -p dash-spv --all-features` -- Integration RPC: `cd dash-spv && DASH_SPV_IP= cargo test --test integration_real_node_test -- --nocapture` - FFI iOS builds: `cd key-wallet-ffi && ./build-ios.sh` - Lint/format: `cargo clippy --workspace --all-targets -- -D warnings` and `cargo fmt --all` - Docs: `cargo doc --workspace` (add `--open` locally) diff --git a/CLAUDE.md b/CLAUDE.md index ffae8810e..2779b0cb6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -101,13 +101,6 @@ DO_LINT=true ./contrib/test.sh DO_FMT=true ./contrib/test.sh ``` -### Integration Tests -```bash -# Run with real Dash node (requires DASH_SPV_IP environment variable) -cd dash-spv -cargo test --test integration_real_node_test -- --nocapture -``` - ## Development Commands ### Linting and Formatting diff --git a/dash-spv/CLAUDE.md b/dash-spv/CLAUDE.md index 17fe37d49..8c649ee71 100644 --- a/dash-spv/CLAUDE.md +++ b/dash-spv/CLAUDE.md @@ -57,7 +57,6 @@ cargo test cargo test --test handshake_test cargo test --test header_sync_test cargo test --test storage_test -cargo test --test integration_real_node_test # Run individual test functions cargo test --test handshake_test test_handshake_with_mainnet_peer @@ -69,19 +68,6 @@ cargo test -- --nocapture cargo test --test handshake_test test_handshake_with_mainnet_peer -- --nocapture ``` -**Integration Tests with Real Node:** -The integration tests in `tests/integration_real_node_test.rs` connect to a live Dash Core node at `127.0.0.1:9999`. These tests gracefully skip if no node is available. - -```bash -# Run real node integration tests -cargo test --test integration_real_node_test -- --nocapture - -# Test specific real node functionality -cargo test --test integration_real_node_test test_real_header_sync_genesis_to_1000 -- --nocapture -``` - -See `run_integration_tests.md` for detailed setup instructions. - ### Code Quality ```bash # Check formatting @@ -201,7 +187,7 @@ Use domain-specific error types: **Common Debug Commands:** ```bash # Run with tracing output -RUST_LOG=debug cargo test --test integration_real_node_test -- --nocapture +RUST_LOG=debug cargo test --test test_handshake_with_mainnet_peer -- --nocapture # Run specific test with verbose output cargo test --test handshake_test test_handshake_with_mainnet_peer -- --nocapture --test-threads=1 diff --git a/dash-spv/run_integration_tests.md b/dash-spv/run_integration_tests.md deleted file mode 100644 index 0bbfd8a6a..000000000 --- a/dash-spv/run_integration_tests.md +++ /dev/null @@ -1,192 +0,0 @@ -# Running Integration Tests with Real Dash Core Node - -This document explains how to run the integration tests that connect to a real Dash Core node. - -## Prerequisites - -1. **Dash Core Node**: You need a Dash Core node running and accessible at `127.0.0.1:9999` -2. **Network**: The node should be connected to Dash mainnet -3. **Sync Status**: The node should be synced (for testing header sync up to 10k headers) - -## Setting Up Dash Core Node - -### Option 1: Local Dash Core Node - -1. Download and install Dash Core from https://github.com/dashpay/dash/releases -2. Configure `dash.conf`: - ``` - # dash.conf - testnet=0 # Use mainnet - rpcuser=dashrpc - rpcpassword=your_password - server=1 - listen=1 - ``` -3. Start Dash Core: `dashd` or use the GUI -4. Wait for initial sync (this can take several hours for mainnet) - -### Option 2: Docker Dash Core Node - -```bash -# Run Dash Core in Docker -docker run -d \ - --name dash-node \ - -p 9999:9999 \ - -p 9998:9998 \ - dashpay/dashd:latest \ - dashd -server=1 -listen=1 -discover=1 -``` - -## Running the Integration Tests - -### Check Node Availability - -First, verify your node is accessible: -```bash -# Test basic connectivity -nc -zv 127.0.0.1 9999 -``` - -### Run Individual Integration Tests - -```bash -cd dash-spv - -# Test basic connectivity -cargo test --test integration_real_node_test test_real_node_connectivity -- --nocapture - -# Test header sync up to 1000 headers -cargo test --test integration_real_node_test test_real_header_sync_genesis_to_1000 -- --nocapture - -# Test header sync up to 10k headers (requires synced node) -cargo test --test integration_real_node_test test_real_header_sync_up_to_10k -- --nocapture - -# Test header validation with real data -cargo test --test integration_real_node_test test_real_header_validation_with_node -- --nocapture - -# Test header chain continuity -cargo test --test integration_real_node_test test_real_header_chain_continuity -- --nocapture - -# Test sync resumption -cargo test --test integration_real_node_test test_real_node_sync_resumption -- --nocapture - -# Run performance benchmarks -cargo test --test integration_real_node_test test_real_node_performance_benchmarks -- --nocapture -``` - -### Run All Integration Tests - -```bash -# Run all integration tests -cargo test --test integration_real_node_test -- --nocapture -``` - -## Expected Test Behavior - -### With Node Available - -When a Dash Core node is running at 127.0.0.1:9999, the tests will: - -1. **Connect and handshake** with the real node -2. **Download actual headers** from the Dash mainnet blockchain -3. **Validate real blockchain data** using the SPV client -4. **Measure performance** of header synchronization -5. **Test chain continuity** with real header linkage -6. **Benchmark sync rates** (typically 50-200+ headers/second) - -Sample output: -``` -Running 6 tests -test test_real_node_connectivity ... ok -test test_real_header_sync_genesis_to_1000 ... ok -test test_real_header_sync_up_to_10k ... ok -test test_real_header_validation_with_node ... ok -test test_real_header_chain_continuity ... ok -test test_real_node_sync_resumption ... ok -test test_real_node_performance_benchmarks ... ok - -test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -``` - -### Without Node Available - -When no node is running, the tests will: - -1. **Detect unavailability** and log a warning -2. **Skip gracefully** without failing -3. **Return immediately** with success - -Sample output: -``` -test test_real_node_connectivity ... ok -Dash Core node not available at 127.0.0.1:9999: Connection refused -Skipping integration test - ensure Dash Core is running on mainnet -``` - -## Performance Expectations - -With a properly synced Dash Core node, you can expect: - -### Header Sync Performance -- **Connection time**: < 5 seconds -- **Handshake time**: < 2 seconds -- **Sync rate**: 50-200+ headers/second (depends on node and network) -- **10k headers**: 30-120 seconds (full sync from genesis) - -### Memory Usage -- **10k headers**: ~2-5 MB RAM -- **Storage efficiency**: Headers stored in compressed format -- **Retrieval speed**: < 100ms for 1000 header ranges - -### Test Timeouts -- **Basic connectivity**: 15 seconds -- **Header sync (1k)**: 2 minutes -- **Header sync (10k)**: 5 minutes -- **Chain validation**: 3 minutes - -## Troubleshooting - -### Connection Issues - -**Error**: "Connection refused" -- Check if Dash Core is running: `ps aux | grep dash` -- Verify port 9999 is open: `netstat -an | grep 9999` -- Check firewall settings - -**Error**: "Connection timeout" -- Node may be starting up - wait a few minutes -- Check if node is still syncing initial blockchain -- Verify network connectivity - -### Sync Issues - -**Error**: "Sync timeout" -- Node may be under heavy load -- Check node sync status: `dash-cli getblockchaininfo` -- Increase timeout values in test configuration - -**Error**: "Header validation failed" -- Node may have corrupted data -- Try restarting Dash Core -- Check node logs for errors - -### Performance Issues - -**Slow sync rates** (< 10 headers/second): -- Node may be under load or syncing -- Check system resources (CPU, memory, disk I/O) -- Consider using SSD storage for the node - -## Test Coverage Summary - -The integration tests provide comprehensive coverage of: - -✅ **Network Layer**: Real TCP connections and Dash protocol handshakes -✅ **Header Sync**: Actual blockchain header downloading and validation -✅ **Storage Layer**: Real data storage and retrieval with large datasets -✅ **Performance**: Real-world sync rates and memory efficiency -✅ **Validation**: Full blockchain header validation with real data -✅ **Error Handling**: Network timeouts and connection recovery -✅ **Chain Continuity**: Real blockchain linkage and consistency checks - -These tests prove the SPV client works correctly with the actual Dash network and can handle real-world data loads and network conditions. diff --git a/dash-spv/tests/integration_real_node_test.rs b/dash-spv/tests/integration_real_node_test.rs deleted file mode 100644 index 76caf9461..000000000 --- a/dash-spv/tests/integration_real_node_test.rs +++ /dev/null @@ -1,614 +0,0 @@ -//! Integration tests with real Dash Core node. -//! -//! These tests require a Dash Core node running at 127.0.0.1:9999 on mainnet. -//! They test actual network connectivity, protocol compliance, and real header sync. - -use std::net::SocketAddr; -use std::time::{Duration, Instant}; - -use dash_spv::storage::BlockHeaderStorage; -use dash_spv::{ - client::{ClientConfig, DashSpvClient}, - network::{NetworkManager, PeerNetworkManager}, - storage::DiskStorageManager, - types::ValidationMode, -}; -use dashcore::Network; -use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo; -use key_wallet_manager::wallet_manager::WalletManager; -use log::{debug, info, warn}; -use std::sync::Arc; -use tempfile::TempDir; -use tokio::sync::RwLock; - -const DASH_NODE_ADDR: &str = "127.0.0.1:9999"; -const MAX_TEST_HEADERS: u32 = 10000; -const HEADER_SYNC_TIMEOUT: Duration = Duration::from_secs(120); // 2 minutes for 10k headers - -/// Helper function to create a DashSpvClient with all required components -async fn create_test_client( - config: ClientConfig, -) -> Result< - DashSpvClient, PeerNetworkManager, DiskStorageManager>, - Box, -> { - // Create network manager - let network_manager = PeerNetworkManager::new(&config).await?; - - // Create storage manager - let storage_manager = - DiskStorageManager::new(TempDir::new().expect("Failed to create tmp dir").path()).await?; - - // Create wallet manager - let wallet = Arc::new(RwLock::new(WalletManager::::new(config.network))); - - Ok(DashSpvClient::new(config, network_manager, storage_manager, wallet).await?) -} - -/// Helper function to check if the Dash node is available -async fn check_node_availability() -> bool { - match tokio::net::TcpStream::connect(DASH_NODE_ADDR).await { - Ok(_) => { - info!("Dash Core node is available at {}", DASH_NODE_ADDR); - true - } - Err(e) => { - warn!("Dash Core node not available at {}: {}", DASH_NODE_ADDR, e); - warn!("Skipping integration test - ensure Dash Core is running on mainnet"); - false - } - } -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_node_connectivity() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing connectivity to real Dash Core node"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().expect("Valid peer address"); - - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - // Add the peer to the configuration - config.peers.push(peer_addr); - - // Test basic network manager connectivity - let mut network = - PeerNetworkManager::new(&config).await.expect("Failed to create network manager"); - - // Connect to the real node (this includes handshake) - let start_time = Instant::now(); - let connect_result = network.connect().await; - let connect_duration = start_time.elapsed(); - - assert!(connect_result.is_ok(), "Failed to connect to Dash node: {:?}", connect_result.err()); - info!("Successfully connected to Dash node (including handshake) in {:?}", connect_duration); - - // Verify connection status - assert!(network.is_connected(), "Should be connected to peer"); - assert_eq!(network.peer_count(), 1, "Should have 1 connected peer"); - - // Disconnect cleanly - let disconnect_result = network.disconnect().await; - assert!(disconnect_result.is_ok(), "Failed to disconnect cleanly"); - - info!("Real node connectivity test completed successfully"); -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_header_sync_genesis_to_1000() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing header sync from genesis to 1000 headers with real node"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - // Create client with memory storage for this test - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - // Add the real peer - config.peers.push(peer_addr); - - // Create client - let mut client = create_test_client(config).await.expect("Failed to create SPV client"); - - // Start the client - client.start().await.expect("Failed to start client"); - - // Check initial state - let initial_progress = - client.sync_progress().await.expect("Failed to get initial sync progress"); - - info!( - "Initial sync state: header_height={} filter_header_height={}", - initial_progress.header_height, initial_progress.filter_header_height - ); - - // Perform header sync - let sync_start = Instant::now(); - let sync_result = tokio::time::timeout(HEADER_SYNC_TIMEOUT, client.sync_to_tip()).await; - - match sync_result { - Ok(Ok(progress)) => { - let sync_duration = sync_start.elapsed(); - info!("Header sync completed in {:?}", sync_duration); - info!("Synced to height: {}", progress.header_height); - - // Verify we synced at least 1000 headers - assert!( - progress.header_height >= 1000, - "Should have synced at least 1000 headers, got: {}", - progress.header_height - ); - - // Verify sync progress - assert!( - progress.header_height > initial_progress.header_height, - "Header height should have increased" - ); - - info!("Successfully synced {} headers from real Dash node", progress.header_height); - } - Ok(Err(e)) => { - panic!("Header sync failed: {:?}", e); - } - Err(_) => { - panic!("Header sync timed out after {:?}", HEADER_SYNC_TIMEOUT); - } - } - - // Stop the client - client.stop().await.expect("Failed to stop client"); - - info!("Real header sync test (1000 headers) completed successfully"); -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_header_sync_up_to_10k() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing header sync up to 10k headers with real Dash node"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - // Create client configuration optimized for bulk sync - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - // Add the real peer - config.peers.push(peer_addr); - - // Create fresh storage and client - let storage = DiskStorageManager::new(TempDir::new().expect("Failed to create tmp dir").path()) - .await - .expect("Failed to create tmp storage"); - - // Verify starting from empty state - assert_eq!(storage.get_tip_height().await, None); - - let mut client = create_test_client(config.clone()).await.expect("Failed to create SPV client"); - - // Start the client - client.start().await.expect("Failed to start client"); - - // Measure sync performance - let sync_start = Instant::now(); - let mut last_report_time = sync_start; - let mut last_height = 0u32; - - info!("Starting header sync from genesis..."); - - // Sync headers with progress monitoring - let sync_result = tokio::time::timeout( - Duration::from_secs(300), // 5 minutes for up to 10k headers - async { - loop { - let progress = client.sync_progress().await?; - let current_time = Instant::now(); - - // Report progress every 30 seconds - if current_time.duration_since(last_report_time) >= Duration::from_secs(30) { - let headers_per_sec = if current_time != last_report_time { - (progress.header_height.saturating_sub(last_height)) as f64 - / current_time.duration_since(last_report_time).as_secs_f64() - } else { - 0.0 - }; - - info!( - "Sync progress: {} headers ({:.1} headers/sec)", - progress.header_height, headers_per_sec - ); - - last_report_time = current_time; - last_height = progress.header_height; - } - - // Check if we've reached our target or sync is complete - if progress.header_height >= MAX_TEST_HEADERS { - return Ok::<_, dash_spv::error::SpvError>(progress); - } - - // Try to sync more - let _sync_progress = client.sync_to_tip().await?; - - // Small delay to prevent busy loop - tokio::time::sleep(Duration::from_millis(100)).await; - } - }, - ) - .await; - - match sync_result { - Ok(Ok(final_progress)) => { - let total_duration = sync_start.elapsed(); - let headers_synced = final_progress.header_height; - let avg_headers_per_sec = headers_synced as f64 / total_duration.as_secs_f64(); - - info!("Header sync completed successfully!"); - info!("Total headers synced: {}", headers_synced); - info!("Total time: {:?}", total_duration); - info!("Average rate: {:.1} headers/second", avg_headers_per_sec); - - // Verify we synced a substantial number of headers - assert!( - headers_synced >= 1000, - "Should have synced at least 1000 headers, got: {}", - headers_synced - ); - - // Performance assertions - assert!( - avg_headers_per_sec > 10.0, - "Sync rate too slow: {:.1} headers/sec", - avg_headers_per_sec - ); - - if headers_synced >= MAX_TEST_HEADERS { - info!("Successfully synced target of {} headers", MAX_TEST_HEADERS); - } else { - info!("Synced {} headers (chain tip reached)", headers_synced); - } - - // Test header retrieval performance with real data - let retrieval_start = Instant::now(); - - // Test retrieving headers from different parts of the chain - let genesis_headers = - storage.load_headers(0..10).await.expect("Failed to load genesis headers"); - assert_eq!(genesis_headers.len(), 10); - - if headers_synced > 1000 { - let mid_headers = - storage.load_headers(500..510).await.expect("Failed to load mid-chain headers"); - assert_eq!(mid_headers.len(), 10); - } - - if headers_synced > 100 { - let recent_start = headers_synced.saturating_sub(10); - let recent_headers = storage - .load_headers(recent_start..(recent_start + 10)) - .await - .expect("Failed to load recent headers"); - assert!(!recent_headers.is_empty()); - } - - let retrieval_duration = retrieval_start.elapsed(); - info!("Header retrieval tests completed in {:?}", retrieval_duration); - } - Ok(Err(e)) => { - panic!("Header sync failed: {:?}", e); - } - Err(_) => { - panic!("Header sync timed out after 5 minutes"); - } - } - - // Stop the client - client.stop().await.expect("Failed to stop client"); - - info!("Real header sync test (up to 10k) completed successfully"); -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_header_validation_with_node() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing header validation with real node data"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - // Test with Full validation mode to ensure headers are properly validated - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Full); - - config.peers.push(peer_addr); - - let mut client = create_test_client(config).await.expect("Failed to create SPV client"); - - client.start().await.expect("Failed to start client"); - - // Sync a smaller number of headers with full validation - let sync_start = Instant::now(); - let sync_result = tokio::time::timeout( - Duration::from_secs(180), // 3 minutes for validation - client.sync_to_tip(), - ) - .await; - - match sync_result { - Ok(Ok(progress)) => { - let sync_duration = sync_start.elapsed(); - info!("Header validation sync completed in {:?}", sync_duration); - info!("Validated {} headers with full validation", progress.header_height); - - // With full validation, we should still sync at least some headers - assert!( - progress.header_height >= 100, - "Should have validated at least 100 headers, got: {}", - progress.header_height - ); - - info!( - "Successfully validated {} real headers from Dash network", - progress.header_height - ); - } - Ok(Err(e)) => { - panic!("Header validation failed: {:?}", e); - } - Err(_) => { - panic!("Header validation timed out"); - } - } - - client.stop().await.expect("Failed to stop client"); - - info!("Real header validation test completed successfully"); -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_header_chain_continuity() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing header chain continuity with real node"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - config.peers.push(peer_addr); - - let storage = DiskStorageManager::new(TempDir::new().expect("Failed to create tmp dir").path()) - .await - .expect("Failed to create tmp storage"); - - let mut client = create_test_client(config).await.expect("Failed to create SPV client"); - - client.start().await.expect("Failed to start client"); - - // Sync a reasonable number of headers for chain validation - let sync_result = tokio::time::timeout(Duration::from_secs(120), client.sync_to_tip()).await; - - let headers_synced = match sync_result { - Ok(Ok(progress)) => { - info!("Synced {} headers for chain continuity test", progress.header_height); - progress.header_height - } - Ok(Err(e)) => panic!("Sync failed: {:?}", e), - Err(_) => panic!("Sync timed out"), - }; - - // Test chain continuity by verifying headers link properly - if headers_synced >= 100 { - let test_range = std::cmp::min(100, headers_synced); - let headers = storage - .load_headers(0..test_range) - .await - .expect("Failed to load headers for continuity test"); - - info!("Validating chain continuity for {} headers", headers.len()); - - // Verify each header links to the previous one - for i in 1..headers.len() { - let _prev_hash = headers[i - 1].block_hash(); - let current_prev = headers[i].prev_blockhash; - - // Note: In real blockchain, each header should reference the previous block's hash - // For our test, we verify the structure is consistent - debug!("Header {}: prev_block={}", i, current_prev); - - // Verify timestamps are increasing (basic sanity check) - assert!( - headers[i].time >= headers[i - 1].time, - "Header timestamps should be non-decreasing: {} >= {}", - headers[i].time, - headers[i - 1].time - ); - } - - info!("Chain continuity verified for {} consecutive headers", headers.len()); - } - - client.stop().await.expect("Failed to stop client"); - - info!("Real header chain continuity test completed successfully"); -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_node_sync_resumption() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing header sync resumption with real node"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - config.peers.push(peer_addr); - - // First sync: Get some headers - info!("Phase 1: Initial sync"); - let mut client1 = - create_test_client(config.clone()).await.expect("Failed to create first client"); - - client1.start().await.expect("Failed to start first client"); - - let initial_sync = tokio::time::timeout(Duration::from_secs(60), client1.sync_to_tip()) - .await - .expect("Initial sync timed out") - .expect("Initial sync failed"); - - let phase1_height = initial_sync.header_height; - info!("Phase 1 completed: {} headers", phase1_height); - - client1.stop().await.expect("Failed to stop first client"); - - // Simulate app restart with persistent storage - // In this test, we'll use memory storage but manually transfer some state - - // Second sync: Resume from where we left off - info!("Phase 2: Resume sync"); - let mut client2 = create_test_client(config).await.expect("Failed to create second client"); - - client2.start().await.expect("Failed to start second client"); - - let resume_sync = tokio::time::timeout(Duration::from_secs(60), client2.sync_to_tip()) - .await - .expect("Resume sync timed out") - .expect("Resume sync failed"); - - let phase2_height = resume_sync.header_height; - info!("Phase 2 completed: {} headers", phase2_height); - - // Verify we can sync more headers (or reached the same tip) - assert!( - phase2_height >= phase1_height, - "Resume sync should reach at least the same height: {} >= {}", - phase2_height, - phase1_height - ); - - client2.stop().await.expect("Failed to stop second client"); - - info!("Sync resumption test completed successfully"); -} - -#[tokio::test] -#[ignore = "requires local Dash Core node"] -async fn test_real_node_performance_benchmarks() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Running performance benchmarks with real node"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - config.peers.push(peer_addr); - - let mut client = create_test_client(config).await.expect("Failed to create client"); - - client.start().await.expect("Failed to start client"); - - // Benchmark different aspects of header sync - let mut benchmarks = Vec::new(); - - // Benchmark 1: Initial connection and handshake - let connection_start = Instant::now(); - let initial_progress = client.sync_progress().await.expect("Failed to get initial progress"); - let connection_time = connection_start.elapsed(); - benchmarks.push(("Connection & Handshake", connection_time)); - - // Benchmark 2: First 1000 headers - let sync_start = Instant::now(); - let mut last_height = initial_progress.header_height; - let target_height = last_height + 1000; - - while last_height < target_height { - let sync_result = tokio::time::timeout(Duration::from_secs(60), client.sync_to_tip()).await; - - match sync_result { - Ok(Ok(progress)) => { - if progress.header_height <= last_height { - // No more headers available - break; - } - last_height = progress.header_height; - } - Ok(Err(e)) => { - warn!("Sync error: {:?}", e); - break; - } - Err(_) => { - warn!("Sync timeout"); - break; - } - } - } - - let sync_time = sync_start.elapsed(); - let headers_synced = last_height - initial_progress.header_height; - benchmarks.push(("Sync Time", sync_time)); - - client.stop().await.expect("Failed to stop client"); - - // Report benchmarks - info!("=== Performance Benchmarks ==="); - for (name, duration) in benchmarks { - info!("{}: {:?}", name, duration); - } - info!("Headers synced: {}", headers_synced); - - if headers_synced > 0 { - let headers_per_sec = headers_synced as f64 / sync_time.as_secs_f64(); - info!("Sync rate: {:.1} headers/second", headers_per_sec); - - // Performance assertions - assert!( - headers_per_sec > 5.0, - "Sync performance too slow: {:.1} headers/sec", - headers_per_sec - ); - assert!( - connection_time < Duration::from_secs(30), - "Connection took too long: {:?}", - connection_time - ); - } - - info!("Performance benchmarks completed successfully"); -} diff --git a/dash-spv/tests/simple_header_test.rs b/dash-spv/tests/simple_header_test.rs deleted file mode 100644 index 6df34a1a0..000000000 --- a/dash-spv/tests/simple_header_test.rs +++ /dev/null @@ -1,121 +0,0 @@ -//! Simple test to verify header sync fix works - -use dash_spv::{ - client::{ClientConfig, DashSpvClient}, - network::PeerNetworkManager, - storage::{BlockHeaderStorage, DiskStorageManager}, - types::ValidationMode, -}; -use dashcore::Network; -use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo; -use key_wallet_manager::wallet_manager::WalletManager; -use log::info; -use std::{net::SocketAddr, sync::Arc, time::Duration}; -use tempfile::TempDir; -use tokio::sync::RwLock; - -const DASH_NODE_ADDR: &str = "127.0.0.1:9999"; - -/// Check if node is available -async fn check_node_availability() -> bool { - match tokio::net::TcpStream::connect(DASH_NODE_ADDR).await { - Ok(_) => { - info!("Dash Core node is available at {}", DASH_NODE_ADDR); - true - } - Err(e) => { - info!("Dash Core node not available at {}: {}", DASH_NODE_ADDR, e); - info!("Skipping test - ensure Dash Core is running on mainnet"); - false - } - } -} - -#[tokio::test] -async fn test_simple_header_sync() { - let _ = env_logger::try_init(); - - if !check_node_availability().await { - return; - } - - info!("Testing simple header sync to verify fix"); - - let peer_addr: SocketAddr = DASH_NODE_ADDR.parse().unwrap(); - - // Create client configuration - let mut config = ClientConfig::new(Network::Dash).with_validation_mode(ValidationMode::Basic); - - config.peers.push(peer_addr); - - // Create fresh storage - let storage = DiskStorageManager::new(TempDir::new().expect("Failed to create tmp dir").path()) - .await - .expect("Failed to create tmp storage"); - - // Verify starting from empty state - assert_eq!(storage.get_tip_height().await, None); - - // Create network manager - let network_manager = - PeerNetworkManager::new(&config).await.expect("Failed to create network manager"); - - // Create wallet manager - let wallet = Arc::new(RwLock::new(WalletManager::::new(config.network))); - - let mut client = DashSpvClient::new(config.clone(), network_manager, storage, wallet) - .await - .expect("Failed to create SPV client"); - - // Start the client - client.start().await.expect("Failed to start client"); - - info!("Starting header sync..."); - - // Sync just a few headers with short timeout - let sync_result = tokio::time::timeout(Duration::from_secs(30), async { - // Try to sync to tip once - info!("Attempting sync to tip..."); - match client.sync_to_tip().await { - Ok(progress) => { - info!("Sync succeeded! Progress: height={}", progress.header_height); - } - Err(e) => { - // This is the critical test - the error should NOT be about headers not connecting - let error_msg = format!("{}", e); - if error_msg.contains("Header does not connect to previous header") { - panic!( - "FAILED: Got the header connection error we were trying to fix: {}", - error_msg - ); - } - info!("Sync failed (may be expected): {}", e); - } - } - - // Check final state - let final_height = - client.storage().lock().await.get_tip_height().await.expect("Failed to get tip height"); - - info!("Final header height: {:?}", final_height); - - // As long as we didn't get the "Header does not connect" error, the fix worked - Ok::<(), Box>(()) - }) - .await; - - match sync_result { - Ok(_) => { - info!("✅ Header sync test completed - no 'Header does not connect' errors detected"); - info!("This means our fix for the GetHeaders protocol is working correctly!"); - } - Err(_) => { - info!( - "⚠️ Test timed out, but that's okay as long as we didn't get the connection error" - ); - info!( - "The important thing is we didn't see 'Header does not connect to previous header'" - ); - } - } -} diff --git a/dash-spv/tests/test_plan.md b/dash-spv/tests/test_plan.md index a0a73e8a0..67f336c91 100644 --- a/dash-spv/tests/test_plan.md +++ b/dash-spv/tests/test_plan.md @@ -190,92 +190,3 @@ This document outlines a systematic testing approach for the Dash SPV client, or - Memory leak detection - CPU usage profiling - Network bandwidth monitoring - -## 10. Integration and End-to-End Tests ✅ (6/6 implemented) - -### File: `tests/integration_real_node_test.rs` (COMPLETED) -- [x] **Real node connectivity** - Tests connection and handshake with live Dash Core node -- [x] **Header sync from genesis to 1k** - Tests real header synchronization up to 1000 headers -- [x] **Header sync up to 10k** - Tests bulk header sync up to 10,000 headers with performance monitoring -- [x] **Header validation with real data** - Tests full validation mode with real blockchain headers -- [x] **Header chain continuity** - Tests chain validation and consistency with real data -- [x] **Sync resumption** - Tests restarting and resuming sync from previous state -- [x] **Performance benchmarks** - Tests and measures real-world sync performance - -### Integration Test Features -- **Graceful fallback**: Tests detect if Dash Core node unavailable and skip gracefully -- **Real network data**: Uses actual Dash mainnet blockchain data for validation -- **Performance monitoring**: Measures headers/second sync rates and connection times -- **Chain validation**: Verifies header linkage and timestamp consistency -- **Memory efficiency**: Tests large dataset handling (10k+ headers) -- **Error resilience**: Tests timeout handling and connection recovery - -## Test Implementation Priority - -### Phase 1: Foundation (Week 1) -1. Complete handshake tests ✅ (3/4 passing) -2. Storage layer tests ✅ (COMPLETED - 9/9 passing) -3. Header sync tests ✅ (COMPLETED - 11/11 passing) -4. Configuration tests - -### Phase 2: Core Functionality (Week 2) -1. Validation layer tests -2. Advanced header sync tests -3. Error handling tests -4. Client lifecycle tests - -### Phase 3: Advanced Features (Week 3) -1. Filter synchronization tests -2. Masternode sync tests -3. Performance tests -4. Integration tests - -### Phase 4: Robustness (Week 4) -1. Edge case testing -2. Load testing -3. Cross-platform testing -4. Documentation and cleanup - -## Test Execution - -### Running Individual Test Suites -```bash -# Run handshake tests -cargo test --test handshake_test - -# Run specific test function -cargo test --test handshake_test test_handshake_with_mainnet_peer - -# Run all tests with output -cargo test -- --nocapture -``` - -### Test Data and Fixtures -- Create test data generators for consistent testing -- Use deterministic test scenarios where possible -- Maintain test vectors for validation testing -- Document test environment requirements - -### Continuous Integration -- Automated test execution on commits -- Performance regression detection -- Cross-platform test matrix -- Integration with Dash Core test networks - -## Success Criteria - -Each test category should achieve: -- **Functional correctness**: All core functionality works as specified -- **Error resilience**: Graceful handling of all error conditions -- **Performance benchmarks**: Meets or exceeds performance targets -- **Memory safety**: No memory leaks or unsafe operations -- **Network compatibility**: Works with real Dash network peers -- **Cross-platform support**: Consistent behavior across platforms - -## Notes - -- Tests assume availability of a Dash Core node at 127.0.0.1:9999 -- Some tests may require specific network conditions or test data -- Performance tests should be run in isolation to get accurate measurements -- Integration tests may take longer to execute due to network operations -- Consider using test containers or mock servers for more controlled testing