use crate::common::{single_mount, write_compressible_data};
use btrfs_uapi::{
defrag::{CompressSpec, CompressType, DefragRangeArgs, defrag_range},
filesystem::sync,
};
use std::{
fs::{File, metadata},
os::unix::{fs::MetadataExt, io::AsFd},
};
#[test]
#[ignore = "requires elevated privileges"]
#[should_panic] fn defrag_compress() {
let (_td, mnt) = single_mount();
write_compressible_data(mnt.path(), "zeros.bin", 10_000_000);
sync(mnt.fd()).unwrap();
let path = mnt.path().join("zeros.bin");
let blocks_before = metadata(&path).unwrap().blocks();
let file = File::options()
.read(true)
.write(true)
.open(&path)
.expect("failed to open test file");
defrag_range(
file.as_fd(),
&DefragRangeArgs::new()
.compress(CompressSpec {
compress_type: CompressType::Zlib,
level: None,
})
.extent_thresh(1),
)
.expect("defrag_range failed");
drop(file);
sync(mnt.fd()).unwrap();
let blocks_after = metadata(&path).unwrap().blocks();
assert!(
blocks_after < blocks_before,
"disk blocks should decrease after compressing: before={blocks_before}, after={blocks_after}",
);
let data = std::fs::read(&path).expect("read failed");
assert_eq!(data.len(), 10_000_000);
assert!(
data.iter().all(|&b| b == 0),
"data should still be all zeros"
);
}
#[test]
#[ignore = "requires elevated privileges"]
fn defrag_no_compression() {
let (_td, mnt) = single_mount();
let path = mnt.path().join("fragmented.bin");
{
use std::io::Write;
let mut file = File::create(&path).expect("create failed");
for i in 0..200u32 {
let chunk = [i as u8; 4096];
file.write_all(&chunk).unwrap();
file.sync_all().unwrap();
}
}
let file = File::options()
.read(true)
.write(true)
.open(&path)
.expect("open failed");
defrag_range(file.as_fd(), &DefragRangeArgs::new())
.expect("defrag_range failed");
drop(file);
sync(mnt.fd()).unwrap();
let data = std::fs::read(&path).expect("read failed");
assert_eq!(data.len(), 200 * 4096);
for (i, chunk) in data.chunks(4096).enumerate() {
assert!(
chunk.iter().all(|&b| b == i as u8),
"data mismatch in chunk {i}",
);
}
}