Merge rust tools into a single pdata_tools exe

This commit is contained in:
Joe Thornber
2021-10-11 12:07:26 +01:00
parent c9b47437f2
commit 024554c987
41 changed files with 840 additions and 567 deletions

View File

@@ -27,7 +27,7 @@ pub fn mk_valid_md(td: &mut TestDir) -> Result<PathBuf> {
write_xml(&xml, &mut gen)?;
let _file = file_utils::create_sized_file(&md, 4096 * 4096);
run_ok(CACHE_RESTORE, args!["-i", &xml, "-o", &md])?;
run_ok(cache_restore_cmd(args!["-i", &xml, "-o", &md]))?;
Ok(md)
}

View File

@@ -13,7 +13,7 @@ pub fn test_help_short<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), args!["-h"])?;
let stdout = run_ok(P::cmd(args!["-h"]))?;
assert_eq!(stdout, P::usage());
Ok(())
}
@@ -22,7 +22,7 @@ pub fn test_help_long<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), args!["--help"])?;
let stdout = run_ok(P::cmd(vec!["--help"]))?;
assert_eq!(stdout, P::usage());
Ok(())
}
@@ -49,7 +49,7 @@ pub fn test_version_short<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), args!["-V"])?;
let stdout = run_ok(P::cmd(args!["-V"]))?;
assert!(stdout.contains(tools_version()));
Ok(())
}
@@ -58,7 +58,7 @@ pub fn test_version_long<'a, P>() -> Result<()>
where
P: Program<'a>,
{
let stdout = run_ok(P::path(), args!["--version"])?;
let stdout = run_ok(P::cmd(args!["--version"]))?;
assert!(stdout.contains(tools_version()));
Ok(())
}
@@ -85,7 +85,7 @@ where
P: Program<'a>,
{
let option = "--hedgehogs-only";
let stderr = run_fail(P::path(), args![option])?;
let stderr = run_fail(P::cmd(args![option]))?;
assert!(stderr.contains(&P::bad_option_hint(option)));
Ok(())
}

View File

@@ -63,7 +63,7 @@ where
P: InputProgram<'a>,
{
let args: [&str; 0] = [];
let stderr = run_fail(P::path(), args)?;
let stderr = run_fail(P::cmd(args))?;
assert!(stderr.contains(P::missing_input_arg()));
Ok(())
}
@@ -85,7 +85,7 @@ where
let mut td = TestDir::new()?;
let output = mk_zeroed_md(&mut td)?;
ensure_untouched(&output, || {
let stderr = run_fail(P::path(), args!["-o", &output])?;
let stderr = run_fail(P::cmd(args!["-o", &output]))?;
assert!(stderr.contains(P::missing_input_arg()));
Ok(())
})
@@ -109,7 +109,7 @@ where
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, "no-such-file".as_ref(), &|args: &[&OsStr]| {
let stderr = run_fail(P::path(), args)?;
let stderr = run_fail(P::cmd(args))?;
assert!(stderr.contains(P::file_not_found()));
Ok(())
})
@@ -133,7 +133,7 @@ where
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, "/tmp".as_ref(), &|args: &[&OsStr]| {
let stderr = run_fail(P::path(), args)?;
let stderr = run_fail(P::cmd(args))?;
assert!(stderr.contains("Not a block device or regular file"));
Ok(())
})
@@ -161,7 +161,7 @@ where
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, input.as_ref(), &|args: &[&OsStr]| {
let stderr = run_fail(P::path(), args)?;
let stderr = run_fail(P::cmd(args))?;
assert!(stderr.contains("Permission denied"));
Ok(())
})
@@ -191,7 +191,8 @@ where
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, input.as_ref(), &|args: &[&OsStr]| {
let stderr = run_fail(P::path(), args)?;
let stderr = run_fail(P::cmd(args))?;
eprintln!("actual: {:?}", stderr);
assert!(stderr.contains("Metadata device/file too small. Is this binary metadata?"));
Ok(())
})
@@ -220,11 +221,9 @@ where
let wrapper = build_args_fn(P::arg_type())?;
wrapper(&mut td, input.as_ref(), &|args: &[&OsStr]| {
let stderr = run_fail(P::path(), args)?;
eprintln!("{}", stderr);
let stderr = run_fail(P::cmd(args))?;
let msg = format!(
"This looks like XML. {} only checks the binary metadata format.",
P::name()
"This looks like XML. This tool only checks the binary metadata format.",
);
assert!(stderr.contains(&msg));
Ok(())
@@ -253,7 +252,7 @@ where
ArgType::IoOptions => with_output_superblock_zeroed,
};
wrapper(&mut td, input.as_ref(), &|args: &[&OsStr]| {
let stderr = run_fail(P::path(), args)?;
let stderr = run_fail(P::cmd(args))?;
assert!(stderr.contains(P::corrupted_input()));
Ok(())
})

View File

@@ -16,7 +16,7 @@ where
{
let mut td = TestDir::new()?;
let input = P::mk_valid_input(&mut td)?;
let stderr = run_fail(P::path(), args!["-i", &input])?;
let stderr = run_fail(P::cmd(args!["-i", &input]))?;
assert!(stderr.contains(P::missing_output_arg()));
Ok(())
}
@@ -37,7 +37,9 @@ where
{
let mut td = TestDir::new()?;
let input = P::mk_valid_input(&mut td)?;
let stderr = run_fail(P::path(), args!["-i", &input, "-o", "no-such-file"])?;
let cmd = P::cmd(args!["-i", &input, "-o", "no-such-file"]);
let stderr = run_fail(cmd)?;
assert!(stderr.contains(<P as MetadataWriter>::file_not_found()));
Ok(())
}
@@ -58,7 +60,7 @@ where
{
let mut td = TestDir::new()?;
let input = P::mk_valid_input(&mut td)?;
let stderr = run_fail(P::path(), args!["-i", &input, "-o", "/tmp"])?;
let stderr = run_fail(P::cmd(args!["-i", &input, "-o", "/tmp"]))?;
assert!(stderr.contains("Not a block device or regular file"));
Ok(())
}
@@ -84,7 +86,7 @@ where
let _file = file_utils::create_sized_file(&output, 4_194_304);
duct::cmd!("chmod", "-w", &output).run()?;
let stderr = run_fail(P::path(), args!["-i", &input, "-o", &output])?;
let stderr = run_fail(P::cmd(args!["-i", &input, "-o", &output]))?;
assert!(stderr.contains("Permission denied"));
Ok(())
}
@@ -113,7 +115,7 @@ where
let output = td.mk_path("meta.bin");
let _file = file_utils::create_sized_file(&output, 4096);
let stderr = run_fail(P::path(), args!["-i", &input, "-o", &output])?;
let stderr = run_fail(P::cmd(args!["-i", &input, "-o", &output]))?;
assert!(stderr.contains("Output file too small"));
Ok(())
}

View File

@@ -1,5 +1,4 @@
use anyhow::Result;
use std::ffi::{OsStr, OsString};
//------------------------------------------
@@ -15,49 +14,29 @@ macro_rules! args {
}
// Returns stdout. The command must return zero.
pub fn run_ok<S, I>(program: S, args: I) -> Result<String>
where
S: AsRef<OsStr>,
I: IntoIterator,
I::Item: Into<OsString>,
{
let command = duct::cmd(program.as_ref(), args)
.stdout_capture()
.stderr_capture();
pub fn run_ok(command: duct::Expression) -> Result<String> {
let command = command.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<S, I>(program: S, args: I) -> Result<std::process::Output>
where
S: AsRef<OsStr>,
I: IntoIterator,
I::Item: Into<OsString>,
{
let command = duct::cmd(program.as_ref(), args)
.stdout_capture()
.stderr_capture();
pub fn run_ok_raw(command: duct::Expression) -> Result<std::process::Output> {
let command = command.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<S, I>(program: S, args: I) -> Result<String>
where
S: AsRef<OsStr>,
I: IntoIterator,
I::Item: Into<OsString>,
{
let command = duct::cmd(program.as_ref(), args)
.stdout_capture()
.stderr_capture();
pub fn run_fail(command: duct::Expression) -> Result<String> {
let command = command.stdout_capture().stderr_capture();
let output = command.unchecked().run()?;
assert!(!output.status.success());
let stderr = std::str::from_utf8(&output.stderr[..]).unwrap().to_string();
@@ -65,15 +44,8 @@ where
}
// Returns the entire output, a non zero status must be returned
pub fn run_fail_raw<S, I>(program: S, args: I) -> Result<std::process::Output>
where
S: AsRef<OsStr>,
I: IntoIterator,
I::Item: Into<OsString>,
{
let command = duct::cmd(program.as_ref(), args)
.stdout_capture()
.stderr_capture();
pub fn run_fail_raw(command: duct::Expression) -> Result<std::process::Output> {
let command = command.stdout_capture().stderr_capture();
let output = command.unchecked().run()?;
assert!(!output.status.success());
Ok(output)

View File

@@ -1,5 +1,4 @@
use anyhow::Result;
use std::ffi::OsStr;
use std::path::PathBuf;
use crate::common::test_dir::TestDir;
@@ -13,7 +12,10 @@ pub enum ArgType {
pub trait Program<'a> {
fn name() -> &'a str;
fn path() -> &'a OsStr;
fn cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<std::ffi::OsString>;
fn usage() -> &'a str;
fn arg_type() -> ArgType;

View File

@@ -1,69 +1,159 @@
//------------------------------------------
#[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)
};
}
use std::ffi::OsString;
use std::path::PathBuf;
//------------------------------------------
pub const CACHE_CHECK: &str = path_to!("cache_check");
pub const CACHE_DUMP: &str = path_to!("cache_dump");
pub const CACHE_REPAIR: &str = path_to!("cache_repair");
pub const CACHE_RESTORE: &str = path_to!("cache_restore");
pub fn cpp_cmd<S, I>(cmd: S, args: I) -> duct::Expression
where
S: Into<OsString>,
I: IntoIterator,
I::Item: Into<OsString>,
{
let mut bin = PathBuf::from("./bin");
bin.push(Into::<OsString>::into(cmd));
duct::cmd(bin.as_path(), args)
}
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!("thin_repair");
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 fn rust_cmd<S, I>(cmd: S, args: I) -> duct::Expression
where
S: Into<OsString>,
I: IntoIterator,
I::Item: Into<OsString>,
{
const RUST_PATH: &str = env!(concat!("CARGO_BIN_EXE_", "pdata_tools"));
//------------------------------------------
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)
let mut all_args = vec![Into::<OsString>::into(cmd)];
for a in args {
all_args.push(Into::<OsString>::into(a));
}
duct::cmd(RUST_PATH, &all_args)
}
pub mod rust_msg {
pub const FILE_NOT_FOUND: &str = "No such file or directory";
pub fn thin_check_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("thin_check", args)
}
pub fn thin_rmap_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
cpp_cmd("thin_rmap", args)
}
pub fn thin_generate_metadata_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
cpp_cmd("thin_generate_metadata", args)
}
pub fn thin_generate_mappings_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
cpp_cmd("thin_generate_mappings", args)
}
pub fn thin_generate_damage_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
cpp_cmd("thin_generate_damage", args)
}
pub fn thin_restore_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("thin_restore", args)
}
pub fn thin_repair_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("thin_restore", args)
}
pub fn thin_dump_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("thin_dump", args)
}
pub fn thin_delta_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
cpp_cmd("thin_delta", args)
}
pub fn thin_metadata_pack_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("thin_metadata_pack", args)
}
pub fn thin_metadata_unpack_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("thin_metadata_unpack", args)
}
pub fn cache_check_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("cache_check", args)
}
pub fn cache_dump_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("cache_dump", args)
}
pub fn cache_restore_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("cache_restore", args)
}
pub fn cache_repair_cmd<I>(args: I) -> duct::Expression
where
I: IntoIterator,
I::Item: Into<OsString>,
{
rust_cmd("cache_repair", args)
}
//------------------------------------------
pub mod 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";
@@ -73,9 +163,4 @@ pub mod rust_msg {
}
}
#[cfg(not(feature = "rust_tests"))]
pub use cpp_msg as msg;
#[cfg(feature = "rust_tests")]
pub use rust_msg as msg;
//------------------------------------------

View File

@@ -28,7 +28,7 @@ pub fn mk_valid_md(td: &mut TestDir) -> Result<PathBuf> {
write_xml(&xml, &mut gen)?;
let _file = file_utils::create_sized_file(&md, 4096 * 4096);
run_ok(THIN_RESTORE, args!["-i", &xml, "-o", &md])?;
run_ok(thin_restore_cmd(args!["-i", &xml, "-o", &md]))?;
Ok(md)
}
@@ -39,11 +39,11 @@ pub fn mk_valid_md(td: &mut TestDir) -> Result<PathBuf> {
pub fn prep_metadata(td: &mut TestDir) -> Result<PathBuf> {
let md = mk_zeroed_md(td)?;
let args = args!["-o", &md, "--format", "--nr-data-blocks", "102400"];
run_ok(THIN_GENERATE_METADATA, args)?;
run_ok(thin_generate_metadata_cmd(args))?;
// Create a 2GB device
let args = args!["-o", &md, "--create-thin", "1"];
run_ok(THIN_GENERATE_METADATA, args)?;
run_ok(thin_generate_metadata_cmd(args))?;
let args = args![
"-o",
&md,
@@ -54,7 +54,7 @@ pub fn prep_metadata(td: &mut TestDir) -> Result<PathBuf> {
"--rw=randwrite",
"--seq-nr=16"
];
run_ok(THIN_GENERATE_MAPPINGS, args)?;
run_ok(thin_generate_mappings_cmd(args))?;
// Take a few snapshots.
let mut snap_id = 2;
@@ -62,7 +62,7 @@ pub fn prep_metadata(td: &mut TestDir) -> Result<PathBuf> {
// take a snapshot
let snap_id_str = snap_id.to_string();
let args = args!["-o", &md, "--create-snap", &snap_id_str, "--origin", "1"];
run_ok(THIN_GENERATE_METADATA, args)?;
run_ok(thin_generate_metadata_cmd(args))?;
// partially overwrite the origin (64MB)
let args = args![
@@ -77,7 +77,7 @@ pub fn prep_metadata(td: &mut TestDir) -> Result<PathBuf> {
"--rw=randwrite",
"--seq-nr=16"
];
run_ok(THIN_GENERATE_MAPPINGS, args)?;
run_ok(thin_generate_mappings_cmd(args))?;
snap_id += 1;
}
@@ -86,7 +86,7 @@ pub fn prep_metadata(td: &mut TestDir) -> Result<PathBuf> {
pub fn set_needs_check(md: &PathBuf) -> Result<()> {
let args = args!["-o", &md, "--set-needs-check"];
run_ok(THIN_GENERATE_METADATA, args)?;
run_ok(thin_generate_metadata_cmd(args))?;
Ok(())
}
@@ -110,7 +110,7 @@ pub fn generate_metadata_leaks(
"--actual",
&actual_str
];
run_ok(THIN_GENERATE_DAMAGE, args)?;
run_ok(thin_generate_damage_cmd(args))?;
Ok(())
}