Browse Source

wasi: fs time precision option (#7569)

* wasi: test for mtime accuracy to 1ms only

* add accurate time configuration

* fix conditional

* extend mtime accuracy cases

* remove unnecessary diff

* more cases

* reworking

* u64 tweak

* use direct precision checks in assertions
pull/7585/head
Guy Bedford 12 months ago
committed by GitHub
parent
commit
6506567cb3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 32
      crates/test-programs/src/bin/preview1_fd_filestat_set.rs
  2. 35
      crates/test-programs/src/bin/preview1_path_filestat.rs
  3. 32
      crates/test-programs/src/bin/preview1_symlink_filestat.rs
  4. 23
      crates/test-programs/src/preview1.rs

32
crates/test-programs/src/bin/preview1_fd_filestat_set.rs

@ -1,7 +1,8 @@
use std::{env, process}; use std::{env, process, time::Duration};
use test_programs::preview1::open_scratch_directory; use test_programs::preview1::{assert_fs_time_eq, open_scratch_directory, TestConfig};
unsafe fn test_fd_filestat_set(dir_fd: wasi::Fd) { unsafe fn test_fd_filestat_set(dir_fd: wasi::Fd) {
let cfg = TestConfig::from_env();
// Create a file in the scratch directory. // Create a file in the scratch directory.
let file_fd = wasi::path_open( let file_fd = wasi::path_open(
dir_fd, dir_fd,
@ -29,15 +30,30 @@ unsafe fn test_fd_filestat_set(dir_fd: wasi::Fd) {
assert_eq!(stat.size, 100, "file size should be 100"); assert_eq!(stat.size, 100, "file size should be 100");
// Check fd_filestat_set_times // Check fd_filestat_set_times
let old_atim = stat.atim; let old_atim = Duration::from_nanos(stat.atim);
let new_mtim = stat.mtim - 100; let new_mtim = Duration::from_nanos(stat.mtim) - cfg.fs_time_precision() * 2;
wasi::fd_filestat_set_times(file_fd, new_mtim, new_mtim, wasi::FSTFLAGS_MTIM) wasi::fd_filestat_set_times(
.expect("fd_filestat_set_times"); file_fd,
new_mtim.as_nanos() as u64,
new_mtim.as_nanos() as u64,
wasi::FSTFLAGS_MTIM,
)
.expect("fd_filestat_set_times");
let stat = wasi::fd_filestat_get(file_fd).expect("failed filestat 3"); let stat = wasi::fd_filestat_get(file_fd).expect("failed filestat 3");
assert_eq!(stat.size, 100, "file size should remain unchanged at 100"); assert_eq!(stat.size, 100, "file size should remain unchanged at 100");
assert_eq!(stat.mtim, new_mtim, "mtim should change");
assert_eq!(stat.atim, old_atim, "atim should not change"); // Support accuracy up to at least 1ms
assert_fs_time_eq!(
Duration::from_nanos(stat.mtim),
new_mtim,
"mtim should change"
);
assert_fs_time_eq!(
Duration::from_nanos(stat.atim),
old_atim,
"atim should not change"
);
// let status = wasi_fd_filestat_set_times(file_fd, new_mtim, new_mtim, wasi::FILESTAT_SET_MTIM | wasi::FILESTAT_SET_MTIM_NOW); // let status = wasi_fd_filestat_set_times(file_fd, new_mtim, new_mtim, wasi::FILESTAT_SET_MTIM | wasi::FILESTAT_SET_MTIM_NOW);
// assert_eq!(status, wasi::EINVAL, "ATIM & ATIM_NOW can't both be set"); // assert_eq!(status, wasi::EINVAL, "ATIM & ATIM_NOW can't both be set");

35
crates/test-programs/src/bin/preview1_path_filestat.rs

@ -1,7 +1,10 @@
use std::{env, process}; use std::{env, process, time::Duration};
use test_programs::preview1::{assert_errno, config, open_scratch_directory}; use test_programs::preview1::{
assert_errno, assert_fs_time_eq, config, open_scratch_directory, TestConfig,
};
unsafe fn test_path_filestat(dir_fd: wasi::Fd) { unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
let cfg = TestConfig::from_env();
let fdflags = if config().support_fdflags_sync() { let fdflags = if config().support_fdflags_sync() {
wasi::FDFLAGS_APPEND | wasi::FDFLAGS_SYNC wasi::FDFLAGS_APPEND | wasi::FDFLAGS_SYNC
} else { } else {
@ -60,13 +63,25 @@ unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
assert_eq!(file_stat.size, 0, "file size should be 0"); assert_eq!(file_stat.size, 0, "file size should be 0");
// Check path_filestat_set_times // Check path_filestat_set_times
let new_mtim = file_stat.mtim - 100; let new_mtim = Duration::from_nanos(file_stat.mtim) - 2 * cfg.fs_time_precision();
wasi::path_filestat_set_times(dir_fd, 0, "file", 0, new_mtim, wasi::FSTFLAGS_MTIM) wasi::path_filestat_set_times(
.expect("path_filestat_set_times should succeed"); dir_fd,
0,
"file",
0,
new_mtim.as_nanos() as u64,
wasi::FSTFLAGS_MTIM,
)
.expect("path_filestat_set_times should succeed");
let modified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file") let modified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file")
.expect("reading file stats after path_filestat_set_times"); .expect("reading file stats after path_filestat_set_times");
assert_eq!(modified_file_stat.mtim, new_mtim, "mtim should change");
assert_fs_time_eq!(
Duration::from_nanos(modified_file_stat.mtim),
new_mtim,
"mtim should change"
);
assert_errno!( assert_errno!(
wasi::path_filestat_set_times( wasi::path_filestat_set_times(
@ -74,7 +89,7 @@ unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
0, 0,
"file", "file",
0, 0,
new_mtim, new_mtim.as_nanos() as u64,
wasi::FSTFLAGS_MTIM | wasi::FSTFLAGS_MTIM_NOW, wasi::FSTFLAGS_MTIM | wasi::FSTFLAGS_MTIM_NOW,
) )
.expect_err("MTIM and MTIM_NOW can't both be set"), .expect_err("MTIM and MTIM_NOW can't both be set"),
@ -84,8 +99,10 @@ unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
// check if the times were untouched // check if the times were untouched
let unmodified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file") let unmodified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file")
.expect("reading file stats after ERRNO_INVAL fd_filestat_set_times"); .expect("reading file stats after ERRNO_INVAL fd_filestat_set_times");
assert_eq!(
unmodified_file_stat.mtim, new_mtim, assert_fs_time_eq!(
Duration::from_nanos(unmodified_file_stat.mtim),
new_mtim,
"mtim should not change" "mtim should not change"
); );

32
crates/test-programs/src/bin/preview1_symlink_filestat.rs

@ -1,7 +1,8 @@
use std::{env, process}; use std::{env, process, time::Duration};
use test_programs::preview1::open_scratch_directory; use test_programs::preview1::{assert_fs_time_eq, open_scratch_directory, TestConfig};
unsafe fn test_path_filestat(dir_fd: wasi::Fd) { unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
let cfg = TestConfig::from_env();
// Create a file in the scratch directory. // Create a file in the scratch directory.
let file_fd = wasi::path_open( let file_fd = wasi::path_open(
dir_fd, dir_fd,
@ -29,21 +30,31 @@ unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
let sym_stat = wasi::path_filestat_get(dir_fd, 0, "symlink").expect("reading symlink stats"); let sym_stat = wasi::path_filestat_get(dir_fd, 0, "symlink").expect("reading symlink stats");
// Modify mtim of symlink // Modify mtim of symlink
let sym_new_mtim = sym_stat.mtim - 200; let sym_new_mtim = Duration::from_nanos(sym_stat.mtim) - cfg.fs_time_precision() * 2;
wasi::path_filestat_set_times(dir_fd, 0, "symlink", 0, sym_new_mtim, wasi::FSTFLAGS_MTIM) wasi::path_filestat_set_times(
.expect("path_filestat_set_times should succeed on symlink"); dir_fd,
0,
"symlink",
0,
sym_new_mtim.as_nanos() as u64,
wasi::FSTFLAGS_MTIM,
)
.expect("path_filestat_set_times should succeed on symlink");
// Check that symlink mtim motification worked // Check that symlink mtim motification worked
let modified_sym_stat = wasi::path_filestat_get(dir_fd, 0, "symlink") let modified_sym_stat = wasi::path_filestat_get(dir_fd, 0, "symlink")
.expect("reading file stats after path_filestat_set_times"); .expect("reading file stats after path_filestat_set_times");
assert_eq!(
modified_sym_stat.mtim, sym_new_mtim, assert_fs_time_eq!(
Duration::from_nanos(modified_sym_stat.mtim),
sym_new_mtim,
"symlink mtim should change" "symlink mtim should change"
); );
// Check that pointee mtim is not modified // Check that pointee mtim is not modified
let unmodified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file") let unmodified_file_stat = wasi::path_filestat_get(dir_fd, 0, "file")
.expect("reading file stats after path_filestat_set_times"); .expect("reading file stats after path_filestat_set_times");
assert_eq!( assert_eq!(
unmodified_file_stat.mtim, file_stat.mtim, unmodified_file_stat.mtim, file_stat.mtim,
"file mtim should not change" "file mtim should not change"
@ -71,7 +82,12 @@ unsafe fn test_path_filestat(dir_fd: wasi::Fd) {
let new_file_stat = wasi::path_filestat_get(dir_fd, 0, "file") let new_file_stat = wasi::path_filestat_get(dir_fd, 0, "file")
.expect("reading file stats after path_filestat_set_times"); .expect("reading file stats after path_filestat_set_times");
assert_eq!(new_file_stat.mtim, sym_stat.mtim, "mtim should change");
assert_fs_time_eq!(
Duration::from_nanos(new_file_stat.mtim),
Duration::from_nanos(sym_stat.mtim),
"mtim should change"
);
wasi::fd_close(file_fd).expect("closing a file"); wasi::fd_close(file_fd).expect("closing a file");
wasi::path_unlink_file(dir_fd, "symlink").expect("removing a symlink"); wasi::path_unlink_file(dir_fd, "symlink").expect("removing a symlink");

23
crates/test-programs/src/preview1.rs

@ -1,4 +1,4 @@
use std::sync::OnceLock; use std::{sync::OnceLock, time::Duration};
pub fn config() -> &'static TestConfig { pub fn config() -> &'static TestConfig {
static TESTCONFIG: OnceLock<TestConfig> = OnceLock::new(); static TESTCONFIG: OnceLock<TestConfig> = OnceLock::new();
@ -45,9 +45,9 @@ pub unsafe fn create_file(dir_fd: wasi::Fd, filename: &str) {
wasi::fd_close(file_fd).expect("closing a file"); wasi::fd_close(file_fd).expect("closing a file");
} }
// Small workaround to get the crate's `assert_errno`, through the // Small workaround to get the crate's macros, through the
// `#[macro_export]` attribute below, also available from this module. // `#[macro_export]` attribute below, also available from this module.
pub use crate::assert_errno; pub use crate::{assert_errno, assert_fs_time_eq};
#[macro_export] #[macro_export]
macro_rules! assert_errno { macro_rules! assert_errno {
@ -114,8 +114,17 @@ macro_rules! assert_errno {
}; };
} }
#[macro_export]
macro_rules! assert_fs_time_eq {
($l:expr, $r:expr, $n:literal) => {
let diff = if $l > $r { $l - $r } else { $r - $l };
assert!(diff < $crate::preview1::config().fs_time_precision(), $n);
};
}
pub struct TestConfig { pub struct TestConfig {
errno_mode: ErrnoMode, errno_mode: ErrnoMode,
fs_time_precision: u64,
no_dangling_filesystem: bool, no_dangling_filesystem: bool,
no_rename_dir_to_empty_dir: bool, no_rename_dir_to_empty_dir: bool,
no_fdflags_sync_support: bool, no_fdflags_sync_support: bool,
@ -139,11 +148,16 @@ impl TestConfig {
} else { } else {
ErrnoMode::Permissive ErrnoMode::Permissive
}; };
let fs_time_precision = match std::env::var("FS_TIME_PRECISION") {
Ok(p) => p.parse().unwrap(),
Err(_) => 100,
};
let no_dangling_filesystem = std::env::var("NO_DANGLING_FILESYSTEM").is_ok(); let no_dangling_filesystem = std::env::var("NO_DANGLING_FILESYSTEM").is_ok();
let no_rename_dir_to_empty_dir = std::env::var("NO_RENAME_DIR_TO_EMPTY_DIR").is_ok(); let no_rename_dir_to_empty_dir = std::env::var("NO_RENAME_DIR_TO_EMPTY_DIR").is_ok();
let no_fdflags_sync_support = std::env::var("NO_FDFLAGS_SYNC_SUPPORT").is_ok(); let no_fdflags_sync_support = std::env::var("NO_FDFLAGS_SYNC_SUPPORT").is_ok();
TestConfig { TestConfig {
errno_mode, errno_mode,
fs_time_precision,
no_dangling_filesystem, no_dangling_filesystem,
no_rename_dir_to_empty_dir, no_rename_dir_to_empty_dir,
no_fdflags_sync_support, no_fdflags_sync_support,
@ -167,6 +181,9 @@ impl TestConfig {
_ => false, _ => false,
} }
} }
pub fn fs_time_precision(&self) -> Duration {
Duration::from_nanos(self.fs_time_precision)
}
pub fn support_dangling_filesystem(&self) -> bool { pub fn support_dangling_filesystem(&self) -> bool {
!self.no_dangling_filesystem !self.no_dangling_filesystem
} }

Loading…
Cancel
Save