use std::path::PathBuf;
use std::time::Duration;
#[cfg(target_os = "macos")]
use arcbox_hypervisor::{
config::VmConfig,
darwin::{DarwinHypervisor, is_supported},
traits::{Hypervisor, VirtualMachine},
types::CpuArch,
};
fn test_resources_dir() -> PathBuf {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
PathBuf::from(manifest_dir)
.parent()
.unwrap()
.parent()
.unwrap()
.join("tests")
.join("resources")
}
fn kernel_available() -> bool {
let kernel_path = test_resources_dir().join("vmlinuz-arm64");
kernel_path.exists()
}
#[cfg(target_os = "macos")]
#[test]
fn test_vm_boot_with_kernel() {
if !is_supported() {
println!("Virtualization not supported, skipping");
return;
}
if !kernel_available() {
println!("Test kernel not found. Run: tests/resources/download-kernel.sh");
println!("Skipping VM boot test.");
return;
}
let _ = tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.with_test_writer()
.try_init();
let kernel_path = test_resources_dir().join("vmlinuz-arm64");
let initrd_path = test_resources_dir().join("initramfs-arm64");
println!("Using kernel: {:?}", kernel_path);
println!("Using initrd: {:?}", initrd_path);
let hypervisor = DarwinHypervisor::new().expect("Failed to create hypervisor");
let caps = hypervisor.capabilities();
println!("Hypervisor capabilities:");
println!(" Max vCPUs: {}", caps.max_vcpus);
println!(
" Max memory: {} GB",
caps.max_memory / (1024 * 1024 * 1024)
);
println!(" Rosetta: {}", caps.rosetta);
let mut config = VmConfig {
vcpu_count: 2,
memory_size: 512 * 1024 * 1024, arch: CpuArch::native(),
kernel_path: Some(kernel_path.to_string_lossy().to_string()),
kernel_cmdline: Some(
"console=hvc0 earlycon=pl011,0x09000000 root=/dev/ram0 rdinit=/bin/sh".to_string(),
),
..Default::default()
};
if initrd_path.exists() {
config.initrd_path = Some(initrd_path.to_string_lossy().to_string());
}
let mut vm = hypervisor.create_vm(config).expect("Failed to create VM");
println!("VM created successfully");
println!("VM ID: {}", vm.id());
println!("Skipping serial console setup (PTY handling issues)");
println!("Starting VM...");
let start_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| vm.start()));
match start_result {
Ok(Ok(())) => {
println!("VM started successfully!");
println!("Letting VM run for 3 seconds...");
std::thread::sleep(Duration::from_secs(3));
println!("VM state: {:?}", vm.state());
println!("VM running: {}", vm.is_running());
println!("Stopping VM...");
match vm.stop() {
Ok(()) => println!("VM stopped successfully"),
Err(e) => println!("Warning: Error stopping VM: {}", e),
}
}
Ok(Err(e)) => {
println!("Failed to start VM: {}", e);
println!(
"Note: This may fail if the kernel format is not compatible with Virtualization.framework"
);
println!("Virtualization.framework requires uncompressed ARM64 Image format");
}
Err(panic) => {
println!("VM start panicked: {:?}", panic);
}
}
println!("VM boot test completed");
}
#[cfg(target_os = "macos")]
#[test]
fn test_vm_lifecycle_without_kernel() {
if !is_supported() {
println!("Virtualization not supported, skipping");
return;
}
let hypervisor = DarwinHypervisor::new().expect("Failed to create hypervisor");
let config = VmConfig {
vcpu_count: 1,
memory_size: 256 * 1024 * 1024, arch: CpuArch::native(),
..Default::default()
};
let vm = hypervisor.create_vm(config).expect("Failed to create VM");
println!("VM created: ID={}", vm.id());
println!("Initial state: {:?}", vm.state());
assert!(!vm.is_running());
drop(vm);
println!("VM lifecycle test (no kernel) passed");
}
#[cfg(target_os = "macos")]
#[test]
fn test_virtio_device_configuration() {
use arcbox_hypervisor::types::VirtioDeviceConfig;
if !is_supported() {
println!("Virtualization not supported, skipping");
return;
}
let hypervisor = DarwinHypervisor::new().expect("Failed to create hypervisor");
let config = VmConfig {
vcpu_count: 1,
memory_size: 256 * 1024 * 1024,
arch: CpuArch::native(),
..Default::default()
};
let mut vm = hypervisor.create_vm(config).expect("Failed to create VM");
let net_config = VirtioDeviceConfig::network();
let result = vm.add_virtio_device(net_config);
println!("Add network device: {:?}", result);
let vsock_config = VirtioDeviceConfig::vsock();
let result = vm.add_virtio_device(vsock_config);
println!("Add vsock device: {:?}", result);
let rng_config = VirtioDeviceConfig::entropy();
let result = vm.add_virtio_device(rng_config);
println!("Add entropy device: {:?}", result);
println!("VirtIO device configuration test passed");
}