OXYGENHUB
◆ v0.7.0 oxygenhub / crates / hub / tests / maintenance.rs
3.4 KiB · Rust · last changed A new hub gives administrator only to whoever brings its setup code 19 days 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();
c8684d44 Andy McCall 30
    // The first account's setup code (oxygenhub#245).
31
    config.registration.setup_code = "test-setup".into();
8a3334b7 Andy McCall ↶ 32
    config.auth.push_tokens = vec!["site".into()];
33
    let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
34
    let port = listener.local_addr().unwrap().port();
35
    config.server.base_url = format!("http://127.0.0.1:{port}");
36
    assert_eq!(config.retention.gc_hour, 3, "nightly at 03:00 UTC by default");
37
    let app = oxygenhub::build(config).await.unwrap();
38
    let router = oxygenhub::router(app.clone());
39
    tokio::spawn(async move { axum::serve(listener, router).await.unwrap() });
40
    db::accounts::create_account(&app.db, "andy", "[email protected]", "x", "salt", true).await.unwrap();
41
    for name in ["one", "two"] {
42
        app.repos.create(&RepoName::parse(&format!("andy/{name}")).unwrap(), None).unwrap();
43
        db::repos::create(&app.db, "andy", name, "", hub_api::Visibility::Public).await.unwrap();
44
    }
45
    // A gc folds what the pushes stored into one pack.
46
    let work = tempfile::tempdir().unwrap();
47
    let mut c = Repo::init(work.path()).unwrap();
48
    c.config.set("remote.origin.url", &format!("http://127.0.0.1:{port}/andy/one")).unwrap();
49
    c.config.set("remote.origin.token", "site").unwrap();
50
    c.save_config().unwrap();
51
    for i in 0..3 {
52
        write(work.path(), &format!("f{i}.txt"), format!("{i}\n").as_bytes());
53
        c.commit(&format!("c{i}"), &[]).unwrap();
54
    }
55
    assert!(c.push("origin", false).unwrap().iter().all(|r| r.ok));
56
    let hosted = app.repos.dir(&RepoName::parse("andy/one").unwrap());
57
    let before = Repo::open(&hosted).unwrap();
58
    assert!(before.store().loose_count().unwrap() > 0, "the push left loose objects");
59
    drop(before);
60
61
    let done = oxygenhub::maintenance::gc_all(&app).await;
62
    assert_eq!(done.len(), 2, "{done:?}");
63
    assert!(done.iter().all(|d| !d.failed), "{done:?}");
64
    assert!(done[0].summary.contains("packed"), "{}", done[0]);
65
    let after = Repo::open(&hosted).unwrap();
66
    assert_eq!(after.store().loose_count().unwrap(), 0, "everything is in a pack");
67
    assert_eq!(after.store().pack_count(), 1);
68
    assert_eq!(after.bookmark_heads().unwrap(), c.bookmark_heads().unwrap(), "and the history is intact");
69
    // The clone after the gc sees the same repository.
70
    let again = tempfile::tempdir().unwrap();
71
    let d = Repo::clone(&format!("http://127.0.0.1:{port}/andy/one"), again.path()).unwrap();
72
    assert_eq!(std::fs::read(again.path().join("f2.txt")).unwrap(), b"2\n");
73
    let _ = d;
74
}