Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port more tests from Wasmtime's testsuite #68

Merged
merged 1 commit into from
Aug 21, 2023
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
1 change: 1 addition & 0 deletions tests/rust/src/bin/dangling_fd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ unsafe fn test_dangling_fd(dir_fd: wasi::Fd) {
wasi::path_unlink_file(dir_fd, FILE_NAME).expect("failed to unlink");
let fd = wasi::path_open(dir_fd, 0, FILE_NAME, wasi::OFLAGS_CREAT, 0, 0, 0).unwrap();
wasi::fd_close(fd).unwrap();
wasi::path_unlink_file(dir_fd, FILE_NAME).expect("failed to unlink");

// Now, repeat the same process but for a directory
wasi::path_create_directory(dir_fd, DIR_NAME).expect("failed to create dir");
Expand Down
25 changes: 1 addition & 24 deletions tests/rust/src/bin/fd_readdir.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{env, mem, process, slice, str};
use wasi::path_create_directory;
use wasi_tests::open_scratch_directory;
use wasi_tests::{create_tmp_dir, open_scratch_directory};

const BUF_LEN: usize = 256;

Expand Down Expand Up @@ -53,28 +52,6 @@ impl<'a> Iterator for ReadDir<'a> {
}
}

unsafe fn create_tmp_dir(dir_fd: wasi::Fd, name: &str) -> wasi::Fd {
path_create_directory(dir_fd, name).expect("failed to create dir");
wasi::path_open(
dir_fd,
0,
name,
wasi::OFLAGS_DIRECTORY,
wasi::RIGHTS_FD_FILESTAT_GET
| wasi::RIGHTS_FD_READDIR
| wasi::RIGHTS_PATH_CREATE_FILE
| wasi::RIGHTS_PATH_OPEN
| wasi::RIGHTS_PATH_UNLINK_FILE,
wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_READDIR
| wasi::RIGHTS_FD_FILESTAT_GET
| wasi::RIGHTS_FD_SEEK,
0,
)
.expect("failed to open dir")
}

/// Return the entries plus a bool indicating EOF.
unsafe fn exec_fd_readdir(fd: wasi::Fd, cookie: wasi::Dircookie) -> (Vec<DirEntry>, bool) {
let mut buf: [u8; BUF_LEN] = [0; BUF_LEN];
Expand Down
77 changes: 77 additions & 0 deletions tests/rust/src/bin/file_allocate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
use std::{env, process};
use wasi_tests::{create_tmp_dir, open_scratch_directory, TESTCONFIG};

unsafe fn test_file_allocate(dir_fd: wasi::Fd) {
// Create a file in the scratch directory.
let file_fd = wasi::path_open(
dir_fd,
0,
"file",
wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ
| wasi::RIGHTS_FD_WRITE
| wasi::RIGHTS_FD_ALLOCATE
| wasi::RIGHTS_FD_FILESTAT_GET,
0,
0,
)
.expect("opening a file");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);

// Check file size
let mut stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
assert_eq!(stat.size, 0, "file size should be 0");

if TESTCONFIG.support_fd_allocate() {
// Allocate some size
wasi::fd_allocate(file_fd, 0, 100).expect("allocating size");
stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
assert_eq!(stat.size, 100, "file size should be 100");

// Allocate should not modify if less than current size
wasi::fd_allocate(file_fd, 10, 10).expect("allocating size less than current size");
stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
assert_eq!(stat.size, 100, "file size should remain unchanged at 100");

// Allocate should modify if offset+len > current_len
wasi::fd_allocate(file_fd, 90, 20).expect("allocating size larger than current size");
stat = wasi::fd_filestat_get(file_fd).expect("reading file stats");
assert_eq!(stat.size, 110, "file size should increase from 100 to 110");
}
wasi::fd_close(file_fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "file").expect("removing a file");
}

fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", prog);
process::exit(1);
};

// Open scratch directory
let base_dir_fd = match open_scratch_directory(&arg) {
Ok(dir_fd) => dir_fd,
Err(err) => {
eprintln!("{}", err);
process::exit(1)
}
};

const DIR_NAME: &str = "file_allocate_dir.cleanup";
let dir_fd;
unsafe {
dir_fd = create_tmp_dir(base_dir_fd, DIR_NAME);
}

// Run the tests.
unsafe { test_file_allocate(dir_fd) }

unsafe { wasi::path_remove_directory(base_dir_fd, DIR_NAME).expect("failed to remove dir") }
}
160 changes: 160 additions & 0 deletions tests/rust/src/bin/file_pread_pwrite.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
use std::convert::TryInto;
use std::{env, process};
use wasi_tests::{create_tmp_dir, open_scratch_directory};

unsafe fn test_file_pread_pwrite(dir_fd: wasi::Fd) {
// Create a file in the scratch directory.
let file_fd = wasi::path_open(
dir_fd,
0,
"file",
wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_SEEK | wasi::RIGHTS_FD_WRITE,
0,
0,
)
.expect("opening a file");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);

let contents = &[0u8, 1, 2, 3];
let ciovec = wasi::Ciovec {
buf: contents.as_ptr() as *const _,
buf_len: contents.len(),
};
let mut nwritten =
wasi::fd_pwrite(file_fd, &mut [ciovec], 0).expect("writing bytes at offset 0");
assert_eq!(nwritten, 4, "nwritten bytes check");

let contents = &mut [0u8; 4];
let iovec = wasi::Iovec {
buf: contents.as_mut_ptr() as *mut _,
buf_len: contents.len(),
};
let mut nread = wasi::fd_pread(file_fd, &[iovec], 0).expect("reading bytes at offset 0");
assert_eq!(nread, 4, "nread bytes check");
assert_eq!(contents, &[0u8, 1, 2, 3], "written bytes equal read bytes");

// Write all the data through multiple iovecs.
//
// Note that this needs to be done with a loop, because some
// platforms do not support writing multiple iovecs at once.
// See https://github.com/rust-lang/rust/issues/74825.
let contents = &[0u8, 1, 2, 3];
let mut offset = 0usize;
loop {
let mut ciovecs: Vec<wasi::Ciovec> = Vec::new();
let mut remaining = contents.len() - offset;
if remaining > 2 {
ciovecs.push(wasi::Ciovec {
buf: contents[offset..].as_ptr() as *const _,
buf_len: 2,
});
remaining -= 2;
}
ciovecs.push(wasi::Ciovec {
buf: contents[contents.len() - remaining..].as_ptr() as *const _,
buf_len: remaining,
});

nwritten = wasi::fd_pwrite(file_fd, ciovecs.as_slice(), offset.try_into().unwrap())
.expect("writing bytes at offset 0");

offset += nwritten;
if offset == contents.len() {
break;
}
}
assert_eq!(offset, 4, "nread bytes check");

// Read all the data through multiple iovecs.
//
// Note that this needs to be done with a loop, because some
// platforms do not support reading multiple iovecs at once.
// See https://github.com/rust-lang/rust/issues/74825.
let contents = &mut [0u8; 4];
let mut offset = 0usize;
loop {
let buffer = &mut [0u8; 4];
let iovecs = &[
wasi::Iovec {
buf: buffer.as_mut_ptr() as *mut _,
buf_len: 2,
},
wasi::Iovec {
buf: buffer[2..].as_mut_ptr() as *mut _,
buf_len: 2,
},
];
nread = wasi::fd_pread(file_fd, iovecs, offset as _).expect("reading bytes at offset 0");
if nread == 0 {
break;
}
contents[offset..offset + nread].copy_from_slice(&buffer[0..nread]);
offset += nread;
}
assert_eq!(offset, 4, "nread bytes check");
assert_eq!(contents, &[0u8, 1, 2, 3], "file cursor was overwritten");

let contents = &mut [0u8; 4];
let iovec = wasi::Iovec {
buf: contents.as_mut_ptr() as *mut _,
buf_len: contents.len(),
};
nread = wasi::fd_pread(file_fd, &[iovec], 2).expect("reading bytes at offset 2");
assert_eq!(nread, 2, "nread bytes check");
assert_eq!(contents, &[2u8, 3, 0, 0], "file cursor was overwritten");

let contents = &[1u8, 0];
let ciovec = wasi::Ciovec {
buf: contents.as_ptr() as *const _,
buf_len: contents.len(),
};
nwritten = wasi::fd_pwrite(file_fd, &mut [ciovec], 2).expect("writing bytes at offset 2");
assert_eq!(nwritten, 2, "nwritten bytes check");

let contents = &mut [0u8; 4];
let iovec = wasi::Iovec {
buf: contents.as_mut_ptr() as *mut _,
buf_len: contents.len(),
};
nread = wasi::fd_pread(file_fd, &[iovec], 0).expect("reading bytes at offset 0");
assert_eq!(nread, 4, "nread bytes check");
assert_eq!(contents, &[0u8, 1, 1, 0], "file cursor was overwritten");

wasi::fd_close(file_fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "file").expect("removing a file");
}

fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", prog);
process::exit(1);
};

// Open scratch directory
let base_dir_fd = match open_scratch_directory(&arg) {
Ok(dir_fd) => dir_fd,
Err(err) => {
eprintln!("{}", err);
process::exit(1)
}
};

const DIR_NAME: &str = "file_pread_pwrite_dir.cleanup";
let dir_fd;
unsafe {
dir_fd = create_tmp_dir(base_dir_fd, DIR_NAME);
}

// Run the tests.
unsafe { test_file_pread_pwrite(dir_fd) }

unsafe { wasi::path_remove_directory(base_dir_fd, DIR_NAME).expect("failed to remove dir") }
}
111 changes: 111 additions & 0 deletions tests/rust/src/bin/file_seek_tell.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use std::{env, process};
use wasi_tests::{assert_errno, create_tmp_dir, open_scratch_directory};

unsafe fn test_file_seek_tell(dir_fd: wasi::Fd) {
// Create a file in the scratch directory.
let file_fd = wasi::path_open(
dir_fd,
0,
"file",
wasi::OFLAGS_CREAT,
wasi::RIGHTS_FD_READ | wasi::RIGHTS_FD_WRITE | wasi::RIGHTS_FD_SEEK | wasi::RIGHTS_FD_TELL,
0,
0,
)
.expect("opening a file");
assert!(
file_fd > libc::STDERR_FILENO as wasi::Fd,
"file descriptor range check",
);

// Check current offset
let mut offset = wasi::fd_tell(file_fd).expect("getting initial file offset");
assert_eq!(offset, 0, "current offset should be 0");

// Write to file
let data = &[0u8; 100];
let iov = wasi::Ciovec {
buf: data.as_ptr() as *const _,
buf_len: data.len(),
};
let nwritten = wasi::fd_write(file_fd, &[iov]).expect("writing to a file");
assert_eq!(nwritten, 100, "should write 100 bytes to file");

// Check current offset
offset = wasi::fd_tell(file_fd).expect("getting file offset after writing");
assert_eq!(offset, 100, "offset after writing should be 100");

// Seek to middle of the file
let mut newoffset =
wasi::fd_seek(file_fd, -50, wasi::WHENCE_CUR).expect("seeking to the middle of a file");
assert_eq!(
newoffset, 50,
"offset after seeking to the middle should be at 50"
);

// Seek to the beginning of the file
newoffset =
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET).expect("seeking to the beginning of the file");
assert_eq!(
newoffset, 0,
"offset after seeking to the beginning of the file should be at 0"
);

// Seek beyond the file should be possible
wasi::fd_seek(file_fd, 1000, wasi::WHENCE_CUR).expect("seeking beyond the end of the file");

// Seek before byte 0 is an error though
assert_errno!(
wasi::fd_seek(file_fd, -2000, wasi::WHENCE_CUR)
.expect_err("seeking before byte 0 should be an error"),
wasi::ERRNO_INVAL
);

// Check that fd_read properly updates the file offset
wasi::fd_seek(file_fd, 0, wasi::WHENCE_SET)
.expect("seeking to the beginning of the file again");

let buffer = &mut [0u8; 100];
let iovec = wasi::Iovec {
buf: buffer.as_mut_ptr(),
buf_len: buffer.len(),
};
let nread = wasi::fd_read(file_fd, &[iovec]).expect("reading file");
assert_eq!(nread, buffer.len(), "should read {} bytes", buffer.len());

offset = wasi::fd_tell(file_fd).expect("getting file offset after reading");
assert_eq!(offset, 100, "offset after reading should be 100");

wasi::fd_close(file_fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "file").expect("deleting a file");
}
fn main() {
let mut args = env::args();
let prog = args.next().unwrap();
let arg = if let Some(arg) = args.next() {
arg
} else {
eprintln!("usage: {} <scratch directory>", prog);
process::exit(1);
};

// Open scratch directory
let base_dir_fd = match open_scratch_directory(&arg) {
Ok(dir_fd) => dir_fd,
Err(err) => {
eprintln!("{}", err);
process::exit(1)
}
};

const DIR_NAME: &str = "file_seek_tell_dir.cleanup";
let dir_fd;
unsafe {
dir_fd = create_tmp_dir(base_dir_fd, DIR_NAME);
}

// Run the tests.
unsafe { test_file_seek_tell(dir_fd) }

unsafe { wasi::path_remove_directory(base_dir_fd, DIR_NAME).expect("failed to remove dir") }
}
Loading