...
This commit is contained in:
288
packages/system/virt/tests/performance_tests.rs
Normal file
288
packages/system/virt/tests/performance_tests.rs
Normal file
@@ -0,0 +1,288 @@
|
||||
/// 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");
|
||||
}
|
Reference in New Issue
Block a user