use std::{fs, os::linux::fs::MetadataExt, path};
use xattr::FileExt;
use zstd::bulk::compress;
#[path = "utils.rs"]
pub mod utils;
pub fn make_usecases
(path: P)
where
P: AsRef,
{
let p = path.as_ref();
fs::create_dir_all(p.join("directory")).unwrap();
// Compressed, but no realsize written to xattrs
fs::write(
p.join("already_compressed.txt.zst"),
compress(b"compressed data", 0).unwrap(),
)
.unwrap();
fs::write(
p.join("directory/already_compressed.txt.zst"),
compress(b"compressed data", 0).unwrap(),
)
.unwrap();
// Uncompressed data
fs::write(p.join("uncompressed.txt"), b"compressed data").unwrap();
fs::write(p.join("directory/uncompressed.txt"), b"compressed data").unwrap();
// Both compressed and uncompressed present
fs::write(p.join("overlap.txt"), b"overlap plain").unwrap();
fs::write(
p.join("overlap.txt.zst"),
compress(b"overlap compressed", 0).unwrap(),
)
.unwrap();
fs::write(p.join("directory/overlap.txt"), b"overlap plain").unwrap();
fs::write(
p.join("directory/overlap.txt.zst"),
compress(b"overlap compressed", 0).unwrap(),
)
.unwrap();
}
pub fn fill_in_size_test(data_dir: P1, mount_point: P2)
where
P1: AsRef,
P2: AsRef,
{
let dd = data_dir.as_ref();
let mp = mount_point.as_ref();
// Size is not filled
assert_eq!(
fs::metadata(mp.join("already_compressed.txt"))
.unwrap()
.st_size(),
0
);
assert!(!dd.join("already_compressed.txt").exists());
// Size is filled after open
let _file = fs::File::open(mp.join("already_compressed.txt")).unwrap();
let sfile = fs::File::open(dd.join("already_compressed.txt.zst")).unwrap();
assert_eq!(
sfile
.get_xattr("user.real_size")
.unwrap()
.map(|e| u64::from_be_bytes(e.to_vec().try_into().unwrap()))
.unwrap(),
15
);
assert!(!dd.join("directory/already_compressed.txt").exists());
// Size is not filled
assert_eq!(
fs::metadata(mp.join("directory/already_compressed.txt"))
.unwrap()
.st_size(),
0
);
assert!(!dd.join("directory/already_compressed.txt").exists());
// Size is filled after open
let _file = fs::File::open(mp.join("directory/already_compressed.txt")).unwrap();
let sfile = fs::File::open(dd.join("directory/already_compressed.txt.zst")).unwrap();
assert_eq!(
sfile
.get_xattr("user.real_size")
.unwrap()
.map(|e| u64::from_be_bytes(e.to_vec().try_into().unwrap()))
.unwrap(),
15
);
assert!(!dd.join("directory/already_compressed.txt").exists());
}
mod no_convert {
use super::utils;
use rstest::*;
use std::fs;
#[fixture]
fn mounted_fs() -> utils::FuseZstdProcess {
let zstd_process = utils::FuseZstdProcess::new(false);
super::make_usecases(zstd_process.data_dir());
zstd_process
}
#[rstest]
fn already_compressed(mounted_fs: utils::FuseZstdProcess) {
super::fill_in_size_test(mounted_fs.data_dir(), mounted_fs.mount_point());
}
#[rstest]
fn uncompressed(mounted_fs: utils::FuseZstdProcess) {
let dd = mounted_fs.data_dir();
let mp = mounted_fs.mount_point();
assert!(dd.join("uncompressed.txt").exists());
assert!(!mp.join("uncompressed.txt").exists());
assert!(fs::File::open(mp.join("uncompressed.txt")).is_err());
assert!(dd.join("uncompressed.txt").exists());
assert!(!mp.join("uncompressed.txt").exists());
assert!(dd.join("directory/uncompressed.txt").exists());
assert!(!mp.join("directory/uncompressed.txt").exists());
assert!(fs::File::open(mp.join("directory/uncompressed.txt")).is_err());
assert!(dd.join("directory/uncompressed.txt").exists());
assert!(!mp.join("directory/uncompressed.txt").exists());
}
#[rstest]
fn overlap(mounted_fs: utils::FuseZstdProcess) {
let dd = mounted_fs.data_dir();
let mp = mounted_fs.mount_point();
assert!(dd.join("overlap.txt").exists());
assert!(dd.join("overlap.txt.zst").exists());
assert!(mp.join("overlap.txt").exists());
assert!(!mp.join("overlap.txt.zst").exists());
assert!(fs::File::open(mp.join("overlap.txt")).is_ok());
assert!(dd.join("overlap.txt").exists());
assert!(dd.join("overlap.txt.zst").exists());
assert!(mp.join("overlap.txt").exists());
assert!(!mp.join("overlap.txt.zst").exists());
assert!(dd.join("directory/overlap.txt").exists());
assert!(dd.join("directory/overlap.txt.zst").exists());
assert!(mp.join("directory/overlap.txt").exists());
assert!(!mp.join("directory/overlap.txt.zst").exists());
assert!(fs::File::open(mp.join("overlap.txt")).is_ok());
assert!(dd.join("directory/overlap.txt").exists());
assert!(dd.join("directory/overlap.txt.zst").exists());
assert!(mp.join("directory/overlap.txt").exists());
assert!(!mp.join("directory/overlap.txt.zst").exists());
}
}
mod convert {
use super::utils;
use rstest::*;
use std::fs;
#[fixture]
fn mounted_fs() -> utils::FuseZstdProcess {
let zstd_process = utils::FuseZstdProcess::new(true);
super::make_usecases(zstd_process.data_dir());
zstd_process
}
#[rstest]
fn already_compressed(mounted_fs: utils::FuseZstdProcess) {
super::fill_in_size_test(mounted_fs.data_dir(), mounted_fs.mount_point());
}
#[rstest]
fn uncompressed(mounted_fs: utils::FuseZstdProcess) {
let dd = mounted_fs.data_dir();
let mp = mounted_fs.mount_point();
// in root
assert!(dd.join("uncompressed.txt").exists());
assert!(mp.join("uncompressed.txt").exists());
assert!(fs::File::open(mp.join("uncompressed.txt")).is_ok());
assert!(!dd.join("uncompressed.txt").exists());
assert!(dd.join("uncompressed.txt.zst").exists());
assert!(mp.join("uncompressed.txt").exists());
// in subfolder
assert!(dd.join("directory/uncompressed.txt").exists());
assert!(mp.join("directory/uncompressed.txt").exists());
assert!(fs::File::open(mp.join("directory/uncompressed.txt")).is_ok());
assert!(!dd.join("directory/uncompressed.txt").exists());
assert!(dd.join("directory/uncompressed.txt.zst").exists());
assert!(mp.join("directory/uncompressed.txt").exists());
}
#[rstest]
fn overlap(mounted_fs: utils::FuseZstdProcess) {
let dd = mounted_fs.data_dir();
let mp = mounted_fs.mount_point();
// in root
assert!(dd.join("overlap.txt").exists());
assert!(dd.join("overlap.txt.zst").exists());
assert_eq!(
fs::read_to_string(dd.join("overlap.txt")).unwrap(),
"overlap plain"
);
assert_eq!(
utils::get_compressed_content(dd.join("overlap.txt.zst")),
"overlap compressed"
);
// mp.join will cause lookup
assert!(mp.join("overlap.txt").exists());
assert!(!mp.join("overlap.txt.zst").exists());
// after lookup uncompressed file should be removed
assert!(!dd.join("overlap.txt").exists());
assert!(dd.join("overlap.txt.zst").exists());
assert_eq!(
utils::get_compressed_content(dd.join("overlap.txt.zst")),
"overlap compressed"
);
// in directory
assert!(dd.join("directory/overlap.txt").exists());
assert!(dd.join("directory/overlap.txt.zst").exists());
assert_eq!(
fs::read_to_string(dd.join("directory/overlap.txt")).unwrap(),
"overlap plain"
);
assert_eq!(
utils::get_compressed_content(dd.join("directory/overlap.txt.zst")),
"overlap compressed"
);
// mp.join will cause lookup
assert!(mp.join("directory/overlap.txt").exists());
assert!(!mp.join("directory/overlap.txt.zst").exists());
// after lookup uncompressed file should be removed
assert!(!dd.join("directory/overlap.txt").exists());
assert!(dd.join("directory/overlap.txt.zst").exists());
assert_eq!(
utils::get_compressed_content(dd.join("directory/overlap.txt.zst")),
"overlap compressed"
);
}
}