crates/gunnar-server/tests/txlog_size_alarm.rs
//! **`txlog.size_over_cap` on the wire** (2026-09-22): `Admin.Health` of a real primary carries
//! the alarm once the log's bytes on disk pass `GUNNAR_TXLOG_ALARM_BYTES`, and is clear under it.
//! ONE test in its own binary, because it sets the process environment.
use std::sync::Arc;
use gunnar_grpc::{AdminService, EventBus, ServerConfig, ServiceContext};
use gunnar_proto::admin_server::Admin;
use gunnar_proto::HealthRequest;
use gunnar_server::stores::ServerStores;
use gunnar_server::CoreControlPlane;
use tonic::Request;
#[tokio::test]
async fn admin_health_raises_the_txlog_size_alarm_over_the_cap_and_clears_it_under() {
let dir = tempfile::tempdir().unwrap();
let stores = Arc::new(ServerStores::open(dir.path()).unwrap());
for i in 0..10 {
stores
.catalog()
.create_namespace(&format!("ns{i}"))
.unwrap();
}
let (bytes, first) = (stores.txlog().bytes(), stores.txlog().first_seq());
let plane: Arc<dyn gunnar_grpc::ControlPlane> =
Arc::new(CoreControlPlane::new(Arc::clone(&stores)));
let admin = AdminService::new(ServiceContext::new(
plane,
Arc::new(EventBus::new(16)),
ServerConfig::default().insecure_allow_all_for_local_development(),
));
let alarms = |cap: u64| {
// This binary holds one test: nothing else reads the environment concurrently.
std::env::set_var(gunnar_server::twin::TXLOG_ALARM_ENV, cap.to_string());
let admin = &admin;
async move {
admin
.health(Request::new(HealthRequest {}))
.await
.unwrap()
.into_inner()
.alarms
}
};
let over = alarms(bytes - 1).await;
let a = over
.iter()
.find(|a| a.event == gunnar_server::twin::TXLOG_SIZE_ALARM)
.unwrap_or_else(|| panic!("no size alarm over the cap: {over:?}"));
assert!(
a.detail.contains(&format!("over the cap of {}", bytes - 1)),
"{}",
a.detail
);
let under = alarms(bytes * 4).await;
assert!(
under
.iter()
.all(|a| a.event != gunnar_server::twin::TXLOG_SIZE_ALARM),
"under the cap it is clear: {under:?}"
);
assert_eq!(
(stores.txlog().bytes(), stores.txlog().first_seq()),
(bytes, first),
"raising it deleted nothing"
);
}