use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use std::time::{Duration, SystemTime};
use mod_tempdir::cleanup_orphans;
fn fake_dir_basename(pid: u32, tag: &str) -> String {
format!(".tmp-{pid}-{tag:0>12}")
}
fn fake_file_basename(pid: u32, tag: &str) -> String {
format!(".tmpfile-{pid}-{tag:0>12}")
}
fn set_dir_modified(path: &Path, when: SystemTime) {
#[cfg(windows)]
let handle = {
use std::os::windows::fs::OpenOptionsExt;
const FILE_FLAG_BACKUP_SEMANTICS: u32 = 0x0200_0000;
OpenOptions::new()
.write(true)
.custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
.open(path)
.expect("open dir for set_modified (windows)")
};
#[cfg(not(windows))]
let handle = File::open(path).expect("open dir for set_modified (unix)");
handle
.set_modified(when)
.expect("set_modified failed on directory handle");
}
fn set_file_modified(path: &Path, when: SystemTime) {
OpenOptions::new()
.write(true)
.open(path)
.expect("open file for set_modified")
.set_modified(when)
.expect("set_modified failed on file handle");
}
fn purge_stale(path: &Path) {
let _ = std::fs::remove_dir_all(path);
let _ = std::fs::remove_file(path);
}
fn create_orphan_dir(pid: u32, tag: &str, age: Duration) -> PathBuf {
let path = std::env::temp_dir().join(fake_dir_basename(pid, tag));
purge_stale(&path);
std::fs::create_dir(&path).expect("create_dir failed for fake orphan dir");
set_dir_modified(&path, SystemTime::now() - age);
path
}
fn create_orphan_file(pid: u32, tag: &str, age: Duration) -> PathBuf {
let path = std::env::temp_dir().join(fake_file_basename(pid, tag));
purge_stale(&path);
File::create(&path).expect("File::create failed for fake orphan file");
set_file_modified(&path, SystemTime::now() - age);
path
}
fn force_remove(path: &PathBuf) {
if path.is_dir() {
let _ = std::fs::remove_dir_all(path);
} else {
let _ = std::fs::remove_file(path);
}
}
#[test]
fn removes_old_orphan_directory() {
let pid = u32::MAX;
let tag = "ZRMVDIRAAAAA";
let age = Duration::from_secs(10 * 3600);
let path = create_orphan_dir(pid, tag, age);
assert!(path.exists(), "fake orphan dir was not created");
let _ = cleanup_orphans(1).expect("cleanup_orphans failed");
assert!(
!path.exists(),
"10-hour-old orphan dir survived cleanup_orphans(1): {path:?}"
);
force_remove(&path);
}
#[test]
fn removes_old_orphan_file() {
let pid = u32::MAX - 1;
let tag = "ZRMVFILEAAAA";
let age = Duration::from_secs(10 * 3600);
let path = create_orphan_file(pid, tag, age);
assert!(path.exists(), "fake orphan file was not created");
let _ = cleanup_orphans(1).expect("cleanup_orphans failed");
assert!(
!path.exists(),
"10-hour-old orphan file survived cleanup_orphans(1): {path:?}"
);
force_remove(&path);
}
#[test]
fn keeps_recent_entry() {
let pid = u32::MAX - 2;
let tag = "ZKPRECENTAAA";
let path = create_orphan_dir(pid, tag, Duration::from_secs(0));
assert!(path.exists());
let _ = cleanup_orphans(1).expect("cleanup_orphans failed");
assert!(
path.exists(),
"recent entry was removed despite age threshold: {path:?}"
);
force_remove(&path);
}
#[test]
fn ignores_custom_prefix_entries() {
let basename = "user-fixture-99999-ZKPCSTOMAAAA";
let path = std::env::temp_dir().join(basename);
purge_stale(&path);
std::fs::create_dir(&path).expect("create_dir failed");
set_dir_modified(&path, SystemTime::now() - Duration::from_secs(48 * 3600));
let _ = cleanup_orphans(1).expect("cleanup_orphans failed");
assert!(path.exists(), "custom-prefix entry was removed: {path:?}");
force_remove(&path);
}
#[test]
fn ignores_legacy_format_entries() {
let basename = ".tmp-ZKPLEGACYAAAA"; let path = std::env::temp_dir().join(basename);
purge_stale(&path);
std::fs::create_dir(&path).expect("create_dir failed");
set_dir_modified(&path, SystemTime::now() - Duration::from_secs(48 * 3600));
let _ = cleanup_orphans(1).expect("cleanup_orphans failed");
assert!(path.exists(), "legacy-format entry was removed: {path:?}");
force_remove(&path);
}
#[cfg(target_os = "linux")]
#[test]
fn keeps_entry_owned_by_live_process_on_linux() {
let pid = std::process::id();
let tag = "ZKPLIVEAAAAA";
let age = Duration::from_secs(10 * 3600);
let path = create_orphan_dir(pid, tag, age);
assert!(path.exists());
let _ = cleanup_orphans(1).expect("cleanup_orphans failed");
assert!(
path.exists(),
"live-process entry was removed by cleanup_orphans on Linux: {path:?}"
);
force_remove(&path);
}