/// 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> = 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 ), } } }