Skip to content

Commit a809d41

Browse files
vagrantarnabcs17b006
authored andcommitted
unit tests added
1 parent dfaac82 commit a809d41

File tree

2 files changed

+202
-21
lines changed

2 files changed

+202
-21
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ libc = { version = "0.2.58", optional = true }
3131
xenctrl = { git = "https://github.com/Wenzel/xenctrl", optional = true }
3232
xenstore = { git = "https://github.com/Wenzel/xenstore", optional = true }
3333
xenforeignmemory = { git = "https://github.com/Wenzel/xenforeignmemory", optional = true }
34-
kvmi = { version = "0.2.1", optional = true }
3534
fdp = { git = "https://github.com/Wenzel/fdp", optional = true }
35+
kvmi = { version = "0.2.1", optional = true }
3636
winapi = { version = "0.3.8", features = ["tlhelp32", "winnt", "handleapi", "securitybaseapi"], optional = true }
3737
widestring = { version = "0.4.0", optional = true }
3838
ntapi = { version = "0.3.3", optional = true }

src/driver/kvm.rs

Lines changed: 201 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ impl<T: KVMIntrospectable> Drop for Kvm<T> {
377377
}
378378
}
379379

380-
#[cfg(test)]
380+
/*#[cfg(test)]
381381
mod tests {
382382
use super::*;
383383
use kvmi::{kvm_regs, kvm_sregs, KvmMsrs};
@@ -386,31 +386,62 @@ mod tests {
386386
use std::fmt::{Debug, Formatter};
387387
use test_case::test_case;
388388
389-
#[test]
390-
fn test_fail_to_create_kvm_driver_if_kvmi_init_returns_error() {
391-
let mut kvmi_mock = MockKVMi::default();
392-
kvmi_mock.expect_init().returning(|_| {
393-
Err(std::io::Error::new(
394-
std::io::ErrorKind::Other,
395-
"something went wrong",
396-
))
397-
});
398389
399-
let result = Kvm::new(
400-
"some_vm",
401-
kvmi_mock,
402-
Some(DriverInitParam::KVMiSocket("/tmp/introspector".to_string())),
403-
);
404390
405-
assert!(result.is_err(), "Expected error, got ok instead!");
406-
}
391+
392+
407393
408394
#[test_case(1; "single vcpu")]
409395
#[test_case(2; "two vcpus")]
410396
#[test_case(16; "sixteen vcpus")]
411-
fn test_create_kvm_driver_if_guest_domain_is_valid(vcpu_count: u32) {
412-
let mut kvmi_mock = MockKVMi::default();
413-
kvmi_mock.expect_init().returning(|_| Ok(()));
397+
398+
399+
#[test_case(1; "single vcpu")]
400+
#[test_case(2; "two vcpus")]
401+
#[test_case(16; "sixteen vcpus")]
402+
403+
404+
mock! {
405+
KVMi{}
406+
trait Debug {
407+
fn fmt<'a>(&self, f: &mut Formatter<'a>) -> std::fmt::Result;
408+
}
409+
trait KVMIntrospectable: Debug {
410+
fn init(&mut self, socket_path: &str) -> Result<(), std::io::Error>;
411+
fn control_events(
412+
&self,
413+
vcpu: u16,
414+
intercept_type: KVMiInterceptType,
415+
enabled: bool,
416+
) -> Result<(), std::io::Error>;
417+
fn control_cr(&self, vcpu: u16, reg: KVMiCr, enabled: bool) -> Result<(), std::io::Error>;
418+
fn control_msr(&self, vcpu: u16, reg: u32, enabled: bool) -> Result<(), std::io::Error>;
419+
fn read_physical(&self, gpa: u64, buffer: &mut [u8]) -> Result<(), std::io::Error>;
420+
fn write_physical(&self, gpa: u64, buffer: &[u8]) -> Result<(), std::io::Error>;
421+
fn get_page_access(&self, gpa: u64) -> Result<KVMiPageAccess, std::io::Error>;
422+
fn set_page_access(&self, gpa: u64, access: KVMiPageAccess) -> Result<(), std::io::Error>;
423+
fn pause(&self) -> Result<(), std::io::Error>;
424+
fn get_vcpu_count(&self) -> Result<u32, std::io::Error>;
425+
fn get_registers(&self, vcpu: u16) -> Result<(kvm_regs, kvm_sregs, KvmMsrs), std::io::Error>;
426+
fn set_registers(&self, vcpu: u16, regs: &kvm_regs) -> Result<(), std::io::Error>;
427+
fn wait_and_pop_event(&self, ms: i32) -> Result<Option<KVMiEvent>, std::io::Error>;
428+
fn reply(&self, event: &KVMiEvent, reply_type: KVMiEventReply) -> Result<(), std::io::Error>;
429+
fn get_maximum_gfn(&self) -> Result<u64, std::io::Error>;
430+
}
431+
}
432+
}*/
433+
434+
#[cfg(test)]
435+
mod tests {
436+
use super::*;
437+
use kvmi::{kvm_regs, kvm_sregs, KvmMsrs};
438+
use mockall::mock;
439+
use mockall::predicate::{eq, function};
440+
use std::fmt::{Debug, Formatter};
441+
use test_case::test_case;
442+
443+
fn setup_mock(kvmi_mock: &mut MockKVMi, vcpu_count: u32) {
444+
kvmi_mock.expect_init().times(1).returning(|_| Ok(()));
414445
kvmi_mock
415446
.expect_get_vcpu_count()
416447
.returning(move || Ok(vcpu_count));
@@ -488,7 +519,33 @@ mod tests {
488519
.times(1)
489520
.returning(|_, _, _| Ok(()));
490521
}
522+
}
523+
524+
#[test]
525+
fn test_fail_to_create_kvm_driver_if_kvmi_init_returns_error() {
526+
let mut kvmi_mock = MockKVMi::default();
527+
kvmi_mock.expect_init().returning(|_| {
528+
Err(std::io::Error::new(
529+
std::io::ErrorKind::Other,
530+
"something went wrong",
531+
))
532+
});
533+
534+
let result = Kvm::new(
535+
"some_vm",
536+
kvmi_mock,
537+
Some(DriverInitParam::KVMiSocket("/tmp/introspector".to_string())),
538+
);
539+
540+
assert!(result.is_err(), "Expected error, got ok instead!");
541+
}
491542

543+
#[test_case(1; "single vcpu")]
544+
#[test_case(2; "two vcpus")]
545+
#[test_case(16; "sixteen vcpus")]
546+
fn test_create_kvm_driver_if_guest_domain_is_valid(vcpu_count: u32) {
547+
let mut kvmi_mock = MockKVMi::default();
548+
setup_mock(&mut kvmi_mock, vcpu_count);
492549
let result = Kvm::new(
493550
"some_vm",
494551
kvmi_mock,
@@ -498,6 +555,130 @@ mod tests {
498555
assert!(result.is_ok(), "Expected ok, got error instead!");
499556
}
500557

558+
#[test_case(1; "single vcpu")]
559+
fn test_pause_vcpu(vcpu_count: u32) {
560+
let mut kvmi_mock = MockKVMi::default();
561+
setup_mock(&mut kvmi_mock, vcpu_count);
562+
kvmi_mock.expect_pause().times(1).returning(|| Ok(()));
563+
let mut kvm = Kvm::new(
564+
"some_vm",
565+
kvmi_mock,
566+
Some(DriverInitParam::KVMiSocket("/tmp/introspector".to_string())),
567+
)
568+
.expect("Failed to create driver");
569+
let result = Kvm::pause(&mut kvm);
570+
assert!(result.is_ok(), "Expected ok, got error instead!");
571+
}
572+
573+
#[test_case(1; "single vcpu")]
574+
fn test_resume_vcpu(vcpu_count: u32) {
575+
let mut kvmi_mock = MockKVMi::default();
576+
setup_mock(&mut kvmi_mock, vcpu_count);
577+
kvmi_mock
578+
.expect_wait_and_pop_event()
579+
.times(5)
580+
.returning(|_| {
581+
Ok(Some(KVMiEvent {
582+
vcpu: 0,
583+
ev_type: KVMiEventType::PauseVCPU,
584+
ffi_event: std::ptr::null_mut(),
585+
}))
586+
});
587+
kvmi_mock.expect_reply().times(5).returning(|_, _| Ok(()));
588+
let mut kvm = Kvm::new(
589+
"some_vm",
590+
kvmi_mock,
591+
Some(DriverInitParam::KVMiSocket("/tmp/introspector".to_string())),
592+
)
593+
.expect("Failed to create driver");
594+
kvm.expect_pause_ev = 5;
595+
let result = Kvm::resume(&mut kvm);
596+
assert!(result.is_ok(), "Expected ok, got error instead!");
597+
}
598+
599+
#[test_case(1; "single vcpu")]
600+
fn test_read_and_write_physical(vcpu_count: u32) {
601+
let mut kvmi_mock = MockKVMi::default();
602+
setup_mock(&mut kvmi_mock, vcpu_count);
603+
kvmi_mock
604+
.expect_read_physical()
605+
.times(1)
606+
.returning(|_, _| Ok(()));
607+
kvmi_mock
608+
.expect_write_physical()
609+
.times(1)
610+
.returning(|_, _| Ok(()));
611+
let mut kvm = Kvm::new(
612+
"some_vm",
613+
kvmi_mock,
614+
Some(DriverInitParam::KVMiSocket("/tmp/introspector".to_string())),
615+
)
616+
.expect("Failed to create driver");
617+
let mut paddr: u64 = 0;
618+
let mut buffer: [u8; 4096] = [0; 4096];
619+
let result_read = Kvm::read_physical(&mut kvm, paddr, &mut buffer);
620+
paddr = 0;
621+
buffer = [0; 4096];
622+
let result_write = Kvm::write_physical(&mut kvm, paddr, &mut buffer);
623+
assert!(result_read.is_ok(), "Expected ok, got error instead!");
624+
assert!(result_write.is_ok(), "Expected ok, got error instead!");
625+
}
626+
627+
#[test_case(1; "single vcpu")]
628+
fn test_toggle_intercept(vcpu_count: u32) {
629+
let mut kvmi_mock = MockKVMi::default();
630+
kvmi_mock
631+
.expect_control_cr()
632+
.with(eq(0), function(|x| matches!(x, KVMiCr::Cr3)), eq(true))
633+
.times(1)
634+
.returning(|_, _, _| Ok(()));
635+
kvmi_mock
636+
.expect_control_msr()
637+
.times(0)
638+
.returning(|_, _, _| Ok(()));
639+
kvmi_mock
640+
.expect_control_events()
641+
.with(
642+
eq(1),
643+
function(|x| matches!(x, KVMiInterceptType::Breakpoint)),
644+
eq(true),
645+
)
646+
.times(1)
647+
.returning(|_, _, _| Ok(()));
648+
kvmi_mock
649+
.expect_control_events()
650+
.with(
651+
eq(1),
652+
function(|x| matches!(x, KVMiInterceptType::Pagefault)),
653+
eq(true),
654+
)
655+
.times(1)
656+
.returning(|_, _, _| Ok(()));
657+
658+
setup_mock(&mut kvmi_mock, vcpu_count);
659+
let mut kvm = Kvm::new(
660+
"some_vm",
661+
kvmi_mock,
662+
Some(DriverInitParam::KVMiSocket("/tmp/introspector".to_string())),
663+
)
664+
.expect("Failed to create driver");
665+
let mut vcpu: u16 = 0;
666+
let mut intercept_type = InterceptType::Cr(CrType::Cr3);
667+
let mut enabled: bool = true;
668+
let result_cr = Kvm::toggle_intercept(&mut kvm, vcpu, intercept_type, enabled);
669+
vcpu = 1;
670+
intercept_type = InterceptType::Breakpoint;
671+
enabled = true;
672+
let result_breakpoint = Kvm::toggle_intercept(&mut kvm, vcpu, intercept_type, enabled);
673+
vcpu = 1;
674+
intercept_type = InterceptType::Pagefault;
675+
enabled = true;
676+
let result_pagefault = Kvm::toggle_intercept(&mut kvm, vcpu, intercept_type, enabled);
677+
assert!(result_cr.is_ok(), "Expected ok, got error instead!");
678+
assert!(result_breakpoint.is_ok(), "Expected ok, got error instead!");
679+
assert!(result_pagefault.is_ok(), "Expected ok, got error instead!");
680+
}
681+
501682
mock! {
502683
KVMi{}
503684
trait Debug {

0 commit comments

Comments
 (0)