thin-provisioning-tools/tests/thin_repair.rs
Ming-Hung Tsai f395bab7be [tests] Use traits to specify test parameters
To deal with variety in target attributes and their expected outputs,
the test parameters are categorized into traits, thus the test program
could define test parameters in a more structured way, without having
to pass multiple tightly-coupled parameters to test functions.
2021-07-09 01:22:22 +08:00

226 lines
5.5 KiB
Rust

use anyhow::Result;
mod common;
use common::common_args::*;
use common::input_arg::*;
use common::output_option::*;
use common::test_dir::*;
use common::*;
//------------------------------------------
const USAGE: &str = "Usage: thin_repair [options] {device|file}\n\
Options:\n \
{-h|--help}\n \
{-i|--input} <input metadata (binary format)>\n \
{-o|--output} <output metadata (binary format)>\n \
{--transaction-id} <natural>\n \
{--data-block-size} <natural>\n \
{--nr-data-blocks} <natural>\n \
{-V|--version}";
//-----------------------------------------
struct ThinRepair;
impl<'a> Program<'a> for ThinRepair {
fn name() -> &'a str {
"thin_repair"
}
fn path() -> &'a str {
THIN_REPAIR
}
fn usage() -> &'a str {
USAGE
}
fn arg_type() -> ArgType {
ArgType::IoOptions
}
fn bad_option_hint(option: &str) -> String {
cpp_msg::bad_option_hint(option)
}
}
impl<'a> InputProgram<'a> for ThinRepair {
fn mk_valid_input(td: &mut TestDir) -> Result<std::path::PathBuf> {
mk_valid_md(td)
}
fn file_not_found() -> &'a str {
cpp_msg::FILE_NOT_FOUND
}
fn missing_input_arg() -> &'a str {
cpp_msg::MISSING_INPUT_ARG
}
fn corrupted_input() -> &'a str {
"The following field needs to be provided on the command line due to corruption in the superblock"
}
}
impl<'a> OutputProgram<'a> for ThinRepair {
fn file_not_found() -> &'a str {
cpp_msg::FILE_NOT_FOUND
}
fn missing_output_arg() -> &'a str {
cpp_msg::MISSING_OUTPUT_ARG
}
}
//-----------------------------------------
test_accepts_help!(ThinRepair);
test_accepts_version!(ThinRepair);
test_rejects_bad_option!(ThinRepair);
test_input_file_not_found!(ThinRepair);
test_corrupted_input_data!(ThinRepair);
test_missing_output_option!(ThinRepair);
//-----------------------------------------
// test output to a small file
// TODO: share with thin_restore
#[test]
fn dont_repair_xml() -> Result<()> {
let mut td = TestDir::new()?;
let md = mk_zeroed_md(&mut td)?;
let xml = mk_valid_xml(&mut td)?;
let xml_path = xml.to_str().unwrap();
let md_path = md.to_str().unwrap();
run_fail(THIN_REPAIR, &["-i", xml_path, "-o", md_path])?;
Ok(())
}
//-----------------------------------------
// TODO: share with thin_dump
fn override_thing(flag: &str, val: &str, pattern: &str) -> Result<()> {
let mut td = TestDir::new()?;
let md1 = mk_valid_md(&mut td)?;
let md2 = mk_zeroed_md(&mut td)?;
let md1_path = md1.to_str().unwrap();
let md2_path = md2.to_str().unwrap();
let output = run_ok_raw(THIN_REPAIR, &[flag, val, "-i", md1_path, "-o", md2_path])?;
assert_eq!(output.stderr.len(), 0);
let md2_path = md2.to_str().unwrap();
let output = run_ok(THIN_DUMP, &[md2_path])?;
assert!(output.contains(pattern));
Ok(())
}
#[test]
fn override_transaction_id() -> Result<()> {
override_thing("--transaction-id", "2345", "transaction=\"2345\"")
}
#[test]
fn override_data_block_size() -> Result<()> {
override_thing("--data-block-size", "8192", "data_block_size=\"8192\"")
}
#[test]
fn override_nr_data_blocks() -> Result<()> {
override_thing("--nr-data-blocks", "234500", "nr_data_blocks=\"234500\"")
}
// FIXME: that's repair_superblock in thin_dump.rs
#[test]
fn superblock_succeeds() -> Result<()> {
let mut td = TestDir::new()?;
let md1 = mk_valid_md(&mut td)?;
let md1_path = md1.to_str().unwrap();
let original = run_ok_raw(
THIN_DUMP,
&[
"--transaction-id=5",
"--data-block-size=128",
"--nr-data-blocks=4096000",
md1_path,
],
)?;
assert_eq!(original.stderr.len(), 0);
damage_superblock(&md1)?;
let md2 = mk_zeroed_md(&mut td)?;
let md2_path = md2.to_str().unwrap();
run_ok(
THIN_REPAIR,
&[
"--transaction-id=5",
"--data-block-size=128",
"--nr-data-blocks=4096000",
"-i",
md1_path,
"-o",
md2_path,
],
)?;
let repaired = run_ok_raw(THIN_DUMP, &[md2_path])?;
assert_eq!(repaired.stderr.len(), 0);
assert_eq!(original.stdout, repaired.stdout);
Ok(())
}
//-----------------------------------------
// TODO: share with thin_dump
fn missing_thing(flag1: &str, flag2: &str, pattern: &str) -> Result<()> {
let mut td = TestDir::new()?;
let md1 = mk_valid_md(&mut td)?;
damage_superblock(&md1)?;
let md2 = mk_zeroed_md(&mut td)?;
let stderr = run_fail(
THIN_REPAIR,
&[
flag1,
flag2,
"-i",
md1.to_str().unwrap(),
"-o",
md2.to_str().unwrap(),
],
)?;
assert!(stderr.contains(pattern));
Ok(())
}
#[test]
fn missing_transaction_id() -> Result<()> {
missing_thing(
"--data-block-size=128",
"--nr-data-blocks=4096000",
"transaction id",
)
}
#[test]
fn missing_data_block_size() -> Result<()> {
missing_thing(
"--transaction-id=5",
"--nr-data-blocks=4096000",
"data block size",
)
}
#[test]
fn missing_nr_data_blocks() -> Result<()> {
missing_thing(
"--transaction-id=5",
"--data-block-size=128",
"nr data blocks",
)
}
//-----------------------------------------