crates/nornir-config/tests/pin_after_read.rs
//! The other order, in its own process: reading the root FIRST must make a later
//! pin fail loudly.
//!
//! Why this deserves a whole test binary: a pin accepted after the root was
//! resolved would leave the process split across two roots — half of it holding
//! handles under `$HOME/.nornir`, half writing under the pinned tree. That is the
//! exact bug the seam exists to remove, so "too late" has to be an error, never a
//! best-effort success.
use std::path::{Path, PathBuf};
/// RED WHEN REVERTED: drop the `BASE_RESOLVED` store from `nornir_home()` (or the
/// `already_resolved` arm of `decide_pin`) and this pin is quietly ACCEPTED —
/// `pin_nornir_base` returns `Ok` and the process ends up with two roots.
#[test]
fn a_pin_after_the_root_was_read_is_refused_and_changes_nothing() {
// SAFETY: single-threaded test process.
unsafe { std::env::set_var("HOME", "/home/reader") };
// Somebody resolves the root first — e.g. a token read on the way up.
let before = nornir_config::nornir_home();
assert_eq!(before, PathBuf::from("/home/reader/.nornir"), "precondition: HOME decides");
let err = nornir_config::pin_nornir_base(Path::new("/home/dwarves/.dwarves"))
.expect_err("pinning after the root was read must be REFUSED");
assert_eq!(
err,
nornir_config::PinRefused::AlreadyResolved {
attempted: PathBuf::from("/home/dwarves/.dwarves"),
},
);
assert!(
err.to_string().contains("pin BEFORE anything reads it"),
"the refusal must say what to do instead: {err}",
);
// Nothing moved, and no base was recorded — a refused pin is not a half-pin.
assert_eq!(nornir_config::pinned_nornir_base(), None);
assert_eq!(nornir_config::nornir_home(), before);
}