#![cfg(unix)]
use crate::config::profile::acquire_scheduler_lock_in;
use tempfile::TempDir;
#[test]
fn first_caller_acquires_the_profile_scheduler() {
let dir = TempDir::new().unwrap();
let guard = acquire_scheduler_lock_in(dir.path(), "default");
assert!(guard.is_some(), "an unheld profile lock must be acquirable");
}
#[test]
fn second_caller_for_same_profile_is_denied_while_held() {
let dir = TempDir::new().unwrap();
let held = acquire_scheduler_lock_in(dir.path(), "ops");
assert!(held.is_some(), "first acquire should win");
let denied = acquire_scheduler_lock_in(dir.path(), "ops");
assert!(
denied.is_none(),
"a second scheduler for a held profile must be denied"
);
}
#[test]
fn different_profiles_do_not_contend() {
let dir = TempDir::new().unwrap();
let ops = acquire_scheduler_lock_in(dir.path(), "ops");
let family = acquire_scheduler_lock_in(dir.path(), "family");
assert!(ops.is_some(), "ops lock is independent");
assert!(
family.is_some(),
"family lock must not be blocked by the ops lock"
);
}
#[test]
fn lock_is_released_on_drop_and_can_be_retaken() {
let dir = TempDir::new().unwrap();
{
let guard = acquire_scheduler_lock_in(dir.path(), "default");
assert!(guard.is_some(), "first acquire should win");
}
let reacquired = (0..10).find_map(|_| {
acquire_scheduler_lock_in(dir.path(), "default").or_else(|| {
std::thread::sleep(std::time::Duration::from_millis(50));
None
})
});
assert!(
reacquired.is_some(),
"after the holder drops, the profile lock must be retakeable (a crashed daemon must not wedge scheduling)"
);
}
#[test]
fn instance_running_true_when_lock_held_by_live_pid() {
let dir = TempDir::new().unwrap();
let lock_dir = dir.path().join("instance");
std::fs::create_dir_all(&lock_dir).unwrap();
let lock_file = lock_dir.join("ops.lock");
std::fs::write(&lock_file, std::process::id().to_string()).unwrap();
assert!(
crate::config::profile::instance_running_in(&lock_dir, "ops"),
"Live process ID should be detected as running instance"
);
}
#[test]
fn instance_running_false_when_no_lock_file() {
let dir = TempDir::new().unwrap();
let lock_dir = dir.path().join("instance");
std::fs::create_dir_all(&lock_dir).unwrap();
assert!(
!crate::config::profile::instance_running_in(&lock_dir, "ops"),
"Missing lock file should report instance not running"
);
}
#[test]
fn instance_running_false_when_pid_dead_or_garbage() {
let dir = TempDir::new().unwrap();
let lock_dir = dir.path().join("instance");
std::fs::create_dir_all(&lock_dir).unwrap();
let dead_file = lock_dir.join("dead.lock");
std::fs::write(&dead_file, u32::MAX.to_string()).unwrap();
assert!(
!crate::config::profile::instance_running_in(&lock_dir, "dead"),
"Dead PID should report instance not running"
);
let garbage_file = lock_dir.join("garbage.lock");
std::fs::write(&garbage_file, "not-a-pid").unwrap();
assert!(
!crate::config::profile::instance_running_in(&lock_dir, "garbage"),
"Garbage PID string should report instance not running"
);
}