robert-w-gries / rxinu

Rust implementation of Xinu educational operating system

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add testing framework for the kernel

robert-w-gries opened this issue · comments

Integration Tests

We should test every component:

  • Memory
  • Interrupts
  • Scheduling
  • Inter-process Communication

Original Post

We are starting to get into the meat of OS dev, so we'll need some proper testing tools.

What do we want in our testing framework?

  • Unit tests
  • Integration tests
  • Regression tests
  • Testing on actual hardware (stretch goal)

What can be done now?

Unit tests and Regression tests can be implemented without much effort. We already have CI with Travis, and unit tests should be able to run without any dependencies on external code/tools.

What needs to be done?

Regression tests are increasingly vital as the kernel grows more complex. A couple of lines of kprintln! output will not be sufficient to test preemption, inter-process communication, and file systems.

Ideally, we can create a test harness that uses a virtualization crate to run our kernel and perform tests.

KVM/libvirt bindings

rust-x86 looks to use the kvm crate to accomplish their testing. This is a good place to start. See gz/rust-x86#20 for a relevant conversation

A full list of virt crates can be found here

utest crate

Another intriguing option is the utest crate. However, there are limitations and requirements that might not mesh well with this kernel.

Regarding unit tests

Unit tests were more complex than I thought. See intermezzOS/kernel#69 for details.

By using utest, I have managed to get a trivial unit test running on qemu for both i686 and x86_64:

$ qemu-x86_64 target/x86_64-rxinu-utest/debug/foo-f0f4593aa62d2a5d
warning: TCG doesn't support requested feature: CPUID.01H:ECX.vmx [bit 5]
running 1 tests
test foo ... OK

test result: OK. 1 passed; 0 failed; 0 ignored

The next challenge is getting rxinu code to run in the unit tests. The most immediate problem is that we can't write extern crate rxinu; in our tests directory because rxinu is compiled as a staticlib.

I believe there are two paths forward from here:

Link rxinu.a into tests module

I believe it's possible to link our rxinu.a library into the tests module. However, this seems impractical because we would need to manually define all rxinu functions as extern.

Use a custom build script to build rxinu crate as normal lib

By using a custom build script, we can first build rxinu as a lib. Then, we can create a staticlib using the rxinu crate. This way, we can easily call our rxinu code in our tests module:

#[test]
fn zero_mapped() {
    use rxinu::arch::memory::Mapper;
    let mut page_table = unsafe { Mapper::new() };

    // address 0 is mapped
    assert!(page_table.translate(0).is_some());
}

If necessary, we can follow this guide to use build.rs only for cargo test

Unit tests are definitely achievable. See Phil's post about unit testing.