unplugged-system/external/crosvm/e2e_tests/tests/suspend_resume.rs

87 lines
3.0 KiB
Rust

// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use fixture::vm::Config;
use fixture::vm::TestVm;
use tempfile::tempdir;
// Tests for suspend/resume.
//
// System-wide suspend/resume, snapshot/restore.
// Tests below check for snapshot/restore functionality, and suspend/resume.
#[ignore]
#[test]
fn suspend_snapshot_restore_resume() -> anyhow::Result<()> {
let mut vm = TestVm::new(Config::new()).unwrap();
suspend_resume_system(&mut vm)
}
#[ignore]
#[test]
fn suspend_snapshot_restore_resume_disable_sandbox() -> anyhow::Result<()> {
let mut vm = TestVm::new(Config::new().disable_sandbox()).unwrap();
suspend_resume_system(&mut vm)
}
fn suspend_resume_system(vm: &mut TestVm) -> anyhow::Result<()> {
// WARNING: Suspend/resume is only partially implemented, some aspects of these tests only work
// by chance. Still, the tests are useful to avoid backslide. If a seemingly unrelated change
// breaks this test, it is probably reasonable to disable the test.
// Verify RAM is saved and restored by interacting with a filesystem pinned in RAM (i.e. tmpfs
// with swap disabled).
vm.exec_in_guest("swapoff -a").unwrap();
vm.exec_in_guest("mount -t tmpfs none /tmp").unwrap();
vm.exec_in_guest("echo foo > /tmp/foo").unwrap();
assert_eq!("foo", vm.exec_in_guest("cat /tmp/foo").unwrap().trim());
// Take snapshot of original VM state
println!("snapshotting VM - clean state");
let dir = tempdir().unwrap();
let snap1_path = dir.path().join("snapshot.bkp");
vm.snapshot(&snap1_path).unwrap();
vm.exec_in_guest("echo bar > /tmp/foo").unwrap();
assert_eq!("bar", vm.exec_in_guest("cat /tmp/foo").unwrap().trim());
// suspend VM
vm.suspend().unwrap();
let snap2_path = dir.path().join("snapshot2.bkp");
// Write command to VM
// This command will get queued and not run while the VM is suspended. The command is saved in
// the serial device. After the snapshot is taken, the VM is resumed. At that point, the
// command runs and is validated.
let echo_cmd = vm.exec_in_guest_async("echo 42").unwrap();
// Take snapshot of modified VM
println!("snapshotting VM - mod state");
vm.snapshot(&snap2_path).unwrap();
vm.resume().unwrap();
assert_eq!("42", echo_cmd.wait(vm).unwrap());
// suspend VM
vm.suspend().unwrap();
// restore VM
println!("restoring VM - to clean state");
vm.restore(&snap1_path).unwrap();
// snapshot VM after restore
println!("snapshotting VM - clean state restored");
let snap3_path = dir.path().join("snapshot3.bkp");
vm.snapshot(&snap3_path).unwrap();
vm.resume().unwrap();
assert_eq!("foo", vm.exec_in_guest("cat /tmp/foo").unwrap().trim());
let snap1 = std::fs::read_to_string(&snap1_path).unwrap();
let snap2 = std::fs::read_to_string(&snap2_path).unwrap();
let snap3 = std::fs::read_to_string(&snap3_path).unwrap();
assert_ne!(snap1, snap2);
assert_eq!(snap1, snap3);
Ok(())
}