mod util;
#[cfg(all(target_os = "linux", feature = "use_linux"))]
mod test {
use std::{process::Command, fs::{File, OpenOptions}, io::SeekFrom};
use std::io::{Seek, Write};
use libfs::{map_extents, sync};
use test_case::test_case;
use crate::util::*;
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(feature = "test_no_reflink", ignore = "No FS support")]
fn file_copy_reflink_always(drv: &str) {
let dir = tempdir_rel().unwrap();
let source_path = dir.path().join("source.bin");
let dest_path = dir.path().join("dest.bin");
let size = 128 * 1024;
{
let mut infd = File::create(&source_path).unwrap();
let data = rand_data(size);
infd.write(&data).unwrap();
}
{
let infd = File::open(&source_path).unwrap();
let inext = map_extents(&infd).unwrap().unwrap();
assert_eq!(false, inext[0].shared);
}
let out = run(&[
"--driver", drv,
"--reflink=always",
source_path.to_str().unwrap(),
dest_path.to_str().unwrap(),
])
.unwrap();
assert!(out.status.success());
assert!(files_match(&source_path, &dest_path));
{
let infd = File::open(&source_path).unwrap();
let outfd = File::open(&dest_path).unwrap();
let inext = map_extents(&infd).unwrap().unwrap();
let outext = map_extents(&outfd).unwrap().unwrap();
assert_eq!(true, inext[0].shared);
assert_eq!(true, outext[0].shared);
}
{
let mut outfd = OpenOptions::new()
.create(false)
.write(true)
.read(true)
.open(&dest_path).unwrap();
outfd.seek(SeekFrom::Start(0)).unwrap();
let data = rand_data(size);
outfd.write(&data).unwrap();
sync(&outfd).unwrap();
}
{
let infd = File::open(&source_path).unwrap();
let outfd = File::open(&dest_path).unwrap();
let inext = map_extents(&infd).unwrap().unwrap();
let outext = map_extents(&outfd).unwrap().unwrap();
assert_eq!(false, inext[0].shared);
assert_eq!(false, outext[0].shared);
}
}
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(feature = "test_no_sparse", ignore = "No FS support")]
fn test_sparse(drv: &str) {
use std::fs::read;
let dir = tempdir_rel().unwrap();
let from = dir.path().join("sparse.bin");
let to = dir.path().join("target.bin");
let slen = create_sparse(&from, 0, 0).unwrap();
assert_eq!(slen, from.metadata().unwrap().len());
assert!(probably_sparse(&from).unwrap());
let out = run(&[
"--driver",
drv,
from.to_str().unwrap(),
to.to_str().unwrap(),
]).unwrap();
assert!(out.status.success());
assert!(probably_sparse(&to).unwrap());
assert_eq!(quickstat(&from).unwrap(), quickstat(&to).unwrap());
let from_data = read(&from).unwrap();
let to_data = read(&to).unwrap();
assert_eq!(from_data, to_data);
}
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(feature = "test_no_sparse", ignore = "No FS support")]
fn test_sparse_leading_gap(drv: &str) {
use std::fs::read;
let dir = tempdir_rel().unwrap();
let from = dir.path().join("sparse.bin");
let to = dir.path().join("target.bin");
let slen = create_sparse(&from, 1024, 0).unwrap();
assert_eq!(slen, from.metadata().unwrap().len());
assert!(probably_sparse(&from).unwrap());
let out = run(&[
"--driver",
drv,
from.to_str().unwrap(),
to.to_str().unwrap(),
]).unwrap();
assert!(out.status.success());
assert!(probably_sparse(&to).unwrap());
assert_eq!(quickstat(&from).unwrap(), quickstat(&to).unwrap());
let from_data = read(&from).unwrap();
let to_data = read(&to).unwrap();
assert_eq!(from_data, to_data);
}
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(feature = "test_no_sparse", ignore = "No FS support")]
fn test_sparse_trailng_gap(drv: &str) {
use std::fs::read;
let dir = tempdir_rel().unwrap();
let from = dir.path().join("sparse.bin");
let to = dir.path().join("target.bin");
let slen = create_sparse(&from, 1024, 1024).unwrap();
assert_eq!(slen, from.metadata().unwrap().len());
assert!(probably_sparse(&from).unwrap());
let out = run(&[
"--driver",
drv,
from.to_str().unwrap(),
to.to_str().unwrap(),
]).unwrap();
assert!(out.status.success());
assert!(probably_sparse(&to).unwrap());
assert_eq!(quickstat(&from).unwrap(), quickstat(&to).unwrap());
let from_data = read(&from).unwrap();
let to_data = read(&to).unwrap();
assert_eq!(from_data, to_data);
}
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(feature = "test_no_sparse", ignore = "No FS support")]
fn test_sparse_single_overwrite(drv: &str) {
use std::fs::read;
let dir = tempdir_rel().unwrap();
let from = dir.path().join("sparse.bin");
let to = dir.path().join("target.bin");
let slen = create_sparse(&from, 1024, 1024).unwrap();
create_file(&to, "").unwrap();
assert_eq!(slen, from.metadata().unwrap().len());
assert!(probably_sparse(&from).unwrap());
let out = run(&[
"--driver",
drv,
from.to_str().unwrap(),
to.to_str().unwrap(),
]).unwrap();
assert!(out.status.success());
assert!(probably_sparse(&to).unwrap());
assert_eq!(quickstat(&from).unwrap(), quickstat(&to).unwrap());
let from_data = read(&from).unwrap();
let to_data = read(&to).unwrap();
assert_eq!(from_data, to_data);
}
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(feature = "test_no_sparse", ignore = "No FS support")]
fn test_empty_sparse(drv: &str) {
use std::fs::read;
let dir = tempdir_rel().unwrap();
let from = dir.path().join("sparse.bin");
let to = dir.path().join("target.bin");
let out = Command::new("/usr/bin/truncate")
.args(["-s", "1M", from.to_str().unwrap()])
.output().unwrap();
assert!(out.status.success());
assert_eq!(from.metadata().unwrap().len(), 1024 * 1024);
let out = run(&[
"--driver",
drv,
from.to_str().unwrap(),
to.to_str().unwrap(),
]).unwrap();
assert!(out.status.success());
assert_eq!(to.metadata().unwrap().len(), 1024 * 1024);
assert!(probably_sparse(&to).unwrap());
assert_eq!(quickstat(&from).unwrap(), quickstat(&to).unwrap());
let from_data = read(&from).unwrap();
let to_data = read(&to).unwrap();
assert_eq!(from_data, to_data);
}
#[cfg_attr(feature = "parblock", test_case("parblock"; "Test with parallel block driver"))]
#[test_case("parfile"; "Test with parallel file driver")]
#[cfg_attr(not(feature = "test_run_expensive"), ignore = "Stress test")]
fn copy_generated_tree_sparse(drv: &str) {
println!("Generating file tree...");
let src = gen_global_filetree(false).unwrap();
let dir = tempdir_rel().unwrap();
let dest = dir.path().join("target");
println!("Running copy...");
let out = run(&[
"--driver", drv,
"-r",
"--no-progress",
src.to_str().unwrap(),
dest.to_str().unwrap(),
]).unwrap();
assert!(out.status.success());
println!("Compare trees...");
compare_trees(&src, &dest).unwrap();
}
}