sal/virt/tests/performance_tests.rs
Mahmoud-Emad 455f84528b
Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
feat: Add support for virt package
- Add sal-virt package to the workspace members
- Update MONOREPO_CONVERSION_PLAN.md to reflect the
  completion of sal-process and sal-virt packages
- Update src/lib.rs to include sal-virt
- Update src/postgresclient to use sal-virt instead of local
  virt module
- Update tests to use sal-virt
2025-06-23 02:37:14 +03:00

289 lines
9.6 KiB
Rust

/// 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<RfsBuilder> = (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<RfsBuilder> = 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<String> = 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<RfsBuilder> = (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<RfsBuilder> = 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<RfsBuilder> = (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");
}