From 9b7edb563f12bc5a83f0108c0406b013e95f0e7f Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:36:06 +0100 Subject: [PATCH 1/3] tests: refactor integration tests to assert_cmd and predicates Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com> --- Cargo.lock | 81 ++++++++++++++++++ Cargo.toml | 4 +- tests/backup_restore.rs | 176 ++++++++++++++-------------------------- 3 files changed, 146 insertions(+), 115 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4ae78b34b..67b72a9d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,6 +196,21 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" +[[package]] +name = "assert_cmd" +version = "2.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467" +dependencies = [ + "anstyle", + "bstr", + "doc-comment", + "predicates", + "predicates-core", + "predicates-tree", + "wait-timeout", +] + [[package]] name = "async-trait" version = "0.1.77" @@ -331,6 +346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" dependencies = [ "memchr", + "regex-automata 0.4.5", "serde", ] @@ -953,6 +969,12 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.10.7" @@ -1027,6 +1049,12 @@ dependencies = [ "const-random", ] +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + [[package]] name = "dunce" version = "1.0.4" @@ -1184,6 +1212,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1938,6 +1975,12 @@ dependencies = [ "libc", ] +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2401,6 +2444,36 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "difflib", + "float-cmp", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -2844,6 +2917,7 @@ dependencies = [ "abscissa_core", "aho-corasick", "anyhow", + "assert_cmd", "bytesize", "chrono", "clap", @@ -2864,6 +2938,7 @@ dependencies = [ "merge", "mimalloc", "once_cell", + "predicates", "pretty_assertions", "quickcheck", "quickcheck_macros", @@ -3625,6 +3700,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "thin-vec" version = "0.2.13" diff --git a/Cargo.toml b/Cargo.toml index b4ba9fc20..a757cdcfd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,7 +89,9 @@ self_update = { version = "0.39", default-features = false, optional = true, fea [dev-dependencies] abscissa_core = { version = "0.7.0", default-features = false, features = ["testing"] } +assert_cmd = "2.0.13" dircmp = "0.2" +predicates = "3.1.0" pretty_assertions = "1.4" quickcheck = "1" quickcheck_macros = "1" @@ -100,8 +102,6 @@ toml = "0.8" [target.'cfg(not(windows))'.dependencies] libc = "0.2.153" - -[workspace.dependencies] # cargo-binstall support # https://github.com/cargo-bins/cargo-binstall/blob/HEAD/SUPPORT.md [package.metadata.binstall] diff --git a/tests/backup_restore.rs b/tests/backup_restore.rs index b701a384b..4eeae4248 100644 --- a/tests/backup_restore.rs +++ b/tests/backup_restore.rs @@ -7,49 +7,39 @@ //! You can run them with 'nextest': //! `cargo nextest run -E 'test(backup)'`. -use abscissa_core::testing::prelude::CmdRunner; -use aho_corasick::PatternID; use dircmp::Comparison; -use pretty_assertions::assert_eq; -use std::io::Read; use tempfile::{tempdir, TempDir}; -use rustic_testing::{get_matches, TestResult}; +use assert_cmd::Command; +use predicates::prelude::{predicate, PredicateBooleanExt}; -pub fn rustic_runner(temp_dir: &TempDir) -> CmdRunner { +use rustic_testing::TestResult; + +pub fn rustic_runner(temp_dir: &TempDir) -> TestResult { let password = "test"; let repo_dir = temp_dir.path().join("repo"); - let mut runner = CmdRunner::new(env!("CARGO_BIN_EXE_rustic")); + + let mut runner = Command::new(env!("CARGO_BIN_EXE_rustic")); + runner .arg("-r") .arg(repo_dir) .arg("--password") .arg(password) - .arg("--no-progress") - .capture_stdout() - .capture_stderr(); - runner + .arg("--no-progress"); + + Ok(runner) } fn setup() -> TestResult { let temp_dir = tempdir()?; - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.args(["init"]).run(); - - let mut stdout = String::new(); - let mut stderr = String::new(); - cmd.stdout().read_to_string(&mut stdout)?; - cmd.stderr().read_to_string(&mut stderr)?; - - let patterns = &["successfully added.", "successfully created."]; - let matches = get_matches(patterns, stderr)?; - - assert_eq!( - matches, - vec![(PatternID::must(0), 19), (PatternID::must(1), 21),] - ); + rustic_runner(&temp_dir)? + .args(["init"]) + .assert() + .success() + .stderr(predicate::str::contains("successfully created.")) + .stderr(predicate::str::contains("successfully added.")); - cmd.wait()?.expect_success(); Ok(temp_dir) } @@ -60,81 +50,51 @@ fn test_backup_and_check_passes() -> TestResult<()> { { // Run `backup` for the first time - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.arg("backup").arg(backup).run(); - - let mut output = String::new(); - cmd.stdout().read_to_string(&mut output)?; - - let patterns = &["successfully saved."]; - let matches = get_matches(patterns, output)?; - - assert_eq!(matches, vec![(PatternID::must(0), 19)]); - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .arg("backup") + .arg(backup) + .assert() + .success() + .stdout(predicate::str::contains("successfully saved.")); } { // Run `snapshots` - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.arg("snapshots").run(); - let mut output = String::new(); - cmd.stdout().read_to_string(&mut output)?; - - let patterns = &["total: 1 snapshot(s)"]; - let matches = get_matches(patterns, output)?; - - assert_eq!(matches, vec![(PatternID::must(0), 20)]); - - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .arg("snapshots") + .assert() + .success() + .stdout(predicate::str::contains("total: 1 snapshot(s)")); } { // Run `backup` a second time - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.arg("backup").arg(backup).run(); - - let mut output = String::new(); - cmd.stdout().read_to_string(&mut output)?; - - let patterns = &["Added to the repo: 0 B", "successfully saved."]; - let matches = get_matches(patterns, output)?; - - assert_eq!( - matches, - vec![(PatternID::must(0), 22), (PatternID::must(1), 19)] - ); - - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .arg("backup") + .arg(backup) + .assert() + .success() + .stdout(predicate::str::contains("Added to the repo: 0 B")) + .stdout(predicate::str::contains("successfully saved.")); } { // Run `snapshots` a second time - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.arg("snapshots").run(); - let mut output = String::new(); - cmd.stdout().read_to_string(&mut output)?; - - let patterns = &["total: 2 snapshot(s)"]; - let matches = get_matches(patterns, output)?; - - assert_eq!(matches, vec![(PatternID::must(0), 20)]); - - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .arg("snapshots") + .assert() + .success() + .stdout(predicate::str::contains("total: 2 snapshot(s)")); } { // Run `check --read-data` - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.args(["check", "--read-data"]).run(); - let mut output = String::new(); - cmd.stderr().read_to_string(&mut output)?; - - let patterns = &["WARN", "ERROR"]; - let matches = get_matches(patterns, output)?; - - assert_eq!(matches.len(), 0); - - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .args(["check", "--read-data"]) + .assert() + .success() + .stdout(predicate::str::contains("WARN").not()) + .stdout(predicate::str::contains("ERROR").not()); } Ok(()) @@ -147,41 +107,31 @@ fn test_backup_and_restore_passes() -> TestResult<()> { let backup = "src/"; // actual repository root to backup - let current_dir = std::env::current_dir()?; - let backup_files = current_dir.join(backup); + let backup_files = std::env::current_dir()?.join(backup); { // Run `backup` for the first time - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.arg("backup").arg(&backup_files).run(); - - let mut output = String::new(); - cmd.stdout().read_to_string(&mut output)?; - - let patterns = &["successfully saved."]; - let matches = get_matches(patterns, output)?; - - assert_eq!(matches, vec![(PatternID::must(0), 19)]); - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .arg("backup") + .arg(&backup_files) + .assert() + .success() + .stdout(predicate::str::contains("successfully saved.")); } { // Run `restore` - let mut runner = rustic_runner(&temp_dir); - let mut cmd = runner.arg("restore").arg("latest").arg(&restore_dir).run(); - - let mut output = String::new(); - cmd.stdout().read_to_string(&mut output)?; - - let patterns = &["restore done"]; - let matches = get_matches(patterns, output)?; - - assert_eq!(matches, vec![(PatternID::must(0), 12)]); - cmd.wait()?.expect_success(); + rustic_runner(&temp_dir)? + .arg("restore") + .arg("latest") + .arg(&restore_dir) + .assert() + .success() + .stdout(predicate::str::contains("restore done")); } - let comparison = Comparison::default(); - let compare_result = comparison.compare(&backup_files, &restore_dir.join(&backup_files))?; - dbg!(&compare_result); + // Compare the backup and the restored directory + let compare_result = + Comparison::default().compare(&backup_files, &restore_dir.join(&backup_files))?; // no differences assert!(compare_result.is_empty()); From 586e0f06246962ddf1266ece6791fefde4543059 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 11 Feb 2024 22:51:33 +0100 Subject: [PATCH 2/3] tests: test all config files in config subdirectory Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com> --- tests/config.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/config.rs b/tests/config.rs index b2da6b823..1741c71ed 100644 --- a/tests/config.rs +++ b/tests/config.rs @@ -7,7 +7,9 @@ use std::{fs, path::PathBuf}; /// Ensure all `configs` parse as a valid config files #[rstest] -fn test_parse_rustic_configs_is_ok(#[files("config/*.toml")] config_path: PathBuf) -> Result<()> { +fn test_parse_rustic_configs_is_ok( + #[files("config/**/*.toml")] config_path: PathBuf, +) -> Result<()> { let toml_string = fs::read_to_string(config_path)?; let _ = toml::from_str::(&toml_string)?; From 527d7ef3b285074df3def3fe2a4847c1fa6f3507 Mon Sep 17 00:00:00 2001 From: simonsan <14062932+simonsan@users.noreply.github.com> Date: Sun, 11 Feb 2024 23:19:50 +0100 Subject: [PATCH 3/3] fix: typo Signed-off-by: simonsan <14062932+simonsan@users.noreply.github.com> --- tests/backup_restore.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/backup_restore.rs b/tests/backup_restore.rs index 4eeae4248..0beaf5b66 100644 --- a/tests/backup_restore.rs +++ b/tests/backup_restore.rs @@ -93,8 +93,8 @@ fn test_backup_and_check_passes() -> TestResult<()> { .args(["check", "--read-data"]) .assert() .success() - .stdout(predicate::str::contains("WARN").not()) - .stdout(predicate::str::contains("ERROR").not()); + .stderr(predicate::str::contains("WARN").not()) + .stderr(predicate::str::contains("ERROR").not()); } Ok(())