OXYGENHUB
# 982864068a59 oxygen / crates / oxy-server / tests / http.rs
4.0 KiB · Rust · last changed Split repo.rs into repo/{config,snapshot,checkout,identity,sync,tests}; hermetic OXY_HOME in tests; identity recorded in user config 1 month ago source blame history raw
1
//! End-to-end: a real server on a loopback port, clients over HTTP.
2
3
use oxy_core::repo::{Repo, SignatureStatus};
4
use std::fs;
5
use std::net::TcpListener;
6
use std::path::Path;
7
8
fn write(root: &Path, rel: &str, content: &[u8]) {
9
    let p = root.join(rel);
10
    fs::create_dir_all(p.parent().unwrap()).unwrap();
11
    fs::write(p, content).unwrap();
12
}
13
14
/// Point `$OXY_HOME` at a throwaway directory once per test process so no
15
/// test reads or writes the developer's real user configuration or keys.
16
fn hermetic() {
17
    static ONCE: std::sync::Once = std::sync::Once::new();
18
    static DIR: std::sync::OnceLock<tempfile::TempDir> = std::sync::OnceLock::new();
19
    ONCE.call_once(|| {
20
        let d = tempfile::tempdir().unwrap();
21
        std::env::set_var("OXY_HOME", d.path());
22
        DIR.set(d).ok();
23
    });
24
}
25
26
fn start(root: &Path, tokens: Vec<String>) -> String {
27
    let listener = TcpListener::bind("127.0.0.1:0").unwrap();
28
    let port = listener.local_addr().unwrap().port();
29
    let cfg = oxy_server::ServerConfig { root: root.to_path_buf(), tokens };
30
    std::thread::spawn(move || oxy_server::run_blocking(listener, cfg).unwrap());
31
    format!("http://127.0.0.1:{port}")
32
}
33
34
#[test]
35
fn clone_push_pull_over_http() {
36
    hermetic();
37
    let dir = tempfile::tempdir().unwrap();
38
    let root = dir.path();
39
    let served = root.join("served");
40
    Repo::init(&served.join("origin")).unwrap();
41
    let base = start(&served, vec![]);
42
    let url = format!("{base}/origin");
43
44
    let mut a = Repo::clone(&url, &root.join("a")).unwrap().with_keys_dir(root.join("keys"));
45
    let (key, _) = a.create_identity("Ada", "[email protected]").unwrap();
46
    write(&root.join("a"), "f.txt", b"hello\n");
47
    let h1 = a.commit("hello", &[]).unwrap();
48
    let r = a.push("origin", false).unwrap();
49
    assert!(r[0].ok, "{}", r[0].reason);
50
51
    let origin = Repo::open(&served.join("origin")).unwrap();
52
    assert_eq!(origin.bookmark_heads().unwrap(), vec![h1]);
53
    assert!(matches!(origin.authenticate_change(&h1).unwrap(), SignatureStatus::Valid { key: k, sealed: true, .. } if k == key));
54
55
    let b = Repo::clone(&url, &root.join("b")).unwrap();
56
    assert_eq!(fs::read(root.join("b/f.txt")).unwrap(), b"hello\n");
57
    write(&root.join("b"), "g.txt", b"g\n");
58
    let h2 = b.commit("g", &[]).unwrap();
59
    assert!(b.push("origin", false).unwrap()[0].ok);
60
61
    let pr = a.pull("origin").unwrap();
62
    assert!(pr.changed && pr.checked_out);
63
    assert_eq!(fs::read(root.join("a/g.txt")).unwrap(), b"g\n");
64
    let mut heads = a.bookmark_heads().unwrap();
65
    heads.sort();
66
    let mut want = vec![h1, h2];
67
    want.sort();
68
    assert_eq!(heads, want);
69
70
    // Unknown repositories and names the server refuses are surfaced as errors.
71
    let err = Repo::clone(&format!("{base}/nope"), &root.join("c")).unwrap_err().to_string();
72
    assert!(err.contains("404"), "{err}");
73
    fs::create_dir_all(served.join(".hidden/.oxy")).unwrap();
74
    assert!(Repo::clone(&format!("{base}/.hidden"), &root.join("d")).unwrap_err().to_string().contains("404"));
75
}
76
77
#[test]
78
fn push_requires_a_token_when_configured() {
79
    hermetic();
80
    let dir = tempfile::tempdir().unwrap();
81
    let root = dir.path();
82
    let served = root.join("served");
83
    Repo::init(&served.join("origin")).unwrap();
84
    let base = start(&served, vec!["s3cret".into()]);
85
    let url = format!("{base}/origin");
86
87
    // Reads are open.
88
    let mut a = Repo::clone(&url, &root.join("a")).unwrap();
89
    write(&root.join("a"), "f.txt", b"x\n");
90
    a.commit("x", &[]).unwrap();
91
    let err = a.push("origin", false).unwrap_err().to_string();
92
    assert!(err.contains("401"), "{err}");
93
94
    a.config.set("remote.origin.token", "wrong").unwrap();
95
    a.save_config().unwrap();
96
    assert!(a.push("origin", false).unwrap_err().to_string().contains("401"));
97
98
    a.config.set("remote.origin.token", "s3cret").unwrap();
99
    a.save_config().unwrap();
100
    assert!(a.push("origin", false).unwrap()[0].ok);
101
    let origin = Repo::open(&served.join("origin")).unwrap();
102
    assert_eq!(origin.bookmark_heads().unwrap().len(), 1);
103
}