cargo/tests/testsuite/lockfile_compat.rs
Alex Crichton 013c1afb9a Add support for new lockfile formats on new projects
This commit adds support to Cargo and refactors the lockfile versioning
slightly. The goal here is that Cargo continually has two thresholds of
lockfile formats to create:

* One is used for new lock files at all times
* The other is used to update old lock files

The logic for these two thresholds is appropriately updated throughout
Cargo, and then this commit also preserves the previous update where new
lock files will get the new format, but old lockfiles will continue to
retain the old format by default.
2019-11-12 07:19:27 -08:00

636 lines
13 KiB
Rust

use cargo_test_support::git;
use cargo_test_support::registry::Package;
use cargo_test_support::{basic_manifest, lines_match, project};
#[cargo_test]
fn oldest_lockfile_still_works() {
let cargo_commands = vec!["build", "update"];
for cargo_command in cargo_commands {
oldest_lockfile_still_works_with_command(cargo_command);
}
}
fn assert_lockfiles_eq(expected: &str, actual: &str) {
for (l, r) in expected.lines().zip(actual.lines()) {
assert!(lines_match(l, r), "Lines differ:\n{}\n\n{}", l, r);
}
assert_eq!(expected.lines().count(), actual.lines().count());
}
fn oldest_lockfile_still_works_with_command(cargo_command: &str) {
Package::new("bar", "0.1.0").publish();
let expected_lockfile = r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar [..]",
]
[metadata]
"[..]" = "[..]"
"#;
let old_lockfile = r#"
[root]
name = "foo"
version = "0.0.1"
dependencies = [
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
"#;
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file("Cargo.lock", old_lockfile)
.build();
p.cargo(cargo_command).run();
let lock = p.read_lockfile();
assert_lockfiles_eq(expected_lockfile, &lock);
}
#[cargo_test]
fn frozen_flag_preserves_old_lockfile() {
let cksum = Package::new("bar", "0.1.0").publish();
let old_lockfile = format!(
r#"[root]
name = "foo"
version = "0.0.1"
dependencies = [
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "{}"
"#,
cksum,
);
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file("Cargo.lock", &old_lockfile)
.build();
p.cargo("build --locked").run();
let lock = p.read_lockfile();
assert_lockfiles_eq(&old_lockfile, &lock);
}
#[cargo_test]
fn totally_wild_checksums_works() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file(
"Cargo.lock",
r#"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum baz 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
"checksum bar 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
"#,
);
let p = p.build();
p.cargo("build").run();
let lock = p.read_lockfile();
assert_lockfiles_eq(
r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar [..]",
]
[metadata]
"[..]" = "[..]"
"#,
&lock,
);
}
#[cargo_test]
fn wrong_checksum_is_an_error() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file(
"Cargo.lock",
r#"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "checksum"
"#,
);
let p = p.build();
p.cargo("build")
.with_status(101)
.with_stderr(
"\
[UPDATING] `[..]` index
error: checksum for `bar v0.1.0` changed between lock files
this could be indicative of a few possible errors:
* the lock file is corrupt
* a replacement source in use (e.g., a mirror) returned a different checksum
* the source itself may be corrupt in one way or another
unable to verify that `bar v0.1.0` is the same as when the lockfile was generated
",
)
.run();
}
// If the checksum is unlisted in the lock file (e.g., <none>) yet we can
// calculate it (e.g., it's a registry dep), then we should in theory just fill
// it in.
#[cargo_test]
fn unlisted_checksum_is_bad_if_we_calculate() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file(
"Cargo.lock",
r#"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bar 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "<none>"
"#,
);
let p = p.build();
p.cargo("fetch")
.with_status(101)
.with_stderr(
"\
[UPDATING] `[..]` index
error: checksum for `bar v0.1.0` was not previously calculated, but a checksum \
could now be calculated
this could be indicative of a few possible situations:
* the source `[..]` did not previously support checksums,
but was replaced with one that does
* newer Cargo implementations know how to checksum this source, but this
older implementation does not
* the lock file is corrupt
",
)
.run();
}
// If the checksum is listed in the lock file yet we cannot calculate it (e.g.,
// Git dependencies as of today), then make sure we choke.
#[cargo_test]
fn listed_checksum_bad_if_we_cannot_compute() {
let git = git::new("bar", |p| {
p.file("Cargo.toml", &basic_manifest("bar", "0.1.0"))
.file("src/lib.rs", "")
});
let p = project()
.file(
"Cargo.toml",
&format!(
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = {{ git = '{}' }}
"#,
git.url()
),
)
.file("src/lib.rs", "")
.file(
"Cargo.lock",
&format!(
r#"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar 0.1.0 (git+{0})"
]
[[package]]
name = "bar"
version = "0.1.0"
source = "git+{0}"
[metadata]
"checksum bar 0.1.0 (git+{0})" = "checksum"
"#,
git.url()
),
);
let p = p.build();
p.cargo("fetch")
.with_status(101)
.with_stderr(
"\
[UPDATING] git repository `[..]`
error: checksum for `bar v0.1.0 ([..])` could not be calculated, but a \
checksum is listed in the existing lock file[..]
this could be indicative of a few possible situations:
* the source `[..]` supports checksums,
but was replaced with one that doesn't
* the lock file is corrupt
unable to verify that `bar v0.1.0 ([..])` is the same as when the lockfile was generated
",
)
.run();
}
#[cargo_test]
fn current_lockfile_format() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "");
let p = p.build();
p.cargo("build").run();
let actual = p.read_lockfile();
let expected = "\
# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.
[[package]]
name = \"bar\"
version = \"0.1.0\"
source = \"registry+https://github.com/rust-lang/crates.io-index\"
checksum = \"[..]\"
[[package]]
name = \"foo\"
version = \"0.0.1\"
dependencies = [
\"bar\",
]
";
assert_lockfiles_eq(expected, &actual);
}
#[cargo_test]
fn lockfile_without_root() {
Package::new("bar", "0.1.0").publish();
let lockfile = r#"
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar",
]
"#;
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file("Cargo.lock", lockfile);
let p = p.build();
p.cargo("build").run();
let lock = p.read_lockfile();
assert_lockfiles_eq(
r#"# [..]
# [..]
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "[..]"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar",
]
"#,
&lock,
);
}
#[cargo_test]
fn locked_correct_error() {
Package::new("bar", "0.1.0").publish();
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "");
let p = p.build();
p.cargo("build --locked")
.with_status(101)
.with_stderr(
"\
[UPDATING] `[..]` index
error: the lock file [CWD]/Cargo.lock needs to be updated but --locked was passed to prevent this
",
)
.run();
}
#[cargo_test]
fn v2_format_preserved() {
let cksum = Package::new("bar", "0.1.0").publish();
let lockfile = format!(
r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "bar"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "{}"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"bar",
]
"#,
cksum
);
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = "0.1.0"
"#,
)
.file("src/lib.rs", "")
.file("Cargo.lock", &lockfile)
.build();
p.cargo("fetch").run();
let lock = p.read_lockfile();
assert_lockfiles_eq(&lockfile, &lock);
}
#[cargo_test]
fn v2_path_and_crates_io() {
let cksum010 = Package::new("a", "0.1.0").publish();
let cksum020 = Package::new("a", "0.2.0").publish();
let lockfile = format!(
r#"# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "a"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "{}"
[[package]]
name = "a"
version = "0.2.0"
[[package]]
name = "a"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "{}"
[[package]]
name = "foo"
version = "0.0.1"
dependencies = [
"a 0.1.0",
"a 0.2.0",
"a 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
"#,
cksum010, cksum020,
);
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
a = { path = 'a' }
b = { version = "0.1", package = 'a' }
c = { version = "0.2", package = 'a' }
"#,
)
.file("src/lib.rs", "")
.file(
"a/Cargo.toml",
r#"
[project]
name = "a"
version = "0.2.0"
"#,
)
.file("a/src/lib.rs", "")
.file("Cargo.lock", &lockfile)
.build();
p.cargo("fetch").run();
p.cargo("fetch").run();
let lock = p.read_lockfile();
assert_lockfiles_eq(&lockfile, &lock);
}