node: Add clone test with seed acting as relay
This commit is contained in:
parent
3e7761740f
commit
3ae826dee2
|
|
@ -1,11 +1,15 @@
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::str::FromStr;
|
||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
|
|
||||||
use radicle::git;
|
use radicle::git;
|
||||||
|
use radicle::prelude::Id;
|
||||||
use radicle::profile::Home;
|
use radicle::profile::Home;
|
||||||
|
use radicle::storage::{ReadRepository, WriteStorage};
|
||||||
use radicle::test::fixtures;
|
use radicle::test::fixtures;
|
||||||
|
|
||||||
|
use radicle_node::service::tracking::Policy;
|
||||||
use radicle_node::test::{
|
use radicle_node::test::{
|
||||||
environment::{Config, Environment},
|
environment::{Config, Environment},
|
||||||
logger,
|
logger,
|
||||||
|
|
@ -267,3 +271,76 @@ fn rad_init_sync_and_clone() {
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
//
|
||||||
|
// alice -- seed -- bob
|
||||||
|
//
|
||||||
|
fn test_replication_via_seed() {
|
||||||
|
logger::init(log::Level::Debug);
|
||||||
|
|
||||||
|
let mut environment = Environment::new();
|
||||||
|
let alice = environment.node("alice");
|
||||||
|
let bob = environment.node("bob");
|
||||||
|
let seed = environment.node("seed");
|
||||||
|
let working = environment.tmp().join("working");
|
||||||
|
let rid = Id::from_str("z42hL2jL4XNk6K8oHQaSWfMgCL7ji").unwrap();
|
||||||
|
|
||||||
|
let mut alice = alice.spawn(Config::default());
|
||||||
|
let mut bob = bob.spawn(Config::default());
|
||||||
|
let seed = seed.spawn(Config {
|
||||||
|
policy: Policy::Track,
|
||||||
|
..Config::default()
|
||||||
|
});
|
||||||
|
|
||||||
|
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_secs(1));
|
||||||
|
|
||||||
|
alice.routes_to(&[]);
|
||||||
|
seed.routes_to(&[]);
|
||||||
|
bob.routes_to(&[]);
|
||||||
|
|
||||||
|
// Initialize a repo as Alice.
|
||||||
|
fixtures::repository(working.join("alice"));
|
||||||
|
alice
|
||||||
|
.rad(
|
||||||
|
"init",
|
||||||
|
&[
|
||||||
|
"--name",
|
||||||
|
"heartwood",
|
||||||
|
"--description",
|
||||||
|
"Radicle Heartwood Protocol & Stack",
|
||||||
|
"--default-branch",
|
||||||
|
"master",
|
||||||
|
],
|
||||||
|
working.join("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)]);
|
||||||
|
|
||||||
|
bob.rad("clone", &[rid.to_string().as_str()], working.join("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)]);
|
||||||
|
|
||||||
|
// Enough time for the Seed to be able to fetch Bob's fork.
|
||||||
|
thread::sleep(time::Duration::from_secs(1));
|
||||||
|
|
||||||
|
seed.storage
|
||||||
|
.repository(rid)
|
||||||
|
.unwrap()
|
||||||
|
.remote(&bob.id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// TODO: Seed should send Bob's ref announcement to Alice, after the fetch.
|
||||||
|
// Currently, it is relayed when received from Bob, before the fetch completes,
|
||||||
|
// which means that Alice fetches too early from Seed, and nothing is fetched.
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -754,7 +754,7 @@ where
|
||||||
// Discard inventory messages we've already seen, otherwise update
|
// Discard inventory messages we've already seen, otherwise update
|
||||||
// out last seen time.
|
// out last seen time.
|
||||||
if !peer.inventory_announced(timestamp) {
|
if !peer.inventory_announced(timestamp) {
|
||||||
debug!(target: "service", "Ignoring stale inventory announcement from {announcer}");
|
debug!(target: "service", "Ignoring stale inventory announcement from {announcer} (t={})", self.clock.as_secs());
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -162,12 +162,21 @@ impl<G: Signer + cyphernet::EcSign> NodeHandle<G> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wait until this node's routing table contains the given routes.
|
/// Wait until this node's routing table contains the given routes.
|
||||||
|
#[track_caller]
|
||||||
pub fn routes_to(&self, routes: &[(Id, NodeId)]) {
|
pub fn routes_to(&self, routes: &[(Id, NodeId)]) {
|
||||||
|
loop {
|
||||||
let mut remaining: BTreeSet<_> = routes.iter().collect();
|
let mut remaining: BTreeSet<_> = routes.iter().collect();
|
||||||
|
|
||||||
while !remaining.is_empty() {
|
|
||||||
for (rid, nid) in self.handle.routing().unwrap() {
|
for (rid, nid) in self.handle.routing().unwrap() {
|
||||||
remaining.remove(&(rid, nid));
|
if !remaining.remove(&(rid, nid)) {
|
||||||
|
panic!(
|
||||||
|
"Node::routes_to: unexpected route for {}: ({rid}, {nid})",
|
||||||
|
self.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if remaining.is_empty() {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
}
|
}
|
||||||
|
|
@ -309,9 +318,12 @@ pub fn converge<'a, G: Signer + cyphernet::EcSign + 'static>(
|
||||||
|
|
||||||
// First build the set of all routes.
|
// First build the set of all routes.
|
||||||
for node in &nodes {
|
for node in &nodes {
|
||||||
let inv = node.storage.inventory().unwrap();
|
// Routes from the routing table.
|
||||||
|
for (rid, seed_id) in node.handle.routing().unwrap() {
|
||||||
for rid in inv {
|
all_routes.insert((rid, seed_id));
|
||||||
|
}
|
||||||
|
// Routes from the local inventory.
|
||||||
|
for rid in node.storage.inventory().unwrap() {
|
||||||
all_routes.insert((rid, node.id));
|
all_routes.insert((rid, node.id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue