Skip to content

Commit

Permalink
Add last remaining test to validate entire packs can be fetched in as…
Browse files Browse the repository at this point in the history
…ync mode without issues.
  • Loading branch information
Byron committed Nov 14, 2022
1 parent 01e99b4 commit 5cc3087
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 6 deletions.
162 changes: 159 additions & 3 deletions git-repository/tests/remote/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ mod blocking_and_async_io {

use super::{repo_path, repo_rw};
use crate::remote::{into_daemon_remote_if_async, spawn_git_daemon_if_async};
use git_features::progress;
use git_protocol::maybe_async;
use git_repository::remote::fetch;
use git_testtools::hex_to_id;

#[maybe_async::test(
Expand All @@ -36,8 +38,11 @@ mod blocking_and_async_io {
async fn fetch_empty_pack() -> crate::Result {
let (repo, _tmp) = repo_rw("two-origins");
let daemon = spawn_git_daemon_if_async(repo_path("base"))?;
let mut remote =
into_daemon_remote_if_async(repo.head()?.into_remote(Fetch).expect("present")?, daemon.as_ref());
let mut remote = into_daemon_remote_if_async(
repo.head()?.into_remote(Fetch).expect("present")?,
daemon.as_ref(),
None,
);
remote.replace_refspecs(Some("HEAD:refs/remotes/origin/does-not-yet-exist"), Fetch)?;

let res = remote
Expand Down Expand Up @@ -69,7 +74,8 @@ mod blocking_and_async_io {
async fn fetch_pack_without_local_destination() -> crate::Result {
let (repo, _tmp) = repo_rw("two-origins");
let daemon = spawn_git_daemon_if_async(repo_path("clone-as-base-with-changes"))?;
let mut remote = into_daemon_remote_if_async(repo.find_remote("changes-on-top-of-origin")?, daemon.as_ref());
let mut remote =
into_daemon_remote_if_async(repo.find_remote("changes-on-top-of-origin")?, daemon.as_ref(), None);
remote.replace_refspecs(Some("HEAD"), Fetch)?;

let res: git::remote::fetch::Outcome = remote
Expand All @@ -93,6 +99,156 @@ mod blocking_and_async_io {
}
Ok(())
}

#[maybe_async::test(
feature = "blocking-network-client",
async(feature = "async-network-client-async-std", async_std::test)
)]
async fn fetch_pack() -> crate::Result {
let daemon = spawn_git_daemon_if_async({
let mut p = repo_path("base");
p.pop();
p
})?;
for (version, expected_objects, expected_hash) in [
(None, 4, "d07c527cf14e524a8494ce6d5d08e28079f5c6ea"),
(
Some(git::protocol::transport::Protocol::V2),
4,
"d07c527cf14e524a8494ce6d5d08e28079f5c6ea",
),
(
Some(git::protocol::transport::Protocol::V1),
4,
"d07c527cf14e524a8494ce6d5d08e28079f5c6ea", // TODO: if these are the same, remove them
),
] {
let (mut repo, _tmp) = repo_rw("two-origins");
if let Some(version) = version {
repo.config_snapshot_mut().set_raw_value(
"protocol",
None,
"version",
(version as u8).to_string().as_str(),
)?;
}

// No updates
{
let remote = into_daemon_remote_if_async(repo.find_remote("origin")?, daemon.as_ref(), "base");
{
remote
.connect(Fetch, progress::Discard)
.await?
.prepare_fetch(Default::default())
.await?;
// early drops are fine and won't block.
}
let outcome = remote
.connect(Fetch, progress::Discard)
.await?
.prepare_fetch(Default::default())
.await?
.receive(&AtomicBool::default())
.await?;
assert!(matches!(outcome.status, git::remote::fetch::Status::NoChange));
}

// Some updates to be fetched
for dry_run in [true, false] {
let remote = into_daemon_remote_if_async(
repo.find_remote("changes-on-top-of-origin")?,
daemon.as_ref(),
"clone-as-base-with-changes",
);
let outcome: git::remote::fetch::Outcome = remote
.connect(Fetch, progress::Discard)
.await?
.prepare_fetch(Default::default())
.await?
.with_dry_run(dry_run)
.receive(&AtomicBool::default())
.await?;
let refs = match outcome.status {
fetch::Status::Change {
write_pack_bundle,
update_refs,
} => {
assert_eq!(write_pack_bundle.pack_version, git::odb::pack::data::Version::V2);
assert_eq!(write_pack_bundle.object_hash, repo.object_hash());
assert_eq!(write_pack_bundle.index.num_objects, expected_objects, "{dry_run}: this value is 4 when git does it with 'consecutive' negotiation style, but could be 33 if completely naive.");
assert_eq!(
write_pack_bundle.index.index_version,
git::odb::pack::index::Version::V2
);
assert_eq!(write_pack_bundle.index.index_hash, hex_to_id(expected_hash));
assert!(write_pack_bundle.data_path.map_or(false, |f| f.is_file()));
assert!(write_pack_bundle.index_path.map_or(false, |f| f.is_file()));
assert_eq!(update_refs.edits.len(), 2);

let edit = &update_refs.edits[0];
assert_eq!(edit.name.as_bstr(), "refs/remotes/changes-on-top-of-origin/main");
assert!(
edit.change.new_value().expect("no deletion").try_id().is_some(),
"a simple peeled ref"
);
let edit = &update_refs.edits[1];
assert_eq!(edit.name.as_bstr(), "refs/remotes/changes-on-top-of-origin/symbolic");
assert!(
edit.change.new_value().expect("no deletion").try_id().is_some(),
"on the remote this is a symbolic ref, we just write its destination object id though"
);

assert!(
!write_pack_bundle.keep_path.map_or(false, |f| f.is_file()),
".keep files are deleted if there is one edit"
);

update_refs
}
fetch::Status::DryRun { update_refs } => update_refs,
fetch::Status::NoChange => unreachable!("we firmly expect changes here"),
};

assert_eq!(
refs.updates,
vec![
fetch::refs::Update {
mode: fetch::refs::update::Mode::New,
edit_index: Some(0),
},
fetch::refs::Update {
mode: fetch::refs::update::Mode::New,
edit_index: Some(1),
}
]
);
for (_update, mapping, _spec, edit) in
refs.iter_mapping_updates(&outcome.ref_map.mappings, remote.refspecs(Fetch))
{
let edit = edit.expect("refedit present even if it's a no-op");
if dry_run {
assert_eq!(
edit.change.new_value().expect("no deletions").id(),
mapping.remote.as_id().expect("no unborn")
);
assert!(
repo.try_find_reference(edit.name.as_ref())?.is_none(),
"no ref created in dry-run mode"
);
} else {
let r = repo.find_reference(edit.name.as_ref()).unwrap();
assert_eq!(
r.id(),
*mapping.remote.as_id().expect("no unborn"),
"local reference should point to remote id"
);
}
}
}
}
Ok(())
}
}

#[cfg(feature = "blocking-network-client")]
Expand Down
9 changes: 7 additions & 2 deletions git-repository/tests/remote/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ pub(crate) fn spawn_git_daemon_if_async(

/// Turn `remote` into a remote that interacts with the git `daemon`, all else being the same, by creating a new stand-in remote.
#[cfg(any(feature = "blocking-network-client", feature = "async-network-client-async-std"))]
pub(crate) fn into_daemon_remote_if_async<'repo>(
pub(crate) fn into_daemon_remote_if_async<'repo, 'a>(
remote: git::Remote<'repo>,
_daemon: Option<&git_testtools::GitDaemon>,
_repo_name: impl Into<Option<&'a str>>,
) -> git::Remote<'repo> {
#[cfg(feature = "blocking-network-client")]
{
Expand All @@ -56,7 +57,11 @@ pub(crate) fn into_daemon_remote_if_async<'repo>(
{
let mut new_remote = remote
.repo()
.remote_at(format!("{}/", _daemon.expect("daemon is available in async mode").url))
.remote_at(format!(
"{}/{}",
_daemon.expect("daemon is available in async mode").url,
_repo_name.into().unwrap_or_default()
))
.expect("valid url to create remote at");
for direction in [git::remote::Direction::Fetch, git::remote::Direction::Push] {
new_remote
Expand Down
2 changes: 1 addition & 1 deletion git-repository/tests/remote/ref_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ mod blocking_and_async_io {
)?;
}

let remote = into_daemon_remote_if_async(repo.find_remote("origin")?, daemon.as_ref());
let remote = into_daemon_remote_if_async(repo.find_remote("origin")?, daemon.as_ref(), None);
let map = remote
.connect(Fetch, progress::Discard)
.await?
Expand Down

0 comments on commit 5cc3087

Please sign in to comment.