#![cfg(target_os = "linux")]
use fsys::{builder, JournalReader};
use std::path::PathBuf;
use std::sync::atomic::{AtomicU64, Ordering};
static C: AtomicU64 = AtomicU64::new(0);
fn tmp_path(tag: &str) -> PathBuf {
let n = C.fetch_add(1, Ordering::Relaxed);
std::env::temp_dir().join(format!(
"fsys_iouring_fallback_{}_{}_{tag}",
std::process::id(),
n
))
}
struct Cleanup(PathBuf);
impl Drop for Cleanup {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.0);
}
}
fn force_fallback_paths() {
use std::sync::Once;
static SET: Once = Once::new();
SET.call_once(|| {
std::env::set_var("FSYS_TEST_FORCE_NO_IOURING_FEATURES", "1");
std::env::set_var("FSYS_TEST_FORCE_POSIX_FALLOCATE", "1");
});
}
#[test]
fn handle_construction_succeeds_with_no_iouring_features() {
force_fallback_paths();
let _h = builder()
.build()
.expect("handle should construct without elite flags");
}
#[test]
fn journal_write_read_round_trip_no_iouring_features() {
force_fallback_paths();
let path = tmp_path("no_iouring_features");
let _g = Cleanup(path.clone());
let h = builder().build().expect("handle");
let log = h.journal(&path).expect("journal");
let lsn1 = log.append(b"alpha").expect("append alpha");
let lsn2 = log.append(b"beta").expect("append beta");
let lsn3 = log.append(b"gamma").expect("append gamma");
assert!(lsn3 > lsn2 && lsn2 > lsn1);
log.sync_through(lsn3).expect("sync_through");
assert!(log.synced_lsn() >= lsn3);
log.close().expect("close");
let mut reader = JournalReader::open(&path).expect("reader");
let payloads: Vec<Vec<u8>> = reader.iter().map(|r| r.expect("decode").payload).collect();
assert_eq!(
payloads,
vec![b"alpha".to_vec(), b"beta".to_vec(), b"gamma".to_vec()]
);
assert_eq!(reader.tail_state(), fsys::JournalTailState::CleanEnd);
}
#[test]
fn write_round_trip_no_iouring_features() {
force_fallback_paths();
let path = tmp_path("write_no_iouring");
let _g = Cleanup(path.clone());
let h = builder().build().expect("handle");
let data = b"baseline-no-elite-flags";
h.write(&path, data).expect("write");
let read_back = h.read(&path).expect("read");
assert_eq!(read_back, data);
}
#[test]
fn preallocate_falls_back_to_posix_fallocate_cleanly() {
force_fallback_paths();
let path = tmp_path("preallocate_fallback");
let _g = Cleanup(path.clone());
let h = builder().build().expect("handle");
let log = h.journal(&path).expect("journal");
const RESERVE_BYTES: u64 = 64 * 1024;
log.preallocate(0, RESERVE_BYTES)
.expect("preallocate must take the posix_fallocate fallback cleanly");
log.close().expect("close");
let meta = std::fs::metadata(&path).expect("stat");
assert!(
meta.len() >= RESERVE_BYTES,
"file size after posix_fallocate fallback: {} < expected {}",
meta.len(),
RESERVE_BYTES
);
}