duplicates testing uses proptest now

This commit is contained in:
Cyryl Płotnicki 2020-11-28 11:48:37 +00:00
parent ee13dd22be
commit 6629977515
6 changed files with 198 additions and 38 deletions

99
Cargo.lock generated
View file

@ -37,6 +37,7 @@ dependencies = [
"hex", "hex",
"log", "log",
"nix 0.19.0", "nix 0.19.0",
"proptest",
"rand 0.7.3", "rand 0.7.3",
"rayon", "rayon",
"rust-crypto", "rust-crypto",
@ -56,6 +57,21 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]]
name = "bit-set"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.2.1" version = "1.2.1"
@ -77,6 +93,12 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" checksum = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820"
[[package]]
name = "byteorder"
version = "1.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
[[package]] [[package]]
name = "cargo-husky" name = "cargo-husky"
version = "1.5.0" version = "1.5.0"
@ -191,6 +213,12 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "fs2" name = "fs2"
version = "0.4.3" version = "0.4.3"
@ -331,6 +359,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "num-traits"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.13.0" version = "1.13.0"
@ -362,6 +399,32 @@ dependencies = [
"unicode-xid", "unicode-xid",
] ]
[[package]]
name = "proptest"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f"
dependencies = [
"bit-set",
"bitflags",
"byteorder",
"lazy_static",
"num-traits",
"quick-error",
"rand 0.7.3",
"rand_chacha",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
"tempfile",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.7" version = "1.0.7"
@ -450,6 +513,15 @@ dependencies = [
"rand_core 0.5.1", "rand_core 0.5.1",
] ]
[[package]]
name = "rand_xorshift"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
dependencies = [
"rand_core 0.5.1",
]
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.5.0" version = "1.5.0"
@ -490,6 +562,12 @@ version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]]
name = "regex-syntax"
version = "0.6.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
[[package]] [[package]]
name = "remove_dir_all" name = "remove_dir_all"
version = "0.5.3" version = "0.5.3"
@ -518,6 +596,18 @@ version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
[[package]]
name = "rusty-fork"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
dependencies = [
"fnv",
"quick-error",
"tempfile",
"wait-timeout",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"
@ -692,6 +782,15 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "walkdir" name = "walkdir"
version = "2.3.1" version = "2.3.1"

View file

@ -27,6 +27,9 @@ thiserror = "1.0"
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
walkdir = "2.3" walkdir = "2.3"
[dev-dependencies]
proptest = "0.10"
[dev-dependencies.cargo-husky] [dev-dependencies.cargo-husky]
version = "1" version = "1"
default-features = false default-features = false

View file

@ -168,3 +168,36 @@ impl<'a> Repository<'a> {
Ok(hasher.finalize()[..].into()) Ok(hasher.finalize()[..].into())
} }
} }
#[cfg(test)]
mod must {
use super::Repository;
use crate::test::source::TempSource;
use anyhow::Result;
use tempfile::tempdir;
#[test]
fn have_size_equal_to_sum_of_sizes_of_backed_up_files() -> Result<()> {
let source = TempSource::new().unwrap();
let repository_path = tempdir().unwrap().into_path();
Repository::init(&repository_path)?;
let file_size1 = 13;
let file_size2 = 27;
let mut backup_repository = Repository::open(&repository_path)?;
source.write_random_bytes_to_file("file1", file_size1)?;
backup_repository.store(&source.file_path("file1"))?;
source.write_random_bytes_to_file("file2", file_size2)?;
backup_repository.store(&source.file_path("file2"))?;
assert_eq!((file_size1 + file_size2) as u64, backup_repository.data_weight()?);
backup_repository.save_index()?;
assert_eq!((file_size1 + file_size2) as u64, backup_repository.data_weight()?);
Ok(())
}
}

View file

@ -33,7 +33,17 @@ pub fn assert_same_after_restore(source_path: &Path) -> Result<()> {
Ok(()) Ok(())
} }
pub fn assert_restored_file_contents(repository_path: &Path, source_file_full_path: &Path, contents: &str) -> Result<()> { pub fn assert_restored_file_contents(repository_path: &Path, source_file_full_path: &Path, contents: &[u8]) -> Result<()> {
let mut restore_repository = Repository::open(repository_path)?;
let item = restore_repository.newest_item_by_source_path(&source_file_full_path)?;
let restore_target = tempdir().unwrap();
let restore_engine = restore::Engine::new(&mut restore_repository, &restore_target.path())?;
restore_engine.restore(&item.unwrap())?;
let restored_file_path = restore_target.path().join(source_file_full_path.strip_prefix("/")?);
assert_target_file_contents(&restored_file_path, contents)
}
pub fn assert_restored_file_byte_contents(repository_path: &Path, source_file_full_path: &Path, contents: &[u8]) -> Result<()> {
let mut restore_repository = Repository::open(repository_path)?; let mut restore_repository = Repository::open(repository_path)?;
let item = restore_repository.newest_item_by_source_path(&source_file_full_path)?; let item = restore_repository.newest_item_by_source_path(&source_file_full_path)?;
let restore_target = tempdir().unwrap(); let restore_target = tempdir().unwrap();
@ -47,7 +57,7 @@ pub fn assert_restored_file_contents(repository_path: &Path, source_file_full_pa
pub fn assert_restored_from_version_has_contents( pub fn assert_restored_from_version_has_contents(
repository_path: &Path, repository_path: &Path,
source_file_full_path: &Path, source_file_full_path: &Path,
old_contents: &str, old_contents: &[u8],
old_id: &ItemId, old_id: &ItemId,
) -> Result<()> { ) -> Result<()> {
let mut restore_repository = Repository::open(repository_path)?; let mut restore_repository = Repository::open(repository_path)?;
@ -78,16 +88,27 @@ pub fn restore_all_from_reloaded_repository(repository_path: &Path, restore_targ
} }
} }
pub fn backup_file_with_contents( pub fn backup_file_with_text_contents(
source: &TempSource, source: &TempSource,
repository_path: &Path, repository_path: &Path,
source_file_relative_path: &str, source_file_relative_path: &str,
contents: &str, contents: &str,
) -> Result<()> {
{
backup_file_with_byte_contents(source, repository_path, source_file_relative_path, contents.as_bytes())
}
}
pub fn backup_file_with_byte_contents(
source: &TempSource,
repository_path: &Path,
source_file_relative_path: &str,
contents: &[u8],
) -> Result<()> { ) -> Result<()> {
{ {
let mut backup_repository = Repository::open(repository_path)?; let mut backup_repository = Repository::open(repository_path)?;
let mut backup_engine = backup::Engine::new(source.path(), &mut backup_repository)?; let mut backup_engine = backup::Engine::new(source.path(), &mut backup_repository)?;
source.write_text_to_file(source_file_relative_path, contents).unwrap(); source.write_bytes_to_file(source_file_relative_path, contents).unwrap();
backup_engine.backup()?; backup_engine.backup()?;
Ok(()) Ok(())
} }
@ -136,13 +157,10 @@ pub fn get_sorted_files_recursively<T: AsRef<Path>>(path: T) -> Result<Vec<Box<P
Ok(result) Ok(result)
} }
fn assert_target_file_contents(restored_path: &Path, expected_contents: &str) -> Result<()> { fn assert_target_file_contents(restored_path: &Path, expected_contents: &[u8]) -> Result<()> {
let mut actual_contents = String::new(); let mut actual_contents = vec![];
assert!(restored_path.exists(), "Expected '{}' to be there", restored_path.display()); assert!(restored_path.exists(), "Expected '{}' to be there", restored_path.display());
File::open(restored_path) File::open(restored_path)?.read_to_end(&mut actual_contents)?;
.unwrap()
.read_to_string(&mut actual_contents)
.unwrap();
assert_eq!(expected_contents, actual_contents); assert_eq!(expected_contents, actual_contents);
Ok(()) Ok(())
} }

View file

@ -25,6 +25,12 @@ impl TempSource {
self.write_bytes_to_file(filename, text.as_bytes()) self.write_bytes_to_file(filename, text.as_bytes())
} }
pub fn write_random_bytes_to_file(&self, filename: &str, size: usize) -> Result<(), Error> {
let random_bytes: Vec<u8> = (0..size).map(|_| rand::random::<u8>()).collect();
self.write_bytes_to_file(filename, &random_bytes)?;
Ok(())
}
pub fn path(&self) -> &Path { pub fn path(&self) -> &Path {
self.directory.path() self.directory.path()
} }

View file

@ -5,6 +5,8 @@ use bakare::backup;
use bakare::repository::Repository; use bakare::repository::Repository;
use bakare::test::{assertions::*, source::TempSource}; use bakare::test::{assertions::*, source::TempSource};
use proptest::prelude::*;
#[test] #[test]
fn restore_multiple_files() -> Result<()> { fn restore_multiple_files() -> Result<()> {
let source = TempSource::new().unwrap(); let source = TempSource::new().unwrap();
@ -26,12 +28,12 @@ fn restore_files_after_reopening_repository() -> Result<()> {
let source_file_relative_path = "some file path"; let source_file_relative_path = "some file path";
let original_contents = "some old contents"; let original_contents = "some old contents";
backup_file_with_contents(&source, &repository_path, source_file_relative_path, original_contents)?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, original_contents)?;
restore_all_from_reloaded_repository(&repository_path, &restore_target)?; restore_all_from_reloaded_repository(&repository_path, &restore_target)?;
let source_file_full_path = &source.file_path(source_file_relative_path); let source_file_full_path = &source.file_path(source_file_relative_path);
assert_restored_file_contents(repository_path, source_file_full_path, original_contents) assert_restored_file_contents(repository_path, source_file_full_path, original_contents.as_bytes())
} }
#[test] #[test]
@ -44,15 +46,15 @@ fn restore_older_version_of_file() -> Result<()> {
let source_file_full_path = source.file_path(source_file_relative_path); let source_file_full_path = source.file_path(source_file_relative_path);
let old_contents = "some old contents"; let old_contents = "some old contents";
backup_file_with_contents(&source, &repository_path, source_file_relative_path, old_contents)?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, old_contents)?;
let old_item = newest_item(&repository_path, &source_file_full_path)?; let old_item = newest_item(&repository_path, &source_file_full_path)?;
let old_id = old_item.id(); let old_id = old_item.id();
let new_contents = "totally new contents"; let new_contents = "totally new contents";
backup_file_with_contents(&source, &repository_path, source_file_relative_path, new_contents)?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, new_contents)?;
assert_restored_from_version_has_contents(&repository_path, &source_file_full_path, old_contents, &old_id) assert_restored_from_version_has_contents(&repository_path, &source_file_full_path, old_contents.as_bytes(), &old_id)
} }
#[test] #[test]
@ -64,12 +66,12 @@ fn newer_version_should_be_greater_than_earlier_version() -> Result<()> {
let source_file_relative_path = "some path"; let source_file_relative_path = "some path";
let source_file_full_path = source.file_path(source_file_relative_path); let source_file_full_path = source.file_path(source_file_relative_path);
backup_file_with_contents(&source, &repository_path, source_file_relative_path, "old")?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, "old")?;
let old_item = newest_item(&repository_path, &source_file_full_path)?; let old_item = newest_item(&repository_path, &source_file_full_path)?;
let old_version = old_item.version(); let old_version = old_item.version();
backup_file_with_contents(&source, &repository_path, source_file_relative_path, "new")?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, "new")?;
let new_item = newest_item(&repository_path, &source_file_full_path)?; let new_item = newest_item(&repository_path, &source_file_full_path)?;
let new_version = new_item.version(); let new_version = new_item.version();
@ -79,26 +81,25 @@ fn newer_version_should_be_greater_than_earlier_version() -> Result<()> {
Ok(()) Ok(())
} }
#[test] proptest! {
fn store_duplicated_files_just_once() -> Result<()> { #[test]
fn store_duplicated_files_just_once(contents in any::<[u8;3]>()) {
let source = TempSource::new().unwrap(); let source = TempSource::new().unwrap();
let repository_path = &tempdir().unwrap().into_path(); let repository_path = &tempdir().unwrap().into_path();
Repository::init(repository_path)?; Repository::init(repository_path).unwrap();
assert_eq!(data_weight(&repository_path)?, 0); assert_eq!(data_weight(&repository_path).unwrap(), 0);
let contents = "some contents"; backup_file_with_byte_contents(&source, &repository_path, "1", &contents).unwrap();
let first_weight = data_weight(&repository_path).unwrap();
backup_file_with_contents(&source, &repository_path, "1", contents)?;
let first_weight = data_weight(&repository_path)?;
assert!(first_weight > 0); assert!(first_weight > 0);
backup_file_with_contents(&source, &repository_path, "2", contents)?; backup_file_with_byte_contents(&source, &repository_path, "2", &contents).unwrap();
let second_weight = data_weight(&repository_path)?; let second_weight = data_weight(&repository_path).unwrap();
assert_eq!(first_weight, second_weight); assert_eq!(first_weight, second_weight);
assert_restored_file_contents(repository_path, &source.file_path("1"), contents)?; assert_restored_file_contents(repository_path, &source.file_path("1"), &contents).unwrap();
assert_restored_file_contents(repository_path, &source.file_path("2"), contents)?; assert_restored_file_contents(repository_path, &source.file_path("2"), &contents).unwrap();
Ok(()) }
} }
#[test] #[test]
@ -108,12 +109,12 @@ fn restore_latest_version_by_default() -> Result<()> {
Repository::init(repository_path)?; Repository::init(repository_path)?;
let source_file_relative_path = "some path"; let source_file_relative_path = "some path";
backup_file_with_contents(&source, &repository_path, source_file_relative_path, "old contents")?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, "old contents")?;
backup_file_with_contents(&source, &repository_path, source_file_relative_path, "newer contents")?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, "newer contents")?;
backup_file_with_contents(&source, &repository_path, source_file_relative_path, "newest contents")?; backup_file_with_text_contents(&source, &repository_path, source_file_relative_path, "newest contents")?;
let source_file_full_path = &source.file_path(source_file_relative_path); let source_file_full_path = &source.file_path(source_file_relative_path);
assert_restored_file_contents(repository_path, source_file_full_path, "newest contents") assert_restored_file_contents(repository_path, source_file_full_path, "newest contents".as_bytes())
} }
#[test] #[test]