Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [ "libkernel" ]
members = ["libkernel", "usertest"]

[package]
name = "moss"
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "nightly"
components = [ "rust-src", "llvm-tools-preview", "rustfmt", "clippy", "rust-analyzer" ]
targets = [ "aarch64-unknown-none-softfloat" ]
targets = ["aarch64-unknown-none-softfloat", "aarch64-unknown-linux-musl"]
5 changes: 5 additions & 0 deletions usertest/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[build]
target = "aarch64-unknown-linux-musl"

[target.aarch64-unknown-linux-musl]
linker = "rust-lld"
7 changes: 7 additions & 0 deletions usertest/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "usertest"
version = "0.1.0"
edition = "2024"

[dependencies]
libc = "0.2"
126 changes: 126 additions & 0 deletions usertest/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
fn test_sync() {
print!("Testing sync syscall ...");
unsafe {
libc::sync();
}
println!(" OK");
}

fn test_opendir() {
print!("Testing opendir syscall ...");
let path = std::ffi::CString::new("/").unwrap();
unsafe {
let dir = libc::opendir(path.as_ptr());
if dir.is_null() {
panic!("opendir failed");
}
libc::closedir(dir);
}
println!(" OK");
}

fn test_readdir() {
print!("Testing readdir syscall ...");
let path = std::ffi::CString::new("/").unwrap();
unsafe {
let dir = libc::opendir(path.as_ptr());
if dir.is_null() {
panic!("opendir failed");
}
let mut count = 0;
loop {
let entry = libc::readdir(dir);
if entry.is_null() {
break;
}
count += 1;
}
libc::closedir(dir);
if count == 0 {
panic!("readdir returned no entries");
}
}
println!(" OK");
}

fn test_chdir() {
print!("Testing chdir syscall ...");
let path = std::ffi::CString::new("/").unwrap();
unsafe {
if libc::chdir(path.as_ptr()) != 0 {
panic!("chdir failed");
}
}
println!(" OK");
}

fn test_fork() {
print!("Testing fork syscall ...");
unsafe {
let pid = libc::fork();
if pid < 0 {
panic!("fork failed");
} else if pid == 0 {
// Child process
libc::_exit(0);
} else {
// Parent process
let mut status = 0;
libc::waitpid(pid, &mut status, 0);
}
}
println!(" OK");
}

fn test_write() {
print!("Testing write syscall ...");
let file = "/dev/null";
let c_file = std::ffi::CString::new(file).unwrap();
let data = b"Hello, world!";
unsafe {
let fd = libc::open(c_file.as_ptr(), libc::O_WRONLY);
if fd < 0 {
panic!("open failed");
}
let ret = libc::write(fd, data.as_ptr() as *const libc::c_void, data.len());
if ret < 0 || ret as usize != data.len() {
panic!("write failed");
}
libc::close(fd);
}
println!(" OK");
}

fn run_test(test_fn: fn()) {
// Fork a new process to run the test
unsafe {
let pid = libc::fork();
if pid < 0 {
panic!("fork failed");
} else if pid == 0 {
// Child process
test_fn();
libc::_exit(0);
} else {
// Parent process
let mut status = 0;
libc::waitpid(pid, &mut status, 0);
if !libc::WIFEXITED(status) || libc::WEXITSTATUS(status) != 0 {
panic!("Test failed in child process");
}
}
}
}

fn main() {
println!("Running userspace tests ...");
let start = std::time::Instant::now();
run_test(test_sync);
run_test(test_opendir);
run_test(test_readdir);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether there's a way to use Rust's standard test infrastructure here to run these tests.

Although, as you say - it will require threading, so we'd need #37 sorting first.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this is a little sturdier because it prevents some breakage by forking, which should help reduce bugs from causing runaway issues, given that forking works.

run_test(test_chdir);
run_test(test_fork);
run_test(test_write);
let end = std::time::Instant::now();
println!("All tests passed in {} ms", (end - start).as_millis());
}