diff --git a/tests/testsuite/freshness_checksum.rs b/tests/testsuite/freshness_checksum.rs index 59d265bd4..20e087cf7 100644 --- a/tests/testsuite/freshness_checksum.rs +++ b/tests/testsuite/freshness_checksum.rs @@ -1,22 +1,17 @@ //! Tests for checksum-based fingerprinting (rebuild detection). use std::fs::{self, OpenOptions}; -use std::io; use std::io::prelude::*; use std::net::TcpListener; -use std::path::{Path, PathBuf}; use std::process::Stdio; use std::thread; -use std::time::SystemTime; -use cargo_test_support::paths; use cargo_test_support::prelude::*; use cargo_test_support::registry::Package; use cargo_test_support::{ basic_lib_manifest, basic_manifest, is_coarse_mtime, project, rustc_host, rustc_host_env, sleep_ms, str, }; -use filetime::FileTime; use super::death; @@ -68,46 +63,6 @@ error[E0583]: file not found for module `a` .run(); } -#[cargo_test] -fn modify_only_some_files() { - let p = project() - .file("src/lib.rs", "mod a;") - .file("src/a.rs", "") - .file("src/main.rs", "mod b; fn main() {}") - .file("src/b.rs", "") - .file("tests/test.rs", "") - .build(); - - p.cargo("build") - .with_stderr_data(str![[r#" -[COMPILING] foo v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - p.cargo("test").run(); - sleep_ms(1000); - - assert!(p.bin("foo").is_file()); - - let lib = p.root().join("src/lib.rs"); - p.change_file("src/lib.rs", "invalid rust code"); - p.change_file("src/b.rs", "#[allow(unused)]fn foo() {}"); - lib.move_into_the_past(); - - // Make sure the binary is rebuilt, not the lib - p.cargo("build -v") - .with_stderr_data(str![[r#" -[DIRTY] foo v0.0.1 ([ROOT]/foo): the file `src/b.rs` has changed ([TIME_DIFF_AFTER_LAST_BUILD]) -[COMPILING] foo v0.0.1 ([ROOT]/foo) -[RUNNING] `rustc --crate-name foo [..] -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - assert!(p.bin("foo").is_file()); -} - #[cargo_test] fn rebuild_sub_package_then_while_package() { let p = project() @@ -871,43 +826,6 @@ fn no_rebuild_if_build_artifacts_move_backwards_in_time() { .run(); } -#[cargo_test] -fn rebuild_if_build_artifacts_move_forward_in_time() { - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2015" - authors = [] - - [dependencies] - a = { path = "a" } - "#, - ) - .file("src/lib.rs", "") - .file("a/Cargo.toml", &basic_manifest("a", "0.0.1")) - .file("a/src/lib.rs", "") - .build(); - - p.cargo("build").run(); - - p.root().move_into_the_future(); - - p.cargo("build") - .env("CARGO_LOG", "") - .with_stdout_data(str![]) - .with_stderr_data(str![[r#" -[COMPILING] a v0.0.1 ([ROOT]/foo/a) -[COMPILING] foo v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); -} - #[cargo_test] fn rebuild_if_environment_changes() { let p = project() @@ -1376,158 +1294,6 @@ fn changing_rustflags_is_cached() { .run(); } -#[cargo_test] -fn update_dependency_mtime_does_not_rebuild() { - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2015" - - [dependencies] - bar = { path = "bar" } - "#, - ) - .file("src/lib.rs", "") - .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) - .file("bar/src/lib.rs", "") - .build(); - - p.cargo("build -Z mtime-on-use") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .env("RUSTFLAGS", "-C linker=cc") - .with_stderr_data(str![[r#" -[LOCKING] 1 package to latest compatible version -[COMPILING] bar v0.0.1 ([ROOT]/foo/bar) -[COMPILING] foo v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - // This does not make new files, but it does update the mtime of the dependency. - p.cargo("build -p bar -Z mtime-on-use") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .env("RUSTFLAGS", "-C linker=cc") - .with_stderr_data(str![[r#" -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - // This should not recompile! - p.cargo("build -Z mtime-on-use") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .env("RUSTFLAGS", "-C linker=cc") - .with_stderr_data(str![[r#" -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); -} - -fn fingerprint_cleaner(mut dir: PathBuf, timestamp: filetime::FileTime) { - // Cargo is experimenting with letting outside projects develop some - // limited forms of GC for target_dir. This is one of the forms. - // Specifically, Cargo is updating the mtime of a file in - // target/profile/.fingerprint each time it uses the fingerprint. - // So a cleaner can remove files associated with a fingerprint - // if all the files in the fingerprint's folder are older then a time stamp without - // effecting any builds that happened since that time stamp. - let mut cleaned = false; - dir.push(".fingerprint"); - for fing in fs::read_dir(&dir).unwrap() { - let fing = fing.unwrap(); - - let outdated = |f: io::Result| { - filetime::FileTime::from_last_modification_time(&f.unwrap().metadata().unwrap()) - <= timestamp - }; - if fs::read_dir(fing.path()).unwrap().all(outdated) { - fs::remove_dir_all(fing.path()).unwrap(); - println!("remove: {:?}", fing.path()); - // a real cleaner would remove the big files in deps and build as well - // but fingerprint is sufficient for our tests - cleaned = true; - } else { - } - } - assert!( - cleaned, - "called fingerprint_cleaner, but there was nothing to remove" - ); -} - -#[cargo_test] -fn fingerprint_cleaner_does_not_rebuild() { - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.0.1" - edition = "2015" - - [dependencies] - bar = { path = "bar" } - - [features] - a = [] - "#, - ) - .file("src/lib.rs", "") - .file("bar/Cargo.toml", &basic_manifest("bar", "0.0.1")) - .file("bar/src/lib.rs", "") - .build(); - - p.cargo("build -Z mtime-on-use") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .run(); - p.cargo("build -Z mtime-on-use --features a") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .with_stderr_data(str![[r#" -[COMPILING] foo v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - if is_coarse_mtime() { - sleep_ms(1000); - } - let timestamp = filetime::FileTime::from_system_time(SystemTime::now()); - if is_coarse_mtime() { - sleep_ms(1000); - } - // This does not make new files, but it does update the mtime. - p.cargo("build -Z mtime-on-use --features a") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .with_stderr_data(str![[r#" -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - fingerprint_cleaner(p.target_debug_dir(), timestamp); - // This should not recompile! - p.cargo("build -Z mtime-on-use --features a") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .with_stderr_data(str![[r#" -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - // But this should be cleaned and so need a rebuild - p.cargo("build -Z mtime-on-use") - .masquerade_as_nightly_cargo(&["mtime-on-use"]) - .with_stderr_data(str![[r#" -[COMPILING] foo v0.0.1 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); -} - #[cargo_test] fn reuse_panic_build_dep_test() { let p = project() @@ -1937,158 +1703,6 @@ fn script_fails_stay_dirty() { .run(); } -#[cargo_test] -fn simulated_docker_deps_stay_cached() { - // Test what happens in docker where the nanoseconds are zeroed out. - Package::new("regdep", "1.0.0").publish(); - Package::new("regdep_old_style", "1.0.0") - .file("build.rs", "fn main() {}") - .file("src/lib.rs", "") - .publish(); - Package::new("regdep_env", "1.0.0") - .file( - "build.rs", - r#" - fn main() { - println!("cargo::rerun-if-env-changed=SOMEVAR"); - } - "#, - ) - .file("src/lib.rs", "") - .publish(); - Package::new("regdep_rerun", "1.0.0") - .file( - "build.rs", - r#" - fn main() { - println!("cargo::rerun-if-changed=build.rs"); - } - "#, - ) - .file("src/lib.rs", "") - .publish(); - - let p = project() - .file( - "Cargo.toml", - r#" - [package] - name = "foo" - version = "0.1.0" - edition = "2015" - - [dependencies] - pathdep = { path = "pathdep" } - regdep = "1.0" - regdep_old_style = "1.0" - regdep_env = "1.0" - regdep_rerun = "1.0" - "#, - ) - .file( - "src/lib.rs", - " - extern crate pathdep; - extern crate regdep; - extern crate regdep_old_style; - extern crate regdep_env; - extern crate regdep_rerun; - ", - ) - .file("build.rs", "fn main() {}") - .file("pathdep/Cargo.toml", &basic_manifest("pathdep", "1.0.0")) - .file("pathdep/src/lib.rs", "") - .build(); - - p.cargo("build").run(); - - let already_zero = { - // This happens on HFS with 1-second timestamp resolution, - // or other filesystems where it just so happens to write exactly on a - // 1-second boundary. - let metadata = fs::metadata(p.root().join("src/lib.rs")).unwrap(); - let mtime = FileTime::from_last_modification_time(&metadata); - mtime.nanoseconds() == 0 - }; - - // Recursively remove `nanoseconds` from every path. - fn zeropath(path: &Path) { - for entry in walkdir::WalkDir::new(path) - .into_iter() - .filter_map(|e| e.ok()) - { - let metadata = fs::metadata(entry.path()).unwrap(); - let mtime = metadata.modified().unwrap(); - let mtime_duration = mtime.duration_since(SystemTime::UNIX_EPOCH).unwrap(); - let trunc_mtime = FileTime::from_unix_time(mtime_duration.as_secs() as i64, 0); - let atime = metadata.accessed().unwrap(); - let atime_duration = atime.duration_since(SystemTime::UNIX_EPOCH).unwrap(); - let trunc_atime = FileTime::from_unix_time(atime_duration.as_secs() as i64, 0); - if let Err(e) = filetime::set_file_times(entry.path(), trunc_atime, trunc_mtime) { - // Windows doesn't allow changing filetimes on some things - // (directories, other random things I'm not sure why). Just - // ignore them. - if e.kind() == std::io::ErrorKind::PermissionDenied { - println!("PermissionDenied filetime on {:?}", entry.path()); - } else { - panic!("FileTime error on {:?}: {:?}", entry.path(), e); - } - } - } - } - zeropath(&p.root()); - zeropath(&paths::home()); - - if already_zero { - println!("already zero"); - // If it was already truncated, then everything stays fresh. - p.cargo("build -v") - .with_stderr_data( - str![[r#" -[FRESH] pathdep [..] -[FRESH] regdep [..] -[FRESH] regdep_env [..] -[FRESH] regdep_old_style [..] -[FRESH] regdep_rerun [..] -[FRESH] foo [..] -[FINISHED] [..] - -"#]] - .unordered(), - ) - .run(); - } else { - println!("not already zero"); - // It is not ideal that `foo` gets recompiled, but that is the current - // behavior. Currently mtimes are ignored for registry deps. - // - // Note that this behavior is due to the fact that `foo` has a build - // script in "old" mode where it doesn't print `rerun-if-*`. In this - // mode we use `Precalculated` to fingerprint a path dependency, where - // `Precalculated` is an opaque string which has the most recent mtime - // in it. It differs between builds because one has nsec=0 and the other - // likely has a nonzero nsec. Hence, the rebuild. - p.cargo("build -v") - .with_stderr_data( - str![[r#" -[FRESH] regdep [..] -[FRESH] pathdep [..] -[FRESH] regdep_env [..] -[DIRTY] foo v0.1.0 ([ROOT]/foo): the precalculated components changed -[COMPILING] foo v0.1.0 ([ROOT]/foo) -[FRESH] regdep_rerun [..] -[FRESH] regdep_old_style [..] -[RUNNING] `[ROOT]/foo/target/debug/build/foo-[HASH]/build-script-build` -[RUNNING] `rustc --crate-name foo [..]` -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]] - .unordered(), - ) - .run(); - } -} - #[cargo_test] fn metadata_change_invalidates() { let p = project() @@ -2883,64 +2497,6 @@ fn env_build_script_no_rebuild() { .run(); } -#[cargo_test] -fn cargo_env_changes() { - // Checks that changes to the env var CARGO in the dep-info file triggers - // a rebuild. - let p = project() - .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) - .file( - "src/main.rs", - r#" - fn main() { - println!("{:?}", env!("CARGO")); - } - "#, - ) - .build(); - - let cargo_exe = cargo_test_support::cargo_exe(); - let other_cargo_path = p.root().join(cargo_exe.file_name().unwrap()); - std::fs::hard_link(&cargo_exe, &other_cargo_path).unwrap(); - let other_cargo = || { - let mut pb = cargo_test_support::process(&other_cargo_path); - pb.cwd(p.root()); - cargo_test_support::execs().with_process_builder(pb) - }; - - p.cargo("check").run(); - other_cargo() - .arg("check") - .arg("-v") - .with_stderr_data(str![[r#" -[DIRTY] foo v1.0.0 ([ROOT]/foo): the environment variable CARGO changed -[CHECKING] foo v1.0.0 ([ROOT]/foo) -[RUNNING] `rustc [..] -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - - // And just to confirm that without using env! it doesn't rebuild. - p.change_file("src/main.rs", "fn main() {}"); - p.cargo("check") - .with_stderr_data(str![[r#" -[CHECKING] foo v1.0.0 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); - other_cargo() - .arg("check") - .arg("-v") - .with_stderr_data(str![[r#" -[FRESH] foo v1.0.0 ([ROOT]/foo) -[FINISHED] `dev` profile [unoptimized + debuginfo] target(s) in [ELAPSED]s - -"#]]) - .run(); -} - #[cargo_test] fn changing_linker() { // Changing linker should rebuild.