summaryrefslogtreecommitdiffstats
path: root/vendor/gix-fs/tests/dir/create.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /vendor/gix-fs/tests/dir/create.rs
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/gix-fs/tests/dir/create.rs')
-rw-r--r--vendor/gix-fs/tests/dir/create.rs194
1 files changed, 194 insertions, 0 deletions
diff --git a/vendor/gix-fs/tests/dir/create.rs b/vendor/gix-fs/tests/dir/create.rs
new file mode 100644
index 000000000..6693fd071
--- /dev/null
+++ b/vendor/gix-fs/tests/dir/create.rs
@@ -0,0 +1,194 @@
+mod all {
+ use gix_fs::dir::create;
+
+ #[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::all(target, Default::default())?;
+ assert_eq!(dir, target, "all subdirectories can be created");
+ Ok(())
+ }
+}
+mod iter {
+ pub use std::io::ErrorKind::*;
+
+ use gix_fs::dir::{
+ create,
+ create::{Error::*, Retries},
+ };
+
+ #[test]
+ fn an_existing_directory_causes_immediate_success() -> crate::Result {
+ let dir = tempfile::tempdir()?;
+ let mut it = create::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::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_automatically() -> crate::Result {
+ let dir = tempfile::tempdir()?;
+ let new_dir = dir.path().join("s1").join("s2").join("new");
+ let mut it = create::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::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::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::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::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(())
+ }
+}