[functional-tests] Recode thin_restore tests in Rust.
Now part of 'cargo test'
This commit is contained in:
parent
fcfcc60b89
commit
084a26bf85
@ -67,104 +67,6 @@
|
|||||||
;; to run.
|
;; to run.
|
||||||
(define (register-thin-tests) #t)
|
(define (register-thin-tests) #t)
|
||||||
|
|
||||||
;;;-----------------------------------------------------------
|
|
||||||
;;; thin_restore scenarios
|
|
||||||
;;;-----------------------------------------------------------
|
|
||||||
|
|
||||||
(define-scenario (thin-restore print-version-v)
|
|
||||||
"print help (-V)"
|
|
||||||
(run-ok-rcv (stdout _) (thin-restore "-V")
|
|
||||||
(assert-equal tools-version stdout)))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore print-version-long)
|
|
||||||
"print help (--version)"
|
|
||||||
(run-ok-rcv (stdout _) (thin-restore "--version")
|
|
||||||
(assert-equal tools-version stdout)))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore h)
|
|
||||||
"print help (-h)"
|
|
||||||
(run-ok-rcv (stdout _) (thin-restore "-h")
|
|
||||||
(assert-equal thin-restore-help stdout)))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore help)
|
|
||||||
"print help (-h)"
|
|
||||||
(run-ok-rcv (stdout _) (thin-restore "--help")
|
|
||||||
(assert-equal thin-restore-help stdout)))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore no-input-file)
|
|
||||||
"forget to specify an input file"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(run-fail-rcv (_ stderr) (thin-restore "-o" md)
|
|
||||||
(assert-starts-with "No input file provided." stderr))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore missing-input-file)
|
|
||||||
"the input file can't be found"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(run-fail-rcv (_ stderr) (thin-restore "-i no-such-file -o" md)
|
|
||||||
(assert-superblock-all-zeroes md)
|
|
||||||
(assert-starts-with "Couldn't stat file" stderr))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore garbage-input-file)
|
|
||||||
"the input file is just zeroes"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(with-temp-file-sized ((xml "thin.xml" 4096))
|
|
||||||
(run-fail-rcv (_ stderr) (thin-restore "-i " xml "-o" md)
|
|
||||||
(assert-superblock-all-zeroes md)))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore missing-output-file)
|
|
||||||
"the output file can't be found"
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-fail-rcv (_ stderr) (thin-restore "-i " xml)
|
|
||||||
(assert-starts-with "No output file provided." stderr))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore tiny-output-file)
|
|
||||||
"Fails if the output file is too small."
|
|
||||||
(with-temp-file-sized ((md "thin.bin" 4096))
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-fail-rcv (_ stderr) (thin-restore "-i" xml "-o" md)
|
|
||||||
(assert-starts-with thin-restore-outfile-too-small-text stderr)))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore q)
|
|
||||||
"thin_restore accepts -q"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-ok-rcv (stdout _) (thin-restore "-i" xml "-o" md "-q")
|
|
||||||
(assert-eof stdout)))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore quiet)
|
|
||||||
"thin_restore accepts --quiet"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-ok-rcv (stdout _) (thin-restore "-i" xml "-o" md "--quiet")
|
|
||||||
(assert-eof stdout)))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore override transaction-id)
|
|
||||||
"thin_restore obeys the --transaction-id override"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-ok-rcv (stdout stderr) (thin-restore "--transaction-id 2345" "-i" xml "-o" md)
|
|
||||||
(assert-eof stderr))
|
|
||||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
|
||||||
(assert-matches ".*transaction=\"2345\"" stdout)))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore override data-block-size)
|
|
||||||
"thin_restore obeys the --data-block-size override"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-ok-rcv (stdout stderr) (thin-restore "--data-block-size 8192" "-i" xml "-o" md)
|
|
||||||
(assert-eof stderr))
|
|
||||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
|
||||||
(assert-matches ".*data_block_size=\"8192\"" stdout)))))
|
|
||||||
|
|
||||||
(define-scenario (thin-restore override nr-data-blocks)
|
|
||||||
"thin_restore obeys the --nr-data-blocks override"
|
|
||||||
(with-empty-metadata (md)
|
|
||||||
(with-thin-xml (xml)
|
|
||||||
(run-ok-rcv (stdout stderr) (thin-restore "--nr-data-blocks 234500" "-i" xml "-o" md)
|
|
||||||
(assert-eof stderr))
|
|
||||||
(run-ok-rcv (stdout stderr) (thin-dump md)
|
|
||||||
(assert-matches ".*nr_data_blocks=\"234500\"" stdout)))))
|
|
||||||
|
|
||||||
;;;-----------------------------------------------------------
|
;;;-----------------------------------------------------------
|
||||||
;;; thin_dump scenarios
|
;;; thin_dump scenarios
|
||||||
;;;-----------------------------------------------------------
|
;;;-----------------------------------------------------------
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use duct::{cmd, Expression};
|
||||||
|
use std::fs::OpenOptions;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::from_utf8;
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
use thinp::file_utils;
|
||||||
|
use std::io::{Read};
|
||||||
|
|
||||||
pub mod xml_generator;
|
pub mod xml_generator;
|
||||||
|
use crate::common::xml_generator::{write_xml, FragmentedS, SingleThinS};
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
pub fn mk_path(dir: &Path, file: &str) -> PathBuf {
|
pub fn mk_path(dir: &Path, file: &str) -> PathBuf {
|
||||||
let mut p = PathBuf::new();
|
let mut p = PathBuf::new();
|
||||||
@ -9,3 +19,91 @@ pub fn mk_path(dir: &Path, file: &str) -> PathBuf {
|
|||||||
p
|
p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: write a macro to generate these commands
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! thin_check {
|
||||||
|
( $( $arg: expr ),* ) => {
|
||||||
|
{
|
||||||
|
use std::ffi::OsString;
|
||||||
|
let args: &[OsString] = &[$( Into::<OsString>::into($arg) ),*];
|
||||||
|
duct::cmd("bin/thin_check", args).stdout_capture().stderr_capture()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! thin_restore {
|
||||||
|
( $( $arg: expr ),* ) => {
|
||||||
|
{
|
||||||
|
use std::ffi::OsString;
|
||||||
|
let args: &[OsString] = &[$( Into::<OsString>::into($arg) ),*];
|
||||||
|
duct::cmd("bin/thin_restore", args).stdout_capture().stderr_capture()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! thin_dump {
|
||||||
|
( $( $arg: expr ),* ) => {
|
||||||
|
{
|
||||||
|
use std::ffi::OsString;
|
||||||
|
let args: &[OsString] = &[$( Into::<OsString>::into($arg) ),*];
|
||||||
|
duct::cmd("bin/thin_dump", args).stdout_capture().stderr_capture()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns stderr, a non zero status must be returned
|
||||||
|
pub fn run_fail(command: Expression) -> Result<String> {
|
||||||
|
let output = command.stderr_capture().unchecked().run()?;
|
||||||
|
assert!(!output.status.success());
|
||||||
|
Ok(from_utf8(&output.stderr[0..]).unwrap().to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mk_valid_xml(dir: &TempDir) -> Result<PathBuf> {
|
||||||
|
let xml = mk_path(dir.path(), "meta.xml");
|
||||||
|
let mut gen = SingleThinS::new(0, 1024, 2048, 2048);
|
||||||
|
write_xml(&xml, &mut gen)?;
|
||||||
|
Ok(xml)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mk_valid_md(dir: &TempDir) -> Result<PathBuf> {
|
||||||
|
let xml = mk_path(dir.path(), "meta.xml");
|
||||||
|
let md = mk_path(dir.path(), "meta.bin");
|
||||||
|
|
||||||
|
let mut gen = SingleThinS::new(0, 1024, 2048, 2048);
|
||||||
|
write_xml(&xml, &mut gen)?;
|
||||||
|
|
||||||
|
let _file = file_utils::create_sized_file(&md, 4096 * 4096);
|
||||||
|
cmd!("bin/thin_restore", "-i", xml, "-o", &md).run()?;
|
||||||
|
Ok(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mk_zeroed_md(dir: &TempDir) -> Result<PathBuf> {
|
||||||
|
let md = mk_path(dir.path(), "meta.bin");
|
||||||
|
let _file = file_utils::create_sized_file(&md, 4096 * 4096);
|
||||||
|
Ok(md)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accepts_flag(flag: &str) -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let md = mk_valid_md(&dir)?;
|
||||||
|
thin_check!(flag, &md).run()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn superblock_all_zeroes(path: &PathBuf) -> Result<bool> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
@ -8,55 +8,11 @@ use thinp::version::TOOLS_VERSION;
|
|||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
use common::mk_path;
|
use common::*;
|
||||||
use common::xml_generator::{write_xml, FragmentedS, SingleThinS};
|
use common::xml_generator::{write_xml, FragmentedS, SingleThinS};
|
||||||
|
|
||||||
//------------------------------------------
|
//------------------------------------------
|
||||||
|
|
||||||
macro_rules! thin_check {
|
|
||||||
( $( $arg: expr ),* ) => {
|
|
||||||
{
|
|
||||||
use std::ffi::OsString;
|
|
||||||
let args: &[OsString] = &[$( Into::<OsString>::into($arg) ),*];
|
|
||||||
duct::cmd("bin/thin_check", args).stdout_capture().stderr_capture()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns stderr, a non zero status must be returned
|
|
||||||
fn run_fail(command: Expression) -> Result<String> {
|
|
||||||
let output = command.stderr_capture().unchecked().run()?;
|
|
||||||
assert!(!output.status.success());
|
|
||||||
Ok(from_utf8(&output.stderr[0..]).unwrap().to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_valid_md(dir: &TempDir) -> Result<PathBuf> {
|
|
||||||
let xml = mk_path(dir.path(), "meta.xml");
|
|
||||||
let md = mk_path(dir.path(), "meta.bin");
|
|
||||||
|
|
||||||
let mut gen = SingleThinS::new(0, 1024, 2048, 2048);
|
|
||||||
write_xml(&xml, &mut gen)?;
|
|
||||||
|
|
||||||
let _file = file_utils::create_sized_file(&md, 4096 * 4096);
|
|
||||||
cmd!("bin/thin_restore", "-i", xml, "-o", &md).run()?;
|
|
||||||
Ok(md)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mk_corrupt_md(dir: &TempDir) -> Result<PathBuf> {
|
|
||||||
let md = mk_path(dir.path(), "meta.bin");
|
|
||||||
let _file = file_utils::create_sized_file(&md, 4096 * 4096);
|
|
||||||
Ok(md)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn accepts_flag(flag: &str) -> Result<()> {
|
|
||||||
let dir = tempdir()?;
|
|
||||||
let md = mk_valid_md(&dir)?;
|
|
||||||
thin_check!(flag, &md).run()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn accepts_v() -> Result<()> {
|
fn accepts_v() -> Result<()> {
|
||||||
let stdout = thin_check!("-V").read()?;
|
let stdout = thin_check!("-V").read()?;
|
||||||
@ -120,6 +76,7 @@ fn accepts_quiet() -> Result<()> {
|
|||||||
let md = mk_valid_md(&dir)?;
|
let md = mk_valid_md(&dir)?;
|
||||||
|
|
||||||
let output = thin_check!("--quiet", &md).run()?;
|
let output = thin_check!("--quiet", &md).run()?;
|
||||||
|
assert!(output.status.success());
|
||||||
assert_eq!(output.stdout.len(), 0);
|
assert_eq!(output.stdout.len(), 0);
|
||||||
assert_eq!(output.stderr.len(), 0);
|
assert_eq!(output.stderr.len(), 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -128,7 +85,7 @@ fn accepts_quiet() -> Result<()> {
|
|||||||
#[test]
|
#[test]
|
||||||
fn detects_corrupt_superblock_with_superblock_only() -> Result<()> {
|
fn detects_corrupt_superblock_with_superblock_only() -> Result<()> {
|
||||||
let dir = tempdir()?;
|
let dir = tempdir()?;
|
||||||
let md = mk_corrupt_md(&dir)?;
|
let md = mk_zeroed_md(&dir)?;
|
||||||
let output = thin_check!("--super-block-only", &md).unchecked().run()?;
|
let output = thin_check!("--super-block-only", &md).unchecked().run()?;
|
||||||
assert!(!output.status.success());
|
assert!(!output.status.success());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
144
tests/thin_restore.rs
Normal file
144
tests/thin_restore.rs
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use duct::{cmd, Expression};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::str::from_utf8;
|
||||||
|
use tempfile::{tempdir, TempDir};
|
||||||
|
use thinp::file_utils;
|
||||||
|
use thinp::version::TOOLS_VERSION;
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
use common::xml_generator::{write_xml, FragmentedS, SingleThinS};
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
//------------------------------------------
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accepts_v() -> Result<()> {
|
||||||
|
let stdout = thin_restore!("-V").read()?;
|
||||||
|
assert_eq!(stdout, TOOLS_VERSION);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accepts_version() -> Result<()> {
|
||||||
|
let stdout = thin_restore!("--version").read()?;
|
||||||
|
assert_eq!(stdout, TOOLS_VERSION);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
const USAGE: &'static str = "Usage: thin_restore [options]\nOptions:\n {-h|--help}\n {-i|--input} <input xml file>\n {-o|--output} <output device or file>\n {--transaction-id} <natural>\n {--data-block-size} <natural>\n {--nr-data-blocks} <natural>\n {-q|--quiet}\n {-V|--version}";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accepts_h() -> Result<()> {
|
||||||
|
let stdout = thin_restore!("-h").read()?;
|
||||||
|
assert_eq!(stdout, USAGE);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accepts_help() -> Result<()> {
|
||||||
|
let stdout = thin_restore!("--help").read()?;
|
||||||
|
assert_eq!(stdout, USAGE);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_input_file() -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let md = mk_zeroed_md(&dir)?;
|
||||||
|
let stderr = run_fail(thin_restore!("-o", &md))?;
|
||||||
|
assert!(stderr.contains("No input file provided."));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_input_file() -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let md = mk_zeroed_md(&dir)?;
|
||||||
|
let stderr = run_fail(thin_restore!("-i", "no-such-file", "-o", &md))?;
|
||||||
|
assert!(superblock_all_zeroes(&md)?);
|
||||||
|
assert!(stderr.contains("Couldn't stat file"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn garbage_input_file() -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let xml = mk_zeroed_md(&dir)?;
|
||||||
|
let md = mk_zeroed_md(&dir)?;
|
||||||
|
let _stderr = run_fail(thin_restore!("-i", &xml, "-o", &md))?;
|
||||||
|
assert!(superblock_all_zeroes(&md)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn no_output_file() -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let xml = mk_valid_xml(&dir)?;
|
||||||
|
let stderr = run_fail(thin_restore!("-i", &xml))?;
|
||||||
|
assert!(stderr.contains("No output file provided."));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn tiny_output_file() -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let xml = mk_valid_xml(&dir)?;
|
||||||
|
let md = mk_path(dir.path(), "meta.bin");
|
||||||
|
let _file = file_utils::create_sized_file(&md, 4096);
|
||||||
|
let stderr = run_fail(thin_restore!("-i", &xml, "-o", &md))?;
|
||||||
|
eprintln!("{}", stderr);
|
||||||
|
assert!(stderr.contains("Output file too small"));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn quiet_flag(flag: &str) -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let xml = mk_valid_xml(&dir)?;
|
||||||
|
let md = mk_zeroed_md(&dir)?;
|
||||||
|
|
||||||
|
let output = thin_restore!("-i", &xml, "-o", &md, flag).run()?;
|
||||||
|
|
||||||
|
assert!(output.status.success());
|
||||||
|
assert_eq!(output.stdout.len(), 0);
|
||||||
|
assert_eq!(output.stderr.len(), 0);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accepts_q() -> Result<()> {
|
||||||
|
quiet_flag("-q")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn accepts_quiet() -> Result<()> {
|
||||||
|
quiet_flag("--quiet")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn override_something(flag: &str, value: &str, pattern: &str) -> Result<()> {
|
||||||
|
let dir = tempdir()?;
|
||||||
|
let xml = mk_valid_xml(&dir)?;
|
||||||
|
let md = mk_zeroed_md(&dir)?;
|
||||||
|
|
||||||
|
thin_restore!("-i", &xml, "-o", &md, flag, value).run()?;
|
||||||
|
|
||||||
|
let output = thin_dump!(&md).run()?;
|
||||||
|
assert!(from_utf8(&output.stdout)?.contains(pattern));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn override_transaction_id() -> Result<()> {
|
||||||
|
override_something("--transaction-id", "2345", "transaction=\"2345\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn override_data_block_size() -> Result<()> {
|
||||||
|
override_something("--data-block-size", "8192", "data_block_size=\"8192\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn override_nr_data_blocks() -> Result<()> {
|
||||||
|
override_something("--nr-data-blocks", "234500", "nr_data_blocks=\"234500\"")
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user