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

nordisk/holger

server/lib/tests/a_purge_follows_the_one_boxs_grace.rs

//! ★ **The ONE box decides the day, holger keeps no count of its own** (lane M5): the ONE
//! box orders the purge after ITS grace (`[nonpay] delete_after_days`, 10 days on the ONE
//! box), and holger purges a repository lapsed by its own clock — Paid until 10 days ago,
//! never moved to Suspended — at once, through the one guard both purge doors ask
//! (`EntitlementService.Purge` and the pulled `purge_tenant`). It refuses only a
//! repository still paid for, or one nobody sold. No day count lives in the purge code.

use holger_server_lib::metered::purgeable;
use monetize_product::{EntitlementFact as SignedFact, State, TenantId};

fn fact(state: State, paid_until_unix_ms: Option<u64>) -> SignedFact {
    SignedFact {
        tenant: TenantId("crates".into()),
        plan: "holger/crates/2026-10-01".into(),
        state,
        paid_until_unix_ms,
        caps: Default::default(),
        source: "operator".into(),
        signature: Vec::new(),
        issued_unix_ms: None,
        issued_signature: Vec::new(),
    }
}

const DAY: i64 = 86_400_000;

#[test]
fn a_purge_the_one_box_ordered_after_its_grace_is_taken_at_once() {
    let now = 100 * DAY;
    let ten_days_ago = Some((now - 10 * DAY) as u64);
    assert_eq!(
        purgeable("crates", Some(&fact(State::Paid, ten_days_ago)), now),
        Ok(()),
        "paid until 10 days ago, the ONE box's grace passed: purged"
    );
    assert_eq!(
        purgeable("crates", Some(&fact(State::Grace, ten_days_ago)), now),
        Ok(())
    );
    assert_eq!(
        purgeable(
            "crates",
            Some(&fact(State::Paid, Some((now - DAY) as u64))),
            now
        ),
        Ok(()),
        "a shorter grace is the ONE box's to decide"
    );
    assert_eq!(
        purgeable("crates", Some(&fact(State::Suspended, None)), now),
        Ok(())
    );
    assert_eq!(
        purgeable("crates", Some(&fact(State::Retention, None)), now),
        Ok(())
    );
}

#[test]
fn a_repository_still_paid_for_or_never_sold_is_refused() {
    let now = 100 * DAY;
    let why = purgeable(
        "crates",
        Some(&fact(State::Paid, Some((now + DAY) as u64))),
        now,
    )
    .unwrap_err();
    assert!(
        why.contains("paid for") && why.contains("nothing was deleted"),
        "{why}"
    );
    assert!(
        purgeable("crates", Some(&fact(State::Free, None)), now).is_err(),
        "a free repository is never purged"
    );
    assert!(purgeable("crates", None, now)
        .unwrap_err()
        .contains("Free (no fact stored)"));
}

#[test]
fn holger_keeps_no_purge_day_of_its_own() {
    for (file, src) in [
        ("purge.rs", include_str!("../src/purge.rs")),
        ("metered.rs", include_str!("../src/metered.rs")),
        ("fleet_box.rs", include_str!("../src/fleet_box.rs")),
    ] {
        let words = src.split("#[cfg(test)]").next().unwrap().to_lowercase();
        for count in ["thirty days", "day 30", "30 days"] {
            assert!(
                !words.contains(count),
                "{file}: holger keeps no purge day of its own: `{count}`"
            );
        }
    }
    let fleet = include_str!("../src/fleet_box.rs");
    assert_eq!(
        fleet.matches("crate::metered::purgeable(").count(),
        1,
        "the pulled purge_tenant asks the one guard"
    );
    let door = include_str!("../src/metered.rs");
    assert_eq!(
        door.matches(
            "if let Err(why) = purgeable(&repo, fact.as_ref(), crate::clock::now_unix_ms())"
        )
        .count(),
        1,
        "EntitlementService.Purge asks the one guard"
    );
}