use super::super::lock::{interpret_lock, lock_or_none, try_acquire};
use std::io;
use std::process::{Command, Stdio};
use tempfile::TempDir;
#[test]
fn acquire_creates_inbox_and_returns_guard() {
let ws = TempDir::new().unwrap();
let inbox = ws.path().join("inbox").join("a1");
assert!(!inbox.exists());
let guard = try_acquire(&inbox).unwrap();
assert!(guard.is_some(), "fresh inbox is acquirable");
assert!(inbox.is_dir(), "acquire creates the inbox home");
}
#[test]
fn second_acquire_is_excluded_while_first_held() {
let ws = TempDir::new().unwrap();
let inbox = ws.path().join("inbox").join("a1");
let held = try_acquire(&inbox).unwrap();
assert!(held.is_some());
let second = try_acquire(&inbox).unwrap();
assert!(second.is_none(), "held lock excludes a second driver");
}
#[test]
fn lock_releases_on_drop() {
let ws = TempDir::new().unwrap();
let inbox = ws.path().join("inbox").join("a1");
let first = try_acquire(&inbox).unwrap().expect("acquirable");
drop(first); let again = try_acquire(&inbox).unwrap();
assert!(again.is_some(), "dropping the guard frees the lock");
}
#[test]
fn release_frees_the_lease_while_a_subprocess_still_holds_its_fd() {
let ws = TempDir::new().unwrap();
let inbox = ws.path().join("inbox").join("a1");
let held = try_acquire(&inbox).unwrap().expect("acquirable");
unsafe { libc::fcntl(held.as_raw_fd(), libc::F_SETFD, 0) };
let mut child = Command::new("/bin/sh")
.args(["-c", "read _line"])
.stdin(Stdio::piped())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.expect("a child that inherits the lease fd and outlives the guard");
drop(held);
let again = try_acquire(&inbox).unwrap();
drop(child.stdin.take()); child.wait().unwrap();
assert!(
again.is_some(),
"the lease is free the moment its guard drops, whoever else holds the fd"
);
}
#[test]
fn acquire_surfaces_io_error_when_inbox_home_blocked() {
let ws = TempDir::new().unwrap();
std::fs::write(ws.path().join("inbox"), b"not a dir").unwrap();
let inbox = ws.path().join("inbox").join("a1");
let err = try_acquire(&inbox).unwrap_err();
assert!(
matches!(
err.kind(),
io::ErrorKind::AlreadyExists | io::ErrorKind::NotADirectory | io::ErrorKind::Other
),
"unexpected kind: {err:?}"
);
}
#[test]
fn interpret_lock_maps_success_to_guard() {
let f = tempfile::tempfile().unwrap();
let out = interpret_lock(f, 0, io::Error::from_raw_os_error(0)).unwrap();
assert!(out.is_some(), "ret==0 is a held lease");
}
#[test]
fn interpret_lock_maps_would_block_to_none() {
let f = tempfile::tempfile().unwrap();
let err = io::Error::from_raw_os_error(libc::EWOULDBLOCK);
let out = interpret_lock(f, -1, err).unwrap();
assert!(out.is_none(), "EWOULDBLOCK means someone else drives");
}
#[test]
fn interpret_lock_propagates_other_errno() {
let f = tempfile::tempfile().unwrap();
let err = io::Error::from_raw_os_error(libc::EBADF);
let out = interpret_lock(f, -1, err);
assert!(out.is_err(), "an unexpected errno propagates");
}
#[test]
fn lock_or_none_locks_a_real_fd() {
let f = tempfile::tempfile().unwrap();
let out = lock_or_none(f).unwrap();
assert!(out.is_some());
}