photoncloud-monorepo/plasmavmc/crates/plasmavmc-firecracker/tests/integration.rs
centra a7ec7e2158 Add T026 practical test + k8shost to flake + workspace files
- Created T026-practical-test task.yaml for MVP smoke testing
- Added k8shost-server to flake.nix (packages, apps, overlays)
- Staged all workspace directories for nix flake build
- Updated flake.nix shellHook to include k8shost

Resolves: T026.S1 blocker (R8 - nix submodule visibility)
2025-12-09 06:07:50 +09:00

113 lines
3.6 KiB
Rust

//! 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");
}