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