/// Performance and resource usage tests for SAL Virt package /// /// These tests verify that: /// - Builders don't leak memory or resources /// - Performance is acceptable for typical usage /// - Resource usage is reasonable /// - Concurrent usage works correctly use sal_virt::rfs::{MountType, RfsBuilder, StoreSpec}; /// Tests memory efficiency of RFS builders /// /// This test verifies that: /// - Builders don't leak memory when created in bulk /// - Builder chaining doesn't cause memory issues /// - Cloning builders works efficiently /// - Large numbers of builders can be created #[test] fn test_rfs_builder_memory_efficiency() { // Test creating many builders let builders: Vec = (0..1000) .map(|i| { RfsBuilder::new( &format!("/src{}", i), &format!("/dst{}", i), MountType::Local, ) }) .collect(); // Verify all builders maintain correct state for (i, builder) in builders.iter().enumerate() { assert_eq!(builder.source(), &format!("/src{}", i)); assert_eq!(builder.target(), &format!("/dst{}", i)); assert!(matches!(builder.mount_type(), MountType::Local)); assert!(builder.options().is_empty()); assert!(!builder.debug()); } // Test builder chaining doesn't cause issues let chained_builders: Vec = builders .into_iter() .take(100) .map(|builder| { builder .with_option("opt1", "val1") .with_option("opt2", "val2") .with_debug(true) }) .collect(); // Verify chained builders maintain state for builder in &chained_builders { assert_eq!(builder.options().len(), 2); assert!(builder.debug()); assert_eq!(builder.options().get("opt1"), Some(&"val1".to_string())); assert_eq!(builder.options().get("opt2"), Some(&"val2".to_string())); } println!("✓ Created and validated 1000 RFS builders + 100 chained builders"); } /// Tests StoreSpec memory efficiency and performance /// /// This test verifies that: /// - StoreSpecs can be created efficiently in bulk /// - String serialization performance is acceptable /// - Memory usage is reasonable for large collections /// - Option handling scales well #[test] fn test_store_spec_performance() { // Create many store specs with different configurations let mut specs = Vec::new(); // File specs for i in 0..200 { let spec = StoreSpec::new("file") .with_option("path", &format!("/storage/file{}", i)) .with_option("compression", if i % 2 == 0 { "gzip" } else { "lz4" }) .with_option("backup", &format!("backup{}", i)); specs.push(spec); } // S3 specs for i in 0..200 { let spec = StoreSpec::new("s3") .with_option("bucket", &format!("bucket-{}", i)) .with_option("region", if i % 3 == 0 { "us-east-1" } else { "us-west-2" }) .with_option("key", &format!("key-{}", i)); specs.push(spec); } // Custom specs for i in 0..100 { let spec = StoreSpec::new(&format!("custom-{}", i)) .with_option("endpoint", &format!("https://storage{}.example.com", i)) .with_option("auth", &format!("token-{}", i)) .with_option("timeout", &format!("{}s", 30 + i % 60)); specs.push(spec); } // Test serialization performance let serialized: Vec = specs.iter().map(|spec| spec.to_string()).collect(); // Verify all serializations are valid for (i, serialized_spec) in serialized.iter().enumerate() { assert!(!serialized_spec.is_empty()); assert!(serialized_spec.contains(":") || !specs[i].options.is_empty()); } // Test that specs maintain their properties assert_eq!(specs.len(), 500); for spec in &specs { assert!(!spec.spec_type.is_empty()); assert!(!spec.to_string().is_empty()); } println!("✓ Created and serialized 500 StoreSpecs with various configurations"); } /// Tests builder pattern performance and chaining /// /// This test verifies that: /// - Method chaining is efficient /// - Builder pattern doesn't cause performance issues /// - Complex configurations can be built efficiently /// - Memory usage is reasonable for complex builders #[test] fn test_builder_chaining_performance() { // Test complex RFS builder chaining let complex_builders: Vec = (0..100) .map(|i| { let mut builder = RfsBuilder::new( &format!("/complex/source/{}", i), &format!("/complex/target/{}", i), match i % 4 { 0 => MountType::Local, 1 => MountType::SSH, 2 => MountType::S3, _ => MountType::Custom(format!("custom-{}", i)), }, ); // Add many options through chaining for j in 0..10 { builder = builder.with_option(&format!("option{}", j), &format!("value{}", j)); } builder.with_debug(i % 2 == 0) }) .collect(); // Verify all complex builders are correct for (i, builder) in complex_builders.iter().enumerate() { assert_eq!(builder.source(), &format!("/complex/source/{}", i)); assert_eq!(builder.target(), &format!("/complex/target/{}", i)); assert_eq!(builder.options().len(), 10); assert_eq!(builder.debug(), i % 2 == 0); // Verify all options are present for j in 0..10 { assert_eq!( builder.options().get(&format!("option{}", j)), Some(&format!("value{}", j)) ); } } println!("✓ Created 100 complex builders with 10 options each via chaining"); } /// Tests concurrent builder usage (thread safety where applicable) /// /// This test verifies that: /// - Builders can be used safely across threads /// - No data races occur /// - Performance is acceptable under concurrent load /// - Resource cleanup works correctly #[test] fn test_concurrent_builder_usage() { use std::thread; // Test concurrent RFS builder creation let handles: Vec<_> = (0..10) .map(|thread_id| { thread::spawn(move || { let mut builders = Vec::new(); // Each thread creates 50 builders for i in 0..50 { let builder = RfsBuilder::new( &format!("/thread{}/src{}", thread_id, i), &format!("/thread{}/dst{}", thread_id, i), MountType::Local, ) .with_option("thread_id", &thread_id.to_string()) .with_option("builder_id", &i.to_string()); builders.push(builder); } // Verify builders in this thread for (i, builder) in builders.iter().enumerate() { assert_eq!(builder.source(), &format!("/thread{}/src{}", thread_id, i)); assert_eq!( builder.options().get("thread_id"), Some(&thread_id.to_string()) ); assert_eq!(builder.options().get("builder_id"), Some(&i.to_string())); } builders.len() }) }) .collect(); // Wait for all threads and collect results let mut total_builders = 0; for handle in handles { let count = handle.join().expect("Thread should complete successfully"); total_builders += count; } assert_eq!(total_builders, 500); // 10 threads * 50 builders each println!( "✓ Successfully created {} builders across 10 concurrent threads", total_builders ); } /// Tests resource cleanup and builder lifecycle /// /// This test verifies that: /// - Builders can be dropped safely /// - No resource leaks occur /// - Large collections can be cleaned up efficiently /// - Memory is reclaimed properly #[test] fn test_resource_cleanup_and_lifecycle() { // Create a large collection of builders with various configurations let mut all_builders = Vec::new(); // Add RFS builders for i in 0..200 { let builder = RfsBuilder::new( &format!("/lifecycle/src{}", i), &format!("/lifecycle/dst{}", i), if i % 2 == 0 { MountType::Local } else { MountType::SSH }, ) .with_option("lifecycle", "test") .with_option("id", &i.to_string()); all_builders.push(builder); } // Test that builders can be moved and cloned let cloned_builders: Vec = all_builders.iter().cloned().collect(); assert_eq!(cloned_builders.len(), 200); // Test partial cleanup let (first_half, second_half) = all_builders.split_at(100); assert_eq!(first_half.len(), 100); assert_eq!(second_half.len(), 100); // Verify builders still work after splitting for (i, builder) in first_half.iter().enumerate() { assert_eq!(builder.source(), &format!("/lifecycle/src{}", i)); assert_eq!(builder.options().get("id"), Some(&i.to_string())); } // Test that we can create new builders after cleanup let new_builders: Vec = (0..50) .map(|i| { RfsBuilder::new( &format!("/new/src{}", i), &format!("/new/dst{}", i), MountType::WebDAV, ) }) .collect(); assert_eq!(new_builders.len(), 50); println!("✓ Successfully tested resource lifecycle with 200 + 200 + 50 builders"); }