sal/virt/tests/rfs_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

354 lines
12 KiB
Rust

use sal_virt::rfs::{MountType, RfsBuilder, RfsError, StoreSpec};
/// Tests RFS builder creation and property validation
///
/// This test verifies that:
/// - Builders are created with correct initial state
/// - Properties are accessible and correct
/// - Initial state is properly set
///
/// No external dependencies required - tests pure Rust logic
#[test]
fn test_rfs_builder_creation_and_properties() {
let builder = RfsBuilder::new("/source/path", "/target/path", MountType::Local);
// Validate builder properties are correctly set
assert_eq!(builder.source(), "/source/path");
assert_eq!(builder.target(), "/target/path");
assert!(matches!(builder.mount_type(), MountType::Local));
assert!(builder.options().is_empty());
assert!(!builder.debug());
}
/// Tests mount type behavior and string conversion
///
/// This test verifies that:
/// - Each mount type is properly stored and accessible
/// - Mount types convert to correct string representations
/// - Custom mount types preserve their values
/// - Builders correctly store mount type information
#[test]
fn test_mount_type_behavior_and_serialization() {
// Test each mount type's specific behavior
let test_cases = vec![
(MountType::Local, "local", "/local/source", "/local/target"),
(
MountType::SSH,
"ssh",
"user@host:/remote/path",
"/ssh/target",
),
(MountType::S3, "s3", "s3://bucket/key", "/s3/target"),
(
MountType::WebDAV,
"webdav",
"https://webdav.example.com/path",
"/webdav/target",
),
(
MountType::Custom("fuse".to_string()),
"fuse",
"fuse://source",
"/fuse/target",
),
];
for (mount_type, expected_str, source, target) in test_cases {
// Test string representation
assert_eq!(mount_type.to_string(), expected_str);
// Test that mount type affects builder behavior correctly
let builder = RfsBuilder::new(source, target, mount_type.clone());
assert_eq!(builder.source(), source);
assert_eq!(builder.target(), target);
// Verify mount type is stored correctly
match (&mount_type, builder.mount_type()) {
(MountType::Local, MountType::Local) => {}
(MountType::SSH, MountType::SSH) => {}
(MountType::S3, MountType::S3) => {}
(MountType::WebDAV, MountType::WebDAV) => {}
(MountType::Custom(expected), MountType::Custom(actual)) => {
assert_eq!(expected, actual);
}
_ => assert!(
false,
"Mount type mismatch: expected {:?}, got {:?}",
mount_type,
builder.mount_type()
),
}
}
}
/// Tests RFS builder option handling and method chaining
///
/// This test verifies that:
/// - Options are properly stored and accessible
/// - Method chaining works correctly
/// - Multiple options can be added
/// - Option values are preserved correctly
#[test]
fn test_rfs_builder_option_handling() {
let builder = RfsBuilder::new("/source", "/target", MountType::Local)
.with_option("read_only", "true")
.with_option("uid", "1000")
.with_option("gid", "1000");
// Verify options are stored correctly
assert_eq!(builder.options().len(), 3);
assert_eq!(
builder.options().get("read_only"),
Some(&"true".to_string())
);
assert_eq!(builder.options().get("uid"), Some(&"1000".to_string()));
assert_eq!(builder.options().get("gid"), Some(&"1000".to_string()));
// Verify other properties are preserved
assert_eq!(builder.source(), "/source");
assert_eq!(builder.target(), "/target");
assert!(matches!(builder.mount_type(), MountType::Local));
}
/// Tests StoreSpec creation and string serialization
///
/// This test verifies that:
/// - StoreSpec objects are created with correct type
/// - Options are properly stored and accessible
/// - String serialization works correctly
/// - Method chaining preserves all data
#[test]
fn test_store_spec_creation_and_serialization() {
// Test file store specification
let file_spec = StoreSpec::new("file").with_option("path", "/path/to/store");
assert_eq!(file_spec.spec_type, "file");
assert_eq!(file_spec.options.len(), 1);
assert_eq!(
file_spec.options.get("path"),
Some(&"/path/to/store".to_string())
);
assert_eq!(file_spec.to_string(), "file:path=/path/to/store");
// Test S3 store specification with multiple options
let s3_spec = StoreSpec::new("s3")
.with_option("bucket", "my-bucket")
.with_option("region", "us-east-1");
assert_eq!(s3_spec.spec_type, "s3");
assert_eq!(s3_spec.options.len(), 2);
assert_eq!(
s3_spec.options.get("bucket"),
Some(&"my-bucket".to_string())
);
assert_eq!(
s3_spec.options.get("region"),
Some(&"us-east-1".to_string())
);
// String representation should contain both options (order may vary)
let s3_string = s3_spec.to_string();
assert!(s3_string.starts_with("s3:"));
assert!(s3_string.contains("bucket=my-bucket"));
assert!(s3_string.contains("region=us-east-1"));
}
#[test]
fn test_rfs_error_types() {
// Test that our error types work correctly
let error = RfsError::CommandFailed("Test error".to_string());
assert!(matches!(error, RfsError::CommandFailed(_)));
let error_msg = format!("{}", error);
assert!(error_msg.contains("Test error"));
}
/// Tests MountType string conversion and round-trip behavior
///
/// This test verifies that:
/// - MountType to_string() produces correct values
/// - MountType from_string() correctly parses values
/// - Round-trip conversion preserves data
/// - Debug formatting works without panicking
#[test]
fn test_mount_type_string_conversion() {
// Test standard mount types
let test_cases = vec![
(MountType::Local, "local"),
(MountType::SSH, "ssh"),
(MountType::S3, "s3"),
(MountType::WebDAV, "webdav"),
];
for (mount_type, expected_string) in test_cases {
// Test to_string conversion
assert_eq!(mount_type.to_string(), expected_string);
// Test round-trip conversion
let parsed = MountType::from_string(expected_string);
assert_eq!(format!("{:?}", mount_type), format!("{:?}", parsed));
// Test debug formatting doesn't panic
let debug_str = format!("{:?}", mount_type);
assert!(!debug_str.is_empty());
}
// Test custom mount type
let custom = MountType::Custom("myfs".to_string());
assert_eq!(custom.to_string(), "myfs");
let parsed_custom = MountType::from_string("myfs");
if let MountType::Custom(value) = parsed_custom {
assert_eq!(value, "myfs");
} else {
assert!(false, "Expected Custom mount type, got {:?}", parsed_custom);
}
}
/// Tests PackBuilder creation and configuration
///
/// This test verifies that:
/// - PackBuilder is created with correct initial state
/// - Store specifications are properly stored
/// - Debug mode can be set and retrieved
/// - Method chaining works correctly
#[test]
fn test_pack_builder_creation_and_configuration() {
use sal_virt::rfs::PackBuilder;
// Test creating a pack builder with store specs
let specs = vec![
StoreSpec::new("file").with_option("path", "/tmp/store"),
StoreSpec::new("s3").with_option("bucket", "test-bucket"),
];
let builder = PackBuilder::new("/source/dir", "/output/file")
.with_store_specs(specs.clone())
.with_debug(true);
// Verify builder properties
assert_eq!(builder.directory(), "/source/dir");
assert_eq!(builder.output(), "/output/file");
assert_eq!(builder.store_specs().len(), 2);
assert!(builder.debug());
// Verify store specs are correctly stored
assert_eq!(builder.store_specs()[0].spec_type, "file");
assert_eq!(builder.store_specs()[1].spec_type, "s3");
assert_eq!(
builder.store_specs()[0].options.get("path"),
Some(&"/tmp/store".to_string())
);
assert_eq!(
builder.store_specs()[1].options.get("bucket"),
Some(&"test-bucket".to_string())
);
}
#[test]
fn test_rfs_functions_availability() {
// Test that RFS functions are available (even if they fail due to missing RFS binary)
use sal_virt::rfs::{list_mounts, unmount_all};
// These functions should exist and be callable
// They will likely fail in test environment due to missing RFS binary, but that's expected
let list_result = list_mounts();
let unmount_result = unmount_all();
// We expect these to fail in test environment, so we just check they're callable
match list_result {
Ok(_) => println!("RFS is available - list_mounts succeeded"),
Err(RfsError::CommandFailed(_)) => {
println!("RFS not available - expected in test environment")
}
Err(e) => println!("RFS error (expected): {:?}", e),
}
match unmount_result {
Ok(_) => println!("RFS is available - unmount_all succeeded"),
Err(RfsError::CommandFailed(_)) => {
println!("RFS not available - expected in test environment")
}
Err(e) => println!("RFS error (expected): {:?}", e),
}
// Test passes if functions are callable and return proper Result types
}
#[test]
fn test_pack_operations_availability() {
// Test that pack operations are available
use sal_virt::rfs::{list_contents, pack_directory, unpack, verify};
let specs = vec![StoreSpec::new("file").with_option("path", "/tmp/test")];
// These functions should exist and be callable
let pack_result = pack_directory("/nonexistent", "/tmp/test.pack", &specs);
let unpack_result = unpack("/tmp/test.pack", "/tmp/unpack");
let list_result = list_contents("/tmp/test.pack");
let verify_result = verify("/tmp/test.pack");
// We expect these to fail in test environment, so we just check they're callable
match pack_result {
Ok(_) => println!("RFS pack succeeded"),
Err(_) => println!("RFS pack failed (expected in test environment)"),
}
match unpack_result {
Ok(_) => println!("RFS unpack succeeded"),
Err(_) => println!("RFS unpack failed (expected in test environment)"),
}
match list_result {
Ok(_) => println!("RFS list_contents succeeded"),
Err(_) => println!("RFS list_contents failed (expected in test environment)"),
}
match verify_result {
Ok(_) => println!("RFS verify succeeded"),
Err(_) => println!("RFS verify failed (expected in test environment)"),
}
// Test passes if all pack operations are callable and return proper Result types
}
/// Tests RFS builder debug mode and advanced chaining
///
/// This test verifies that:
/// - Debug mode can be set and retrieved
/// - Builder chaining preserves all properties
/// - Multiple options can be added in sequence
/// - Builder state is immutable (each call returns new instance)
#[test]
fn test_rfs_builder_debug_and_chaining() {
let base_builder = RfsBuilder::new("/src", "/dst", MountType::SSH);
// Test debug mode
let debug_builder = base_builder.clone().with_debug(true);
assert!(debug_builder.debug());
assert!(!base_builder.debug()); // Original should be unchanged
// Test complex chaining
let complex_builder = base_builder
.with_option("port", "2222")
.with_option("user", "testuser")
.with_debug(true)
.with_option("timeout", "30");
// Verify all properties are preserved
assert_eq!(complex_builder.source(), "/src");
assert_eq!(complex_builder.target(), "/dst");
assert!(matches!(complex_builder.mount_type(), MountType::SSH));
assert!(complex_builder.debug());
assert_eq!(complex_builder.options().len(), 3);
assert_eq!(
complex_builder.options().get("port"),
Some(&"2222".to_string())
);
assert_eq!(
complex_builder.options().get("user"),
Some(&"testuser".to_string())
);
assert_eq!(
complex_builder.options().get("timeout"),
Some(&"30".to_string())
);
}