use super::*;
use std::fs::File;
fn record_aged(directory: &Path, age: Duration) -> std::path::PathBuf {
let path: std::path::PathBuf = directory.join("owner.json");
let file: File = File::create(path.as_path()).expect("create the record");
file.set_modified(SystemTime::now() - age).expect("age the record");
return path;
}
#[test]
#[cfg(target_os = "linux")]
fn the_current_namespace_is_named_the_way_the_kernel_names_it() {
let name: String = current_pid_namespace().expect("a Linux process has a PID namespace");
assert!(name.starts_with("pid:["), "{name}");
assert!(name.ends_with(']'), "{name}");
}
#[test]
fn only_two_known_and_different_names_are_another_namespace() {
assert!(is_other_namespace(Some("pid:[1]"), Some("pid:[2]")));
assert!(!is_other_namespace(Some("pid:[1]"), Some("pid:[1]")));
assert!(!is_other_namespace(None, Some("pid:[2]")), "an old record names no namespace");
assert!(!is_other_namespace(Some("pid:[1]"), None), "a reader without a namespace cannot tell");
assert!(!is_other_namespace(None, None));
}
#[test]
fn a_foreign_record_expires_only_after_the_patience() {
let directory: std::path::PathBuf = crate::test_support::fixture("pid-namespace-1");
let fresh = record_aged(directory.as_path(), Duration::from_secs(60));
assert!(!age_outlives_patience(foreign_record_age(fresh.as_path()).expect("a measurable age")));
let old = record_aged(directory.as_path(), FOREIGN_OWNER_PATIENCE + Duration::from_secs(60));
assert!(age_outlives_patience(foreign_record_age(old.as_path()).expect("a measurable age")));
let nearly = record_aged(directory.as_path(), FOREIGN_OWNER_PATIENCE - Duration::from_secs(60));
assert!(!age_outlives_patience(foreign_record_age(nearly.as_path()).expect("a measurable age")), "just inside the patience stays alive");
}
#[test]
fn a_record_that_cannot_be_measured_does_not_expire() {
let directory: std::path::PathBuf = crate::test_support::fixture("pid-namespace-2");
assert_eq!(foreign_record_age(directory.as_path().join("absent.json").as_path()), None);
let future = record_aged(directory.as_path(), Duration::ZERO);
File::options().write(true).open(future.as_path()).expect("open").set_modified(
SystemTime::now() + Duration::from_secs(7200),
).expect("move the time ahead");
assert_eq!(foreign_record_age(future.as_path()), None, "a record from the future has no age, so it is not old");
}
#[test]
#[cfg(target_os = "linux")]
fn a_foreign_owner_is_alive_until_its_record_expires() {
let directory: std::path::PathBuf = crate::test_support::fixture("pid-namespace-3");
let fresh = record_aged(directory.as_path(), Duration::from_secs(60));
let own: String = current_pid_namespace().expect("namespace");
assert_eq!(foreign_owner_standing(Some(own.as_str()), fresh.as_path()), None);
assert_eq!(foreign_owner_standing(None, fresh.as_path()), None);
assert_eq!(foreign_owner_standing(Some("pid:[1]"), fresh.as_path()), Some(Ok(())));
let old = record_aged(directory.as_path(), FOREIGN_OWNER_PATIENCE + Duration::from_secs(60));
let Some(Err(expired)) = foreign_owner_standing(Some("pid:[1]"), old.as_path()) else { panic!("an expired foreign record is refused") };
let text: String = expired.describe(31337);
assert!(text.contains("31337") && text.contains("pid:[1]") && text.contains("21 minutes old") && text.contains("20 minutes") && text.contains("rm -- "), "{text}");
assert!(text.contains("another container") && text.contains("left running") && text.contains(old.to_string_lossy().as_ref()), "{text}");
}
#[test]
fn the_patience_boundary_is_exclusive() {
assert!(!age_outlives_patience(FOREIGN_OWNER_PATIENCE));
assert!(age_outlives_patience(FOREIGN_OWNER_PATIENCE + Duration::from_nanos(1)));
assert!(!age_outlives_patience(FOREIGN_OWNER_PATIENCE - Duration::from_nanos(1)));
}
#[test]
fn the_patience_is_twice_the_lock_ceiling() {
assert_eq!(FOREIGN_OWNER_PATIENCE, 2 * crate::wait_ceilings::LOCK_CEILING);
}
#[test]
fn the_patience_outlasts_the_longest_measured_command() {
const LONGEST_COMMAND_MEASURED: Duration = Duration::from_millis(750_604);
assert!(FOREIGN_OWNER_PATIENCE > LONGEST_COMMAND_MEASURED);
}