mod all { use git_tempfile::create_dir; #[test] fn a_deeply_nested_directory() -> crate::Result { let dir = tempfile::tempdir()?; let target = &dir.path().join("1").join("2").join("3").join("4").join("5").join("6"); let dir = create_dir::all(target, Default::default())?; assert_eq!(dir, target, "all subdirectories can be created"); Ok(()) }}mod iter { pub use std::io::ErrorKind::*; use git_tempfile::{ create_dir, create_dir::{Error::*, Retries}, }; #[test] fn an_existing_directory_causes_immediate_success() -> crate::Result { let dir = tempfile::tempdir()?; let mut it = create_dir::Iter::new(dir.path()); assert_eq!( it.next().expect("item").expect("success"), dir.path(), "first iteration is immediately successful" ); assert!(it.next().is_none(), "iterator exhausted afterwards"); Ok(()) } #[test] fn a_single_directory_can_be_created_too() -> crate::Result { let dir = tempfile::tempdir()?; let new_dir = dir.path().join("new"); let mut it = create_dir::Iter::new(&new_dir); assert_eq!( it.next().expect("item").expect("success"), &new_dir, "first iteration is immediately successful" ); assert!(it.next().is_none(), "iterator exhausted afterwards"); assert!(new_dir.is_dir(), "the directory exists"); Ok(()) } #[test] fn multiple_intermediate_directories_are_created_automaticaly() -> crate::Result { let dir = tempfile::tempdir()?; let new_dir = dir.path().join("s1").join("s2").join("new"); let mut it = create_dir::Iter::new(&new_dir); assert!( matches!(it.next(), Some(Err(Intermediate{dir, kind: k})) if k == NotFound && dir == new_dir), "dir is not present" ); assert!( matches!(it.next(), Some(Err(Intermediate{dir, kind:k})) if k == NotFound && dir == new_dir.parent().unwrap()), "parent dir is not present" ); assert_eq!( it.next().expect("item").expect("success"), new_dir.parent().unwrap().parent().unwrap(), "first subdir is created" ); assert_eq!( it.next().expect("item").expect("success"), new_dir.parent().unwrap(), "second subdir is created" ); assert_eq!( it.next().expect("item").expect("success"), new_dir, "target directory is created" ); assert!(it.next().is_none(), "iterator depleted"); assert!(new_dir.is_dir(), "the directory exists"); Ok(()) } #[test] fn multiple_intermediate_directories_are_created_up_to_retries_limit() -> crate::Result { let dir = tempfile::tempdir()?; let new_dir = dir.path().join("s1").join("s2").join("new"); let mut it = create_dir::Iter::new_with_retries( &new_dir, Retries { on_create_directory_failure: 1, ..Default::default() }, ); assert!( matches!(it.next(), Some(Err(Permanent{ retries_left, dir, err, ..})) if retries_left.on_create_directory_failure == 0 && err.kind() == NotFound && dir == new_dir), "parent dir is not present and we run out of attempts" ); assert!(it.next().is_none(), "iterator depleted"); assert!(!new_dir.is_dir(), "the wasn't created"); Ok(()) } #[test] fn an_existing_file_makes_directory_creation_fail_permanently() -> crate::Result { let dir = tempfile::tempdir()?; let new_dir = dir.path().join("also-file"); std::fs::write(&new_dir, [42])?; assert!(new_dir.is_file()); let mut it = create_dir::Iter::new(&new_dir); assert!( matches!(it.next(), Some(Err(Permanent{ dir, err, .. })) if err.kind() == AlreadyExists && dir == new_dir), "parent dir is not present and we run out of attempts" ); assert!(it.next().is_none(), "iterator depleted"); assert!(new_dir.is_file(), "file is untouched"); Ok(()) } #[test] fn racy_directory_creation_with_new_directory_being_deleted_not_enough_retries() -> crate::Result { let dir = tempfile::tempdir()?; let new_dir = dir.path().join("a").join("new"); let parent_dir = new_dir.parent().unwrap(); let mut it = create_dir::Iter::new_with_retries( &new_dir, Retries { to_create_entire_directory: 2, on_create_directory_failure: 2, ..Default::default() }, ); assert!( matches!(it.nth(1), Some(Ok(dir)) if dir == parent_dir), "parent dir is created" ); // Someone deletes the new directory std::fs::remove_dir(parent_dir)?; assert!( matches!(it.nth(1), Some(Ok(dir)) if dir == parent_dir), "parent dir is created" ); // Someone deletes the new directory, again std::fs::remove_dir(parent_dir)?; assert!( matches!(it.next(), Some(Err(Permanent{ retries_left, dir, err, .. })) if retries_left.to_create_entire_directory == 0 && retries_left.on_create_directory_failure == 1 && err.kind() == NotFound && dir == new_dir), "we run out of attempts to retry to combat against raciness" ); Ok(()) } #[test] fn racy_directory_creation_with_new_directory_being_deleted() -> crate::Result { let dir = tempfile::tempdir()?; let new_dir = dir.path().join("a").join("new"); let parent_dir = new_dir.parent().unwrap(); let mut it = create_dir::Iter::new(&new_dir); assert!( matches!(it.next(), Some(Err(Intermediate{dir, kind:k})) if k == NotFound && dir == new_dir), "dir is not present, and we go up a level" ); assert!( matches!(it.next(), Some(Ok(dir)) if dir == parent_dir), "parent dir is created" ); // Someone deletes the new directory std::fs::remove_dir(parent_dir)?; assert!( matches!(it.next(), Some(Err(Intermediate{dir, kind:k})) if k == NotFound && dir == new_dir), "now when it tries the actual dir its not found" ); assert!( matches!(it.next(), Some(Ok(dir)) if dir == parent_dir), "parent dir is created as it retries" ); assert!( matches!(it.next(), Some(Ok(dir)) if dir == new_dir), "target dir is created successfully" ); assert!(it.next().is_none(), "iterator depleted"); assert!(new_dir.is_dir()); Ok(()) }}
mod all {
use git_tempfile::create_dir;
#[test]
fn a_deeply_nested_directory() -> crate::Result {
let dir = tempfile::tempdir()?;
let target = &dir.path().join("1").join("2").join("3").join("4").join("5").join("6");
let dir = create_dir::all(target, Default::default())?;
assert_eq!(dir, target, "all subdirectories can be created");
Ok(())
}
}
mod iter {
pub use std::io::ErrorKind::*;
use git_tempfile::{
create_dir,
create_dir::{Error::*, Retries},
};
#[test]
fn an_existing_directory_causes_immediate_success() -> crate::Result {
let dir = tempfile::tempdir()?;
let mut it = create_dir::Iter::new(dir.path());
assert_eq!(
it.next().expect("item").expect("success"),
dir.path(),
"first iteration is immediately successful"
);
assert!(it.next().is_none(), "iterator exhausted afterwards");
Ok(())
}
#[test]
fn a_single_directory_can_be_created_too() -> crate::Result {
let dir = tempfile::tempdir()?;
let new_dir = dir.path().join("new");
let mut it = create_dir::Iter::new(&new_dir);
assert_eq!(
it.next().expect("item").expect("success"),
&new_dir,
"first iteration is immediately successful"
);
assert!(it.next().is_none(), "iterator exhausted afterwards");
assert!(new_dir.is_dir(), "the directory exists");
Ok(())
}
#[test]
fn multiple_intermediate_directories_are_created_automaticaly() -> crate::Result {
let dir = tempfile::tempdir()?;
let new_dir = dir.path().join("s1").join("s2").join("new");
let mut it = create_dir::Iter::new(&new_dir);
assert!(
matches!(it.next(), Some(Err(Intermediate{dir, kind: k})) if k == NotFound && dir == new_dir),
"dir is not present"
);
assert!(
matches!(it.next(), Some(Err(Intermediate{dir, kind:k})) if k == NotFound && dir == new_dir.parent().unwrap()),
"parent dir is not present"
);
assert_eq!(
it.next().expect("item").expect("success"),
new_dir.parent().unwrap().parent().unwrap(),
"first subdir is created"
);
assert_eq!(
it.next().expect("item").expect("success"),
new_dir.parent().unwrap(),
"second subdir is created"
);
assert_eq!(
it.next().expect("item").expect("success"),
new_dir,
"target directory is created"
);
assert!(it.next().is_none(), "iterator depleted");
assert!(new_dir.is_dir(), "the directory exists");
Ok(())
}
#[test]
fn multiple_intermediate_directories_are_created_up_to_retries_limit() -> crate::Result {
let dir = tempfile::tempdir()?;
let new_dir = dir.path().join("s1").join("s2").join("new");
let mut it = create_dir::Iter::new_with_retries(
&new_dir,
Retries {
on_create_directory_failure: 1,
..Default::default()
},
);
assert!(
matches!(it.next(), Some(Err(Permanent{ retries_left, dir, err, ..})) if retries_left.on_create_directory_failure == 0
&& err.kind() == NotFound
&& dir == new_dir),
"parent dir is not present and we run out of attempts"
);
assert!(it.next().is_none(), "iterator depleted");
assert!(!new_dir.is_dir(), "the wasn't created");
Ok(())
}
#[test]
fn an_existing_file_makes_directory_creation_fail_permanently() -> crate::Result {
let dir = tempfile::tempdir()?;
let new_dir = dir.path().join("also-file");
std::fs::write(&new_dir, [42])?;
assert!(new_dir.is_file());
let mut it = create_dir::Iter::new(&new_dir);
assert!(
matches!(it.next(), Some(Err(Permanent{ dir, err, .. })) if err.kind() == AlreadyExists
&& dir == new_dir),
"parent dir is not present and we run out of attempts"
);
assert!(it.next().is_none(), "iterator depleted");
assert!(new_dir.is_file(), "file is untouched");
Ok(())
}
#[test]
fn racy_directory_creation_with_new_directory_being_deleted_not_enough_retries() -> crate::Result {
let dir = tempfile::tempdir()?;
let new_dir = dir.path().join("a").join("new");
let parent_dir = new_dir.parent().unwrap();
let mut it = create_dir::Iter::new_with_retries(
&new_dir,
Retries {
to_create_entire_directory: 2,
on_create_directory_failure: 2,
..Default::default()
},
);
assert!(
matches!(it.nth(1), Some(Ok(dir)) if dir == parent_dir),
"parent dir is created"
);
// Someone deletes the new directory
std::fs::remove_dir(parent_dir)?;
assert!(
matches!(it.nth(1), Some(Ok(dir)) if dir == parent_dir),
"parent dir is created"
);
// Someone deletes the new directory, again
std::fs::remove_dir(parent_dir)?;
assert!(
matches!(it.next(), Some(Err(Permanent{ retries_left, dir, err, .. })) if retries_left.to_create_entire_directory == 0
&& retries_left.on_create_directory_failure == 1
&& err.kind() == NotFound
&& dir == new_dir),
"we run out of attempts to retry to combat against raciness"
);
Ok(())
}
#[test]
fn racy_directory_creation_with_new_directory_being_deleted() -> crate::Result {
let dir = tempfile::tempdir()?;
let new_dir = dir.path().join("a").join("new");
let parent_dir = new_dir.parent().unwrap();
let mut it = create_dir::Iter::new(&new_dir);
assert!(
matches!(it.next(), Some(Err(Intermediate{dir, kind:k})) if k == NotFound && dir == new_dir),
"dir is not present, and we go up a level"
);
assert!(
matches!(it.next(), Some(Ok(dir)) if dir == parent_dir),
"parent dir is created"
);
// Someone deletes the new directory
std::fs::remove_dir(parent_dir)?;
assert!(
matches!(it.next(), Some(Err(Intermediate{dir, kind:k})) if k == NotFound && dir == new_dir),
"now when it tries the actual dir its not found"
);
assert!(
matches!(it.next(), Some(Ok(dir)) if dir == parent_dir),
"parent dir is created as it retries"
);
assert!(
matches!(it.next(), Some(Ok(dir)) if dir == new_dir),
"target dir is created successfully"
);
assert!(it.next().is_none(), "iterator depleted");
assert!(new_dir.is_dir());
Ok(())
}
}