mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 11:25:20 +00:00
tests: Add test for Windows guest multiple disk hotplug
Additionally, he disk creation routine is extended to support NTFS and variable image size. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
parent
a36ac96444
commit
dc15e44e2a
@ -5313,11 +5313,24 @@ mod tests {
|
||||
mod windows {
|
||||
use crate::tests::*;
|
||||
|
||||
lazy_static! {
|
||||
static ref NEXT_DISK_ID: Mutex<u8> = Mutex::new(1);
|
||||
}
|
||||
|
||||
struct WindowsGuest {
|
||||
guest: Guest,
|
||||
auth: PasswordAuth,
|
||||
}
|
||||
|
||||
trait FsType {
|
||||
const FS_FAT: u8;
|
||||
const FS_NTFS: u8;
|
||||
}
|
||||
impl FsType for WindowsGuest {
|
||||
const FS_FAT: u8 = 0;
|
||||
const FS_NTFS: u8 = 1;
|
||||
}
|
||||
|
||||
impl WindowsGuest {
|
||||
fn new() -> Self {
|
||||
let disk = WindowsDiskConfig::new(WINDOWS_IMAGE_NAME.to_string());
|
||||
@ -5405,20 +5418,24 @@ mod tests {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// XXX Follow up test involving multiple disks will require:
|
||||
// - Make image size variable
|
||||
// - Make image filename random
|
||||
// - Cleanup image file after test
|
||||
// - NTFS should be added for use along with FAT for better coverage, needs mkfs.ntfs in the container.
|
||||
fn disk_new(&self) -> String {
|
||||
let img = PathBuf::from(
|
||||
String::from_utf8_lossy(b"/tmp/test-fat-hotplug-0.raw").to_string(),
|
||||
);
|
||||
// TODO Cleanup image file explicitly after test, if there's some space issues.
|
||||
fn disk_new(&self, fs: u8, sz: usize) -> String {
|
||||
let mut guard = NEXT_DISK_ID.lock().unwrap();
|
||||
let id = *guard;
|
||||
*guard = id + 1;
|
||||
|
||||
let img = PathBuf::from(format!("/tmp/test-hotplug-{}.raw", id));
|
||||
let _ = fs::remove_file(&img);
|
||||
|
||||
// Create an image file
|
||||
let out = Command::new("qemu-img")
|
||||
.args(&["create", "-f", "raw", &img.to_str().unwrap(), "100m"])
|
||||
.args(&[
|
||||
"create",
|
||||
"-f",
|
||||
"raw",
|
||||
&img.to_str().unwrap(),
|
||||
format!("{}m", sz).as_str(),
|
||||
])
|
||||
.output()
|
||||
.expect("qemu-img command failed")
|
||||
.stdout;
|
||||
@ -5472,13 +5489,16 @@ mod tests {
|
||||
let loop_dev = _tmp.trim();
|
||||
println!("{:?}", out);
|
||||
|
||||
// Create msdos filesystem.
|
||||
// XXX mkfs.ntfs is missing in the docker image and should be added
|
||||
// For mkfs.ntfs also add -f.
|
||||
let out = Command::new("mkfs.msdos")
|
||||
// Create filesystem.
|
||||
let fs_cmd = match fs {
|
||||
WindowsGuest::FS_FAT => "mkfs.msdos",
|
||||
WindowsGuest::FS_NTFS => "mkfs.ntfs",
|
||||
_ => panic!("Unknown filesystem type '{}'", fs),
|
||||
};
|
||||
let out = Command::new(fs_cmd)
|
||||
.args(&[&loop_dev])
|
||||
.output()
|
||||
.expect("mkfs.msdos failed")
|
||||
.unwrap_or_else(|_| panic!("{} failed", fs_cmd))
|
||||
.stdout;
|
||||
println!("{:?}", out);
|
||||
|
||||
@ -5486,7 +5506,7 @@ mod tests {
|
||||
let out = Command::new("losetup")
|
||||
.args(&["-d", &loop_dev])
|
||||
.output()
|
||||
.expect("loop device not found")
|
||||
.unwrap_or_else(|_| panic!("loop device '{}' not found", loop_dev))
|
||||
.stdout;
|
||||
println!("{:?}", out);
|
||||
|
||||
@ -6031,7 +6051,7 @@ mod tests {
|
||||
|
||||
let mut child_dnsmasq = windows_guest.run_dnsmasq();
|
||||
|
||||
let disk = windows_guest.disk_new();
|
||||
let disk = windows_guest.disk_new(WindowsGuest::FS_FAT, 100);
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Wait to make sure Windows boots up
|
||||
@ -6097,6 +6117,135 @@ mod tests {
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "mshv"))]
|
||||
fn test_windows_guest_disk_hotplug_multi() {
|
||||
let windows_guest = WindowsGuest::new();
|
||||
|
||||
let mut ovmf_path = dirs::home_dir().unwrap();
|
||||
ovmf_path.push("workloads");
|
||||
ovmf_path.push(OVMF_NAME);
|
||||
|
||||
let tmp_dir = TempDir::new_with_prefix("/tmp/ch").unwrap();
|
||||
let api_socket = temp_api_path(&tmp_dir);
|
||||
|
||||
let mut child = GuestCommand::new(windows_guest.guest())
|
||||
.args(&["--api-socket", &api_socket])
|
||||
.args(&["--cpus", "boot=2,kvm_hyperv=on"])
|
||||
.args(&["--memory", "size=2G"])
|
||||
.args(&["--kernel", ovmf_path.to_str().unwrap()])
|
||||
.args(&["--serial", "tty"])
|
||||
.args(&["--console", "off"])
|
||||
.default_disks()
|
||||
.default_net()
|
||||
.capture_output()
|
||||
.spawn()
|
||||
.unwrap();
|
||||
|
||||
let mut child_dnsmasq = windows_guest.run_dnsmasq();
|
||||
|
||||
// Predefined data to used at various test stages
|
||||
let disk_test_data: [[String; 4]; 2] = [
|
||||
[
|
||||
"_disk2".to_string(),
|
||||
windows_guest.disk_new(WindowsGuest::FS_FAT, 123),
|
||||
"d:\\world".to_string(),
|
||||
"hello".to_string(),
|
||||
],
|
||||
[
|
||||
"_disk3".to_string(),
|
||||
windows_guest.disk_new(WindowsGuest::FS_NTFS, 333),
|
||||
"e:\\hello".to_string(),
|
||||
"world".to_string(),
|
||||
],
|
||||
];
|
||||
|
||||
let r = std::panic::catch_unwind(|| {
|
||||
// Wait to make sure Windows boots up
|
||||
assert!(windows_guest.wait_for_boot());
|
||||
|
||||
// Initially present disk device
|
||||
let disk_num = 1;
|
||||
assert_eq!(windows_guest.disk_count(), disk_num);
|
||||
assert_eq!(disk_ctrl_threads_count(child.id()), disk_num);
|
||||
|
||||
for it in &disk_test_data {
|
||||
let disk_id = it[0].as_str();
|
||||
let disk = it[1].as_str();
|
||||
// Hotplug disk device
|
||||
let (cmd_success, cmd_output) = remote_command_w_output(
|
||||
&api_socket,
|
||||
"add-disk",
|
||||
Some(format!("path={},readonly=off", disk).as_str()),
|
||||
);
|
||||
assert!(cmd_success);
|
||||
assert!(String::from_utf8_lossy(&cmd_output)
|
||||
.contains(format!("\"id\":\"{}\"", disk_id).as_str()));
|
||||
thread::sleep(std::time::Duration::new(5, 0));
|
||||
// Online disk devices
|
||||
windows_guest.disks_set_rw();
|
||||
windows_guest.disks_online();
|
||||
}
|
||||
// Verify the devices are on the system
|
||||
let disk_num = (disk_test_data.len() + 1) as u8;
|
||||
assert_eq!(windows_guest.disk_count(), disk_num);
|
||||
assert_eq!(disk_ctrl_threads_count(child.id()), disk_num);
|
||||
|
||||
// Put test data
|
||||
for it in &disk_test_data {
|
||||
let fname = it[2].as_str();
|
||||
let data = it[3].as_str();
|
||||
windows_guest.disk_file_put(fname, data);
|
||||
}
|
||||
|
||||
// Unmount disk devices
|
||||
for it in &disk_test_data {
|
||||
let disk_id = it[0].as_str();
|
||||
let cmd_success = remote_command(&api_socket, "remove-device", Some(disk_id));
|
||||
assert!(cmd_success);
|
||||
thread::sleep(std::time::Duration::new(5, 0));
|
||||
}
|
||||
|
||||
// Verify the devices have been removed
|
||||
let disk_num = 1;
|
||||
assert_eq!(windows_guest.disk_count(), disk_num);
|
||||
assert_eq!(disk_ctrl_threads_count(child.id()), disk_num);
|
||||
|
||||
// Remount
|
||||
for it in &disk_test_data {
|
||||
let disk = it[1].as_str();
|
||||
let (cmd_success, _cmd_output) = remote_command_w_output(
|
||||
&api_socket,
|
||||
"add-disk",
|
||||
Some(format!("path={},readonly=off", disk).as_str()),
|
||||
);
|
||||
assert!(cmd_success);
|
||||
thread::sleep(std::time::Duration::new(5, 0));
|
||||
}
|
||||
|
||||
// Check the files exists with the expected contents
|
||||
for it in &disk_test_data {
|
||||
let fname = it[2].as_str();
|
||||
let data = it[3].as_str();
|
||||
let out = windows_guest.disk_file_read(fname);
|
||||
assert_eq!(data, out.trim());
|
||||
}
|
||||
|
||||
// Intentionally no unmount, it'll happen at shutdown.
|
||||
|
||||
windows_guest.shutdown();
|
||||
});
|
||||
|
||||
let _ = child.wait_timeout(std::time::Duration::from_secs(60));
|
||||
let _ = child.kill();
|
||||
let output = child.wait_with_output().unwrap();
|
||||
|
||||
let _ = child_dnsmasq.kill();
|
||||
let _ = child_dnsmasq.wait();
|
||||
|
||||
handle_child_output(r, &output);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
Loading…
Reference in New Issue
Block a user