#[cfg(test)]
mod tests {
use super::virtio::{VIRTIO_MMIO_BASE, VIRTIO_MMIO_GAP, VIRTIO_MMIO_SIZE};
use super::*;
use crate::memory::PAGE_SIZE;
use crate::traits::VirtualMachine;
use crate::types::CpuArch;
use std::sync::Arc;
#[test]
#[ignore] fn test_vm_creation() {
let kvm = Arc::new(KvmSystem::open().expect("Failed to open KVM"));
let mmap_size = kvm.vcpu_mmap_size().expect("Failed to get mmap size");
let config = VmConfig {
vcpu_count: 2,
memory_size: 128 * 1024 * 1024,
arch: CpuArch::native(),
..Default::default()
};
let vm = KvmVm::new(kvm, mmap_size, config).unwrap();
assert_eq!(vm.state(), VmState::Created);
assert!(!vm.is_running());
}
#[test]
#[ignore] fn test_vcpu_creation() {
let kvm = Arc::new(KvmSystem::open().expect("Failed to open KVM"));
let mmap_size = kvm.vcpu_mmap_size().expect("Failed to get mmap size");
let config = VmConfig {
vcpu_count: 4,
memory_size: 128 * 1024 * 1024,
..Default::default()
};
let mut vm = KvmVm::new(kvm, mmap_size, config).unwrap();
let vcpu0 = vm.create_vcpu(0);
assert!(vcpu0.is_ok());
assert_eq!(vcpu0.unwrap().id(), 0);
let vcpu1 = vm.create_vcpu(1);
assert!(vcpu1.is_ok());
let vcpu0_again = vm.create_vcpu(0);
assert!(vcpu0_again.is_err());
let vcpu99 = vm.create_vcpu(99);
assert!(vcpu99.is_err());
}
#[test]
#[ignore] fn test_vm_lifecycle() {
let kvm = Arc::new(KvmSystem::open().expect("Failed to open KVM"));
let mmap_size = kvm.vcpu_mmap_size().expect("Failed to get mmap size");
let config = VmConfig {
vcpu_count: 1,
memory_size: 64 * 1024 * 1024,
..Default::default()
};
let mut vm = KvmVm::new(kvm, mmap_size, config).unwrap();
assert_eq!(vm.state(), VmState::Created);
vm.start().unwrap();
assert_eq!(vm.state(), VmState::Running);
assert!(vm.is_running());
vm.pause().unwrap();
assert_eq!(vm.state(), VmState::Paused);
vm.resume().unwrap();
assert_eq!(vm.state(), VmState::Running);
vm.stop().unwrap();
assert_eq!(vm.state(), VmState::Stopped);
assert!(!vm.is_running());
}
#[test]
#[ignore] fn test_add_virtio_device() {
let kvm = Arc::new(KvmSystem::open().expect("Failed to open KVM"));
let mmap_size = kvm.vcpu_mmap_size().expect("Failed to get mmap size");
let config = VmConfig {
vcpu_count: 1,
memory_size: 64 * 1024 * 1024,
..Default::default()
};
let mut vm = KvmVm::new(kvm, mmap_size, config).unwrap();
assert_eq!(vm.state(), VmState::Created);
let blk_config = VirtioDeviceConfig::block("/dev/null", true);
vm.add_virtio_device(blk_config).unwrap();
let devices = vm.virtio_devices().unwrap();
assert_eq!(devices.len(), 1);
assert_eq!(devices[0].device_type, VirtioDeviceType::Block);
assert_eq!(devices[0].mmio_base, VIRTIO_MMIO_BASE);
assert_eq!(devices[0].mmio_size, VIRTIO_MMIO_SIZE);
assert!(devices[0].irq_fd >= 0);
assert!(devices[0].notify_fd >= 0);
let net_config = VirtioDeviceConfig::net();
vm.add_virtio_device(net_config).unwrap();
let devices = vm.virtio_devices().unwrap();
assert_eq!(devices.len(), 2);
assert_eq!(devices[1].device_type, VirtioDeviceType::Net);
assert_eq!(
devices[1].mmio_base,
VIRTIO_MMIO_BASE + VIRTIO_MMIO_SIZE + VIRTIO_MMIO_GAP
);
vm.start().unwrap();
let fs_config = VirtioDeviceConfig::filesystem("/share", "share");
let result = vm.add_virtio_device(fs_config);
assert!(result.is_err());
}
#[test]
fn test_parse_dirty_bitmap_empty() {
let bitmap: Vec<u64> = vec![0; 4];
let pages = KvmVm::parse_dirty_bitmap(&bitmap, 0, 1024 * 1024);
assert!(pages.is_empty());
}
#[test]
fn test_parse_dirty_bitmap_all_dirty() {
let bitmap: Vec<u64> = vec![u64::MAX];
let pages = KvmVm::parse_dirty_bitmap(&bitmap, 0, 64 * PAGE_SIZE);
assert_eq!(pages.len(), 64);
assert_eq!(pages[0].guest_addr, 0);
assert_eq!(pages[0].size, PAGE_SIZE);
assert_eq!(pages[63].guest_addr, 63 * PAGE_SIZE);
}
#[test]
fn test_parse_dirty_bitmap_sparse() {
let mut bitmap: Vec<u64> = vec![0; 2];
bitmap[0] = 1 | (1 << 63); bitmap[1] = 1 | (1 << 63);
let pages = KvmVm::parse_dirty_bitmap(&bitmap, 0x1000_0000, 128 * PAGE_SIZE);
assert_eq!(pages.len(), 4);
assert_eq!(pages[0].guest_addr, 0x1000_0000);
assert_eq!(pages[1].guest_addr, 0x1000_0000 + 63 * PAGE_SIZE);
assert_eq!(pages[2].guest_addr, 0x1000_0000 + 64 * PAGE_SIZE);
assert_eq!(pages[3].guest_addr, 0x1000_0000 + 127 * PAGE_SIZE);
}
#[test]
#[ignore] fn test_dirty_tracking_enable_disable() {
let kvm = Arc::new(KvmSystem::open().expect("Failed to open KVM"));
let mmap_size = kvm.vcpu_mmap_size().expect("Failed to get mmap size");
let config = VmConfig {
vcpu_count: 1,
memory_size: 16 * 1024 * 1024, ..Default::default()
};
let vm = KvmVm::new(kvm, mmap_size, config).unwrap();
assert!(!vm.is_dirty_tracking_enabled());
assert!(vm.get_dirty_pages().is_err());
vm.enable_dirty_tracking().unwrap();
assert!(vm.is_dirty_tracking_enabled());
vm.enable_dirty_tracking().unwrap();
assert!(vm.is_dirty_tracking_enabled());
let pages = vm.get_dirty_pages().unwrap();
println!("Initial dirty pages: {}", pages.len());
vm.disable_dirty_tracking().unwrap();
assert!(!vm.is_dirty_tracking_enabled());
assert!(vm.get_dirty_pages().is_err());
}
}