server/lib/tests/readyz_is_real.rs
//! **What `/readyz` asks** (lane B4, A31 §7.3): [`Readiness::check`] — every
//! repository's storage place is there, the data root takes a write, and the
//! scan sandbox answers when the server scans. Each failure is named, all of
//! them at once, so one probe line tells the operator what to fix.
use std::os::unix::fs::PermissionsExt as _;
use std::sync::Arc;
use holger_server_lib::ready::{Place, Readiness};
#[test]
fn a_server_whose_storage_and_sandbox_answer_is_ready() {
let d = tempfile::tempdir().unwrap();
std::fs::create_dir_all(d.path().join("raw")).unwrap();
let r = Readiness {
places: vec![
("raw".into(), Place::Files(d.path().join("raw"))),
("fresh".into(), Place::Files(d.path().join("fresh"))),
],
data_root: d.path().to_path_buf(),
sandbox: Some(Arc::new(|| Ok(()))),
};
r.check().expect("ready");
let left: Vec<_> = std::fs::read_dir(d.path())
.unwrap()
.filter_map(|e| e.ok())
.map(|e| e.file_name())
.collect();
assert_eq!(
left,
vec![std::ffi::OsString::from("raw")],
"the write probe leaves nothing behind, and a fresh repository is not made by a probe"
);
}
#[test]
fn a_missing_storage_place_and_a_sandbox_that_does_not_answer_are_both_named() {
let d = tempfile::tempdir().unwrap();
let r = Readiness {
places: vec![(
"charts".into(),
Place::Archive(d.path().join("charts.znippy")),
)],
data_root: d.path().to_path_buf(),
sandbox: Some(Arc::new(|| {
Err("[holger-sandbox-1] the scan sidecar is not there".into())
})),
};
let e = r.check().unwrap_err();
assert!(
e.contains("storage `charts`") && e.contains("charts.znippy"),
"{e}"
);
assert!(
e.contains("sandbox") && e.contains("holger-sandbox-1"),
"{e}"
);
}
#[test]
fn a_data_root_that_takes_no_write_is_not_ready() {
if rustix_is_root() {
return; // root writes through a 0555 directory; the check is for the pod's uid
}
let d = tempfile::tempdir().unwrap();
let ro = d.path().join("ro");
std::fs::create_dir(&ro).unwrap();
std::fs::set_permissions(&ro, std::fs::Permissions::from_mode(0o555)).unwrap();
let r = Readiness {
places: vec![("raw".into(), Place::Files(ro.join("raw")))],
data_root: ro.clone(),
sandbox: None,
};
let e = r.check().unwrap_err();
std::fs::set_permissions(&ro, std::fs::Permissions::from_mode(0o755)).unwrap();
assert!(e.contains("data root"), "{e}");
assert!(
e.contains("storage `raw`") && e.contains("cannot be made"),
"a fresh repository under a read-only parent is named too: {e}"
);
}
#[test]
fn a_server_that_does_not_scan_needs_no_sandbox_to_be_ready() {
let d = tempfile::tempdir().unwrap();
Readiness {
places: vec![],
data_root: d.path().to_path_buf(),
sandbox: None,
}
.check()
.expect("ready");
}
fn rustix_is_root() -> bool {
std::fs::read_to_string("/proc/self/status")
.ok()
.and_then(|s| {
s.lines()
.find(|l| l.starts_with("Uid:"))
.map(|l| l.split_whitespace().nth(1) == Some("0"))
})
.unwrap_or(false)
}