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

338 lines
12 KiB
Rust

/// Integration tests for SAL Virt package
///
/// These tests verify that:
/// - All modules work together correctly
/// - Error types are consistent across modules
/// - Integration between buildah, nerdctl, and rfs works
/// - Module APIs are compatible
use sal_virt::{
buildah::{BuildahError, Builder},
nerdctl::{Container, NerdctlError},
rfs::{MountType, RfsBuilder, RfsError, StoreSpec},
};
/// Tests cross-module error type consistency
///
/// This test verifies that:
/// - All error types implement std::error::Error
/// - Error messages are properly formatted
/// - Error types can be converted to strings
/// - Error handling is consistent across modules
#[test]
fn test_cross_module_error_consistency() {
// Test BuildahError
let buildah_error = BuildahError::CommandFailed("Buildah command failed".to_string());
let buildah_msg = format!("{}", buildah_error);
assert!(!buildah_msg.is_empty());
assert!(buildah_msg.contains("Buildah command failed"));
// Test NerdctlError
let nerdctl_error = NerdctlError::CommandFailed("Nerdctl command failed".to_string());
let nerdctl_msg = format!("{}", nerdctl_error);
assert!(!nerdctl_msg.is_empty());
assert!(nerdctl_msg.contains("Nerdctl command failed"));
// Test RfsError
let rfs_error = RfsError::CommandFailed("RFS command failed".to_string());
let rfs_msg = format!("{}", rfs_error);
assert!(!rfs_msg.is_empty());
assert!(rfs_msg.contains("RFS command failed"));
// Test that all errors can be used as trait objects
let errors: Vec<Box<dyn std::error::Error>> = vec![
Box::new(buildah_error),
Box::new(nerdctl_error),
Box::new(rfs_error),
];
for error in errors {
let error_string = error.to_string();
assert!(!error_string.is_empty());
}
}
/// Tests module integration and compatibility
///
/// This test verifies that:
/// - All modules can be used together
/// - Builder patterns are consistent
/// - Error handling works across modules
/// - No conflicts between module APIs
#[test]
fn test_module_integration_compatibility() {
// Test that all modules can be instantiated together
let buildah_result = Builder::new("integration-test", "alpine:latest");
let nerdctl_result = Container::new("integration-test");
let rfs_builder = RfsBuilder::new("/src", "/dst", MountType::Local);
// Test RFS builder (should always work)
assert_eq!(rfs_builder.source(), "/src");
assert_eq!(rfs_builder.target(), "/dst");
assert!(matches!(rfs_builder.mount_type(), MountType::Local));
// Test error handling consistency
match (buildah_result, nerdctl_result) {
(Ok(buildah_builder), Ok(nerdctl_container)) => {
// Both tools available - verify they work together
assert_eq!(buildah_builder.name(), "integration-test");
assert_eq!(nerdctl_container.name, "integration-test");
println!("✓ Both buildah and nerdctl are available");
}
(
Err(BuildahError::CommandExecutionFailed(_)),
Err(NerdctlError::CommandExecutionFailed(_)),
) => {
// Both tools unavailable - expected in test environment
println!("⚠️ Both buildah and nerdctl unavailable - test environment detected");
}
(Ok(buildah_builder), Err(NerdctlError::CommandExecutionFailed(_))) => {
// Only buildah available
assert_eq!(buildah_builder.name(), "integration-test");
println!("✓ Buildah available, nerdctl unavailable");
}
(Err(BuildahError::CommandExecutionFailed(_)), Ok(nerdctl_container)) => {
// Only nerdctl available
assert_eq!(nerdctl_container.name, "integration-test");
println!("✓ Nerdctl available, buildah unavailable");
}
(Err(buildah_err), Err(nerdctl_err)) => {
// Other errors - should be consistent
println!(
"⚠️ Both tools failed with errors: buildah={:?}, nerdctl={:?}",
buildah_err, nerdctl_err
);
}
(Ok(_), Err(nerdctl_err)) => {
println!("⚠️ Buildah succeeded, nerdctl failed: {:?}", nerdctl_err);
}
(Err(buildah_err), Ok(_)) => {
println!("⚠️ Nerdctl succeeded, buildah failed: {:?}", buildah_err);
}
}
}
/// Tests store specification integration with different modules
///
/// This test verifies that:
/// - StoreSpec works with different storage backends
/// - String serialization is consistent
/// - Options are properly handled
/// - Integration with pack operations works
#[test]
fn test_store_spec_integration() {
// Test different store specifications
let file_spec = StoreSpec::new("file")
.with_option("path", "/tmp/storage")
.with_option("compression", "gzip");
let s3_spec = StoreSpec::new("s3")
.with_option("bucket", "my-bucket")
.with_option("region", "us-east-1")
.with_option("access_key", "test-key");
let custom_spec = StoreSpec::new("custom-backend")
.with_option("endpoint", "https://storage.example.com")
.with_option("auth", "bearer-token");
// Test that all specs serialize correctly
let file_string = file_spec.to_string();
assert!(file_string.starts_with("file:"));
assert!(file_string.contains("path=/tmp/storage"));
assert!(file_string.contains("compression=gzip"));
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"));
assert!(s3_string.contains("access_key=test-key"));
let custom_string = custom_spec.to_string();
assert!(custom_string.starts_with("custom-backend:"));
assert!(custom_string.contains("endpoint=https://storage.example.com"));
assert!(custom_string.contains("auth=bearer-token"));
// Test that specs can be used in collections
let specs = vec![file_spec, s3_spec, custom_spec];
assert_eq!(specs.len(), 3);
for spec in &specs {
assert!(!spec.spec_type.is_empty());
assert!(!spec.to_string().is_empty());
}
}
/// Tests mount type integration across different scenarios
///
/// This test verifies that:
/// - Mount types work with different builders
/// - String conversion is bidirectional
/// - Custom mount types preserve data
/// - Integration with RFS operations works
#[test]
fn test_mount_type_integration() {
let mount_types = vec![
MountType::Local,
MountType::SSH,
MountType::S3,
MountType::WebDAV,
MountType::Custom("fuse-overlay".to_string()),
];
for mount_type in mount_types {
// Test with RFS builder
let builder = RfsBuilder::new("/test/source", "/test/target", mount_type.clone());
// Verify mount type is preserved
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 not preserved: expected {:?}, got {:?}",
mount_type,
builder.mount_type()
),
}
// Test string conversion round-trip
let mount_string = mount_type.to_string();
let parsed_mount = MountType::from_string(&mount_string);
// Verify round-trip conversion
match (&mount_type, &parsed_mount) {
(MountType::Local, MountType::Local) => {}
(MountType::SSH, MountType::SSH) => {}
(MountType::S3, MountType::S3) => {}
(MountType::WebDAV, MountType::WebDAV) => {}
(MountType::Custom(orig), MountType::Custom(parsed)) => {
assert_eq!(orig, parsed);
}
_ => {
// For custom types, from_string might return Custom variant
if let MountType::Custom(_) = mount_type {
assert!(matches!(parsed_mount, MountType::Custom(_)));
} else {
assert!(
false,
"Round-trip conversion failed: {:?} -> {} -> {:?}",
mount_type, mount_string, parsed_mount
);
}
}
}
}
}
/// Tests Rhai integration and function registration
///
/// This test verifies that:
/// - Rhai module registration works correctly
/// - All expected functions are available
/// - Function signatures are correct
/// - No registration conflicts occur
#[test]
fn test_rhai_integration_and_registration() {
use rhai::Engine;
// Create a new Rhai engine
let mut engine = Engine::new();
// Test that we can register virt functions
// Note: We test the registration process, not the actual function execution
let registration_result = sal_virt::rhai::register_virt_module(&mut engine);
assert!(
registration_result.is_ok(),
"Rhai function registration should succeed"
);
// Test that expected function categories are available
let expected_function_prefixes = vec![
"bah_", // Buildah functions
"nerdctl_", // Nerdctl functions
"rfs_", // RFS functions
];
// Test compilation of scripts that reference these functions
for prefix in expected_function_prefixes {
let test_script = format!("fn test_{}() {{ return type_of({}new); }}", prefix, prefix);
// Try to compile the script - this tests function availability
let compile_result = engine.compile(&test_script);
// We expect this to either succeed (function exists) or fail with a specific error
match compile_result {
Ok(_) => {
println!("✓ Function family '{}' is available", prefix);
}
Err(e) => {
// Check if it's a "function not found" error vs other compilation errors
let error_msg = e.to_string();
if error_msg.contains("not found") || error_msg.contains("unknown") {
println!("⚠️ Function family '{}' not found: {}", prefix, error_msg);
} else {
println!("⚠️ Compilation error for '{}': {}", prefix, error_msg);
}
}
}
}
}
/// Tests Rhai script compilation and basic syntax
///
/// This test verifies that:
/// - Basic Rhai scripts compile correctly
/// - Virt module functions can be referenced
/// - No syntax conflicts exist
/// - Error handling works in Rhai context
#[test]
fn test_rhai_script_compilation() {
use rhai::Engine;
let mut engine = Engine::new();
// Register virt functions
let _ = sal_virt::rhai::register_virt_module(&mut engine);
// Test basic script compilation
let basic_scripts = vec![
"let x = 42; x + 1",
"fn test() { return true; } test()",
"let result = \"hello world\"; result.len()",
];
for script in basic_scripts {
let compile_result = engine.compile(script);
assert!(
compile_result.is_ok(),
"Basic script should compile: {}",
script
);
}
// Test scripts that reference virt functions (compilation only)
let virt_scripts = vec![
"fn test_buildah() { return type_of(bah_new); }",
"fn test_nerdctl() { return type_of(nerdctl_run); }",
"fn test_rfs() { return type_of(rfs_mount); }",
];
for script in virt_scripts {
let compile_result = engine.compile(script);
// We don't require these to succeed (functions might not be registered)
// but we test that compilation doesn't crash
match compile_result {
Ok(_) => println!("✓ Virt script compiled successfully: {}", script),
Err(e) => println!(
"⚠️ Virt script compilation failed (expected): {} - {}",
script, e
),
}
}
}