use std::time::Duration;
use fixture::vm::Config;
use fixture::vm::TestVm;
#[test]
fn boot_test_vm() -> anyhow::Result<()> {
let mut vm = TestVm::new(Config::new()).unwrap();
assert_eq!(vm.exec_in_guest("echo 42")?.stdout.trim(), "42");
Ok(())
}
#[test]
fn boot_custom_vm_kernel_initrd() -> anyhow::Result<()> {
let cfg = Config::new()
.with_kernel("https://storage.googleapis.com/crosvm/integration_tests/benchmarks/custom-guest-bzimage-x86_64-r0001")
.with_initrd("https://storage.googleapis.com/crosvm/integration_tests/benchmarks/custom-initramfs.cpio.gz-r0005")
.with_rootfs("https://storage.googleapis.com/crosvm/integration_tests/guest-bzimage-aarch64-r0007")
.with_stdout_hardware("serial").extra_args(vec!["--mem".to_owned(), "512".to_owned()]);
let mut vm = TestVm::new(cfg).unwrap();
assert_eq!(
vm.exec_in_guest_async("echo 42")?
.with_timeout(Duration::from_secs(500))
.wait_ok(&mut vm)?
.stdout
.trim(),
"42"
);
Ok(())
}
#[test]
fn boot_test_vm_uring() -> anyhow::Result<()> {
let mut vm = TestVm::new(
Config::new().extra_args(vec!["--async-executor".to_string(), "uring".to_string()]),
)
.unwrap();
assert_eq!(vm.exec_in_guest("echo 42")?.stdout.trim(), "42");
Ok(())
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn boot_test_vm_odirect() {
let mut vm = TestVm::new(Config::new().o_direct()).unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn vcpu_suspend_resume_succeeds() {
let mut vm = TestVm::new(Config::new()).unwrap();
vm.suspend().unwrap();
vm.resume().unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn vcpu_suspend_resume_succeeds_with_pvclock() {
let mut config = Config::new();
config = config.extra_args(vec!["--pvclock".to_string()]);
let mut vm = TestVm::new(config).unwrap();
vm.suspend().unwrap();
vm.resume().unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn full_suspend_resume_test_suspend_resume_full() {
let mut config = Config::new();
config = config.extra_args(vec![
"--no-usb".to_string(),
"--no-balloon".to_string(),
"--no-rng".to_string(),
]);
let mut vm = TestVm::new(config).unwrap();
vm.suspend_full().unwrap();
vm.resume_full().unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn full_suspend_resume_with_pvclock() {
let mut config = Config::new();
config = config.extra_args(vec![
"--no-usb".to_string(),
"--no-balloon".to_string(),
"--no-rng".to_string(),
"--pvclock".to_string(),
]);
let mut vm = TestVm::new(config).unwrap();
vm.suspend_full().unwrap();
vm.resume_full().unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn vcpu_suspend_resume_with_pvclock_adjusts_guest_clocks() {
use readclock::ClockValues;
const SUSPEND_DURATION: Duration = Duration::from_secs(2);
const ALLOWANCE: Duration = Duration::from_secs(1);
let mut config = Config::new();
config = config.extra_args(vec![
"--no-usb".to_string(),
"--no-balloon".to_string(),
"--no-rng".to_string(),
"--pvclock".to_string(),
]);
let mut vm = TestVm::new(config).unwrap();
vm.exec_in_guest("mount proc /proc -t proc").unwrap();
assert_eq!(
vm.exec_in_guest("cat /proc/config.gz | gunzip | grep '^CONFIG_VIRTIO_PVCLOCK'")
.unwrap()
.stdout
.trim(),
"CONFIG_VIRTIO_PVCLOCK=y"
);
let guest_clocks_before = vm.guest_clock_values().unwrap();
let host_clocks_before = ClockValues::now();
vm.suspend().unwrap();
println!("Sleeping {SUSPEND_DURATION:?}...");
std::thread::sleep(SUSPEND_DURATION);
vm.resume().unwrap();
std::thread::sleep(SUSPEND_DURATION);
let guest_clocks_after = vm.guest_clock_values().unwrap();
let host_clocks_after = ClockValues::now();
let guest_mono_diff = guest_clocks_after.clock_monotonic().as_secs_f64()
- guest_clocks_before.clock_monotonic().as_secs_f64();
let guest_boot_diff = guest_clocks_after.clock_boottime().as_secs_f64()
- guest_clocks_before.clock_boottime().as_secs_f64();
let host_boot_diff = host_clocks_after.clock_boottime().as_secs_f64()
- host_clocks_before.clock_boottime().as_secs_f64();
assert!(host_boot_diff > SUSPEND_DURATION.as_secs_f64());
let monotonic_error = guest_mono_diff + SUSPEND_DURATION.as_secs_f64() - host_boot_diff;
assert!(monotonic_error < ALLOWANCE.as_secs_f64());
let guest_suspend_duration = guest_boot_diff - guest_mono_diff;
let boottime_error = (guest_suspend_duration - SUSPEND_DURATION.as_secs_f64()).abs();
assert!(boottime_error < ALLOWANCE.as_secs_f64());
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn boot_test_vm_disable_sandbox() {
let mut vm = TestVm::new(Config::new().disable_sandbox()).unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn boot_test_vm_disable_sandbox_odirect() {
let mut vm = TestVm::new(Config::new().disable_sandbox().o_direct()).unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}
#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
fn boot_test_disable_sandbox_suspend_resume() {
let mut vm = TestVm::new(Config::new().disable_sandbox()).unwrap();
vm.suspend().unwrap();
vm.resume().unwrap();
assert_eq!(vm.exec_in_guest("echo 42").unwrap().stdout.trim(), "42");
}