Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
Speed up node E2E tests
Alexis Sellier committed 3 years ago
commit d31968509da970f8d124e3b9a2e79e281206cdcd
parent 72cb2fd713544c4f0f42a393e9c9ec2d9e3d916d
15 files changed +100 -57
modified radicle-cli/src/commands/clone.rs
@@ -80,7 +80,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {

pub fn clone(id: Id, _interactive: Interactive, ctx: impl term::Context) -> anyhow::Result<()> {
    let profile = ctx.profile()?;
-
    let mut node = radicle::node::connect(profile.node())?;
+
    let mut node = radicle::node::connect(profile.socket())?;
    let signer = term::signer(&profile)?;

    // Track & fetch project.
modified radicle-cli/src/commands/track.rs
@@ -94,7 +94,7 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
    let storage = &profile.storage;
    let (_, rid) = radicle::rad::cwd().context("this command must be run within a project")?;
    let project = storage.repository(rid)?.project_of(profile.id())?;
-
    let mut node = radicle::node::connect(profile.node())?;
+
    let mut node = radicle::node::connect(profile.socket())?;

    term::info!(
        "Establishing 🌱 tracking relationship for {}",
modified radicle-cli/src/commands/untrack.rs
@@ -88,6 +88,6 @@ pub fn run(options: Options, ctx: impl term::Context) -> anyhow::Result<()> {
}

pub fn untrack(id: Id, profile: &Profile) -> anyhow::Result<bool> {
-
    let mut node = radicle::node::connect(profile.node())?;
+
    let mut node = radicle::node::connect(profile.socket())?;
    node.untrack_repo(id).map_err(|e| anyhow!(e))
}
modified radicle-cli/tests/commands.rs
@@ -16,7 +16,7 @@ fn test(
    let base = Path::new(env!("CARGO_MANIFEST_DIR"));
    let tmp = tempfile::tempdir().unwrap();
    let home = if let Some(profile) = profile {
-
        profile.home.as_path().to_path_buf()
+
        profile.home().to_path_buf()
    } else {
        tmp.path().to_path_buf()
    };
modified radicle-crypto/src/test/signer.rs
@@ -71,3 +71,28 @@ impl Signer for MockSigner {
        Ok(self.sign(msg))
    }
}
+

+
#[cfg(feature = "cyphernet")]
+
impl cyphernet::EcSk for MockSigner {
+
    type Pk = PublicKey;
+

+
    fn generate_keypair() -> (Self, Self::Pk)
+
    where
+
        Self: Sized,
+
    {
+
        unimplemented! {}
+
    }
+

+
    fn to_pk(&self) -> Result<Self::Pk, cyphernet::EcSkInvalid> {
+
        Ok(*self.public_key())
+
    }
+
}
+

+
#[cfg(feature = "cyphernet")]
+
impl cyphernet::EcSign for MockSigner {
+
    type Sig = Signature;
+

+
    fn sign(&self, msg: impl AsRef<[u8]>) -> Self::Sig {
+
        Signer::sign(self, msg.as_ref())
+
    }
+
}
modified radicle-httpd/src/lib.rs
@@ -51,7 +51,7 @@ pub async fn run(options: Options) -> anyhow::Result<()> {
    tracing::info!("{}", str::from_utf8(&git_version)?.trim());

    let profile = Arc::new(radicle::Profile::load()?);
-
    tracing::info!("using radicle home at {}", profile.home.display());
+
    tracing::info!("using radicle home at {}", profile.home().display());

    let git_router = Router::new()
        .route("/:project/*request", any(git_handler))
modified radicle-node/src/client.rs
@@ -1,8 +1,9 @@
-
use std::io;
-
use std::{net, thread, time};
+
use std::{io, net, thread, time};

use cyphernet::{Cert, EcSign};
use netservices::resource::NetAccept;
+
use radicle::profile::Paths;
+
use radicle::Storage;
use reactor::poller::popol;
use reactor::Reactor;
use thiserror::Error;
@@ -14,7 +15,7 @@ use crate::node::NodeId;
use crate::service::{routing, tracking};
use crate::wire::Wire;
use crate::worker::{WorkerPool, WorkerReq};
-
use crate::{crypto, profile, service, LocalTime};
+
use crate::{crypto, service, LocalTime};

pub mod handle;
use handle::Handle;
@@ -66,19 +67,19 @@ impl<G: crypto::Signer + EcSign<Pk = NodeId, Sig = Signature> + Clone + 'static>
    ///
    /// This function spawns threads.
    pub fn with(
-
        profile: profile::Profile,
+
        paths: Paths,
        config: service::Config,
        listen: Vec<net::SocketAddr>,
        proxy: net::SocketAddr,
        signer: G,
    ) -> Result<Runtime<G>, Error> {
-
        let id = *profile.id();
-
        let node = profile.node();
+
        let id = *signer.public_key();
+
        let node_sock = paths.socket();
+
        let node_dir = paths.node();
        let network = config.network;
        let rng = fastrand::Rng::new();
        let clock = LocalTime::now();
-
        let storage = profile.storage;
-
        let node_dir = profile.home.join(NODE_DIR);
+
        let storage = Storage::open(paths.storage())?;
        let address_db = node_dir.join(ADDRESS_DB_FILE);
        let routing_db = node_dir.join(ROUTING_DB_FILE);
        let tracking_db = node_dir.join(TRACKING_DB_FILE);
@@ -122,7 +123,7 @@ impl<G: crypto::Signer + EcSign<Pk = NodeId, Sig = Signature> + Clone + 'static>
        let handle = Handle::from(reactor.controller());
        let control = thread::spawn({
            let handle = handle.clone();
-
            move || control::listen(node, handle)
+
            move || control::listen(node_sock, handle)
        });
        let controller = reactor.controller();
        let mut local_addrs = Vec::new();
modified radicle-node/src/main.rs
@@ -6,8 +6,9 @@ use nakamoto_net::LocalDuration;

use radicle::profile;
use radicle_node::client::Runtime;
-
use radicle_node::crypto::ssh::keystore::MemorySigner;
+
use radicle_node::crypto::ssh::keystore::{Keystore, MemorySigner};
use radicle_node::prelude::{Address, NodeId};
+
use radicle_node::profile::Paths;
use radicle_node::{logger, service};

#[derive(Debug)]
@@ -77,11 +78,13 @@ fn main() -> anyhow::Result<()> {
    logger::init(log::Level::Debug)?;

    let options = Options::from_env()?;
-
    let profile = radicle::Profile::load().context("Failed to load node profile")?;
+
    let home = profile::home()?;
+
    let paths = Paths::new(home);
    let passphrase = env::var(profile::env::RAD_PASSPHRASE)
        .context("`RAD_PASSPHRASE` is required to be set for the node to establish connections")?
        .into();
-
    let signer = MemorySigner::load(&profile.keystore, passphrase)?;
+
    let keystore = Keystore::new(&paths.keys());
+
    let signer = MemorySigner::load(&keystore, passphrase)?;
    let config = service::Config {
        connect: options.connect.into_iter().collect(),
        external_addresses: options.external_addresses,
@@ -89,7 +92,7 @@ fn main() -> anyhow::Result<()> {
        ..service::Config::default()
    };
    let proxy = net::SocketAddr::new(net::Ipv4Addr::LOCALHOST.into(), 9050);
-
    let runtime = Runtime::with(profile, config, options.listen, proxy, signer)?;
+
    let runtime = Runtime::with(paths, config, options.listen, proxy, signer)?;

    runtime.run()?;

modified radicle-node/src/tests/e2e.rs
@@ -5,13 +5,13 @@ use std::{
    time::Duration,
};

-
use radicle::crypto::ssh::keystore::MemorySigner;
+
use radicle::crypto::test::signer::MockSigner;
use radicle::git::refname;
use radicle::identity::Id;
use radicle::node::Handle;
+
use radicle::profile::Paths;
use radicle::storage::WriteStorage;
use radicle::test::fixtures;
-
use radicle::Profile;
use radicle::Storage;
use radicle::{assert_matches, rad};

@@ -27,8 +27,8 @@ use crate::{client, client::Runtime, service};
struct Node {
    id: NodeId,
    addr: net::SocketAddr,
-
    handle: client::handle::Handle<Wire<routing::Table, address::Book, Storage, MemorySigner>>,
-
    signer: MemorySigner,
+
    handle: client::handle::Handle<Wire<routing::Table, address::Book, Storage, MockSigner>>,
+
    signer: MockSigner,
    storage: Storage,
    #[allow(dead_code)]
    thread: thread::JoinHandle<Result<(), client::Error>>,
@@ -42,15 +42,12 @@ impl Node {
                .take(8)
                .collect::<String>(),
        );
-

-
        let profile = Profile::init(home.as_path(), "pasphrase".to_owned()).unwrap();
-
        let signer = MemorySigner::load(&profile.keystore, "pasphrase".to_owned().into()).unwrap();
+
        let paths = Paths::init(home).unwrap();
+
        let signer = MockSigner::default();
        let listen = vec![([0, 0, 0, 0], 0).into()];
        let proxy = net::SocketAddr::new(net::Ipv4Addr::LOCALHOST.into(), 9050);
-
        let storage = profile.storage.clone();
-

-
        let rt = Runtime::with(profile, config, listen, proxy, signer.clone()).unwrap();
-

+
        let storage = Storage::open(paths.storage()).unwrap();
+
        let rt = Runtime::with(paths, config, listen, proxy, signer.clone()).unwrap();
        let addr = *rt.local_addrs.first().unwrap();
        let id = rt.id;
        let handle = rt.handle.clone();
modified radicle-remote-helper/src/lib.rs
@@ -108,7 +108,7 @@ pub fn run(profile: radicle::Profile) -> Result<(), Box<dyn std::error::Error +
                        // Connect to local node and announce refs to the network.
                        // If our node is not running, we simply skip this step, as the
                        // refs will be announced eventually, when the node restarts.
-
                        if let Ok(mut conn) = radicle::node::connect(profile.node()) {
+
                        if let Ok(mut conn) = radicle::node::connect(profile.socket()) {
                            conn.announce_refs(url.repo)?;
                        }
                    }
modified radicle-tools/src/rad-auth.rs
@@ -9,7 +9,7 @@ fn main() -> anyhow::Result<()> {
    };

    println!("id: {}", profile.id());
-
    println!("home: {}", profile.home.display());
+
    println!("home: {}", profile.home().display());

    Ok(())
}
modified radicle-tools/src/rad-clone.rs
@@ -11,7 +11,7 @@ fn main() -> anyhow::Result<()> {

    if let Some(id) = env::args().nth(1) {
        let id = Id::from_str(&id)?;
-
        let mut node = radicle::node::connect(profile.node())?;
+
        let mut node = radicle::node::connect(profile.socket())?;
        let repo = radicle::rad::clone(id, &cwd, &signer, &profile.storage, &mut node)?;

        println!(
modified radicle-tools/src/rad-push.rs
@@ -16,7 +16,7 @@ fn main() -> anyhow::Result<()> {
    let sigrefs = project.sign_refs(&signer)?;
    let head = project.set_head()?;

-
    radicle::node::connect(profile.node())?.announce_refs(id)?;
+
    radicle::node::connect(profile.socket())?.announce_refs(id)?;

    println!("head: {}", head);
    println!("ok: {}", sigrefs.signature);
modified radicle-tools/src/rad-self.rs
@@ -7,7 +7,7 @@ fn main() -> anyhow::Result<()> {
        "fingerprint: {}",
        radicle::crypto::ssh::fmt::fingerprint(profile.id())
    );
-
    println!("home: {}", profile.home.display());
+
    println!("home: {}", profile.home().display());

    Ok(())
}
modified radicle/src/profile.rs
@@ -59,7 +59,7 @@ pub enum Error {

#[derive(Debug, Clone)]
pub struct Profile {
-
    pub home: PathBuf,
+
    pub paths: Paths,
    pub storage: Storage,
    pub keystore: Keystore,
    pub public_key: PublicKey,
@@ -68,19 +68,15 @@ pub struct Profile {
impl Profile {
    pub fn init(home: impl AsRef<Path>, passphrase: impl Into<Passphrase>) -> Result<Self, Error> {
        let home = home.as_ref().to_path_buf();
-
        let paths = Paths {
-
            home: home.as_path(),
-
        };
+
        let paths = Paths::init(home.as_path())?;
        let storage = Storage::open(paths.storage())?;
        let keystore = Keystore::new(&paths.keys());
        let public_key = keystore.init("radicle", passphrase)?;

-
        fs::create_dir_all(paths.node()).ok();
-

        transport::local::register(storage.clone());

        Ok(Profile {
-
            home,
+
            paths,
            storage,
            keystore,
            public_key,
@@ -89,16 +85,17 @@ impl Profile {

    pub fn load() -> Result<Self, Error> {
        let home = self::home()?;
-
        let storage = Storage::open(home.join("storage"))?;
-
        let keystore = Keystore::new(&home.join("keys"));
+
        let paths = Paths::new(home);
+
        let storage = Storage::open(paths.storage())?;
+
        let keystore = Keystore::new(&paths.keys());
        let public_key = keystore
            .public_key()?
-
            .ok_or_else(|| Error::NotFound(home.clone()))?;
+
            .ok_or_else(|| Error::NotFound(paths.home.clone()))?;

        transport::local::register(storage.clone());

        Ok(Profile {
-
            home,
+
            paths,
            storage,
            keystore,
            public_key,
@@ -130,19 +127,22 @@ impl Profile {

    /// Return the path to the keys folder.
    pub fn keys(&self) -> PathBuf {
-
        self.home.join("keys")
+
        self.paths.keys()
+
    }
+

+
    /// Get the profile home directory.
+
    pub fn home(&self) -> &Path {
+
        self.paths.home()
    }

    /// Get the path to the radicle node socket.
-
    pub fn node(&self) -> PathBuf {
-
        env::var_os(env::RAD_SOCKET)
-
            .map(PathBuf::from)
-
            .unwrap_or_else(|| self.home.join("node").join(node::DEFAULT_SOCKET_NAME))
+
    pub fn socket(&self) -> PathBuf {
+
        self.paths.socket()
    }

    /// Get `Paths` of profile
-
    pub fn paths(&self) -> Paths {
-
        Paths { home: &self.home }
+
    pub fn paths(&self) -> &Paths {
+
        &self.paths
    }
}

@@ -161,13 +161,24 @@ pub fn home() -> Result<PathBuf, io::Error> {
}

#[derive(Debug, Clone)]
-
pub struct Paths<'a> {
-
    home: &'a Path,
+
pub struct Paths {
+
    home: PathBuf,
}

-
impl<'a> Paths<'a> {
-
    pub fn new(home: &'a Path) -> Self {
-
        Self { home }
+
impl Paths {
+
    pub fn init(home: impl Into<PathBuf>) -> Result<Self, io::Error> {
+
        let paths = Self::new(home);
+
        fs::create_dir_all(paths.node()).ok();
+

+
        Ok(paths)
+
    }
+

+
    pub fn new(home: impl Into<PathBuf>) -> Self {
+
        Self { home: home.into() }
+
    }
+

+
    pub fn home(&self) -> &Path {
+
        self.home.as_path()
    }

    pub fn storage(&self) -> PathBuf {
@@ -181,4 +192,10 @@ impl<'a> Paths<'a> {
    pub fn node(&self) -> PathBuf {
        self.home.join("node")
    }
+

+
    pub fn socket(&self) -> PathBuf {
+
        env::var_os(env::RAD_SOCKET)
+
            .map(PathBuf::from)
+
            .unwrap_or_else(|| self.node().join(node::DEFAULT_SOCKET_NAME))
+
    }
}