use libnewsboat::fslock::FsLock;
use std::env;
use std::io::{Error, ErrorKind};
use std::io::{Read, Write};
use std::path::PathBuf;
use std::process::{Command, Stdio};
use tempfile::NamedTempFile;
fn get_exe_path(exe: &str) -> Result<PathBuf, Error> {
let mut p = env::current_exe().expect("exe path");
while p.pop() {
if p.join(exe).exists() {
return Ok(p.join(exe));
}
}
Err(Error::new(ErrorKind::NotFound, exe))
}
#[test]
fn t_returns_an_error_if_invalid_lock_location() {
let tmp = tempfile::tempdir().unwrap();
let non_existing_dir = tmp.as_ref().join("does-not-exist/");
let lock_location = non_existing_dir.join("lockfile");
let mut lock = FsLock::default();
let mut pid = -1;
assert!(lock.try_lock(lock_location.as_ref(), &mut pid).is_err());
assert_eq!(pid, 0);
}
#[test]
fn t_returns_an_error_lock_file_without_write_access() {
let lock_location = NamedTempFile::new().unwrap();
let mut perms = lock_location.as_file().metadata().unwrap().permissions();
perms.set_readonly(true);
lock_location.as_file().set_permissions(perms).unwrap();
let mut lock = FsLock::default();
let mut pid = -1;
assert!(lock.try_lock(lock_location.as_ref(), &mut pid).is_err());
assert_eq!(pid, 0);
}
#[test]
fn t_fails_if_lock_was_already_created() {
let lock_location = NamedTempFile::new().unwrap();
let cmd = match env::var("CARGO_BIN_EXE_lock-process") {
Ok(dir) => dir,
Err(_) => get_exe_path("lock-process")
.unwrap()
.to_str()
.unwrap()
.to_string(),
};
let mut child = Command::new(cmd)
.arg(lock_location.path())
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
let mut lock = FsLock::default();
let mut pid = 0;
let cid = child.id() as i32;
let stdout = child.stdout.as_mut().unwrap();
stdout.read_exact(&mut [0]).unwrap();
let result = lock.try_lock(lock_location.as_ref(), &mut pid);
assert!(result.is_err());
if let Err(e) = result {
assert!(!e.is_empty());
}
assert_eq!(pid, cid, "pid should be process holding the lock");
let stdin = child.stdin.as_mut().unwrap();
stdin.write_all(b"\n").unwrap();
child.wait().unwrap();
}
#[test]
fn t_succeeds_if_lock_file_location_is_valid_and_not_locked_by_different_process() {
let lock_location = NamedTempFile::new().unwrap();
let mut lock = FsLock::default();
let mut pid = 0;
assert!(lock.try_lock(lock_location.as_ref(), &mut pid).is_ok());
assert!(lock_location.path().exists());
assert!(
lock.try_lock(lock_location.as_ref(), &mut pid).is_ok(),
"recall succeeds"
);
let new_lock_location = NamedTempFile::new().unwrap();
assert!(lock_location.path().exists());
assert!(lock.try_lock(new_lock_location.as_ref(), &mut pid).is_ok());
assert!(!lock_location.path().exists());
assert!(new_lock_location.path().exists());
}