pub const FAULT_VARIABLE: &str = "CLI_GIT_TEST_ONLY_SERVICE_FAULT";
pub const FAULT_POINTS: [&str; 5] = ["after-objects", "after-intent", "after-ref", "after-index", "before-ack"];
pub fn reach(point: &str) {
#[cfg(test)]
hooks::run(point);
if std::env::var(FAULT_VARIABLE).is_ok_and(|armed| { return armed == point; }) {
crate::service_log!("test fault at {point}");
#[cfg(unix)]
unsafe {
libc::kill(libc::getpid(), libc::SIGKILL);
}
std::process::exit(137);
}
}
pub fn note(event: &str) {
#[cfg(test)]
hooks::record(event);
#[cfg(not(test))]
let _unused: &str = event;
}
pub fn fails(point: &str) -> bool {
#[cfg(test)]
return hooks::failing(point);
#[cfg(not(test))]
return {
let _unused: &str = point;
false
};
}
pub const QUEUED_DIRECTORY_VARIABLE: &str = "CLI_GIT_TEST_ONLY_SERVICE_QUEUED_DIRECTORY";
pub fn queued(id: &str) {
let Some(directory) = std::env::var_os(QUEUED_DIRECTORY_VARIABLE) else { return };
let name: String = id.chars().map(|character| { return if character.is_ascii_alphanumeric() { character } else { '_' }; }).collect();
let path: std::path::PathBuf = std::path::Path::new(&directory).join(format!("queued-{name}"));
if let Err(error) = std::fs::write(&path, b"") {
crate::service_warn!("cannot leave the queued-request file {}: {error}", path.display());
}
}
pub const FIRST_BATCH_VARIABLE: &str = "CLI_GIT_TEST_ONLY_SERVICE_FIRST_BATCH";
pub fn pinned_first_batch() -> Option<u64> {
return std::env::var(FIRST_BATCH_VARIABLE).ok().and_then(|text| { return text.parse::<u64>().ok(); });
}
#[cfg(test)]
pub(crate) mod hooks {
use std::cell::RefCell;
thread_local! {
static EVENTS: RefCell<Vec<String>> = const { RefCell::new(Vec::new()) };
static HOOK: RefCell<Option<(String, std::rc::Rc<dyn Fn()>)>> = const { RefCell::new(None) };
static FAILING: RefCell<Vec<String>> = const { RefCell::new(Vec::new()) };
}
pub(crate) fn fail_at(point: &str) {
FAILING.with(|failing| { failing.borrow_mut().push(point.to_string()); });
}
pub(crate) fn clear_failures() {
FAILING.with(|failing| { failing.borrow_mut().clear(); });
}
pub(super) fn failing(point: &str) -> bool {
return FAILING.with(|failing| { return failing.borrow().iter().any(|named| { return named == point; }); });
}
pub(crate) fn set(point: &str, code: std::rc::Rc<dyn Fn()>) {
HOOK.with(|hook| { *hook.borrow_mut() = Some((point.to_string(), code)); });
}
pub(super) fn record(event: &str) {
EVENTS.with(|events| { events.borrow_mut().push(event.to_string()); });
}
pub(crate) fn take_events() -> Vec<String> {
return EVENTS.with(|events| { return std::mem::take(&mut *events.borrow_mut()); });
}
pub(super) fn run(point: &str) {
let found: Option<std::rc::Rc<dyn Fn()>> = HOOK.with(|hook| { return hook.borrow().as_ref().filter(|(named, _)| { return named == point; }).map(|(_, code)| { return std::rc::Rc::clone(code); }); });
if let Some(hook) = found {
hook();
}
}
}