From 16190f0f9aa7c2098ce131c6e0f1f206bece716d Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai Date: Tue, 20 Jul 2021 17:37:55 +0800 Subject: [PATCH] [tests] Pull out common submodules New modules: fixture, process, program, target, and thin --- tests/cache_check.rs | 7 +- tests/cache_dump.rs | 6 +- tests/common/common_args.rs | 6 +- tests/common/fixture.rs | 69 +++++++ tests/common/input_arg.rs | 10 +- tests/common/mod.rs | 379 +--------------------------------- tests/common/output_option.rs | 8 +- tests/common/process.rs | 71 +++++++ tests/common/program.rs | 43 ++++ tests/common/target.rs | 79 +++++++ tests/common/thin.rs | 135 ++++++++++++ tests/thin_check.rs | 6 +- tests/thin_delta.rs | 5 +- tests/thin_dump.rs | 6 +- tests/thin_metadata_pack.rs | 4 +- tests/thin_metadata_unpack.rs | 6 +- tests/thin_repair.rs | 6 +- tests/thin_restore.rs | 6 +- tests/thin_rmap.rs | 5 +- 19 files changed, 469 insertions(+), 388 deletions(-) create mode 100644 tests/common/fixture.rs create mode 100644 tests/common/process.rs create mode 100644 tests/common/program.rs create mode 100644 tests/common/target.rs create mode 100644 tests/common/thin.rs diff --git a/tests/cache_check.rs b/tests/cache_check.rs index 6b6b668..f73c7ae 100644 --- a/tests/cache_check.rs +++ b/tests/cache_check.rs @@ -3,9 +3,12 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::fixture::*; use common::input_arg::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; //------------------------------------------ @@ -48,7 +51,7 @@ impl<'a> Program<'a> for CacheCheck { impl<'a> InputProgram<'a> for CacheCheck { fn mk_valid_input(td: &mut TestDir) -> Result { - mk_valid_md(td) + common::thin::mk_valid_md(td) // FIXME: create cache metadata } fn file_not_found() -> &'a str { diff --git a/tests/cache_dump.rs b/tests/cache_dump.rs index 365d69b..f1b0f25 100644 --- a/tests/cache_dump.rs +++ b/tests/cache_dump.rs @@ -4,8 +4,10 @@ mod common; use common::common_args::*; use common::input_arg::*; + +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; //------------------------------------------ @@ -44,7 +46,7 @@ impl<'a> Program<'a> for CacheDump { impl<'a> InputProgram<'a> for CacheDump { fn mk_valid_input(td: &mut TestDir) -> Result { - mk_valid_md(td) + common::thin::mk_valid_md(td) // FIXME: generate cache metadata } fn file_not_found() -> &'a str { diff --git a/tests/common/common_args.rs b/tests/common/common_args.rs index 41387df..095e74b 100644 --- a/tests/common/common_args.rs +++ b/tests/common/common_args.rs @@ -1,6 +1,10 @@ -use crate::common::*; +use anyhow::Result; + use thinp::version::tools_version; +use crate::common::process::*; +use crate::common::program::*; + //------------------------------------------ // help diff --git a/tests/common/fixture.rs b/tests/common/fixture.rs new file mode 100644 index 0000000..2ddc82d --- /dev/null +++ b/tests/common/fixture.rs @@ -0,0 +1,69 @@ +use anyhow::Result; +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::path::PathBuf; + +use thinp::file_utils; + +use crate::common::test_dir::TestDir; + +//------------------------------------------ + +pub fn mk_zeroed_md(td: &mut TestDir) -> Result { + let md = td.mk_path("meta.bin"); + eprintln!("path = {:?}", md); + let _file = file_utils::create_sized_file(&md, 1024 * 1024 * 16); + Ok(md) +} + +pub fn damage_superblock(path: &PathBuf) -> Result<()> { + let mut output = OpenOptions::new().read(false).write(true).open(path)?; + let buf = [0u8; 512]; + output.write_all(&buf)?; + Ok(()) +} + +//------------------------------------------ + +pub fn md5(md: &PathBuf) -> Result { + let output = duct::cmd!("md5sum", "-b", &md).stdout_capture().run()?; + let csum = std::str::from_utf8(&output.stdout[0..])?.to_string(); + let csum = csum.split_ascii_whitespace().next().unwrap().to_string(); + Ok(csum) +} + +// This checksums the file before and after the thunk is run to +// ensure it is unchanged. +pub fn ensure_untouched(p: &PathBuf, thunk: F) -> Result<()> +where + F: Fn() -> Result<()>, +{ + let csum = md5(p)?; + thunk()?; + assert_eq!(csum, md5(p)?); + Ok(()) +} + +pub fn superblock_all_zeroes(path: &PathBuf) -> Result { + let mut input = OpenOptions::new().read(true).write(false).open(path)?; + let mut buf = vec![0; 4096]; + input.read_exact(&mut buf[0..])?; + for b in buf { + if b != 0 { + return Ok(false); + } + } + + Ok(true) +} + +pub fn ensure_superblock_zeroed(p: &PathBuf, thunk: F) -> Result<()> +where + F: Fn() -> Result<()>, +{ + thunk()?; + assert!(superblock_all_zeroes(p)?); + Ok(()) +} + +//------------------------------------------ diff --git a/tests/common/input_arg.rs b/tests/common/input_arg.rs index 20feac4..6b3e00f 100644 --- a/tests/common/input_arg.rs +++ b/tests/common/input_arg.rs @@ -1,5 +1,11 @@ +use anyhow::Result; +use thinp::file_utils; + +use crate::common::fixture::*; +use crate::common::process::*; +use crate::common::program::*; +use crate::common::test_dir::*; use crate::common::thin_xml_generator::{write_xml, FragmentedS}; -use crate::common::*; //------------------------------------------ // wrappers @@ -148,7 +154,7 @@ where let mut td = TestDir::new()?; // input an unreadable file - let input = mk_valid_md(&mut td)?; + let input = P::mk_valid_input(&mut td)?; duct::cmd!("chmod", "-r", &input).run()?; let wrapper = build_args_fn(P::arg_type())?; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index e9dffd8..a8e1717 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,380 +1,15 @@ +// suppress all the false alarms by cargo test +// https://github.com/rust-lang/rust/issues/46379 #![allow(dead_code)] -use anyhow::Result; -use std::ffi::{OsStr, OsString}; -use std::fs::OpenOptions; -use std::io::{Read, Write}; -use std::path::PathBuf; - -use thinp::file_utils; -use thinp::io_engine::*; - pub mod cache_xml_generator; pub mod common_args; +pub mod fixture; pub mod input_arg; pub mod output_option; +pub mod process; +pub mod program; +pub mod target; pub mod test_dir; +pub mod thin; pub mod thin_xml_generator; - -use crate::common::thin_xml_generator::{write_xml, SingleThinS}; -use test_dir::TestDir; - -//------------------------------------------ - -pub mod cpp_msg { - pub const FILE_NOT_FOUND: &str = "No such file or directory"; - pub const MISSING_INPUT_ARG: &str = "No input file provided"; - pub const MISSING_OUTPUT_ARG: &str = "No output file provided"; - pub const BAD_SUPERBLOCK: &str = "bad checksum in superblock"; - - pub fn bad_option_hint(option: &str) -> String { - format!("unrecognized option '{}'", option) - } -} - -pub mod rust_msg { - pub const FILE_NOT_FOUND: &str = "Couldn't find input file"; - pub const MISSING_INPUT_ARG: &str = "The following required arguments were not provided"; // TODO: be specific - pub const MISSING_OUTPUT_ARG: &str = "The following required arguments were not provided"; // TODO: be specific - pub const BAD_SUPERBLOCK: &str = "bad checksum in superblock"; - - pub fn bad_option_hint(option: &str) -> String { - format!("Found argument '{}' which wasn't expected", option) - } -} - -#[cfg(not(feature = "rust_tests"))] -pub use cpp_msg as msg; -#[cfg(feature = "rust_tests")] -pub use rust_msg as msg; - -//------------------------------------------ - -#[macro_export] -macro_rules! path_to_cpp { - ($name: literal) => { - concat!("bin/", $name) - }; -} - -#[macro_export] -macro_rules! path_to_rust { - ($name: literal) => { - env!(concat!("CARGO_BIN_EXE_", $name)) - }; -} - -#[cfg(not(feature = "rust_tests"))] -#[macro_export] -macro_rules! path_to { - ($name: literal) => { - path_to_cpp!($name) - }; -} - -#[cfg(feature = "rust_tests")] -#[macro_export] -macro_rules! path_to { - ($name: literal) => { - path_to_rust!($name) - }; -} - -//------------------------------------------ - -pub const CACHE_CHECK: &str = path_to!("cache_check"); -pub const CACHE_DUMP: &str = path_to!("cache_dump"); - -pub const THIN_CHECK: &str = path_to!("thin_check"); -pub const THIN_DELTA: &str = path_to_cpp!("thin_delta"); // TODO: rust version -pub const THIN_DUMP: &str = path_to!("thin_dump"); -pub const THIN_METADATA_PACK: &str = path_to_rust!("thin_metadata_pack"); // rust-only -pub const THIN_METADATA_UNPACK: &str = path_to_rust!("thin_metadata_unpack"); // rust-only -pub const THIN_REPAIR: &str = path_to_cpp!("thin_repair"); // TODO: rust version -pub const THIN_RESTORE: &str = path_to!("thin_restore"); -pub const THIN_RMAP: &str = path_to_cpp!("thin_rmap"); // TODO: rust version -pub const THIN_GENERATE_METADATA: &str = path_to_cpp!("thin_generate_metadata"); // cpp-only -pub const THIN_GENERATE_MAPPINGS: &str = path_to_cpp!("thin_generate_mappings"); // cpp-only -pub const THIN_GENERATE_DAMAGE: &str = path_to_cpp!("thin_generate_damage"); // cpp-only - -//------------------------------------------ - -pub enum ArgType { - InputArg, - IoOptions, -} - -pub trait Program<'a> { - fn name() -> &'a str; - fn path() -> &'a OsStr; - fn usage() -> &'a str; - fn arg_type() -> ArgType; - - // error messages - fn bad_option_hint(option: &str) -> String; -} - -pub trait InputProgram<'a>: Program<'a> { - fn mk_valid_input(td: &mut TestDir) -> Result; - - // error messages - fn missing_input_arg() -> &'a str; - fn file_not_found() -> &'a str; - fn corrupted_input() -> &'a str; -} - -pub trait BinaryInputProgram<'a>: InputProgram<'a> {} - -pub trait OutputProgram<'a>: InputProgram<'a> { - // error messages - fn missing_output_arg() -> &'a str; - fn file_not_found() -> &'a str; -} - -pub trait BinaryOutputProgram<'a>: OutputProgram<'a> {} - -//------------------------------------------ - -// Returns stdout. The command must return zero. -pub fn run_ok(program: S, args: I) -> Result -where - S: AsRef, - I: IntoIterator, - I::Item: Into, -{ - let command = duct::cmd(program.as_ref(), args) - .stdout_capture() - .stderr_capture(); - let output = command.run()?; - assert!(output.status.success()); - let stdout = std::str::from_utf8(&output.stdout[..]) - .unwrap() - .trim_end_matches(|c| c == '\n' || c == '\r') - .to_string(); - Ok(stdout) -} - -// Returns the entire output. The command must return zero. -pub fn run_ok_raw(program: S, args: I) -> Result -where - S: AsRef, - I: IntoIterator, - I::Item: Into, -{ - let command = duct::cmd(program.as_ref(), args) - .stdout_capture() - .stderr_capture(); - let output = command.run()?; - assert!(output.status.success()); - Ok(output) -} - -// Returns stderr, a non zero status must be returned -pub fn run_fail(program: S, args: I) -> Result -where - S: AsRef, - I: IntoIterator, - I::Item: Into, -{ - let command = duct::cmd(program.as_ref(), args) - .stdout_capture() - .stderr_capture(); - let output = command.unchecked().run()?; - assert!(!output.status.success()); - let stderr = std::str::from_utf8(&output.stderr[..]).unwrap().to_string(); - Ok(stderr) -} - -// Returns the entire output, a non zero status must be returned -pub fn run_fail_raw(program: S, args: I) -> Result -where - S: AsRef, - I: IntoIterator, - I::Item: Into, -{ - let command = duct::cmd(program.as_ref(), args) - .stdout_capture() - .stderr_capture(); - let output = command.unchecked().run()?; - assert!(!output.status.success()); - Ok(output) -} - -//------------------------------------------ - -pub fn mk_valid_xml(td: &mut TestDir) -> Result { - let xml = td.mk_path("meta.xml"); - let mut gen = SingleThinS::new(0, 1024, 2048, 2048); - write_xml(&xml, &mut gen)?; - Ok(xml) -} - -pub fn mk_valid_md(td: &mut TestDir) -> Result { - let xml = td.mk_path("meta.xml"); - let md = td.mk_path("meta.bin"); - - let mut gen = SingleThinS::new(0, 1024, 20480, 20480); - write_xml(&xml, &mut gen)?; - - let _file = file_utils::create_sized_file(&md, 4096 * 4096); - let args = ["-i", xml.to_str().unwrap(), "-o", md.to_str().unwrap()]; - run_ok(THIN_RESTORE, &args)?; - - Ok(md) -} - -pub fn mk_zeroed_md(td: &mut TestDir) -> Result { - let md = td.mk_path("meta.bin"); - eprintln!("path = {:?}", md); - let _file = file_utils::create_sized_file(&md, 1024 * 1024 * 16); - Ok(md) -} - -pub fn superblock_all_zeroes(path: &PathBuf) -> Result { - let mut input = OpenOptions::new().read(true).write(false).open(path)?; - let mut buf = vec![0; 4096]; - input.read_exact(&mut buf[0..])?; - for b in buf { - if b != 0 { - return Ok(false); - } - } - - Ok(true) -} - -pub fn damage_superblock(path: &PathBuf) -> Result<()> { - let mut output = OpenOptions::new().read(false).write(true).open(path)?; - let buf = [0u8; 512]; - output.write_all(&buf)?; - Ok(()) -} - -//----------------------------------------------- - -// FIXME: replace mk_valid_md with this? -pub fn prep_metadata(td: &mut TestDir) -> Result { - let md = mk_zeroed_md(td)?; - let args = [ - "-o", - md.to_str().unwrap(), - "--format", - "--nr-data-blocks", - "102400", - ]; - run_ok(THIN_GENERATE_METADATA, &args)?; - - // Create a 2GB device - let args = ["-o", md.to_str().unwrap(), "--create-thin", "1"]; - run_ok(THIN_GENERATE_METADATA, &args)?; - let args = [ - "-o", - md.to_str().unwrap(), - "--dev-id", - "1", - "--size", - "2097152", - "--rw=randwrite", - "--seq-nr=16", - ]; - run_ok(THIN_GENERATE_MAPPINGS, &args)?; - - // Take a few snapshots. - let mut snap_id = 2; - for _i in 0..10 { - // take a snapshot - let args = [ - "-o", - md.to_str().unwrap(), - "--create-snap", - &snap_id.to_string(), - "--origin", - "1", - ]; - run_ok(THIN_GENERATE_METADATA, &args)?; - - // partially overwrite the origin (64MB) - let args = [ - "-o", - md.to_str().unwrap(), - "--dev-id", - "1", - "--size", - "2097152", - "--io-size", - "131072", - "--rw=randwrite", - "--seq-nr=16", - ]; - run_ok(THIN_GENERATE_MAPPINGS, &args)?; - snap_id += 1; - } - - Ok(md) -} - -pub fn set_needs_check(md: &PathBuf) -> Result<()> { - let args = ["-o", md.to_str().unwrap(), "--set-needs-check"]; - run_ok(THIN_GENERATE_METADATA, &args)?; - Ok(()) -} - -pub fn generate_metadata_leaks( - md: &PathBuf, - nr_blocks: u64, - expected: u32, - actual: u32, -) -> Result<()> { - let args = [ - "-o", - md.to_str().unwrap(), - "--create-metadata-leaks", - "--nr-blocks", - &nr_blocks.to_string(), - "--expected", - &expected.to_string(), - "--actual", - &actual.to_string(), - ]; - run_ok(THIN_GENERATE_DAMAGE, &args)?; - - Ok(()) -} - -pub fn get_needs_check(md: &PathBuf) -> Result { - use thinp::thin::superblock::*; - - let engine = SyncIoEngine::new(&md, 1, false)?; - let sb = read_superblock(&engine, SUPERBLOCK_LOCATION)?; - Ok(sb.flags.needs_check) -} - -pub fn md5(md: &PathBuf) -> Result { - let output = duct::cmd!("md5sum", "-b", &md).stdout_capture().run()?; - let csum = std::str::from_utf8(&output.stdout[0..])?.to_string(); - let csum = csum.split_ascii_whitespace().next().unwrap().to_string(); - Ok(csum) -} - -// This checksums the file before and after the thunk is run to -// ensure it is unchanged. -pub fn ensure_untouched(p: &PathBuf, thunk: F) -> Result<()> -where - F: Fn() -> Result<()>, -{ - let csum = md5(p)?; - thunk()?; - assert_eq!(csum, md5(p)?); - Ok(()) -} - -pub fn ensure_superblock_zeroed(p: &PathBuf, thunk: F) -> Result<()> -where - F: Fn() -> Result<()>, -{ - thunk()?; - assert!(superblock_all_zeroes(p)?); - Ok(()) -} - -//------------------------------------------ diff --git a/tests/common/output_option.rs b/tests/common/output_option.rs index a5e5e7b..8cd2da1 100644 --- a/tests/common/output_option.rs +++ b/tests/common/output_option.rs @@ -1,4 +1,10 @@ -use crate::common::*; +use anyhow::Result; + +use thinp::file_utils; + +use crate::common::process::*; +use crate::common::program::*; +use crate::common::test_dir::*; //----------------------------------------- // test invalid arguments diff --git a/tests/common/process.rs b/tests/common/process.rs new file mode 100644 index 0000000..c87e2bc --- /dev/null +++ b/tests/common/process.rs @@ -0,0 +1,71 @@ +use anyhow::Result; +use std::ffi::{OsStr, OsString}; + +//------------------------------------------ + +// Returns stdout. The command must return zero. +pub fn run_ok(program: S, args: I) -> Result +where + S: AsRef, + I: IntoIterator, + I::Item: Into, +{ + let command = duct::cmd(program.as_ref(), args) + .stdout_capture() + .stderr_capture(); + let output = command.run()?; + assert!(output.status.success()); + let stdout = std::str::from_utf8(&output.stdout[..]) + .unwrap() + .trim_end_matches(|c| c == '\n' || c == '\r') + .to_string(); + Ok(stdout) +} + +// Returns the entire output. The command must return zero. +pub fn run_ok_raw(program: S, args: I) -> Result +where + S: AsRef, + I: IntoIterator, + I::Item: Into, +{ + let command = duct::cmd(program.as_ref(), args) + .stdout_capture() + .stderr_capture(); + let output = command.run()?; + assert!(output.status.success()); + Ok(output) +} + +// Returns stderr, a non zero status must be returned +pub fn run_fail(program: S, args: I) -> Result +where + S: AsRef, + I: IntoIterator, + I::Item: Into, +{ + let command = duct::cmd(program.as_ref(), args) + .stdout_capture() + .stderr_capture(); + let output = command.unchecked().run()?; + assert!(!output.status.success()); + let stderr = std::str::from_utf8(&output.stderr[..]).unwrap().to_string(); + Ok(stderr) +} + +// Returns the entire output, a non zero status must be returned +pub fn run_fail_raw(program: S, args: I) -> Result +where + S: AsRef, + I: IntoIterator, + I::Item: Into, +{ + let command = duct::cmd(program.as_ref(), args) + .stdout_capture() + .stderr_capture(); + let output = command.unchecked().run()?; + assert!(!output.status.success()); + Ok(output) +} + +//------------------------------------------ diff --git a/tests/common/program.rs b/tests/common/program.rs new file mode 100644 index 0000000..51b63e9 --- /dev/null +++ b/tests/common/program.rs @@ -0,0 +1,43 @@ +use anyhow::Result; +use std::ffi::OsStr; +use std::path::PathBuf; + +use crate::common::test_dir::TestDir; + +//------------------------------------------ + +pub enum ArgType { + InputArg, + IoOptions, +} + +pub trait Program<'a> { + fn name() -> &'a str; + fn path() -> &'a OsStr; + fn usage() -> &'a str; + fn arg_type() -> ArgType; + + // error messages + fn bad_option_hint(option: &str) -> String; +} + +pub trait InputProgram<'a>: Program<'a> { + fn mk_valid_input(td: &mut TestDir) -> Result; + + // error messages + fn missing_input_arg() -> &'a str; + fn file_not_found() -> &'a str; + fn corrupted_input() -> &'a str; +} + +pub trait BinaryInputProgram<'a>: InputProgram<'a> {} + +pub trait OutputProgram<'a>: InputProgram<'a> { + // error messages + fn missing_output_arg() -> &'a str; + fn file_not_found() -> &'a str; +} + +pub trait BinaryOutputProgram<'a>: OutputProgram<'a> {} + +//------------------------------------------ diff --git a/tests/common/target.rs b/tests/common/target.rs new file mode 100644 index 0000000..65885bc --- /dev/null +++ b/tests/common/target.rs @@ -0,0 +1,79 @@ +//------------------------------------------ + +#[macro_export] +macro_rules! path_to_cpp { + ($name: literal) => { + concat!("bin/", $name) + }; +} + +#[macro_export] +macro_rules! path_to_rust { + ($name: literal) => { + env!(concat!("CARGO_BIN_EXE_", $name)) + }; +} + +#[cfg(not(feature = "rust_tests"))] +#[macro_export] +macro_rules! path_to { + ($name: literal) => { + path_to_cpp!($name) + }; +} + +#[cfg(feature = "rust_tests")] +#[macro_export] +macro_rules! path_to { + ($name: literal) => { + path_to_rust!($name) + }; +} + +//------------------------------------------ + +pub const CACHE_CHECK: &str = path_to!("cache_check"); +pub const CACHE_DUMP: &str = path_to!("cache_dump"); + +pub const THIN_CHECK: &str = path_to!("thin_check"); +pub const THIN_DELTA: &str = path_to_cpp!("thin_delta"); // TODO: rust version +pub const THIN_DUMP: &str = path_to!("thin_dump"); +pub const THIN_METADATA_PACK: &str = path_to_rust!("thin_metadata_pack"); // rust-only +pub const THIN_METADATA_UNPACK: &str = path_to_rust!("thin_metadata_unpack"); // rust-only +pub const THIN_REPAIR: &str = path_to_cpp!("thin_repair"); // TODO: rust version +pub const THIN_RESTORE: &str = path_to!("thin_restore"); +pub const THIN_RMAP: &str = path_to_cpp!("thin_rmap"); // TODO: rust version +pub const THIN_GENERATE_METADATA: &str = path_to_cpp!("thin_generate_metadata"); // cpp-only +pub const THIN_GENERATE_MAPPINGS: &str = path_to_cpp!("thin_generate_mappings"); // cpp-only +pub const THIN_GENERATE_DAMAGE: &str = path_to_cpp!("thin_generate_damage"); // cpp-only + +//------------------------------------------ + +pub mod cpp_msg { + pub const FILE_NOT_FOUND: &str = "No such file or directory"; + pub const MISSING_INPUT_ARG: &str = "No input file provided"; + pub const MISSING_OUTPUT_ARG: &str = "No output file provided"; + pub const BAD_SUPERBLOCK: &str = "bad checksum in superblock"; + + pub fn bad_option_hint(option: &str) -> String { + format!("unrecognized option '{}'", option) + } +} + +pub mod rust_msg { + pub const FILE_NOT_FOUND: &str = "Couldn't find input file"; + pub const MISSING_INPUT_ARG: &str = "The following required arguments were not provided"; // TODO: be specific + pub const MISSING_OUTPUT_ARG: &str = "The following required arguments were not provided"; // TODO: be specific + pub const BAD_SUPERBLOCK: &str = "bad checksum in superblock"; + + pub fn bad_option_hint(option: &str) -> String { + format!("Found argument '{}' which wasn't expected", option) + } +} + +#[cfg(not(feature = "rust_tests"))] +pub use cpp_msg as msg; +#[cfg(feature = "rust_tests")] +pub use rust_msg as msg; + +//------------------------------------------ diff --git a/tests/common/thin.rs b/tests/common/thin.rs new file mode 100644 index 0000000..0004f2d --- /dev/null +++ b/tests/common/thin.rs @@ -0,0 +1,135 @@ +use anyhow::Result; +use std::path::PathBuf; + +use thinp::file_utils; +use thinp::io_engine::*; + +use crate::common::fixture::*; +use crate::common::process::*; +use crate::common::target::*; +use crate::common::test_dir::TestDir; +use crate::common::thin_xml_generator::{write_xml, SingleThinS}; + +//----------------------------------------------- + +pub fn mk_valid_xml(td: &mut TestDir) -> Result { + let xml = td.mk_path("meta.xml"); + let mut gen = SingleThinS::new(0, 1024, 2048, 2048); + write_xml(&xml, &mut gen)?; + Ok(xml) +} + +pub fn mk_valid_md(td: &mut TestDir) -> Result { + let xml = td.mk_path("meta.xml"); + let md = td.mk_path("meta.bin"); + + let mut gen = SingleThinS::new(0, 1024, 20480, 20480); + write_xml(&xml, &mut gen)?; + + let _file = file_utils::create_sized_file(&md, 4096 * 4096); + let args = ["-i", xml.to_str().unwrap(), "-o", md.to_str().unwrap()]; + run_ok(THIN_RESTORE, &args)?; + + Ok(md) +} + +//----------------------------------------------- + +// FIXME: replace mk_valid_md with this? +pub fn prep_metadata(td: &mut TestDir) -> Result { + let md = mk_zeroed_md(td)?; + let args = [ + "-o", + md.to_str().unwrap(), + "--format", + "--nr-data-blocks", + "102400", + ]; + run_ok(THIN_GENERATE_METADATA, &args)?; + + // Create a 2GB device + let args = ["-o", md.to_str().unwrap(), "--create-thin", "1"]; + run_ok(THIN_GENERATE_METADATA, &args)?; + let args = [ + "-o", + md.to_str().unwrap(), + "--dev-id", + "1", + "--size", + "2097152", + "--rw=randwrite", + "--seq-nr=16", + ]; + run_ok(THIN_GENERATE_MAPPINGS, &args)?; + + // Take a few snapshots. + let mut snap_id = 2; + for _i in 0..10 { + // take a snapshot + let args = [ + "-o", + md.to_str().unwrap(), + "--create-snap", + &snap_id.to_string(), + "--origin", + "1", + ]; + run_ok(THIN_GENERATE_METADATA, &args)?; + + // partially overwrite the origin (64MB) + let args = [ + "-o", + md.to_str().unwrap(), + "--dev-id", + "1", + "--size", + "2097152", + "--io-size", + "131072", + "--rw=randwrite", + "--seq-nr=16", + ]; + run_ok(THIN_GENERATE_MAPPINGS, &args)?; + snap_id += 1; + } + + Ok(md) +} + +pub fn set_needs_check(md: &PathBuf) -> Result<()> { + let args = ["-o", md.to_str().unwrap(), "--set-needs-check"]; + run_ok(THIN_GENERATE_METADATA, &args)?; + Ok(()) +} + +pub fn generate_metadata_leaks( + md: &PathBuf, + nr_blocks: u64, + expected: u32, + actual: u32, +) -> Result<()> { + let args = [ + "-o", + md.to_str().unwrap(), + "--create-metadata-leaks", + "--nr-blocks", + &nr_blocks.to_string(), + "--expected", + &expected.to_string(), + "--actual", + &actual.to_string(), + ]; + run_ok(THIN_GENERATE_DAMAGE, &args)?; + + Ok(()) +} + +pub fn get_needs_check(md: &PathBuf) -> Result { + use thinp::thin::superblock::*; + + let engine = SyncIoEngine::new(&md, 1, false)?; + let sb = read_superblock(&engine, SUPERBLOCK_LOCATION)?; + Ok(sb.flags.needs_check) +} + +//----------------------------------------------- diff --git a/tests/thin_check.rs b/tests/thin_check.rs index bfe1161..7b166a7 100644 --- a/tests/thin_check.rs +++ b/tests/thin_check.rs @@ -3,9 +3,13 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::fixture::*; use common::input_arg::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_delta.rs b/tests/thin_delta.rs index 7455f10..63e0ce8 100644 --- a/tests/thin_delta.rs +++ b/tests/thin_delta.rs @@ -3,8 +3,11 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_dump.rs b/tests/thin_dump.rs index 2f1fae6..ae11219 100644 --- a/tests/thin_dump.rs +++ b/tests/thin_dump.rs @@ -6,9 +6,13 @@ use std::str::from_utf8; mod common; use common::common_args::*; +use common::fixture::*; use common::input_arg::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_metadata_pack.rs b/tests/thin_metadata_pack.rs index bbcb8c0..dea1eff 100644 --- a/tests/thin_metadata_pack.rs +++ b/tests/thin_metadata_pack.rs @@ -5,8 +5,10 @@ mod common; use common::common_args::*; use common::input_arg::*; use common::output_option::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_metadata_unpack.rs b/tests/thin_metadata_unpack.rs index 3702e73..5cd8966 100644 --- a/tests/thin_metadata_unpack.rs +++ b/tests/thin_metadata_unpack.rs @@ -3,10 +3,14 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::fixture::*; use common::input_arg::*; use common::output_option::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_repair.rs b/tests/thin_repair.rs index e9b3b92..e7a3ef3 100644 --- a/tests/thin_repair.rs +++ b/tests/thin_repair.rs @@ -3,10 +3,14 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::fixture::*; use common::input_arg::*; use common::output_option::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_restore.rs b/tests/thin_restore.rs index 7408be0..7da5cbf 100644 --- a/tests/thin_restore.rs +++ b/tests/thin_restore.rs @@ -3,10 +3,14 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::fixture::*; use common::input_arg::*; use common::output_option::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------ diff --git a/tests/thin_rmap.rs b/tests/thin_rmap.rs index bdee4cd..1fa2a66 100644 --- a/tests/thin_rmap.rs +++ b/tests/thin_rmap.rs @@ -3,8 +3,11 @@ use anyhow::Result; mod common; use common::common_args::*; +use common::process::*; +use common::program::*; +use common::target::*; use common::test_dir::*; -use common::*; +use common::thin::*; //------------------------------------------