Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
cli/tests: Refactor sync command tests
Fintan Halpenny committed 1 month ago
commit d282e0d0f82e2cd7ca2b50925b3a87d48fe64c5c
parent 7d2842a
2 files changed +200 -192
modified crates/radicle-cli/tests/commands.rs
@@ -1,24 +1,21 @@
use core::panic;
+
use std::fs;
use std::path::Path;
use std::str::FromStr;
-
use std::{fs, thread, time};

use radicle::node::config::seeds::RADICLE_NODE_BOOTSTRAP_IRIS;
-
use radicle::node::config::DefaultSeedingPolicy;
-
use radicle::node::events::Event;
use radicle::node::policy::Scope;
use radicle::node::{Alias, Config, Handle as _, DEFAULT_TIMEOUT};
use radicle::prelude::RepoId;
use radicle::profile;
use radicle::profile::Home;
-
use radicle::storage::{ReadStorage, RemoteRepository};
use radicle::test::fixtures;

#[allow(unused_imports)]
use radicle_node::test::logger;

mod util;
-
use util::environment::{config, Environment};
+
use util::environment::Environment;
use util::formula::formula;

mod commands {
@@ -35,6 +32,7 @@ mod commands {
    mod patch;
    mod policy;
    mod remote;
+
    mod sync;
}

/// Run a CLI test file.
@@ -226,37 +224,6 @@ fn rad_clean() {
}

#[test]
-
fn rad_sync_without_node() {
-
    let mut environment = Environment::new();
-
    let alice = environment.seed("alice");
-
    let bob = environment.seed("bob");
-
    let mut eve = environment.seed("eve");
-

-
    let rid = RepoId::from_urn("rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5").unwrap();
-
    eve.policies.seed(&rid, Scope::All).unwrap();
-

-
    formula(&environment.tempdir(), "examples/rad-sync-without-node.md")
-
        .unwrap()
-
        .home(
-
            "alice",
-
            alice.home.path(),
-
            [("RAD_HOME", alice.home.path().display())],
-
        )
-
        .home(
-
            "bob",
-
            bob.home.path(),
-
            [("RAD_HOME", bob.home.path().display())],
-
        )
-
        .home(
-
            "eve",
-
            eve.home.path(),
-
            [("RAD_HOME", eve.home.path().display())],
-
        )
-
        .run()
-
        .unwrap();
-
}
-

-
#[test]
fn rad_self() {
    let mut environment = Environment::new();
    let alice = environment.node_with(Config {
@@ -268,27 +235,6 @@ fn rad_self() {
    test("examples/rad-self.md", working, Some(&alice.home), []).unwrap();
}

-
#[test]
-
fn rad_fetch() {
-
    let mut environment = Environment::new();
-
    let alice = environment.node("alice");
-
    let bob = environment.node("bob");
-

-
    let mut alice = alice.spawn();
-
    let bob = bob.spawn();
-

-
    alice.connect(&bob);
-
    environment.repository(&alice);
-

-
    // Alice initializes a repo after her node has started, and after bob has connected to it.
-
    environment.test("rad-init-sync", &alice).unwrap();
-

-
    // Wait for bob to get any updates to the routing table.
-
    bob.converge([&alice]);
-

-
    environment.test("rad-fetch", &bob).unwrap();
-
}
-

#[cfg(unix)]
#[test]
fn rad_diff() {
@@ -307,141 +253,6 @@ fn rad_diff() {
}

#[test]
-
fn rad_sync() {
-
    let mut environment = Environment::new();
-
    let working = environment.tempdir().join("working");
-
    let alice = environment.seed("alice");
-
    let bob = environment.seed("bob");
-
    let eve = environment.seed("eve");
-
    let acme = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
-

-
    fixtures::repository(working.join("acme"));
-

-
    test(
-
        "examples/rad-init.md",
-
        working.join("acme"),
-
        Some(&alice.home),
-
        [],
-
    )
-
    .unwrap();
-

-
    let mut alice = alice.spawn();
-
    let mut bob = bob.spawn();
-
    let mut eve = eve.spawn();
-

-
    bob.handle.seed(acme, Scope::All).unwrap();
-
    eve.handle.seed(acme, Scope::All).unwrap();
-

-
    alice.connect(&bob);
-
    eve.connect(&alice);
-

-
    bob.routes_to(&[(acme, alice.id)]);
-
    eve.routes_to(&[(acme, alice.id)]);
-
    alice.routes_to(&[(acme, alice.id), (acme, eve.id), (acme, bob.id)]);
-
    alice.is_synced_with(&acme, &eve.id);
-
    alice.is_synced_with(&acme, &bob.id);
-

-
    test(
-
        "examples/rad-sync.md",
-
        working.join("acme"),
-
        Some(&alice.home),
-
        [],
-
    )
-
    .unwrap();
-
}
-

-
#[test]
-
//
-
//     alice -- seed -- bob
-
//
-
fn test_replication_via_seed() {
-
    let mut environment = Environment::new();
-
    let alice = environment.relay("alice");
-
    let bob = environment.relay("bob");
-
    let seed = environment.node_with(Config {
-
        seeding_policy: DefaultSeedingPolicy::permissive(),
-
        ..config::relay("seed")
-
    });
-
    let rid = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
-

-
    let mut alice = alice.spawn();
-
    let mut bob = bob.spawn();
-
    let seed = seed.spawn();
-

-
    alice.connect(&seed);
-
    bob.connect(&seed);
-

-
    // Enough time for the next inventory from Seed to not be considered stale by Bob.
-
    thread::sleep(time::Duration::from_millis(3));
-

-
    alice.routes_to(&[]);
-
    seed.routes_to(&[]);
-
    bob.routes_to(&[]);
-

-
    // Initialize a repo as Alice.
-
    environment.repository(&alice);
-
    alice
-
        .rad(
-
            "init",
-
            &[
-
                "--name",
-
                "heartwood",
-
                "--description",
-
                "Radicle Heartwood Protocol & Stack",
-
                "--default-branch",
-
                "master",
-
                "--public",
-
            ],
-
            environment.work(&alice),
-
        )
-
        .unwrap();
-

-
    alice
-
        .rad("follow", &[&bob.id.to_human()], environment.work(&alice))
-
        .unwrap();
-

-
    alice.routes_to(&[(rid, alice.id), (rid, seed.id)]);
-
    seed.routes_to(&[(rid, alice.id), (rid, seed.id)]);
-
    bob.routes_to(&[(rid, alice.id), (rid, seed.id)]);
-

-
    let seed_events = seed.handle.events();
-
    let alice_events = alice.handle.events();
-

-
    bob.fork(rid, environment.work(&bob)).unwrap();
-

-
    alice.routes_to(&[(rid, alice.id), (rid, seed.id), (rid, bob.id)]);
-
    seed.routes_to(&[(rid, alice.id), (rid, seed.id), (rid, bob.id)]);
-
    bob.routes_to(&[(rid, alice.id), (rid, seed.id), (rid, bob.id)]);
-

-
    seed_events.iter().any(|e| {
-
        matches!(
-
            e, Event::RefsFetched { updated, remote, .. }
-
            if remote == bob.id && updated.iter().any(|u| u.is_created())
-
        )
-
    });
-
    alice_events.iter().any(|e| {
-
        matches!(
-
            e, Event::RefsFetched { updated, remote, .. }
-
            if remote == seed.id && updated.iter().any(|u| u.is_created())
-
        )
-
    });
-

-
    seed.storage
-
        .repository(rid)
-
        .unwrap()
-
        .remote(&bob.id)
-
        .unwrap();
-

-
    // Seed should send Bob's ref announcement to Alice, after the fetch.
-
    alice
-
        .storage
-
        .repository(rid)
-
        .unwrap()
-
        .remote(&bob.id)
-
        .unwrap();
-
}
-

-
#[test]
fn framework_home() {
    let mut environment = Environment::new();
    let alice = environment.node("alice");
added crates/radicle-cli/tests/commands/sync.rs
@@ -0,0 +1,197 @@
+
use std::str::FromStr as _;
+

+
use radicle::node::config::DefaultSeedingPolicy;
+
use radicle::node::policy::Scope;
+
use radicle::node::Handle as _;
+
use radicle::prelude::RepoId;
+
use radicle::storage::{ReadStorage as _, RemoteRepository as _};
+

+
use crate::test;
+
use crate::util::{environment::Environment, formula::formula};
+

+
#[test]
+
fn rad_sync_without_node() {
+
    let mut environment = Environment::new();
+
    let alice = environment.seed("alice");
+
    let bob = environment.seed("bob");
+
    let mut eve = environment.seed("eve");
+

+
    let rid = RepoId::from_urn("rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5").unwrap();
+
    eve.policies.seed(&rid, Scope::All).unwrap();
+

+
    formula(&environment.tempdir(), "examples/rad-sync-without-node.md")
+
        .unwrap()
+
        .home(
+
            "alice",
+
            alice.home.path(),
+
            [("RAD_HOME", alice.home.path().display())],
+
        )
+
        .home(
+
            "bob",
+
            bob.home.path(),
+
            [("RAD_HOME", bob.home.path().display())],
+
        )
+
        .home(
+
            "eve",
+
            eve.home.path(),
+
            [("RAD_HOME", eve.home.path().display())],
+
        )
+
        .run()
+
        .unwrap();
+
}
+

+
#[test]
+
fn rad_fetch() {
+
    let mut environment = Environment::new();
+
    let alice = environment.node("alice");
+
    let bob = environment.node("bob");
+

+
    let mut alice = alice.spawn();
+
    let bob = bob.spawn();
+

+
    alice.connect(&bob);
+
    environment.repository(&alice);
+

+
    // Alice initializes a repo after her node has started, and after bob has connected to it.
+
    environment.test("rad-init-sync", &alice).unwrap();
+

+
    // Wait for bob to get any updates to the routing table.
+
    bob.converge([&alice]);
+

+
    environment.test("rad-fetch", &bob).unwrap();
+
}
+

+
#[test]
+
fn rad_sync() {
+
    let mut environment = Environment::new();
+
    let working = environment.tempdir().join("working");
+
    let alice = environment.seed("alice");
+
    let bob = environment.seed("bob");
+
    let eve = environment.seed("eve");
+
    let acme = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
+

+
    radicle::test::fixtures::repository(working.join("acme"));
+

+
    test(
+
        "examples/rad-init.md",
+
        working.join("acme"),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+

+
    let mut alice = alice.spawn();
+
    let mut bob = bob.spawn();
+
    let mut eve = eve.spawn();
+

+
    bob.handle.seed(acme, Scope::All).unwrap();
+
    eve.handle.seed(acme, Scope::All).unwrap();
+

+
    alice.connect(&bob);
+
    eve.connect(&alice);
+

+
    bob.routes_to(&[(acme, alice.id)]);
+
    eve.routes_to(&[(acme, alice.id)]);
+
    alice.routes_to(&[(acme, alice.id), (acme, eve.id), (acme, bob.id)]);
+
    alice.is_synced_with(&acme, &eve.id);
+
    alice.is_synced_with(&acme, &bob.id);
+

+
    test(
+
        "examples/rad-sync.md",
+
        working.join("acme"),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+
}
+

+
#[test]
+
//
+
//     alice -- seed -- bob
+
//
+
fn test_replication_via_seed() {
+
    let mut environment = Environment::new();
+
    let alice = environment.relay("alice");
+
    let bob = environment.relay("bob");
+
    let seed = environment.node_with(radicle::node::Config {
+
        seeding_policy: DefaultSeedingPolicy::permissive(),
+
        ..crate::util::environment::config::relay("seed")
+
    });
+
    let rid = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
+

+
    let mut alice = alice.spawn();
+
    let mut bob = bob.spawn();
+
    let seed = seed.spawn();
+

+
    alice.connect(&seed);
+
    bob.connect(&seed);
+

+
    // Enough time for the next inventory from Seed to not be considered stale by Bob.
+
    std::thread::sleep(std::time::Duration::from_millis(3));
+

+
    alice.routes_to(&[]);
+
    seed.routes_to(&[]);
+
    bob.routes_to(&[]);
+

+
    // Initialize a repo as Alice.
+
    environment.repository(&alice);
+
    alice
+
        .rad(
+
            "init",
+
            &[
+
                "--name",
+
                "heartwood",
+
                "--description",
+
                "Radicle Heartwood Protocol & Stack",
+
                "--default-branch",
+
                "master",
+
                "--public",
+
            ],
+
            environment.work(&alice),
+
        )
+
        .unwrap();
+

+
    alice
+
        .rad("follow", &[&bob.id.to_human()], environment.work(&alice))
+
        .unwrap();
+

+
    alice.routes_to(&[(rid, alice.id), (rid, seed.id)]);
+
    seed.routes_to(&[(rid, alice.id), (rid, seed.id)]);
+
    bob.routes_to(&[(rid, alice.id), (rid, seed.id)]);
+

+
    let seed_events = seed.handle.events();
+
    let alice_events = alice.handle.events();
+

+
    bob.fork(rid, environment.work(&bob)).unwrap();
+

+
    alice.routes_to(&[(rid, alice.id), (rid, seed.id), (rid, bob.id)]);
+
    seed.routes_to(&[(rid, alice.id), (rid, seed.id), (rid, bob.id)]);
+
    bob.routes_to(&[(rid, alice.id), (rid, seed.id), (rid, bob.id)]);
+

+
    seed_events.iter().any(|e| {
+
        matches!(
+
            e, radicle::node::Event::RefsFetched { updated, remote, .. }
+
            if remote == bob.id && updated.iter().any(|u| u.is_created())
+
        )
+
    });
+
    alice_events.iter().any(|e| {
+
        matches!(
+
            e, radicle::node::Event::RefsFetched { updated, remote, .. }
+
            if remote == seed.id && updated.iter().any(|u| u.is_created())
+
        )
+
    });
+

+
    seed.storage
+
        .repository(rid)
+
        .unwrap()
+
        .remote(&bob.id)
+
        .unwrap();
+

+
    // Seed should send Bob's ref announcement to Alice, after the fetch.
+
    alice
+
        .storage
+
        .repository(rid)
+
        .unwrap()
+
        .remote(&bob.id)
+
        .unwrap();
+
}