OXYGENHUB
◆ image-check oxygenhub / crates / hub / tests / maintenance.rs
3.3 KiB · Rust · last changed The hub garbage-collects every repository nightly 1 month ago source blame history raw
8a3334b7 Andy McCall ↶ 1
//! The nightly garbage collection (hub spec §17.2), run by hand.
2
3
use oxy_core::repo::Repo;
4
use oxygenhub::config::Config;
5
use oxygenhub::db;
6
use oxygenhub::repos::RepoName;
7
use std::path::Path;
8
9
fn hermetic() {
10
    static ONCE: std::sync::Once = std::sync::Once::new();
11
    static DIR: std::sync::OnceLock<tempfile::TempDir> = std::sync::OnceLock::new();
12
    ONCE.call_once(|| {
13
        let d = tempfile::tempdir().unwrap();
14
        std::env::set_var("OXY_HOME", d.path());
15
        DIR.set(d).ok();
16
    });
17
}
18
19
fn write(root: &Path, rel: &str, content: &[u8]) {
20
    let p = root.join(rel);
21
    std::fs::create_dir_all(p.parent().unwrap()).unwrap();
22
    std::fs::write(p, content).unwrap();
23
}
24
25
#[tokio::test(flavor = "multi_thread")]
26
async fn every_repository_is_garbage_collected_in_turn() {
27
    hermetic();
28
    let dir = tempfile::tempdir().unwrap();
29
    let mut config = Config::load(dir.path()).unwrap();
30
    config.auth.push_tokens = vec!["site".into()];
31
    let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
32
    let port = listener.local_addr().unwrap().port();
33
    config.server.base_url = format!("http://127.0.0.1:{port}");
34
    assert_eq!(config.retention.gc_hour, 3, "nightly at 03:00 UTC by default");
35
    let app = oxygenhub::build(config).await.unwrap();
36
    let router = oxygenhub::router(app.clone());
37
    tokio::spawn(async move { axum::serve(listener, router).await.unwrap() });
38
    db::accounts::create_account(&app.db, "andy", "[email protected]", "x", "salt", true).await.unwrap();
39
    for name in ["one", "two"] {
40
        app.repos.create(&RepoName::parse(&format!("andy/{name}")).unwrap(), None).unwrap();
41
        db::repos::create(&app.db, "andy", name, "", hub_api::Visibility::Public).await.unwrap();
42
    }
43
    // A gc folds what the pushes stored into one pack.
44
    let work = tempfile::tempdir().unwrap();
45
    let mut c = Repo::init(work.path()).unwrap();
46
    c.config.set("remote.origin.url", &format!("http://127.0.0.1:{port}/andy/one")).unwrap();
47
    c.config.set("remote.origin.token", "site").unwrap();
48
    c.save_config().unwrap();
49
    for i in 0..3 {
50
        write(work.path(), &format!("f{i}.txt"), format!("{i}\n").as_bytes());
51
        c.commit(&format!("c{i}"), &[]).unwrap();
52
    }
53
    assert!(c.push("origin", false).unwrap().iter().all(|r| r.ok));
54
    let hosted = app.repos.dir(&RepoName::parse("andy/one").unwrap());
55
    let before = Repo::open(&hosted).unwrap();
56
    assert!(before.store().loose_count().unwrap() > 0, "the push left loose objects");
57
    drop(before);
58
59
    let done = oxygenhub::maintenance::gc_all(&app).await;
60
    assert_eq!(done.len(), 2, "{done:?}");
61
    assert!(done.iter().all(|d| !d.failed), "{done:?}");
62
    assert!(done[0].summary.contains("packed"), "{}", done[0]);
63
    let after = Repo::open(&hosted).unwrap();
64
    assert_eq!(after.store().loose_count().unwrap(), 0, "everything is in a pack");
65
    assert_eq!(after.store().pack_count(), 1);
66
    assert_eq!(after.bookmark_heads().unwrap(), c.bookmark_heads().unwrap(), "and the history is intact");
67
    // The clone after the gc sees the same repository.
68
    let again = tempfile::tempdir().unwrap();
69
    let d = Repo::clone(&format!("http://127.0.0.1:{port}/andy/one"), again.path()).unwrap();
70
    assert_eq!(std::fs::read(again.path().join("f2.txt")).unwrap(), b"2\n");
71
    let _ = d;
72
}