#[test]
#[serial]
fn checkpoint_config_env_override() {
if crate::test_process::run_in_child(|_| {}) {
return;
}
crate::test_process::set_var("KHIVE_CHECKPOINT_INTERVAL_MS", "250");
crate::test_process::set_var("KHIVE_WAL_WARN_PAGES", "1500");
crate::test_process::set_var("KHIVE_WAL_HIGH_WATER_PAGES", "8000");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_HIGH_WATER_PAGES", "12000");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_MIN_INTERVAL_SECS", "60");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_BUSY_MS", "500");
crate::test_process::set_var("KHIVE_TX_WARN_SECS", "15");
crate::test_process::set_var("KHIVE_TX_MAX_AGE_SECS", "90");
let cfg = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_CHECKPOINT_INTERVAL_MS");
crate::test_process::remove_var("KHIVE_WAL_WARN_PAGES");
crate::test_process::remove_var("KHIVE_WAL_HIGH_WATER_PAGES");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_HIGH_WATER_PAGES");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_MIN_INTERVAL_SECS");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_BUSY_MS");
crate::test_process::remove_var("KHIVE_TX_WARN_SECS");
crate::test_process::remove_var("KHIVE_TX_MAX_AGE_SECS");
assert_eq!(cfg.interval, Duration::from_millis(250));
assert_eq!(cfg.warn_pages, 1500);
assert_eq!(cfg.high_water_pages, 8000);
assert_eq!(cfg.truncate_high_water_pages, 12000);
assert_eq!(cfg.truncate_min_interval, Duration::from_secs(60));
assert_eq!(cfg.truncate_busy_timeout, Duration::from_millis(500));
assert_eq!(cfg.tx_warn_secs, Duration::from_secs(15));
assert_eq!(cfg.tx_max_age_secs, Duration::from_secs(90));
}
#[test]
#[serial]
fn checkpoint_config_defaults_on_invalid_env() {
if crate::test_process::run_in_child(|_| {}) {
return;
}
let default = CheckpointConfig::default();
crate::test_process::set_var("KHIVE_CHECKPOINT_INTERVAL_MS", "not_a_number");
crate::test_process::set_var("KHIVE_WAL_WARN_PAGES", "");
crate::test_process::set_var("KHIVE_WAL_HIGH_WATER_PAGES", "0");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_HIGH_WATER_PAGES", "not_a_number");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_MIN_INTERVAL_SECS", "");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_BUSY_MS", "0");
crate::test_process::set_var("KHIVE_TX_WARN_SECS", "not_a_number");
crate::test_process::set_var("KHIVE_TX_MAX_AGE_SECS", "0");
let cfg = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_CHECKPOINT_INTERVAL_MS");
crate::test_process::remove_var("KHIVE_WAL_WARN_PAGES");
crate::test_process::remove_var("KHIVE_WAL_HIGH_WATER_PAGES");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_HIGH_WATER_PAGES");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_MIN_INTERVAL_SECS");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_BUSY_MS");
crate::test_process::remove_var("KHIVE_TX_WARN_SECS");
crate::test_process::remove_var("KHIVE_TX_MAX_AGE_SECS");
assert_eq!(cfg.interval, default.interval);
assert_eq!(cfg.warn_pages, default.warn_pages);
assert_eq!(cfg.high_water_pages, default.high_water_pages);
assert_eq!(
cfg.truncate_high_water_pages,
default.truncate_high_water_pages
);
assert_eq!(cfg.truncate_min_interval, default.truncate_min_interval);
assert_eq!(cfg.truncate_busy_timeout, default.truncate_busy_timeout);
assert_eq!(cfg.tx_warn_secs, default.tx_warn_secs);
assert_eq!(cfg.tx_max_age_secs, default.tx_max_age_secs);
}
#[test]
#[serial]
fn checkpoint_config_rejects_zero_for_all_fields() {
if crate::test_process::run_in_child(|_| {}) {
return;
}
let default = CheckpointConfig::default();
crate::test_process::set_var("KHIVE_CHECKPOINT_INTERVAL_MS", "0");
crate::test_process::set_var("KHIVE_WAL_WARN_PAGES", "0");
crate::test_process::set_var("KHIVE_WAL_HIGH_WATER_PAGES", "0");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_HIGH_WATER_PAGES", "0");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_MIN_INTERVAL_SECS", "0");
crate::test_process::set_var("KHIVE_WAL_TRUNCATE_BUSY_MS", "0");
crate::test_process::set_var("KHIVE_TX_WARN_SECS", "0");
crate::test_process::set_var("KHIVE_TX_MAX_AGE_SECS", "0");
let cfg = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_CHECKPOINT_INTERVAL_MS");
crate::test_process::remove_var("KHIVE_WAL_WARN_PAGES");
crate::test_process::remove_var("KHIVE_WAL_HIGH_WATER_PAGES");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_HIGH_WATER_PAGES");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_MIN_INTERVAL_SECS");
crate::test_process::remove_var("KHIVE_WAL_TRUNCATE_BUSY_MS");
crate::test_process::remove_var("KHIVE_TX_WARN_SECS");
crate::test_process::remove_var("KHIVE_TX_MAX_AGE_SECS");
assert_eq!(
cfg.interval, default.interval,
"zero interval must fall back to default"
);
assert_eq!(
cfg.warn_pages, default.warn_pages,
"zero warn_pages must fall back to default"
);
assert_eq!(
cfg.high_water_pages, default.high_water_pages,
"zero high_water_pages must fall back to default"
);
assert_eq!(
cfg.truncate_high_water_pages, default.truncate_high_water_pages,
"zero truncate_high_water_pages must fall back to default"
);
assert_eq!(
cfg.truncate_min_interval, default.truncate_min_interval,
"zero truncate_min_interval must fall back to default"
);
assert_eq!(
cfg.truncate_busy_timeout, default.truncate_busy_timeout,
"zero truncate_busy_timeout must fall back to default"
);
assert_eq!(
cfg.tx_warn_secs, default.tx_warn_secs,
"zero tx_warn_secs must fall back to default"
);
assert_eq!(
cfg.tx_max_age_secs, default.tx_max_age_secs,
"zero tx_max_age_secs must fall back to default"
);
}
#[test]
#[serial]
fn checkpoint_config_rejects_reversed_tx_thresholds() {
if crate::test_process::run_in_child(|_| {}) {
return;
}
let default = CheckpointConfig::default();
crate::test_process::set_var("KHIVE_TX_WARN_SECS", "120");
crate::test_process::set_var("KHIVE_TX_MAX_AGE_SECS", "30");
let cfg = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_TX_WARN_SECS");
crate::test_process::remove_var("KHIVE_TX_MAX_AGE_SECS");
assert_eq!(
cfg.tx_warn_secs, default.tx_warn_secs,
"a reversed pair must fall back tx_warn_secs to its default, got: {:?}",
cfg.tx_warn_secs
);
assert_eq!(
cfg.tx_max_age_secs, default.tx_max_age_secs,
"a reversed pair must fall back tx_max_age_secs to its default, got: {:?}",
cfg.tx_max_age_secs
);
}
#[test]
#[serial]
fn checkpoint_config_rejects_equal_tx_thresholds() {
if crate::test_process::run_in_child(|_| {}) {
return;
}
let default = CheckpointConfig::default();
crate::test_process::set_var("KHIVE_TX_WARN_SECS", "60");
crate::test_process::set_var("KHIVE_TX_MAX_AGE_SECS", "60");
let cfg = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_TX_WARN_SECS");
crate::test_process::remove_var("KHIVE_TX_MAX_AGE_SECS");
assert_eq!(
cfg.tx_warn_secs, default.tx_warn_secs,
"an equal pair must fall back tx_warn_secs to its default, got: {:?}",
cfg.tx_warn_secs
);
assert_eq!(
cfg.tx_max_age_secs, default.tx_max_age_secs,
"an equal pair must fall back tx_max_age_secs to its default, got: {:?}",
cfg.tx_max_age_secs
);
}
#[test]
#[serial]
fn checkpoint_config_warn_sustained_cycles_env_override() {
if crate::test_process::run_in_child(|_| {}) {
return;
}
let default = CheckpointConfig::default();
assert_eq!(default.warn_sustained_cycles, DEFAULT_WARN_SUSTAINED_CYCLES);
crate::test_process::set_var("KHIVE_WAL_WARN_SUSTAINED_CYCLES", "5");
let cfg = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_WAL_WARN_SUSTAINED_CYCLES");
assert_eq!(cfg.warn_sustained_cycles, 5);
crate::test_process::set_var("KHIVE_WAL_WARN_SUSTAINED_CYCLES", "0");
let cfg_zero = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_WAL_WARN_SUSTAINED_CYCLES");
assert_eq!(
cfg_zero.warn_sustained_cycles, DEFAULT_WARN_SUSTAINED_CYCLES,
"zero must fall back to the default"
);
crate::test_process::set_var("KHIVE_WAL_WARN_SUSTAINED_CYCLES", "not_a_number");
let cfg_invalid = CheckpointConfig::from_env();
crate::test_process::remove_var("KHIVE_WAL_WARN_SUSTAINED_CYCLES");
assert_eq!(
cfg_invalid.warn_sustained_cycles,
DEFAULT_WARN_SUSTAINED_CYCLES
);
}
#[test]
fn session_sweep_environment_preserves_interval_and_threshold_defaults() {
const INTERVAL: &str = "KHIVE_SESSION_SWEEP_INTERVAL_MS";
const WARN: &str = "KHIVE_TX_WARN_SECS";
const MAX_AGE: &str = "KHIVE_TX_MAX_AGE_SECS";
const CYCLES: &str = "KHIVE_WAL_WARN_SUSTAINED_CYCLES";
if crate::test_process::run_in_child(|command| {
for key in [INTERVAL, WARN, MAX_AGE, CYCLES] {
command.env_remove(key);
}
}) {
return;
}
assert_eq!(
SessionSweepConfig::from_env().interval,
Duration::from_secs(5)
);
for value in ["0", "invalid", " 25 ", "18446744073709551616"] {
crate::test_process::set_var(INTERVAL, value);
assert_eq!(
SessionSweepConfig::from_env().interval,
Duration::from_secs(5)
);
}
crate::test_process::set_var(INTERVAL, "25");
assert_eq!(
SessionSweepConfig::from_env().interval,
Duration::from_millis(25)
);
crate::test_process::remove_var(INTERVAL);
assert_eq!(
SessionSweepConfig::from_env().interval,
Duration::from_secs(5)
);
#[cfg(unix)]
{
use std::os::unix::ffi::OsStrExt;
crate::test_process::set_var(INTERVAL, std::ffi::OsStr::from_bytes(b"\xff"));
assert_eq!(
SessionSweepConfig::from_env().interval,
Duration::from_secs(5)
);
crate::test_process::remove_var(INTERVAL);
}
crate::test_process::set_var(CYCLES, "255");
assert_eq!(CheckpointConfig::from_env().warn_sustained_cycles, 255);
crate::test_process::set_var(CYCLES, "256");
assert_eq!(CheckpointConfig::from_env().warn_sustained_cycles, 3);
crate::test_process::remove_var(CYCLES);
let defaults = (
Duration::from_millis(30_001),
Duration::from_millis(120_001),
);
assert_eq!(tx_age_thresholds_from_env(defaults.0, defaults.1), defaults);
crate::test_process::set_var(WARN, "0");
crate::test_process::set_var(MAX_AGE, "invalid");
assert_eq!(tx_age_thresholds_from_env(defaults.0, defaults.1), defaults);
crate::test_process::set_var(WARN, "300");
crate::test_process::set_var(MAX_AGE, "1");
assert_eq!(tx_age_thresholds_from_env(defaults.0, defaults.1), defaults);
crate::test_process::set_var(WARN, "15");
crate::test_process::set_var(MAX_AGE, "90");
assert_eq!(
tx_age_thresholds_from_env(defaults.0, defaults.1),
(Duration::from_secs(15), Duration::from_secs(90))
);
crate::test_process::remove_var(WARN);
crate::test_process::remove_var(MAX_AGE);
}