299 lines
8.0 KiB
Rust
299 lines
8.0 KiB
Rust
use std::{thread, time};
|
|
|
|
use radicle::crypto::Signer;
|
|
use radicle::node::{FetchResult, Handle as _};
|
|
use radicle::storage::{ReadRepository, ReadStorage};
|
|
use radicle::{assert_matches, rad};
|
|
|
|
use crate::service;
|
|
use crate::service::tracking::Scope;
|
|
use crate::storage::git::transport;
|
|
use crate::test::environment::{converge, Node};
|
|
use crate::test::logger;
|
|
|
|
#[test]
|
|
//
|
|
// alice -- bob
|
|
//
|
|
fn test_inventory_sync_basic() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
|
|
let mut alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
|
|
alice.project("alice", "");
|
|
bob.project("bob", "");
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let bob = bob.spawn(service::Config::default());
|
|
|
|
alice.connect(&bob);
|
|
|
|
let routes = converge([&alice, &bob]);
|
|
assert_eq!(routes.len(), 2);
|
|
}
|
|
|
|
#[test]
|
|
//
|
|
// alice -- bob -- eve
|
|
//
|
|
fn test_inventory_sync_bridge() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
|
|
let mut alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
let mut eve = Node::init(tmp.path());
|
|
|
|
alice.project("alice", "");
|
|
bob.project("bob", "");
|
|
eve.project("eve", "");
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let mut bob = bob.spawn(service::Config::default());
|
|
let eve = eve.spawn(service::Config::default());
|
|
|
|
alice.connect(&bob);
|
|
bob.connect(&eve);
|
|
|
|
let routes = converge([&alice, &bob, &eve]);
|
|
assert_eq!(routes.len(), 3);
|
|
}
|
|
|
|
#[test]
|
|
//
|
|
// alice -- bob
|
|
// | |
|
|
// carol -- eve
|
|
//
|
|
fn test_inventory_sync_ring() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
|
|
let mut alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
let mut eve = Node::init(tmp.path());
|
|
let mut carol = Node::init(tmp.path());
|
|
|
|
alice.project("alice", "");
|
|
bob.project("bob", "");
|
|
eve.project("eve", "");
|
|
carol.project("carol", "");
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let mut bob = bob.spawn(service::Config::default());
|
|
let mut eve = eve.spawn(service::Config::default());
|
|
let mut carol = carol.spawn(service::Config::default());
|
|
|
|
alice.connect(&bob);
|
|
bob.connect(&eve);
|
|
eve.connect(&carol);
|
|
carol.connect(&alice);
|
|
|
|
let routes = converge([&alice, &bob, &eve, &carol]);
|
|
assert_eq!(routes.len(), 4);
|
|
}
|
|
|
|
#[test]
|
|
//
|
|
// dave
|
|
// |
|
|
// eve -- alice -- bob
|
|
// |
|
|
// carol
|
|
//
|
|
fn test_inventory_sync_star() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
|
|
let mut alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
let mut eve = Node::init(tmp.path());
|
|
let mut carol = Node::init(tmp.path());
|
|
let mut dave = Node::init(tmp.path());
|
|
|
|
alice.project("alice", "");
|
|
bob.project("bob", "");
|
|
eve.project("eve", "");
|
|
carol.project("carol", "");
|
|
dave.project("dave", "");
|
|
|
|
let alice = alice.spawn(service::Config::default());
|
|
let mut bob = bob.spawn(service::Config::default());
|
|
let mut eve = eve.spawn(service::Config::default());
|
|
let mut carol = carol.spawn(service::Config::default());
|
|
let mut dave = dave.spawn(service::Config::default());
|
|
|
|
bob.connect(&alice);
|
|
eve.connect(&alice);
|
|
carol.connect(&alice);
|
|
dave.connect(&alice);
|
|
|
|
let routes = converge([&alice, &bob, &eve, &carol, &dave]);
|
|
assert_eq!(routes.len(), 5);
|
|
}
|
|
|
|
#[test]
|
|
fn test_replication() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
let acme = bob.project("acme", "");
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let bob = bob.spawn(service::Config::default());
|
|
|
|
alice.connect(&bob);
|
|
converge([&alice, &bob]);
|
|
|
|
let inventory = alice.handle.inventory().unwrap();
|
|
assert!(inventory.try_iter().next().is_none());
|
|
|
|
let tracked = alice.handle.track_repo(acme, Scope::All).unwrap();
|
|
assert!(tracked);
|
|
|
|
let seeds = alice.handle.seeds(acme).unwrap();
|
|
assert!(seeds.is_connected(&bob.id));
|
|
|
|
let result = alice.handle.fetch(acme, bob.id).unwrap();
|
|
assert!(result.is_success());
|
|
|
|
let updated = match result {
|
|
FetchResult::Success { updated } => updated,
|
|
FetchResult::Failed { reason } => {
|
|
panic!("Fetch failed from {}: {reason}", bob.id);
|
|
}
|
|
};
|
|
assert_eq!(*updated, vec![]);
|
|
|
|
log::debug!(target: "test", "Fetch complete with {}", bob.id);
|
|
|
|
let inventory = alice.handle.inventory().unwrap();
|
|
let alice_repo = alice.storage.repository(acme).unwrap();
|
|
let bob_repo = bob.storage.repository(acme).unwrap();
|
|
|
|
let alice_refs = alice_repo
|
|
.references()
|
|
.unwrap()
|
|
.collect::<Result<Vec<_>, _>>()
|
|
.unwrap();
|
|
let bob_refs = bob_repo
|
|
.references()
|
|
.unwrap()
|
|
.collect::<Result<Vec<_>, _>>()
|
|
.unwrap();
|
|
|
|
assert_eq!(inventory.try_iter().next(), Some(acme));
|
|
assert_eq!(alice_refs, bob_refs);
|
|
assert_matches!(alice.storage.repository(acme).unwrap().verify(), Ok(()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_clone() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
let acme = bob.project("acme", "");
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let bob = bob.spawn(service::Config::default());
|
|
|
|
alice.connect(&bob);
|
|
converge([&alice, &bob]);
|
|
|
|
transport::local::register(alice.storage.clone());
|
|
|
|
let _ = alice.handle.track_repo(acme, Scope::All).unwrap();
|
|
let seeds = alice.handle.seeds(acme).unwrap();
|
|
assert!(seeds.is_connected(&bob.id));
|
|
|
|
let result = alice.handle.fetch(acme, bob.id).unwrap();
|
|
assert!(result.is_success());
|
|
|
|
rad::fork(acme, &alice.signer, &alice.storage).unwrap();
|
|
|
|
let working = rad::checkout(
|
|
acme,
|
|
alice.signer.public_key(),
|
|
tmp.path().join("clone"),
|
|
&alice.storage,
|
|
)
|
|
.unwrap();
|
|
|
|
// Makes test finish faster.
|
|
drop(alice);
|
|
|
|
let head = working.head().unwrap();
|
|
let oid = head.target().unwrap();
|
|
|
|
let (_, canonical) = bob
|
|
.storage
|
|
.repository(acme)
|
|
.unwrap()
|
|
.canonical_head()
|
|
.unwrap();
|
|
|
|
assert_eq!(oid, *canonical);
|
|
}
|
|
|
|
#[test]
|
|
fn test_fetch_up_to_date() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let alice = Node::init(tmp.path());
|
|
let mut bob = Node::init(tmp.path());
|
|
let acme = bob.project("acme", "");
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let bob = bob.spawn(service::Config::default());
|
|
|
|
alice.connect(&bob);
|
|
converge([&alice, &bob]);
|
|
|
|
transport::local::register(alice.storage.clone());
|
|
|
|
let _ = alice.handle.track_repo(acme, Scope::All).unwrap();
|
|
let result = alice.handle.fetch(acme, bob.id).unwrap();
|
|
assert!(result.is_success());
|
|
|
|
// Fetch again! This time, everything's up to date.
|
|
let result = alice.handle.fetch(acme, bob.id).unwrap();
|
|
assert_eq!(result.success(), Some(vec![]));
|
|
}
|
|
|
|
#[test]
|
|
#[ignore = "failing"]
|
|
#[should_panic]
|
|
// TODO: This test currently passes but the behavior is wrong. The test should not panic.
|
|
// We should figure out why we end up with no sessions established.
|
|
fn test_connection_crossing() {
|
|
logger::init(log::Level::Debug);
|
|
|
|
let tmp = tempfile::tempdir().unwrap();
|
|
let alice = Node::init(tmp.path());
|
|
let bob = Node::init(tmp.path());
|
|
|
|
let mut alice = alice.spawn(service::Config::default());
|
|
let mut bob = bob.spawn(service::Config::default());
|
|
|
|
alice.handle.connect(bob.id, bob.addr.into()).unwrap();
|
|
bob.handle.connect(alice.id, alice.addr.into()).unwrap();
|
|
|
|
thread::sleep(time::Duration::from_secs(1));
|
|
|
|
let s1 = alice.handle.sessions().unwrap().contains_key(&bob.id);
|
|
let s2 = bob.handle.sessions().unwrap().contains_key(&alice.id);
|
|
|
|
assert!(s1 ^ s2, "Exactly one session should be established");
|
|
}
|