Some checks are pending
Rhai Tests / Run Rhai Tests (push) Waiting to run
- 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
289 lines
9.6 KiB
Rust
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");
|
|
}
|