Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

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"
    );
}