Move tests with mount as integration tests

This commit is contained in:
Wildan M
2025-09-25 20:58:49 +07:00
parent 25cc366a63
commit 2d61aceff9
10 changed files with 495 additions and 268 deletions
+1 -1
View File
@@ -128,7 +128,7 @@ fn print_usage_exit() -> ! {
}
fn usage() {
println!("redoxfs --no-daemon [-d] [--uuid] [disk or uuid] [mountpoint] [block in hex]");
println!("redoxfs [--no-daemon|-d] [--uuid] [disk or uuid] [mountpoint] [block in hex]");
}
enum DiskId {
+1 -1
View File
@@ -126,7 +126,7 @@ impl DirList {
self.count == 0
}
pub fn entries(&self) -> DirEntryIterator {
pub fn entries(&self) -> DirEntryIterator<'_> {
DirEntryIterator {
dir_list: self,
emit_count: 0,
+3
View File
@@ -10,6 +10,9 @@ use self::scheme::FileScheme;
pub mod resource;
pub mod scheme;
//FIXME: mut callback is not mut
#[allow(unused_mut)]
pub fn mount<D, P, T, F>(filesystem: FileSystem<D>, mountpoint: P, mut callback: F) -> io::Result<T>
where
D: Disk,
+6 -4
View File
@@ -518,8 +518,8 @@ impl<D: Disk> Resource<D> for FileResource {
if let Some(mut fmap) = v_opt {
fmap.rc += 1;
fmap.flags |= flags;
fmap_info
//FIXME: Use result?
let _ = fmap_info
.ranges
.insert(range.start, range.end - range.start, fmap);
} else {
@@ -533,7 +533,8 @@ impl<D: Disk> Resource<D> for FileResource {
tx,
)?
};
fmap_info.ranges.insert(offset, aligned_size as u64, map);
//FIXME: Use result?
let _ = fmap_info.ranges.insert(offset, aligned_size as u64, map);
}
}
//dbg!(&self.fmaps);
@@ -572,7 +573,8 @@ impl<D: Disk> Resource<D> for FileResource {
}
if fmap.rc > 0 {
fmap_info
//FIXME: Use result?
let _ = fmap_info
.ranges
.insert(range.start, range.end - range.start, fmap);
}
+2 -2
View File
@@ -652,7 +652,7 @@ impl<'sock, D: Disk> SchemeSync for FileScheme<'sock, D> {
let scheme_name = &self.name;
self.fs.tx(|tx| {
let orig_parent_ptr = match file.parent_ptr_opt() {
let _orig_parent_ptr = match file.parent_ptr_opt() {
Some(some) => some,
None => {
// println!("orig is root");
@@ -1043,7 +1043,7 @@ impl<'sock, D: Disk> SchemeSync for FileScheme<'sock, D> {
id: usize,
payload: &mut [u8],
metadata: &[u64],
ctx: &CallerCtx,
_ctx: &CallerCtx,
) -> Result<usize> {
let Some(verb) = FsCall::try_from_raw(metadata[0] as usize) else {
return Err(Error::new(EINVAL));
+3 -258
View File
@@ -1,17 +1,11 @@
use crate::htree::{HTreeHash, HTreeNode, HTreePtr, HTREE_IDX_ENTRIES};
use crate::{
unmount_path, BlockAddr, BlockData, BlockLevel, BlockPtr, DirEntry, DirList, DiskMemory,
DiskSparse, FileSystem, Node, TreePtr, ALLOC_GC_THRESHOLD, BLOCK_SIZE,
BlockAddr, BlockData, BlockLevel, BlockPtr, DirEntry, DirList, DiskMemory, DiskSparse,
FileSystem, Node, TreePtr, ALLOC_GC_THRESHOLD, BLOCK_SIZE,
};
use core::panic::AssertUnwindSafe;
use std::panic::catch_unwind;
use std::path::Path;
use std::process::Command;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
use std::thread::sleep;
use std::time::Duration;
use std::{fs, thread, time};
use std::{fs, time};
static IMAGE_SEQ: AtomicUsize = AtomicUsize::new(0);
@@ -36,226 +30,6 @@ where
res
}
fn with_mounted<T, F>(callback: F) -> T
where
T: Send + Sync + 'static,
F: FnOnce(&Path) -> T + Send + Sync + 'static,
{
let mount_path_o = format!("image{}", IMAGE_SEQ.fetch_add(1, Relaxed));
let mount_path = mount_path_o.clone();
let res = with_redoxfs(move |fs| {
if cfg!(not(target_os = "redox")) {
if !Path::new(&mount_path).exists() {
dbg!(fs::create_dir(dbg!(&mount_path))).unwrap();
}
}
let join_handle = crate::mount(fs, dbg!(mount_path), move |real_path| {
let real_path = real_path.to_owned();
thread::spawn(move || {
let res = catch_unwind(AssertUnwindSafe(|| callback(&real_path)));
let real_path = real_path.to_str().unwrap();
if cfg!(target_os = "redox") {
dbg!(fs::remove_file(dbg!(format!(":{}", real_path)))).unwrap();
} else {
if !dbg!(Command::new("sync").status()).unwrap().success() {
panic!("sync failed");
}
if !unmount_path(real_path).is_ok() {
// There seems to be a race condition where the device can be busy when trying to unmount.
// So, we pause for a moment and retry. There will still be an error output to the logs
// for the first failed attempt.
sleep(Duration::from_millis(200));
if !unmount_path(real_path).is_ok() {
panic!("umount failed");
}
}
}
res.unwrap()
})
})
.unwrap();
join_handle.join().unwrap()
});
if cfg!(not(target_os = "redox")) {
dbg!(fs::remove_dir(dbg!(mount_path_o))).unwrap();
}
res
}
#[test]
fn simple() {
with_mounted(|path| {
dbg!(fs::create_dir(&path.join("test"))).unwrap();
})
}
#[test]
fn create_and_remove_file() {
with_mounted(|path| {
let file_name = "test_file.txt";
let file_path = path.join(file_name);
// Create the file
fs::write(&file_path, "Hello, world!").unwrap();
assert!(fs::exists(&file_path).unwrap());
// Read the file
let contents = fs::read_to_string(&file_path).unwrap();
assert_eq!(contents, "Hello, world!");
// Remove the file
fs::remove_file(&file_path).unwrap();
assert!(!fs::exists(&file_path).unwrap());
});
}
#[test]
fn create_and_remove_directory() {
with_mounted(|path| {
let dir_name = "test_dir";
let dir_path = path.join(dir_name);
// Create the directory
fs::create_dir(&dir_path).unwrap();
assert!(fs::exists(&dir_path).unwrap());
// Check that the directory is empty
let entries: Vec<_> = fs::read_dir(&dir_path)
.unwrap()
.map(|e| e.unwrap().file_name())
.collect();
assert!(entries.is_empty());
// Add a file to the directory
let file_name = "test_file.txt";
let file_path = dir_path.join(file_name);
fs::write(&file_path, "Hello, world!").unwrap();
// Check that the dir cannot be removed when not empty
let error = fs::remove_dir(&dir_path);
assert!(error.is_err());
assert_eq!(
error.unwrap_err().kind(),
std::io::ErrorKind::DirectoryNotEmpty
);
// Remove the file
fs::remove_file(&file_path).unwrap();
// Remove the directory
fs::remove_dir(&dir_path).unwrap();
assert!(!fs::exists(&dir_path).unwrap());
});
}
#[test]
fn create_and_remove_symlink() {
with_mounted(|path| {
let real_file = "real_file.txt";
let real_path = path.join(real_file);
let symlink_file = "symlink_to_real_file.txt";
let symlink_path = path.join(symlink_file);
// Create the real file
fs::write(&real_path, "Hello, world!").unwrap();
// Create the symmlink according to the platform
#[cfg(unix)]
std::os::unix::fs::symlink(&real_file, &symlink_path).unwrap();
#[cfg(windows)]
std::os::windows::fs::symlink_file(&real_file, &symlink_path).unwrap();
// Check that the symlink exists and points to the correct target
let exists = fs::exists(&symlink_path);
assert!(
exists.is_ok() && exists.unwrap(),
"Symlink should exist but was: {:?}",
fs::exists(&symlink_path)
);
let symlink_metadata = fs::symlink_metadata(&symlink_path).unwrap();
assert!(symlink_metadata.file_type().is_symlink());
let target = fs::read_link(&symlink_path).unwrap();
assert_eq!(target.to_str().unwrap(), real_file);
assert_eq!(fs::read(&symlink_path).unwrap(), b"Hello, world!");
// Confirm the symlink cannot be removed as a directory
let error = fs::remove_dir(&symlink_path);
assert!(error.is_err());
assert_eq!(error.unwrap_err().kind(), std::io::ErrorKind::NotADirectory);
// Remove the symlink
fs::remove_file(&symlink_path).unwrap();
assert!(!fs::exists(&symlink_path).unwrap());
});
}
#[cfg(target_os = "redox")]
#[test]
fn mmap() {
use syscall;
//TODO
with_mounted(|path| {
use std::slice;
let path = dbg!(path.join("test"));
let mmap_inner = |write: bool| {
let fd = dbg!(libredox::call::open(
path.to_str().unwrap(),
libredox::flag::O_CREAT | libredox::flag::O_RDWR | libredox::flag::O_CLOEXEC,
0,
))
.unwrap();
let map = unsafe {
slice::from_raw_parts_mut(
dbg!(libredox::call::mmap(libredox::call::MmapArgs {
fd,
offset: 0,
length: 128,
prot: libredox::flag::PROT_READ | libredox::flag::PROT_WRITE,
flags: libredox::flag::MAP_SHARED,
addr: core::ptr::null_mut(),
}))
.unwrap() as *mut u8,
128,
)
};
// Maps should be available after closing
assert_eq!(dbg!(libredox::call::close(fd)), Ok(()));
for i in 0..128 {
if write {
map[i as usize] = i;
}
assert_eq!(map[i as usize], i);
}
//TODO: add msync
unsafe {
assert_eq!(
dbg!(libredox::call::munmap(map.as_mut_ptr().cast(), map.len())),
Ok(())
);
}
};
mmap_inner(true);
mmap_inner(false);
})
}
#[test]
fn many_create_remove_should_not_increase_size() {
with_redoxfs(|mut fs| {
@@ -466,35 +240,6 @@ fn many_create_write_list_find_read_delete() {
}
}
#[test]
fn many_write_read_delete_mounted() {
with_mounted(|path| {
let total_count = 500;
for i in 0..total_count {
fs::write(
&path.join(format!("file{}", i)),
format!("Hello, number {i}!"),
)
.unwrap();
}
// Confirm each of the created files can be found and read
for i in 0..total_count {
let contents = fs::read_to_string(&path.join(format!("file{}", i))).unwrap();
assert_eq!(contents, format!("Hello, number {i}!"));
}
// Remove all the files
for i in 0..total_count {
let file_path = path.join(format!("file{i}"));
assert!(fs::exists(&file_path).unwrap());
fs::remove_file(&file_path).unwrap();
assert!(!fs::exists(&file_path).unwrap());
}
});
}
//
// MARK: H-Tree tests
//
+1 -1
View File
@@ -33,7 +33,7 @@ fn unmount_linux_path(mount_path: &str) -> io::Result<ExitStatus> {
pub fn unmount_path(mount_path: &str) -> Result<(), io::Error> {
if cfg!(target_os = "redox") {
fs::remove_file(format!(":{}", mount_path))?
fs::remove_file(format!("{}", mount_path))?
} else {
let status_res = if cfg!(target_os = "linux") {
unmount_linux_path(mount_path)