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/repo_purge.rs

//! **`repo delete` reclaims the disk** (2026-08-30).
//!
//! MEASURED on the appliance 2026-08-29: after the linux push a `repo delete`
//! removed the catalog row and left **25 GB** of `gunnar-git.znippy/` behind —
//! pack, journal, tail, exploded tier — with the indexer still running on it.
//! `ServerStores::purge_repo` is the one verb both the CLI and the gRPC delete
//! route through; this walks the bytes before and after, as `du` would.
//!
//! Seen RED with `purge_repo`'s `remove_dir_all` commented out: "the
//! directory is still there" and `after == before`.

use gunnar_core::{NewRepo, RepoRef};
use gunnar_server::stores::{dir_bytes, ServerStores};

#[test]
fn delete_removes_the_store_directory_and_the_bytes_are_measured() {
    let dir = tempfile::tempdir().expect("tempdir");
    let stores = ServerStores::open(dir.path()).expect("stores");
    stores
        .catalog()
        .create_namespace("alice")
        .expect("namespace");
    let path = RepoRef::new("alice", "linux").expect("legal");
    let repo = stores
        .catalog()
        .create(NewRepo::new(path.clone()))
        .expect("create");
    // Open it — the engine lays down its files (pack, journal, tail, …).
    let handle = stores.repo_store(&repo).expect("open");
    let git_dir = handle.git_dir().to_path_buf();
    drop(handle);
    assert!(git_dir.is_dir(), "{} was not created", git_dir.display());
    // Stand in for an exploded tier: 4 MiB the engine did not write, so the
    // measurement is of the whole directory and not of one file the engine
    // happens to hold open.
    std::fs::write(
        git_dir
            .join("gunnar-git.znippy")
            .join("objects.exploded.fixture"),
        vec![7u8; 4 << 20],
    )
    .expect("fixture");
    let before = dir_bytes(&git_dir);
    assert!(
        before >= 4 << 20,
        "measured {before} bytes before; the fixture alone is 4 MiB"
    );

    stores.catalog().delete(&path).expect("catalog delete");
    let (b, a) = stores.purge_repo(&path).expect("purge");
    assert_eq!(
        b, before,
        "purge measured a different 'before' than the walk"
    );
    assert_eq!(a, 0, "bytes left after the purge");
    assert!(
        !git_dir.exists(),
        "the directory is still there: {}",
        git_dir.display()
    );
    assert_eq!(dir_bytes(&git_dir), 0);
    assert!(
        stores.catalog().get(&path).expect("catalog").is_none(),
        "still catalogued"
    );
    // Idempotent: a second purge of a gone directory is not an error.
    let (b2, a2) = stores.purge_repo(&path).expect("purge twice");
    assert_eq!((b2, a2), (0, 0));
}