From ba9dd1ea2e6859a3a931a24a0908c4f8e8b3d9f0 Mon Sep 17 00:00:00 2001 From: Joe Neeman Date: Mon, 10 Jun 2024 14:12:05 -0500 Subject: [PATCH] Adds tests for source overlays. --- crates/cargo-test-support/src/lib.rs | 11 + crates/cargo-test-support/src/registry.rs | 7 +- tests/testsuite/main.rs | 1 + tests/testsuite/registry_overlay.rs | 308 ++++++++++++++++++++++ 4 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 tests/testsuite/registry_overlay.rs diff --git a/crates/cargo-test-support/src/lib.rs b/crates/cargo-test-support/src/lib.rs index 751a0a7d9b5..09644298316 100644 --- a/crates/cargo-test-support/src/lib.rs +++ b/crates/cargo-test-support/src/lib.rs @@ -877,6 +877,17 @@ impl Execs { self } + pub fn overlay_registry(&mut self, url: &Url, path: &str) -> &mut Self { + if let Some(ref mut p) = self.process_builder { + let env_value = format!("{}={}", url, path); + p.env( + "__CARGO_TEST_DEPENDENCY_CONFUSION_VULNERABILITY_DO_NOT_USE_THIS", + env_value, + ); + } + self + } + pub fn enable_split_debuginfo_packed(&mut self) -> &mut Self { self.env("CARGO_PROFILE_DEV_SPLIT_DEBUGINFO", "packed") .env("CARGO_PROFILE_TEST_SPLIT_DEBUGINFO", "packed") diff --git a/crates/cargo-test-support/src/registry.rs b/crates/cargo-test-support/src/registry.rs index f8b4b144782..6ddd59e38a8 100644 --- a/crates/cargo-test-support/src/registry.rs +++ b/crates/cargo-test-support/src/registry.rs @@ -1649,7 +1649,12 @@ impl Package { /// Returns the path to the compressed package file. pub fn archive_dst(&self) -> PathBuf { if self.local { - registry_path().join(format!("{}-{}.crate", self.name, self.vers)) + let path = if self.alternative { + alt_registry_path() + } else { + registry_path() + }; + path.join(format!("{}-{}.crate", self.name, self.vers)) } else if self.alternative { alt_dl_path() .join(&self.name) diff --git a/tests/testsuite/main.rs b/tests/testsuite/main.rs index a335ce6bef2..f27f2aae158 100644 --- a/tests/testsuite/main.rs +++ b/tests/testsuite/main.rs @@ -152,6 +152,7 @@ mod publish_lockfile; mod read_manifest; mod registry; mod registry_auth; +mod registry_overlay; mod rename_deps; mod replace; mod required_features; diff --git a/tests/testsuite/registry_overlay.rs b/tests/testsuite/registry_overlay.rs new file mode 100644 index 00000000000..20bb0a1e73f --- /dev/null +++ b/tests/testsuite/registry_overlay.rs @@ -0,0 +1,308 @@ +//! Tests for local-registry sources. + +use cargo_test_support::project; +use cargo_test_support::registry::{Package, RegistryBuilder, TestRegistry}; + +fn setup() -> (TestRegistry, String) { + let alt = RegistryBuilder::new().alternative().build(); + ( + RegistryBuilder::new().http_index().build(), + alt.index_url() + .to_file_path() + .unwrap() + .into_os_string() + .into_string() + .unwrap(), + ) +} + +#[cargo_test] +fn overlay_hit() { + let (reg, alt_path) = setup(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + baz = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + // baz is only in the local registry, but it gets found + Package::new("baz", "0.1.1") + .alternative(true) + .local(true) + .publish(); + + p.cargo("check") + .overlay_registry(®.index_url(), &alt_path) + .run(); +} + +#[cargo_test] +fn registry_version_wins() { + let (reg, alt_path) = setup(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + baz = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + // The latest one is in the main registry, so it will get chosen. + Package::new("baz", "0.1.1").publish(); + Package::new("baz", "0.1.0") + .alternative(true) + .local(true) + .publish(); + + p.cargo("check") + .overlay_registry(®.index_url(), &alt_path) + .with_stderr_data( + "\ +[UPDATING] [..] +[LOCKING] 2 packages to latest compatible versions +[DOWNLOADING] crates ... +[DOWNLOADED] baz v0.1.1 (registry [..]) +[CHECKING] baz v0.1.1 +[CHECKING] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +", + ) + .run(); +} + +#[cargo_test] +fn overlay_version_wins() { + let (reg, alt_path) = setup(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + baz = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + // The latest one is in the overlay registry, so it will get chosen. + Package::new("baz", "0.1.0").publish(); + Package::new("baz", "0.1.1") + .alternative(true) + .local(true) + .publish(); + + p.cargo("check") + .overlay_registry(®.index_url(), &alt_path) + .with_stderr_data( + "\ +[UPDATING] [..] +[LOCKING] 2 packages to latest compatible versions +[UNPACKING] baz v0.1.1 (registry [..]) +[CHECKING] baz v0.1.1 +[CHECKING] foo v0.0.1 ([ROOT]/foo) +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +", + ) + .run(); +} + +#[cargo_test] +fn version_collision() { + let (reg, alt_path) = setup(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + baz = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + // The one we want is in the main registry. + Package::new("baz", "0.1.1").publish(); + Package::new("baz", "0.1.1") + .alternative(true) + .local(true) + .publish(); + + p.cargo("check") + .overlay_registry(®.index_url(), &alt_path) + .with_status(101) + .with_stderr_data( + "\ +[UPDATING] [..] +[ERROR] failed to get `baz` [..] + +Caused by: + failed to query replaced source registry `crates-io` + +Caused by: + found a package in the remote registry and the local overlay: baz@0.1.1 +", + ) + .run(); +} + +#[cargo_test] +fn local_depends_on_old_registry_package() { + let (reg, alt_path) = setup(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + baz = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + Package::new("baz", "0.0.1").publish(); + // A new local package can depend on an older version in the registry. + Package::new("baz", "0.1.1") + .dep("baz", "=0.0.1") + .alternative(true) + .local(true) + .publish(); + + p.cargo("check") + .overlay_registry(®.index_url(), &alt_path) + .run(); +} + +#[cargo_test] +fn registry_dep_depends_on_new_local_package() { + let (reg, alt_path) = setup(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + registry-package = "0.1.0" + workspace-package = "0.0.1" + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + Package::new("registry-package", "0.1.0") + .dep("workspace-package", "0.1.0") + .publish(); + // The local overlay contains an updated version of workspace-package + Package::new("workspace-package", "0.1.1") + .alternative(true) + .local(true) + .publish(); + + // The registry contains older versions of workspace-package (one of which + // we depend on directly). + Package::new("workspace-package", "0.1.0").publish(); + Package::new("workspace-package", "0.0.1").publish(); + + p.cargo("check") + .overlay_registry(®.index_url(), &alt_path) + .with_stderr_data( + "\ +[UPDATING] [..] +[LOCKING] 4 packages to latest compatible versions +[ADDING] workspace-package v0.0.1 (latest: v0.1.1) +[DOWNLOADING] crates ... +[UNPACKING] [..] +[DOWNLOADED] [..] +[DOWNLOADED] [..] +[CHECKING] workspace-package v0.1.1 +[CHECKING] workspace-package v0.0.1 +[CHECKING] registry-package v0.1.0 +[CHECKING] foo v0.0.1 [..] +[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s +", + ) + .run(); +} + +// Test that we can overlay on top of alternate registries, not just crates-io. +// Since the test framework only supports a single alternate registry, we repurpose +// the dummy crates-io as the registry to overlay on top. +#[cargo_test] +fn alt_registry() { + let alt = RegistryBuilder::new().http_index().alternative().build(); + let crates_io = RegistryBuilder::new().build(); + let crates_io_path = crates_io + .index_url() + .to_file_path() + .unwrap() + .into_os_string() + .into_string() + .unwrap(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2015" + authors = [] + + [dependencies] + baz = { version = "0.1.0", registry = "alternative" } + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + // This package isn't used, but publishing it forces the creation of the registry index. + Package::new("bar", "0.0.1").local(true).publish(); + Package::new("baz", "0.1.1").alternative(true).publish(); + + p.cargo("check") + .overlay_registry(&alt.index_url(), &crates_io_path) + .run(); +}