Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
cli: Refactor out clone, inbox, jj, seed and watch tests
✗ CI failure Adrian Duke committed 2 months ago
commit b0c4f81b84090d9de94ce99f983886173d448138
parent 383a4d439bd2f3133122d78026e40c3875678340
1 failed (1 total) View logs
8 files changed +476 -447
modified crates/radicle-cli/tests/commands.rs
@@ -6,14 +6,19 @@ mod util;
use util::formula::formula;

mod commands {
+
    mod clone;
    mod cob;
    mod git;
    mod id;
+
    mod inbox;
    mod init;
    mod issue;
+
    mod jj;
    mod misc;
    mod node;
    mod patch;
+
    mod seed;
+
    mod watch;
}

/// Run a CLI test file.
added crates/radicle-cli/tests/commands/clone.rs
@@ -0,0 +1,259 @@
+
use crate::test;
+
use crate::util::environment::Environment;
+
use radicle::node;
+
use radicle::node::address::Store as _;
+
use radicle::node::policy::Scope;
+
use radicle::node::routing::Store as _;
+
use radicle::node::UserAgent;
+
use radicle::node::{Alias, Handle as _};
+
use radicle::prelude::{NodeId, RepoId};
+
use radicle::storage::ReadStorage as _;
+
use radicle_localtime::LocalTime;
+
use radicle_node::PROTOCOL_VERSION;
+
use std::net;
+
use std::str::FromStr;
+

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

+
    // Setup a test project.
+
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+

+
    let mut alice = alice.spawn();
+
    let mut bob = bob.spawn();
+
    // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
+
    alice.handle.seed(acme, Scope::Followed).unwrap();
+

+
    bob.connect(&alice).converge([&alice]);
+

+
    test("examples/rad-clone.md", working, Some(&bob.home), []).unwrap();
+
}
+

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

+
    // Setup a test project.
+
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+

+
    let mut alice = alice.spawn();
+
    let mut bob = bob.spawn();
+
    // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
+
    alice.handle.seed(acme, Scope::Followed).unwrap();
+

+
    bob.connect(&alice).converge([&alice]);
+

+
    test("examples/rad-clone-bare.md", working, Some(&bob.home), []).unwrap();
+
}
+

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

+
    // Setup a test project.
+
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+

+
    let mut alice = alice.spawn();
+
    let mut bob = bob.spawn();
+
    // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
+
    alice.handle.seed(acme, Scope::Followed).unwrap();
+

+
    bob.connect(&alice).converge([&alice]);
+

+
    test(
+
        "examples/rad-clone-directory.md",
+
        working,
+
        Some(&bob.home),
+
        [],
+
    )
+
    .unwrap();
+
}
+

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

+
    // Setup a test project.
+
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+

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

+
    alice.handle.seed(acme, Scope::All).unwrap();
+
    bob.connect(&alice).converge([&alice]);
+
    eve.connect(&alice).converge([&alice]);
+

+
    // Fork and sync repo.
+
    bob.fork(acme, bob.home.path()).unwrap();
+
    bob.announce(acme, 2, bob.home.path()).unwrap();
+
    bob.has_remote_of(&acme, &alice.id);
+
    alice.has_remote_of(&acme, &bob.id);
+

+
    test(
+
        "examples/rad-clone-all.md",
+
        environment.work(&eve),
+
        Some(&eve.home),
+
        [],
+
    )
+
    .unwrap();
+
    eve.has_remote_of(&acme, &bob.id);
+
}
+

+
#[test]
+
fn rad_clone_partial_fail() {
+
    let mut environment = Environment::new();
+
    let mut alice = environment.node("alice");
+
    let bob = environment.node("bob");
+
    let mut eve = environment.node("eve");
+
    let carol = NodeId::from_str("z6MksFqXN3Yhqk8pTJdUGLwBTkRfQvwZXPqR2qMEhbS9wzpT").unwrap();
+

+
    // Setup a test project.
+
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+

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

+
    // Make Even think she knows about a seed called "carol" that has the repo.
+
    eve.db
+
        .addresses_mut()
+
        .insert(
+
            &carol,
+
            PROTOCOL_VERSION,
+
            node::Features::SEED,
+
            &Alias::new("carol"),
+
            0,
+
            &UserAgent::default(),
+
            LocalTime::now().into(),
+
            [node::KnownAddress::new(
+
                // Eve will fail to connect to this address.
+
                node::Address::from(net::SocketAddr::from(([0, 0, 0, 0], 19873))),
+
                node::address::Source::Imported,
+
            )],
+
        )
+
        .unwrap();
+
    eve.db
+
        .routing_mut()
+
        .add_inventory([&acme], carol, LocalTime::now().into())
+
        .unwrap();
+
    eve.config.peers = node::config::PeerConfig::Static;
+

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

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

+
    bob.connect(&alice).converge([&alice]);
+
    eve.connect(&alice);
+
    eve.connect(&bob);
+
    eve.routes_to(&[(acme, carol), (acme, bob.id), (acme, alice.id)]);
+
    bob.storage.repository(acme).unwrap().remove().unwrap(); // Cause the fetch from Bob to fail.
+
    bob.storage.temporary_repository(acme).ok(); // Prevent repo from being re-fetched.
+

+
    test(
+
        "examples/rad-clone-partial-fail.md",
+
        environment.work(&eve),
+
        Some(&eve.home),
+
        [],
+
    )
+
    .unwrap();
+
}
+

+
#[test]
+
fn rad_clone_connect() {
+
    let mut environment = Environment::new();
+
    let working = environment.tempdir().join("working");
+
    let alice = environment.node("alice");
+
    let bob = environment.node("bob");
+
    let mut eve = environment.node("eve");
+
    let acme = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
+
    let ua = UserAgent::default();
+
    let now = LocalTime::now().into();
+

+
    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 Eve know about Alice and Bob having the repo.
+
    eve.db
+
        .addresses_mut()
+
        .insert(
+
            &alice.id,
+
            PROTOCOL_VERSION,
+
            node::Features::SEED,
+
            &Alias::new("alice"),
+
            0,
+
            &ua,
+
            now,
+
            [node::KnownAddress::new(
+
                node::Address::from(alice.addr),
+
                node::address::Source::Imported,
+
            )],
+
        )
+
        .unwrap();
+
    eve.db
+
        .addresses_mut()
+
        .insert(
+
            &bob.id,
+
            PROTOCOL_VERSION,
+
            node::Features::SEED,
+
            &Alias::new("bob"),
+
            0,
+
            &ua,
+
            now,
+
            [node::KnownAddress::new(
+
                node::Address::from(bob.addr),
+
                node::address::Source::Imported,
+
            )],
+
        )
+
        .unwrap();
+
    eve.db
+
        .routing_mut()
+
        .add_inventory([&acme], alice.id, now)
+
        .unwrap();
+
    eve.db
+
        .routing_mut()
+
        .add_inventory([&acme], bob.id, now)
+
        .unwrap();
+
    eve.config.peers = node::config::PeerConfig::Static;
+

+
    let eve = eve.spawn();
+

+
    alice.handle.seed(acme, Scope::Followed).unwrap();
+
    bob.handle.seed(acme, Scope::Followed).unwrap();
+
    alice.connect(&bob);
+
    bob.routes_to(&[(acme, alice.id)]);
+
    eve.routes_to(&[(acme, alice.id), (acme, bob.id)]);
+
    alice.routes_to(&[(acme, alice.id), (acme, bob.id)]);
+

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

added crates/radicle-cli/tests/commands/inbox.rs
@@ -0,0 +1,36 @@
+
use crate::util::environment::Environment;
+
use crate::util::formula::formula;
+
use radicle::test::fixtures;
+

+
#[test]
+
fn rad_inbox() {
+
    let mut environment = Environment::new();
+
    let mut alice = environment.node("alice");
+
    let bob = environment.node("bob");
+
    let (repo1, _) = fixtures::repository(environment.work(&alice).join("heartwood"));
+
    let (repo2, _) = fixtures::repository(environment.work(&alice).join("radicle-git"));
+
    let rid1 = alice.project_from("heartwood", "Radicle Heartwood Protocol & Stack", &repo1);
+
    let rid2 = alice.project_from("radicle-git", "Radicle Git", &repo2);
+

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

+
    bob.connect(&alice).converge([&alice]);
+
    bob.clone(rid1, environment.work(&bob)).unwrap();
+
    bob.clone(rid2, environment.work(&bob)).unwrap();
+

+
    formula(&environment.tempdir(), "examples/rad-inbox.md")
+
        .unwrap()
+
        .home(
+
            "alice",
+
            environment.work(&alice),
+
            [("RAD_HOME", alice.home.path().display())],
+
        )
+
        .home(
+
            "bob",
+
            environment.work(&bob),
+
            [("RAD_HOME", bob.home.path().display())],
+
        )
+
        .run()
+
        .unwrap();
+
}
modified crates/radicle-cli/tests/commands/init.rs
@@ -2,21 +2,14 @@ use crate::test;
use crate::util::environment::Environment;
use crate::util::formula::formula;
use radicle::git;
-
use radicle::node;
-
use radicle::node::address::Store as _;
use radicle::node::config::DefaultSeedingPolicy;
use radicle::node::policy::Scope;
-
use radicle::node::routing::Store as _;
-
use radicle::node::UserAgent;
use radicle::node::DEFAULT_TIMEOUT;
use radicle::node::{Alias, Handle as _};
-
use radicle::prelude::{NodeId, RepoId};
+
use radicle::prelude::RepoId;
use radicle::profile;
use radicle::storage::{ReadStorage as _, RemoteRepository as _};
-
use radicle_localtime::LocalTime;
use radicle_node::test::node::Node;
-
use radicle_node::PROTOCOL_VERSION;
-
use std::net;
use std::str::FromStr;

#[test]
@@ -257,320 +250,6 @@ fn rad_clean() {
        .unwrap();
}

-
#[test]
-
fn rad_seed_and_follow() {
-
    Environment::alice(["rad-seed-and-follow"]);
-
}
-

-
#[test]
-
fn rad_seed_many() {
-
    let mut environment = Environment::new();
-
    let alice = environment.node("alice");
-
    let mut bob = environment.node("bob");
-
    // Bob creates two projects that Alice seeds in the test
-
    let _ = bob.project("heartwood", "Radicle Heartwood Protocol & Stack");
-
    let _ = bob.project("nixpkgs", "Home for Nix Packages");
-
    let alice = alice.spawn();
-
    let mut bob = bob.spawn();
-

-
    bob.connect(&alice).converge([&alice]);
-

-
    test(
-
        "examples/rad-seed-many.md",
-
        environment.work(&alice),
-
        Some(&alice.home),
-
        [],
-
    )
-
    .unwrap();
-
}
-

-
#[test]
-
fn rad_unseed() {
-
    let mut environment = Environment::new();
-
    let mut alice = environment.node("alice");
-
    let working = tempfile::tempdir().unwrap();
-

-
    // Setup a test project.
-
    alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-
    let alice = alice.spawn();
-

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

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

-
    // Setup a test project.
-
    alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-
    alice.project("nixpkgs", "Home for Nix Packages");
-
    let alice = alice.spawn();
-

-
    test(
-
        "examples/rad-unseed-many.md",
-
        environment.work(&alice),
-
        Some(&alice.home),
-
        [],
-
    )
-
    .unwrap();
-
}
-

-
#[test]
-
fn rad_block() {
-
    let mut environment = Environment::new();
-
    let alice = environment.node_with(radicle::node::Config {
-
        seeding_policy: DefaultSeedingPolicy::permissive(),
-
        ..radicle::node::Config::test(Alias::new("alice"))
-
    });
-
    let working = tempfile::tempdir().unwrap();
-

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

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

-
    // Setup a test project.
-
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-

-
    let mut alice = alice.spawn();
-
    let mut bob = bob.spawn();
-
    // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
-
    alice.handle.seed(acme, Scope::Followed).unwrap();
-

-
    bob.connect(&alice).converge([&alice]);
-

-
    test("examples/rad-clone.md", working, Some(&bob.home), []).unwrap();
-
}
-

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

-
    // Setup a test project.
-
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-

-
    let mut alice = alice.spawn();
-
    let mut bob = bob.spawn();
-
    // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
-
    alice.handle.seed(acme, Scope::Followed).unwrap();
-

-
    bob.connect(&alice).converge([&alice]);
-

-
    test("examples/rad-clone-bare.md", working, Some(&bob.home), []).unwrap();
-
}
-

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

-
    // Setup a test project.
-
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-

-
    let mut alice = alice.spawn();
-
    let mut bob = bob.spawn();
-
    // Prevent Alice from fetching Bob's fork, as we're not testing that and it may cause errors.
-
    alice.handle.seed(acme, Scope::Followed).unwrap();
-

-
    bob.connect(&alice).converge([&alice]);
-

-
    test(
-
        "examples/rad-clone-directory.md",
-
        working,
-
        Some(&bob.home),
-
        [],
-
    )
-
    .unwrap();
-
}
-

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

-
    // Setup a test project.
-
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-

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

-
    alice.handle.seed(acme, Scope::All).unwrap();
-
    bob.connect(&alice).converge([&alice]);
-
    eve.connect(&alice).converge([&alice]);
-

-
    // Fork and sync repo.
-
    bob.fork(acme, bob.home.path()).unwrap();
-
    bob.announce(acme, 2, bob.home.path()).unwrap();
-
    bob.has_remote_of(&acme, &alice.id);
-
    alice.has_remote_of(&acme, &bob.id);
-

-
    test(
-
        "examples/rad-clone-all.md",
-
        environment.work(&eve),
-
        Some(&eve.home),
-
        [],
-
    )
-
    .unwrap();
-
    eve.has_remote_of(&acme, &bob.id);
-
}
-

-
#[test]
-
fn rad_clone_partial_fail() {
-
    let mut environment = Environment::new();
-
    let mut alice = environment.node("alice");
-
    let bob = environment.node("bob");
-
    let mut eve = environment.node("eve");
-
    let carol = NodeId::from_str("z6MksFqXN3Yhqk8pTJdUGLwBTkRfQvwZXPqR2qMEhbS9wzpT").unwrap();
-

-
    // Setup a test project.
-
    let acme = alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
-

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

-
    // Make Even think she knows about a seed called "carol" that has the repo.
-
    eve.db
-
        .addresses_mut()
-
        .insert(
-
            &carol,
-
            PROTOCOL_VERSION,
-
            node::Features::SEED,
-
            &Alias::new("carol"),
-
            0,
-
            &UserAgent::default(),
-
            LocalTime::now().into(),
-
            [node::KnownAddress::new(
-
                // Eve will fail to connect to this address.
-
                node::Address::from(net::SocketAddr::from(([0, 0, 0, 0], 19873))),
-
                node::address::Source::Imported,
-
            )],
-
        )
-
        .unwrap();
-
    eve.db
-
        .routing_mut()
-
        .add_inventory([&acme], carol, LocalTime::now().into())
-
        .unwrap();
-
    eve.config.peers = node::config::PeerConfig::Static;
-

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

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

-
    bob.connect(&alice).converge([&alice]);
-
    eve.connect(&alice);
-
    eve.connect(&bob);
-
    eve.routes_to(&[(acme, carol), (acme, bob.id), (acme, alice.id)]);
-
    bob.storage.repository(acme).unwrap().remove().unwrap(); // Cause the fetch from Bob to fail.
-
    bob.storage.temporary_repository(acme).ok(); // Prevent repo from being re-fetched.
-

-
    test(
-
        "examples/rad-clone-partial-fail.md",
-
        environment.work(&eve),
-
        Some(&eve.home),
-
        [],
-
    )
-
    .unwrap();
-
}
-

-
#[test]
-
fn rad_clone_connect() {
-
    let mut environment = Environment::new();
-
    let working = environment.tempdir().join("working");
-
    let alice = environment.node("alice");
-
    let bob = environment.node("bob");
-
    let mut eve = environment.node("eve");
-
    let acme = RepoId::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
-
    let ua = UserAgent::default();
-
    let now = LocalTime::now().into();
-

-
    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 Eve know about Alice and Bob having the repo.
-
    eve.db
-
        .addresses_mut()
-
        .insert(
-
            &alice.id,
-
            PROTOCOL_VERSION,
-
            node::Features::SEED,
-
            &Alias::new("alice"),
-
            0,
-
            &ua,
-
            now,
-
            [node::KnownAddress::new(
-
                node::Address::from(alice.addr),
-
                node::address::Source::Imported,
-
            )],
-
        )
-
        .unwrap();
-
    eve.db
-
        .addresses_mut()
-
        .insert(
-
            &bob.id,
-
            PROTOCOL_VERSION,
-
            node::Features::SEED,
-
            &Alias::new("bob"),
-
            0,
-
            &ua,
-
            now,
-
            [node::KnownAddress::new(
-
                node::Address::from(bob.addr),
-
                node::address::Source::Imported,
-
            )],
-
        )
-
        .unwrap();
-
    eve.db
-
        .routing_mut()
-
        .add_inventory([&acme], alice.id, now)
-
        .unwrap();
-
    eve.db
-
        .routing_mut()
-
        .add_inventory([&acme], bob.id, now)
-
        .unwrap();
-
    eve.config.peers = node::config::PeerConfig::Static;
-

-
    let eve = eve.spawn();
-

-
    alice.handle.seed(acme, Scope::Followed).unwrap();
-
    bob.handle.seed(acme, Scope::Followed).unwrap();
-
    alice.connect(&bob);
-
    bob.routes_to(&[(acme, alice.id)]);
-
    eve.routes_to(&[(acme, alice.id), (acme, bob.id)]);
-
    alice.routes_to(&[(acme, alice.id), (acme, bob.id)]);
-

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

#[test]
fn rad_sync_without_node() {
@@ -1164,23 +843,3 @@ fn rad_publish() {
        .unwrap();
}

-
#[test]
-
fn rad_seed_policy_allow_no_scope() {
-
    let mut environment = Environment::new();
-
    let alice = environment.node_with(radicle::node::Config {
-
        seeding_policy: DefaultSeedingPolicy::Allow {
-
            scope: node::config::Scope::implicit(),
-
        },
-
        ..radicle::node::Config::test(Alias::new("alice"))
-
    });
-

-
    let alice = alice.spawn();
-

-
    test(
-
        "examples/rad-seed-policy-allow-no-scope.md",
-
        environment.work(&alice),
-
        Some(&alice.home),
-
        [],
-
    )
-
    .unwrap();
-
}
added crates/radicle-cli/tests/commands/jj.rs
@@ -0,0 +1,45 @@
+
use crate::util::environment::Environment;
+
use crate::{program_reports_version, test};
+
use radicle::git;
+

+
#[test]
+
fn rad_jj_bare() {
+
    // We test whether `jj` is installed, and have this test succeed if it is not.
+
    // Programmatic skipping of tests is not supported as of 2024-08.
+
    if !program_reports_version("jj") {
+
        return;
+
    }
+

+
    let mut environment = Environment::new();
+
    let mut profile = environment.node("alice");
+
    let rid = profile.project("heartwood", "Radicle Heartwood Protocol & Stack");
+

+
    test(
+
        "examples/rad-init-existing-bare.md",
+
        environment.work(&profile),
+
        Some(&profile.home),
+
        [(
+
            "URL",
+
            git::url::File::new(profile.storage.path())
+
                .rid(rid)
+
                .to_string()
+
                .as_str(),
+
        )],
+
    )
+
    .unwrap();
+

+
    environment
+
        .tests(["jj-config", "jj-init-bare"], &profile)
+
        .unwrap();
+
}
+

+
#[test]
+
fn rad_jj_colocated_patch() {
+
    // We test whether `jj` is installed, and have this test succeed if it is not.
+
    // Programmatic skipping of tests is not supported as of 2024-08.
+
    if !program_reports_version("jj") {
+
        return;
+
    }
+

+
    Environment::alice(["rad-init", "jj-config", "jj-init-colocate", "rad-patch-jj"])
+
}
modified crates/radicle-cli/tests/commands/patch.rs
@@ -1,7 +1,6 @@
use crate::util::environment::Environment;
use crate::util::formula::formula;
-
use crate::{program_reports_version, test};
-
use radicle::git;
+
use crate::test;
use radicle::node::policy::Scope;
use radicle::node::Handle as _;
use radicle::prelude::RepoId;
@@ -13,47 +12,6 @@ fn rad_patch() {
    Environment::alice(["rad-init", "rad-patch"]);
}

-
#[test]
-
fn rad_jj_bare() {
-
    // We test whether `jj` is installed, and have this test succeed if it is not.
-
    // Programmatic skipping of tests is not supported as of 2024-08.
-
    if !program_reports_version("jj") {
-
        return;
-
    }
-

-
    let mut environment = Environment::new();
-
    let mut profile = environment.node("alice");
-
    let rid = profile.project("heartwood", "Radicle Heartwood Protocol & Stack");
-

-
    test(
-
        "examples/rad-init-existing-bare.md",
-
        environment.work(&profile),
-
        Some(&profile.home),
-
        [(
-
            "URL",
-
            git::url::File::new(profile.storage.path())
-
                .rid(rid)
-
                .to_string()
-
                .as_str(),
-
        )],
-
    )
-
    .unwrap();
-

-
    environment
-
        .tests(["jj-config", "jj-init-bare"], &profile)
-
        .unwrap();
-
}
-

-
#[test]
-
fn rad_jj_colocated_patch() {
-
    // We test whether `jj` is installed, and have this test succeed if it is not.
-
    // Programmatic skipping of tests is not supported as of 2024-08.
-
    if !program_reports_version("jj") {
-
        return;
-
    }
-

-
    Environment::alice(["rad-init", "jj-config", "jj-init-colocate", "rad-patch-jj"])
-
}

#[test]
fn rad_patch_diff() {
@@ -317,68 +275,6 @@ fn rad_patch_fetch_1() {
        .unwrap();
}

-
#[test]
-
fn rad_watch() {
-
    let mut environment = Environment::new();
-
    let mut alice = environment.node("alice");
-
    let bob = environment.node("bob");
-
    let (repo, _) = environment.repository(&alice);
-
    let rid = alice.project_from("heartwood", "Radicle Heartwood Protocol & Stack", &repo);
-

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

-
    bob.connect(&alice).converge([&alice]);
-
    bob.clone(rid, environment.work(&bob)).unwrap();
-

-
    formula(&environment.tempdir(), "examples/rad-watch.md")
-
        .unwrap()
-
        .home(
-
            "alice",
-
            environment.work(&alice),
-
            [("RAD_HOME", alice.home.path().display())],
-
        )
-
        .home(
-
            "bob",
-
            environment.work(&bob).join("heartwood"),
-
            [("RAD_HOME", bob.home.path().display())],
-
        )
-
        .run()
-
        .unwrap();
-
}
-

-
#[test]
-
fn rad_inbox() {
-
    let mut environment = Environment::new();
-
    let mut alice = environment.node("alice");
-
    let bob = environment.node("bob");
-
    let (repo1, _) = fixtures::repository(environment.work(&alice).join("heartwood"));
-
    let (repo2, _) = fixtures::repository(environment.work(&alice).join("radicle-git"));
-
    let rid1 = alice.project_from("heartwood", "Radicle Heartwood Protocol & Stack", &repo1);
-
    let rid2 = alice.project_from("radicle-git", "Radicle Git", &repo2);
-

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

-
    bob.connect(&alice).converge([&alice]);
-
    bob.clone(rid1, environment.work(&bob)).unwrap();
-
    bob.clone(rid2, environment.work(&bob)).unwrap();
-

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

#[test]
fn rad_patch_fetch_2() {
added crates/radicle-cli/tests/commands/seed.rs
@@ -0,0 +1,97 @@
+
use crate::test;
+
use crate::util::environment::Environment;
+
use radicle::node;
+
use radicle::node::config::DefaultSeedingPolicy;
+
use radicle::node::Alias;
+

+
#[test]
+
fn rad_seed_and_follow() {
+
    Environment::alice(["rad-seed-and-follow"]);
+
}
+

+
#[test]
+
fn rad_seed_many() {
+
    let mut environment = Environment::new();
+
    let alice = environment.node("alice");
+
    let mut bob = environment.node("bob");
+
    // Bob creates two projects that Alice seeds in the test
+
    let _ = bob.project("heartwood", "Radicle Heartwood Protocol & Stack");
+
    let _ = bob.project("nixpkgs", "Home for Nix Packages");
+
    let alice = alice.spawn();
+
    let mut bob = bob.spawn();
+

+
    bob.connect(&alice).converge([&alice]);
+

+
    test(
+
        "examples/rad-seed-many.md",
+
        environment.work(&alice),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+
}
+

+
#[test]
+
fn rad_unseed() {
+
    let mut environment = Environment::new();
+
    let mut alice = environment.node("alice");
+
    let working = tempfile::tempdir().unwrap();
+

+
    // Setup a test project.
+
    alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+
    let alice = alice.spawn();
+

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

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

+
    // Setup a test project.
+
    alice.project("heartwood", "Radicle Heartwood Protocol & Stack");
+
    alice.project("nixpkgs", "Home for Nix Packages");
+
    let alice = alice.spawn();
+

+
    test(
+
        "examples/rad-unseed-many.md",
+
        environment.work(&alice),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+
}
+

+
#[test]
+
fn rad_block() {
+
    let mut environment = Environment::new();
+
    let alice = environment.node_with(radicle::node::Config {
+
        seeding_policy: DefaultSeedingPolicy::permissive(),
+
        ..radicle::node::Config::test(Alias::new("alice"))
+
    });
+
    let working = tempfile::tempdir().unwrap();
+

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

+
#[test]
+
fn rad_seed_policy_allow_no_scope() {
+
    let mut environment = Environment::new();
+
    let alice = environment.node_with(radicle::node::Config {
+
        seeding_policy: DefaultSeedingPolicy::Allow {
+
            scope: node::config::Scope::implicit(),
+
        },
+
        ..radicle::node::Config::test(Alias::new("alice"))
+
    });
+

+
    let alice = alice.spawn();
+

+
    test(
+
        "examples/rad-seed-policy-allow-no-scope.md",
+
        environment.work(&alice),
+
        Some(&alice.home),
+
        [],
+
    )
+
    .unwrap();
+
}
added crates/radicle-cli/tests/commands/watch.rs
@@ -0,0 +1,32 @@
+
use crate::util::environment::Environment;
+
use crate::util::formula::formula;
+

+
#[test]
+
fn rad_watch() {
+
    let mut environment = Environment::new();
+
    let mut alice = environment.node("alice");
+
    let bob = environment.node("bob");
+
    let (repo, _) = environment.repository(&alice);
+
    let rid = alice.project_from("heartwood", "Radicle Heartwood Protocol & Stack", &repo);
+

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

+
    bob.connect(&alice).converge([&alice]);
+
    bob.clone(rid, environment.work(&bob)).unwrap();
+

+
    formula(&environment.tempdir(), "examples/rad-watch.md")
+
        .unwrap()
+
        .home(
+
            "alice",
+
            environment.work(&alice),
+
            [("RAD_HOME", alice.home.path().display())],
+
        )
+
        .home(
+
            "bob",
+
            environment.work(&bob).join("heartwood"),
+
            [("RAD_HOME", bob.home.path().display())],
+
        )
+
        .run()
+
        .unwrap();
+
}