From 39cd7fb5d5da3576e19eb4e13fa8a52cc45687ab Mon Sep 17 00:00:00 2001 From: Fintan Halpenny Date: Fri, 18 Jun 2021 12:04:51 +0100 Subject: [PATCH] replication: adopt rad/self Before this patch a `rad/self` would be replicated, however, there would be no corresponding `rad/id` at the top-level. This patch introduces the adding of the `rad/id` and creating a symbolic ref between `rad/id` and `rad/self` for each tracked peer. Signed-off-by: Fintan Halpenny --- librad/src/git/replication.rs | 56 ++++++++++++++----- .../test/integration/daemon/replication.rs | 49 ++++++++++++++++ 2 files changed, 91 insertions(+), 14 deletions(-) diff --git a/librad/src/git/replication.rs b/librad/src/git/replication.rs index 3f41e77c4..ceabb083b 100644 --- a/librad/src/git/replication.rs +++ b/librad/src/git/replication.rs @@ -20,7 +20,7 @@ use super::{ refs::{self, Refs}, storage::{self, ReadOnlyStorage, Storage}, tracking, - types::{reference, Force, Namespace, Reference}, + types::{reference, Force, Namespace, One, Reference}, }; use crate::{ identities::git::{Person, Project, Revision, SomeIdentity, VerifiedPerson, VerifiedProject}, @@ -426,6 +426,40 @@ fn ensure_rad_id(storage: &Storage, urn: &Urn, tip: ext::Oid) -> Result Result<(), Error> { + let rad_self = Reference::rad_self(Namespace::from(urn), peer); + + // We only need to crate the rad/id there's a rad/self + if storage.has_ref(&rad_self)? { + if let Some(person) = + identities::person::verify(storage, &unsafe_into_urn(rad_self.clone()))? + { + let rad_id = unsafe_into_urn(Reference::rad_id(Namespace::from(person.urn()))); + if !storage.has_urn(&person.urn())? { + ensure_rad_id(storage, &rad_id, person.content_id)?; + symref(storage, &rad_id, rad_self)?; + tracking::track(storage, &rad_id, peer)?; + } + } + } + + Ok(()) +} + +fn symref(storage: &Storage, top_level: &Urn, symbolic: Reference) -> Result<(), Error> { + // Now point our view to the top-level + Reference::try_from(top_level) + .map_err(|e| Error::RefFromUrn { + urn: top_level.clone(), + source: e, + })? + .symbolic_ref::<_, PeerId>(symbolic, Force::False) + .create(storage.as_raw()) + .and(Ok(())) + .or_matches(is_exists_err, || Ok(())) + .map_err(|e: git2::Error| Error::Store(e.into())) +} + /// Untrack the list of `PeerId`s, which also has the side-effect of removing /// that peer's remote references in the storage. /// @@ -531,6 +565,7 @@ mod person { for peer_id in delegations.iter() { if peer_id != local_peer { tracking::track(storage, &urn, *peer_id)?; + adopt_rad_self(storage, &urn, *peer_id)?; } } @@ -648,6 +683,7 @@ mod project { for peer in tracked { if peer != *local_peer { tracking::track(&storage, &urn, peer)?; + adopt_rad_self(storage, &urn, peer)?; } } @@ -776,19 +812,11 @@ mod project { tracking::track(storage, &project_urn, peer)?; // Now point our view to the top-level - Reference::try_from(&delegate_urn) - .map_err(|e| Error::RefFromUrn { - urn: delegate_urn.clone(), - source: e, - })? - .symbolic_ref::<_, PeerId>( - Reference::rad_delegate(Namespace::from(project_urn), &delegate_urn), - Force::False, - ) - .create(storage.as_raw()) - .and(Ok(())) - .or_matches(is_exists_err, || Ok(())) - .map_err(|e: git2::Error| Error::Store(e.into())) + symref( + storage, + &delegate_urn, + Reference::rad_delegate(Namespace::from(project_urn), &delegate_urn), + ) } /// Track all direct delegations of a `Project`. diff --git a/test/src/test/integration/daemon/replication.rs b/test/src/test/integration/daemon/replication.rs index ba81d4884..521594690 100644 --- a/test/src/test/integration/daemon/replication.rs +++ b/test/src/test/integration/daemon/replication.rs @@ -466,3 +466,52 @@ fn track_peer() -> Result<(), anyhow::Error> { Ok(()) }) } + +#[test] +fn replication_includes_user() -> Result<(), anyhow::Error> { + logging::init(); + + let mut harness = Harness::new(); + let alice = harness.add_peer("alice", RunConfig::default(), &[])?; + let bob = harness.add_peer( + "bob", + RunConfig::default(), + &[Seed { + addrs: alice.listen_addrs.clone(), + peer_id: alice.peer_id, + }], + )?; + harness.enter(async move { + let project = state::init_project( + &alice.peer, + &alice.owner, + shia_le_pathbuf(alice.path.join("radicle")), + ) + .await?; + + state::clone_project( + &bob.peer, + project.urn(), + alice.peer_id, + alice.listen_addrs.clone(), + None, + ) + .await?; + + state::track(&alice.peer, project.urn(), bob.peer_id).await?; + state::fetch( + &alice.peer, + project.urn(), + bob.peer_id, + bob.listen_addrs.clone(), + None, + ) + .await?; + + let bob_malkovich = state::get_user(&alice.peer, bob.owner.urn()).await?; + + assert_eq!(bob_malkovich, Some(bob.owner.into_inner().into_inner())); + + Ok(()) + }) +}