//! Integration tests for FireCracker backend //! //! These tests require: //! - FireCracker binary at /usr/bin/firecracker (or PLASMAVMC_FIRECRACKER_PATH) //! - Kernel image (PLASMAVMC_FIRECRACKER_KERNEL_PATH) //! - Rootfs image (PLASMAVMC_FIRECRACKER_ROOTFS_PATH) //! //! Set PLASMAVMC_FIRECRACKER_TEST=1 to enable these tests. use plasmavmc_firecracker::FireCrackerBackend; use plasmavmc_hypervisor::HypervisorBackend; use plasmavmc_types::{VmSpec, VirtualMachine, VmState}; use std::path::Path; use std::time::Duration; use tokio::time::sleep; #[tokio::test] #[ignore] async fn integration_firecracker_lifecycle() { // Check if test is enabled if std::env::var("PLASMAVMC_FIRECRACKER_TEST").is_err() { eprintln!("Skipping integration test: PLASMAVMC_FIRECRACKER_TEST not set"); return; } // Check for required environment variables let kernel_path = match std::env::var("PLASMAVMC_FIRECRACKER_KERNEL_PATH") { Ok(path) => path, Err(_) => { eprintln!("Skipping integration test: PLASMAVMC_FIRECRACKER_KERNEL_PATH not set"); return; } }; let rootfs_path = match std::env::var("PLASMAVMC_FIRECRACKER_ROOTFS_PATH") { Ok(path) => path, Err(_) => { eprintln!("Skipping integration test: PLASMAVMC_FIRECRACKER_ROOTFS_PATH not set"); return; } }; // Verify paths exist if !Path::new(&kernel_path).exists() { eprintln!("Skipping integration test: kernel path does not exist: {}", kernel_path); return; } if !Path::new(&rootfs_path).exists() { eprintln!("Skipping integration test: rootfs path does not exist: {}", rootfs_path); return; } // Check for FireCracker binary let firecracker_path = std::env::var("PLASMAVMC_FIRECRACKER_PATH") .unwrap_or_else(|_| "/usr/bin/firecracker".to_string()); if !Path::new(&firecracker_path).exists() { eprintln!("Skipping integration test: FireCracker binary not found: {}", firecracker_path); return; } // Create backend let backend = match FireCrackerBackend::from_env() { Ok(backend) => backend, Err(e) => { eprintln!("Skipping integration test: Failed to create backend: {}", e); return; } }; // Create VM spec let mut spec = VmSpec::default(); spec.cpu.vcpus = 1; spec.memory.size_mib = 128; // Create VM let vm = VirtualMachine::new("test-vm", "org1", "proj1", spec); let handle = backend.create(&vm).await.expect("create VM"); // Start VM backend.start(&handle).await.expect("start VM"); // Wait a bit for VM to boot (FireCracker boots very fast, < 125ms) sleep(Duration::from_millis(500)).await; // Check status - FireCracker should be running after start let status = backend.status(&handle).await.expect("get status"); assert!( matches!(status.actual_state, VmState::Running | VmState::Starting), "VM should be running or starting, got: {:?}", status.actual_state ); eprintln!("VM started successfully, state: {:?}", status.actual_state); // Stop VM backend.stop(&handle, Duration::from_secs(5)) .await .expect("stop VM"); // Verify stopped let status = backend.status(&handle).await.expect("get status after stop"); assert!( matches!(status.actual_state, VmState::Stopped | VmState::Failed), "VM should be stopped, got: {:?}", status.actual_state ); // Delete VM backend.delete(&handle).await.expect("delete VM"); eprintln!("Integration test completed successfully"); }