sausage-vfs: review fixes (fallible growth, symlink flags, stream cancel, sized reads, timestamps, error kinds, linker shadowing)
API: Layer::stat(path, follow), Layer::readlink, Open::follow, Stat::symlink and Entry::symlink. Process::idle documents the shutdown order: abort, await the task, await idle, release locks.
This commit is contained in:
+43
-8
@@ -283,7 +283,7 @@ async fn apply_layer(layer: &dyn Layer, op: &Operation) -> std::io::Result<()> {
|
||||
2 => layer.mkdir(path).await,
|
||||
3 => layer.remove_dir(path).await,
|
||||
4 => layer.rename(path, PATHS[op.to]).await,
|
||||
8 => layer.stat(path).await.map(|_| ()),
|
||||
8 => layer.stat(path, true).await.map(|_| ()),
|
||||
_ => {
|
||||
let file = layer
|
||||
.open(
|
||||
@@ -330,7 +330,7 @@ fn apply_std(root: &std::path::Path, op: &Operation) -> std::io::Result<()> {
|
||||
}
|
||||
}
|
||||
async fn compare_tree(
|
||||
host: &Host,
|
||||
host: &dyn Layer,
|
||||
root: &std::path::Path,
|
||||
) -> std::result::Result<(), TestCaseError> {
|
||||
let mut pending = vec!["/".to_string()];
|
||||
@@ -343,6 +343,7 @@ async fn compare_tree(
|
||||
Entry {
|
||||
name: entry.file_name().to_str().unwrap().into(),
|
||||
directory: entry.file_type().unwrap().is_dir(),
|
||||
symlink: false,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
@@ -350,7 +351,7 @@ async fn compare_tree(
|
||||
prop_assert_eq!(host.list(&path).await.unwrap(), entries.clone());
|
||||
for entry in entries {
|
||||
let child = resolve(&path, &entry.name);
|
||||
let stat = host.stat(&child).await.unwrap();
|
||||
let stat = host.stat(&child, true).await.unwrap();
|
||||
prop_assert_eq!(stat.directory, entry.directory);
|
||||
if entry.directory {
|
||||
pending.push(child);
|
||||
@@ -371,25 +372,53 @@ async fn compare_tree(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
async fn check_host_differential(ops: Vec<Operation>) -> std::result::Result<(), TestCaseError> {
|
||||
async fn check_differential(
|
||||
ops: Vec<Operation>,
|
||||
memory: bool,
|
||||
) -> std::result::Result<(), TestCaseError> {
|
||||
let actual = tempfile::tempdir().unwrap();
|
||||
let expected = tempfile::tempdir().unwrap();
|
||||
let host = Host::new(actual.path(), Process::default()).unwrap();
|
||||
for root in [actual.path(), expected.path()] {
|
||||
let host: Arc<dyn Layer> = if memory {
|
||||
Arc::new(Memory::default())
|
||||
} else {
|
||||
Arc::new(Host::new(actual.path(), Process::default()).unwrap())
|
||||
};
|
||||
{
|
||||
let root = expected.path();
|
||||
std::fs::create_dir_all(root.join("a/nested")).unwrap();
|
||||
std::fs::create_dir_all(root.join("b/nested")).unwrap();
|
||||
std::fs::write(root.join("a/child"), b"source").unwrap();
|
||||
std::fs::write(root.join("target"), b"destination").unwrap();
|
||||
}
|
||||
host.mkdir("/a").await.unwrap();
|
||||
host.mkdir("/a/nested").await.unwrap();
|
||||
host.mkdir("/b").await.unwrap();
|
||||
host.mkdir("/b/nested").await.unwrap();
|
||||
host.open("/a/child", rw())
|
||||
.await
|
||||
.unwrap()
|
||||
.write(0, b"source".to_vec())
|
||||
.await
|
||||
.unwrap();
|
||||
host.open("/target", rw())
|
||||
.await
|
||||
.unwrap()
|
||||
.write(0, b"destination".to_vec())
|
||||
.await
|
||||
.unwrap();
|
||||
for op in ops {
|
||||
let actual = apply_layer(&host, &op).await.map_err(|e| e.kind());
|
||||
let actual = apply_layer(host.as_ref(), &op).await.map_err(|e| e.kind());
|
||||
let expected_result = apply_std(expected.path(), &op).map_err(|e| e.kind());
|
||||
prop_assert_eq!(actual, expected_result, "operation: {:?}", op);
|
||||
compare_tree(&host, expected.path()).await?;
|
||||
compare_tree(host.as_ref(), expected.path()).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn check_host_differential(ops: Vec<Operation>) -> std::result::Result<(), TestCaseError> {
|
||||
check_differential(ops, false).await
|
||||
}
|
||||
|
||||
/// Nested renames replace existing files and empty folders just like std::fs.
|
||||
#[tokio::test]
|
||||
async fn nested_rename_replacements() {
|
||||
@@ -416,6 +445,12 @@ proptest! {
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(check_memory_model(ops))?;
|
||||
}
|
||||
|
||||
/// Random memory namespace operations match std::fs and the complete tree.
|
||||
#[test]
|
||||
fn memory_differential(ops in operations()) {
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(check_differential(ops, true))?;
|
||||
}
|
||||
|
||||
/// Random nested operations match std::fs results and the complete tree.
|
||||
#[test]
|
||||
fn host_differential(ops in operations()) {
|
||||
|
||||
Reference in New Issue
Block a user