use super::*;
fn file_in(dir: &Path) -> std::io::Result<tempfile::NamedTempFile> {
tempfile::NamedTempFile::new_in(dir)
}
fn files_in(dir: &Path) -> usize {
std::fs::read_dir(dir).unwrap().count()
}
#[test]
fn a_sweep_waits_for_a_writer_that_stops() {
let dir = tempfile::tempdir().unwrap();
let unfinished = Unfinished::default();
let stop = Arc::new(AtomicBool::new(false));
let writer = unfinished.writer(stop.clone());
let (claimed, wait) = std::sync::mpsc::channel();
let worker = {
let dir = dir.path().to_path_buf();
std::thread::spawn(move || {
let (file, claim) = writer
.create(|| file_in(&dir))
.unwrap()
.expect("not stopped yet");
claimed.send(()).unwrap();
while !writer.stopped() {
std::thread::sleep(Duration::from_millis(5));
}
drop(file);
drop(claim);
})
};
wait.recv().unwrap();
stop.store(true, Ordering::Relaxed);
let began = Instant::now();
unfinished.sweep(began + Duration::from_secs(30));
assert!(
began.elapsed() < Duration::from_secs(10),
"not the whole grace"
);
assert_eq!(files_in(dir.path()), 0);
assert!(!unfinished.writing());
worker.join().unwrap();
}
#[test]
fn a_sweep_removes_what_a_writer_still_holds() {
let dir = tempfile::tempdir().unwrap();
let unfinished = Unfinished::default();
let writer = unfinished.writer(Arc::default());
let (file, claim) = writer
.create(|| file_in(dir.path()))
.unwrap()
.expect("not stopped yet");
let path = file.path().to_path_buf();
unfinished.sweep(Instant::now() + Duration::from_millis(20));
assert!(!path.exists());
assert!(!unfinished.writing());
drop(file);
drop(claim);
}
#[test]
fn a_sweep_waits_for_a_file_being_created() {
let dir = tempfile::tempdir().unwrap();
let unfinished = Unfinished::default();
let stop = Arc::new(AtomicBool::new(false));
let writer = unfinished.writer(stop.clone());
let (creating, wait) = std::sync::mpsc::channel();
let (go, gate) = std::sync::mpsc::channel::<()>();
let worker = {
let dir = dir.path().to_path_buf();
std::thread::spawn(move || {
writer
.create(|| {
creating.send(()).unwrap();
gate.recv().unwrap();
file_in(&dir)
})
.unwrap()
.is_none()
})
};
wait.recv().unwrap();
stop.store(true, Ordering::Relaxed);
let sweeper = {
let unfinished = unfinished.clone();
std::thread::spawn(move || unfinished.sweep(Instant::now() + Duration::from_secs(30)))
};
assert!(
unfinished.a_sweep_waits_within(Duration::from_secs(30)),
"the sweep waits for the file"
);
assert!(unfinished.writing());
assert!(!sweeper.is_finished());
go.send(()).unwrap();
sweeper.join().unwrap();
assert_eq!(files_in(dir.path()), 0, "the sweep waited for the file");
assert!(!unfinished.writing());
assert!(worker.join().unwrap(), "a stopped open's file is refused");
}
#[test]
fn a_file_its_holder_could_not_remove_is_removed_later() {
let dir = tempfile::tempdir().unwrap();
let unfinished = Unfinished::default();
let writer = unfinished.writer(Arc::default());
let left_over = |name: &str| {
let path = dir.path().join(name);
let (path, claim) = writer
.create(|| std::fs::write(&path, b"x").map(|()| path.clone()))
.unwrap()
.expect("not stopped yet");
drop(claim);
assert!(path.exists());
path
};
let first = left_over("first");
assert!(!unfinished.writing(), "nothing is writing it");
let (file, claim) = writer
.create(|| file_in(dir.path()))
.unwrap()
.expect("not stopped yet");
drop(file);
drop(claim);
assert!(!first.exists(), "the next claim tried it again");
let second = left_over("second");
let began = Instant::now();
unfinished.sweep(began + Duration::from_secs(30));
assert!(began.elapsed() < Duration::from_secs(10), "not waited on");
assert!(!second.exists(), "the sweep removed it");
assert_eq!(files_in(dir.path()), 0);
}
#[test]
fn a_stopped_or_swept_open_refuses_new_files() {
let dir = tempfile::tempdir().unwrap();
let unfinished = Unfinished::default();
let made = |writer: &Writer| {
writer
.create(|| file_in(dir.path()))
.unwrap()
.map(|(file, _)| file)
};
let stopped = unfinished.writer(Arc::new(AtomicBool::new(true)));
assert!(made(&stopped).is_none());
let writer = unfinished.writer(Arc::default());
unfinished.sweep(Instant::now());
assert!(made(&writer).is_none());
assert_eq!(files_in(dir.path()), 0);
}