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
338 lines
12 KiB
Rust
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
|
|
),
|
|
}
|
|
}
|
|
}
|