tests: Add basic integration testing

Add basic integration testing of the hypervisor using a cloud-init to
configure the VM at boot and SSH to control it at runtime.

Initial test just boots the VM up checks some basic resources and
reboots. With a second test that calls into the first to check that
subsequent tests work correctly.

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
This commit is contained in:
Rob Bradford
2019-05-23 16:45:13 +01:00
parent f63d4a7418
commit ddce3df826
7 changed files with 423 additions and 1 deletions

View File

@@ -116,3 +116,123 @@ fn main() {
process::exit(1);
}
}
#[cfg(test)]
#[cfg(feature = "integration_tests")]
mod tests {
extern crate vmm;
use ssh2::Session;
use std::fs;
use std::io::Read;
use std::net::TcpStream;
use std::thread;
use vmm::config;
fn ssh_command(command: &str) -> String {
let mut s = String::new();
#[derive(Debug)]
enum Error {
Connection,
Authentication,
Command,
};
let mut counter = 0;
loop {
match (|| -> Result<(), Error> {
let tcp = TcpStream::connect("192.168.2.2:22").map_err(|_| Error::Connection)?;
let mut sess = Session::new().unwrap();
sess.handshake(&tcp).map_err(|_| Error::Connection)?;
sess.userauth_password("admin", "cloud123")
.map_err(|_| Error::Authentication)?;
assert!(sess.authenticated());
let mut channel = sess.channel_session().map_err(|_| Error::Command)?;
channel.exec(command).map_err(|_| Error::Command)?;
// Intentionally ignore these results here as their failure
// does not precipitate a repeat
let _ = channel.read_to_string(&mut s);
let _ = channel.close();
let _ = channel.wait_close();
Ok(())
})() {
Ok(_) => break,
Err(e) => {
counter += 1;
if counter >= 6 {
panic!("Took too many attempts to run command. Last error: {:?}", e);
}
}
};
thread::sleep(std::time::Duration::new(10, 0));
}
s
}
fn prepare_files() -> (Vec<&'static str>, String) {
let mut workload_path = dirs::home_dir().unwrap();
workload_path.push("workloads");
let mut fw_path = workload_path.clone();
fw_path.push("hypervisor-fw");
let mut osdisk_base_path = workload_path.clone();
osdisk_base_path.push("clear-29620-cloud.img");
let osdisk_path = "/tmp/osdisk.img";
let cloudinit_path = "/tmp/cloudinit.img";
fs::copy(osdisk_base_path, osdisk_path).expect("copying of OS source disk image failed");
let disks = vec![osdisk_path, cloudinit_path];
(disks, String::from(fw_path.to_str().unwrap()))
}
#[test]
fn test_simple_launch() {
let handler = thread::spawn(|| {
let (disks, fw_path) = prepare_files();
let vm_config = config::VmConfig::parse(config::VmParams {
cpus: "1",
memory: "512",
kernel: fw_path.as_str(),
cmdline: None,
disks,
rng: "/dev/urandom",
net: Some("tap=,mac=,ip=192.168.2.1,mask=255.255.255.0"),
})
.expect("Failed parsing parameters");
vmm::boot_kernel(vm_config).expect("Booting kernel failed");
});
thread::sleep(std::time::Duration::new(10, 0));
assert_eq!(ssh_command("grep -c processor /proc/cpuinfo").trim(), "1");
assert_eq!(
ssh_command("grep MemTotal /proc/meminfo").trim(),
"MemTotal: 496400 kB"
);
assert!(
ssh_command("cat /proc/sys/kernel/random/entropy_avail")
.trim()
.parse::<u32>()
.unwrap()
>= 1000
);
ssh_command("sudo reboot");
handler.join().unwrap();
}
#[test]
fn test_simple_launch_again() {
test_simple_launch()
}
}