History

feat: use `GIX_TEST_FIXTURE_HASH` environment variable.

For now, there is no direct way to set it, but that may change once we have tests that need it.

Christoph Rüßler committed 9 months ago

Commit 7f50c301 parent 28fbeb84 files · +64 −20Browse files

Unified · Split

4 files
  1. Cargo.lock +1 −0
  2. tests/tools/Cargo.toml +1 −0
  3. tests/tools/src/lib.rs +56 −19
  4. tests/tools/src/tests.rs +6 −1
Cargo.lock+1−0
@@ -2418,6 +2418,7 @@ dependencies = [ · 2417 unmodified lines
2418 "fs_extra",2418 "fs_extra",
2419 "gix-discover",2419 "gix-discover",
2420 "gix-fs",2420 "gix-fs",
2421 "gix-hash",
2421 "gix-lock",2422 "gix-lock",
2422 "gix-tempfile",2423 "gix-tempfile",
2423 "gix-worktree",2424 "gix-worktree",
tests/tools/Cargo.toml+1−0
@@ -25,6 +25,7 @@ default = [] · 24 unmodified lines
25xz = ["dep:xz2"]25xz = ["dep:xz2"]
26 26
27[dependencies]27[dependencies]
28gix-hash = { version = "^0.22.0", path = "../../gix-hash" }
28gix-lock = { version = "^21.0.0", path = "../../gix-lock" }29gix-lock = { version = "^21.0.0", path = "../../gix-lock" }
29gix-discover = { version = "^0.46.0", path = "../../gix-discover" }30gix-discover = { version = "^0.46.0", path = "../../gix-discover" }
30gix-worktree = { version = "^0.47.0", path = "../../gix-worktree" }31gix-worktree = { version = "^0.47.0", path = "../../gix-worktree" }
tests/tools/src/lib.rs+56−19
@@ -287,7 +287,7 @@ enum DirectoryRoot { · 286 unmodified lines
287 StandaloneTest,287 StandaloneTest,
288}288}
289 289
290/// Don't add a suffix to the archive name as `args` are platform dependent, none-deterministic,290/// Don't add a suffix to the archive name as `args` are platform dependent, non-deterministic,
291/// or otherwise don't influence the content of the archive.291/// or otherwise don't influence the content of the archive.
292/// Note that this also means that `args` won't be used to control the hash of the archive itself.292/// Note that this also means that `args` won't be used to control the hash of the archive itself.
293#[derive(Copy, Clone)]293#[derive(Copy, Clone)]
@@ -508,7 +508,7 @@ pub fn copy_recursively_into_existing_dir(src_dir: impl AsRef<Path>, dst_dir: im · 214 unmodified lines
508 Ok(())508 Ok(())
509}509}
510 510
511/// Like `scripted_fixture_read_only()`], but passes `args` to `script_name`.511/// Like [`scripted_fixture_read_only()`], but passes `args` to `script_name`.
512pub fn scripted_fixture_read_only_with_args(512pub fn scripted_fixture_read_only_with_args(
513 script_name: impl AsRef<Path>,513 script_name: impl AsRef<Path>,
514 args: impl IntoIterator<Item = impl Into<String>>,514 args: impl IntoIterator<Item = impl Into<String>>,
@@ -874,7 +874,7 @@ pub fn rust_fixture_read_only<T, F>(name: &str, version: u32, make_fixture: F) - · 359 unmodified lines
874where874where
875 F: FnOnce(FixtureState<'_>) -> PostResult<T>,875 F: FnOnce(FixtureState<'_>) -> PostResult<T>,
876{876{
877 rust_fixture_read_only_inner(name, version, make_fixture, None, DirectoryRoot::IntegrationTest)877 rust_fixture_read_only_inner(name, version, None, make_fixture, None, DirectoryRoot::IntegrationTest)
878}878}
879 879
880/// Like [`rust_fixture_read_only()`], but does not prefix the fixture directory with `tests`.880/// Like [`rust_fixture_read_only()`], but does not prefix the fixture directory with `tests`.
@@ -882,7 +882,7 @@ pub fn rust_fixture_read_only_standalone<T, F>(name: &str, version: u32, make_fi · 1 unmodified line
882where882where
883 F: FnOnce(FixtureState<'_>) -> PostResult<T>,883 F: FnOnce(FixtureState<'_>) -> PostResult<T>,
884{884{
885 rust_fixture_read_only_inner(name, version, make_fixture, None, DirectoryRoot::StandaloneTest)885 rust_fixture_read_only_inner(name, version, None, make_fixture, None, DirectoryRoot::StandaloneTest)
886}886}
887 887
888/// Execute a Rust closure in a directory, returning a writable temporary directory.888/// Execute a Rust closure in a directory, returning a writable temporary directory.
@@ -922,7 +922,7 @@ pub fn rust_fixture_writable<T, F>( · 33 unmodified lines
922where922where
923 F: FnMut(FixtureState<'_>) -> PostResult<T>,923 F: FnMut(FixtureState<'_>) -> PostResult<T>,
924{924{
925 rust_fixture_writable_inner(name, version, make_fixture, mode, DirectoryRoot::IntegrationTest)925 rust_fixture_writable_inner(name, version, None, make_fixture, mode, DirectoryRoot::IntegrationTest)
926}926}
927 927
928/// Like [`rust_fixture_writable()`], but does not prefix the fixture directory with `tests`.928/// Like [`rust_fixture_writable()`], but does not prefix the fixture directory with `tests`.
@@ -935,12 +935,13 @@ pub fn rust_fixture_writable_standalone<T, F>( · 6 unmodified lines
935where935where
936 F: FnMut(FixtureState<'_>) -> PostResult<T>,936 F: FnMut(FixtureState<'_>) -> PostResult<T>,
937{937{
938 rust_fixture_writable_inner(name, version, make_fixture, mode, DirectoryRoot::StandaloneTest)938 rust_fixture_writable_inner(name, version, None, make_fixture, mode, DirectoryRoot::StandaloneTest)
939}939}
940 940
941fn rust_fixture_writable_inner<T, F>(941fn rust_fixture_writable_inner<T, F>(
942 name: &str,942 name: &str,
943 version: u32,943 version: u32,
944 object_hash: Option<gix_hash::Kind>,
944 mut make_fixture: F,945 mut make_fixture: F,
945 mode: Creation,946 mode: Creation,
946 root: DirectoryRoot,947 root: DirectoryRoot,
@@ -951,13 +952,15 @@ where · 4 unmodified lines
951 let dst = tempfile::TempDir::new()?;952 let dst = tempfile::TempDir::new()?;
952 let res = match mode {953 let res = match mode {
953 Creation::CopyFromReadOnly => {954 Creation::CopyFromReadOnly => {
954 let (ro_dir, _res_ignored) = rust_fixture_read_only_inner(name, version, &mut make_fixture, None, root)?;955 let (ro_dir, _res_ignored) =
956 rust_fixture_read_only_inner(name, version, object_hash, &mut make_fixture, None, root)?;
955 copy_recursively_into_existing_dir(ro_dir, dst.path())?;957 copy_recursively_into_existing_dir(ro_dir, dst.path())?;
956 let res = make_fixture(FixtureState::Fresh(dst.path()))?;958 let res = make_fixture(FixtureState::Fresh(dst.path()))?;
957 res959 res
958 }960 }
959 Creation::Execute => {961 Creation::Execute => {
960 let (_, res) = rust_fixture_read_only_inner(name, version, make_fixture, Some(dst.path()), root)?;962 let (_, res) =
963 rust_fixture_read_only_inner(name, version, object_hash, make_fixture, Some(dst.path()), root)?;
961 res964 res
962 }965 }
963 };966 };
@@ -967,6 +970,7 @@ where · 3 unmodified lines
967fn rust_fixture_read_only_inner<T, F>(970fn rust_fixture_read_only_inner<T, F>(
968 name: &str,971 name: &str,
969 version: u32,972 version: u32,
973 object_hash: Option<gix_hash::Kind>,
970 make_fixture: F,974 make_fixture: F,
971 destination_dir: Option<&Path>,975 destination_dir: Option<&Path>,
972 root: DirectoryRoot,976 root: DirectoryRoot,
@@ -988,7 +992,8 @@ where · 15 unmodified lines
988 Path::new(ARCHIVE_DIR_NAME).join(format!("{archive_name}.{}", tar_extension())),992 Path::new(ARCHIVE_DIR_NAME).join(format!("{archive_name}.{}", tar_extension())),
989 root,993 root,
990 );994 );
991 let (force_run, script_result_directory) = force_and_dir(destination_dir, root, &archive_name, &script_identity);995 let (force_run, script_result_directory) =
996 force_and_dir(destination_dir, root, &archive_name, object_hash, &script_identity);
992 let _marker = marker_if_needed(destination_dir, archive_name)?;997 let _marker = marker_if_needed(destination_dir, archive_name)?;
993 998
994 run_fixture_generator_with_marker_handling(999 run_fixture_generator_with_marker_handling(
@@ -1024,16 +1029,16 @@ fn force_and_dir( · 29 unmodified lines
1024 destination_dir: Option<&Path>,1029 destination_dir: Option<&Path>,
1025 root: DirectoryRoot,1030 root: DirectoryRoot,
1026 archive_name: impl AsRef<Path>,1031 archive_name: impl AsRef<Path>,
1032 hash_kind: Option<gix_hash::Kind>,
1027 script_identity: &dyn std::fmt::Display,1033 script_identity: &dyn std::fmt::Display,
1028) -> (bool, PathBuf) {1034) -> (bool, PathBuf) {
1029 destination_dir.map_or_else(1035 destination_dir.map_or_else(
1030 || {1036 || {
1031 let dir = fixture_path_inner(1037 let dir = fixture_path_inner(
1032 Path::new("generated-do-not-edit").join(archive_name).join(format!(1038 Path::new("generated-do-not-edit")
1033 "{}-{}",1039 .join(archive_name)
1034 script_identity,1040 .join(hash_kind.unwrap_or_else(hash_kind_from_env).to_string())
1035 family_name()1041 .join(format!("{}-{}", script_identity, family_name())),
1036 )),
1037 root,1042 root,
1038 );1043 );
1039 (false, dir)1044 (false, dir)
@@ -1127,6 +1132,9 @@ where · 87 unmodified lines
1127 gix_tempfile::signal::handler::Mode::DeleteTempfilesOnTerminationAndRestoreDefaultBehaviour,1132 gix_tempfile::signal::handler::Mode::DeleteTempfilesOnTerminationAndRestoreDefaultBehaviour,
1128 );1133 );
1129 1134
1135 let hash_kind = hash_kind_from_env();
1136 eprintln!("Using hash '{hash_kind}' when determining which fixture to use or recreate");
1137
1130 let script_location = script_name.as_ref();1138 let script_location = script_name.as_ref();
1131 let script_path = fixture_path_inner(script_location, root);1139 let script_path = fixture_path_inner(script_location, root);
1132 1140
@@ -1135,7 +1143,12 @@ where · 2 unmodified lines
1135 let post_version = post_process.as_ref().map(|(v, _)| *v);1143 let post_version = post_process.as_ref().map(|(v, _)| *v);
1136 let script_identity = {1144 let script_identity = {
1137 let mut map = SCRIPT_IDENTITY.lock();1145 let mut map = SCRIPT_IDENTITY.lock();
1138 let key = args.iter().fold(script_path.clone(), |p, a| p.join(a));1146 let init = if hash_kind == gix_hash::Kind::Sha1 {
1147 script_path.clone()
1148 } else {
1149 script_path.clone().join(hash_kind.to_string())
1150 };
1151 let key = args.iter().fold(init, |p, a| p.join(a));
1139 // Include post_version in the key if present1152 // Include post_version in the key if present
1140 let key = if let Some(v) = post_version {1153 let key = if let Some(v) = post_version {
1141 key.join(format!("post-v{v}"))1154 key.join(format!("post-v{v}"))
@@ -1178,15 +1191,26 @@ where · 36 unmodified lines
1178 }1191 }
1179 ArgsInHash::No => "".into(),1192 ArgsInHash::No => "".into(),
1180 };1193 };
1194 let potential_hash_suffix = if hash_kind == gix_hash::Kind::Sha1 {
1195 "".into()
1196 } else {
1197 format!("_{hash_kind}")
1198 };
1181 Path::new(ARCHIVE_DIR_NAME).join(format!(1199 Path::new(ARCHIVE_DIR_NAME).join(format!(
1182 "{}{suffix}.{}",1200 "{}{suffix}{potential_hash_suffix}.{}",
1183 script_basename.to_str().expect("valid UTF-8"),1201 script_basename.to_str().expect("valid UTF-8"),
1184 tar_extension()1202 tar_extension()
1185 ))1203 ))
1186 },1204 },
1187 root,1205 root,
1188 );1206 );
1189 let (force_run, script_result_directory) = force_and_dir(destination_dir, root, script_basename, &script_identity);1207 let (force_run, script_result_directory) = force_and_dir(
1208 destination_dir,
1209 root,
1210 script_basename,
1211 Some(hash_kind),
1212 &script_identity,
1213 );
1190 let _marker = marker_if_needed(destination_dir, script_basename)?;1214 let _marker = marker_if_needed(destination_dir, script_basename)?;
1191 1215
1192 let script_identity_for_archive = match args_in_hash {1216 let script_identity_for_archive = match args_in_hash {
@@ -1205,14 +1229,14 @@ where · 12 unmodified lines
1205 |fixture_state| {1229 |fixture_state| {
1206 if let FixtureState::Uninitialized(dir) = fixture_state {1230 if let FixtureState::Uninitialized(dir) = fixture_state {
1207 let mut cmd = std::process::Command::new(&script_absolute_path);1231 let mut cmd = std::process::Command::new(&script_absolute_path);
1208 let output = match configure_command(&mut cmd, &args, dir).output() {1232 let output = match configure_command(&mut cmd, hash_kind, &args, dir).output() {
1209 Ok(out) => out,1233 Ok(out) => out,
1210 Err(err)1234 Err(err)
1211 if err.kind() == std::io::ErrorKind::PermissionDenied1235 if err.kind() == std::io::ErrorKind::PermissionDenied
1212 || err.raw_os_error() == Some(193) /* windows */ =>1236 || err.raw_os_error() == Some(193) /* windows */ =>
1213 {1237 {
1214 cmd = std::process::Command::new(bash_program());1238 cmd = std::process::Command::new(bash_program());
1215 configure_command(cmd.arg(&script_absolute_path), &args, dir).output()?1239 configure_command(cmd.arg(&script_absolute_path), hash_kind, &args, dir).output()?
1216 }1240 }
1217 Err(err) => return Err(err.into()),1241 Err(err) => return Err(err.into()),
1218 };1242 };
@@ -1233,6 +1257,17 @@ where · 14 unmodified lines
1233 Ok((script_result_directory, res))1257 Ok((script_result_directory, res))
1234}1258}
1235 1259
1260fn hash_kind_from_env() -> gix_hash::Kind {
1261 env::var_os("GIX_TEST_FIXTURE_HASH").and_then(|value| value.into_string().ok()).map(|object_kind| {
1262 gix_hash::Kind::from_str(&object_kind).unwrap_or_else(|_| {
1263 panic!(
1264 "GIX_TEST_FIXTURE_HASH was set to {object_kind} which is an invalid value. Valid values are {}. Exiting.",
1265 gix_hash::Kind::all().iter().map(std::string::ToString::to_string).collect::<Vec<_>>().join(", ")
1266 )
1267 })
1268 }).unwrap_or_default()
1269}
1270
1236#[cfg(windows)]1271#[cfg(windows)]
1237const NULL_DEVICE: &str = "nul"; // See `gix_path::env::git::NULL_DEVICE` on why this form is used.1272const NULL_DEVICE: &str = "nul"; // See `gix_path::env::git::NULL_DEVICE` on why this form is used.
1238#[cfg(not(windows))]1273#[cfg(not(windows))]
@@ -1240,6 +1275,7 @@ const NULL_DEVICE: &str = "/dev/null"; · 1 unmodified line
1240 1275
1241fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>(1276fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
1242 cmd: &'a mut std::process::Command,1277 cmd: &'a mut std::process::Command,
1278 hash_kind: gix_hash::Kind,
1243 args: I,1279 args: I,
1244 script_result_directory: &Path,1280 script_result_directory: &Path,
1245) -> &'a mut std::process::Command {1281) -> &'a mut std::process::Command {
@@ -1279,6 +1315,7 @@ fn configure_command<'a, I: IntoIterator<Item = S>, S: AsRef<OsStr>>( · 33 unmodified lines
1279 .env("GIT_CONFIG_VALUE_2", "main")1315 .env("GIT_CONFIG_VALUE_2", "main")
1280 .env("GIT_CONFIG_KEY_3", "protocol.file.allow")1316 .env("GIT_CONFIG_KEY_3", "protocol.file.allow")
1281 .env("GIT_CONFIG_VALUE_3", "always")1317 .env("GIT_CONFIG_VALUE_3", "always")
1318 .env("GIT_DEFAULT_HASH", hash_kind.to_string())
1282}1319}
1283 1320
1284/// Get the path attempted as a `bash` interpreter, for fixture scripts having no `#!` we can use.1321/// Get the path attempted as a `bash` interpreter, for fixture scripts having no `#!` we can use.
tests/tools/src/tests.rs+6−1
@@ -44,7 +44,12 @@ fn configure_command_clears_external_config() { · 43 unmodified lines
44 let mut cmd = std::process::Command::new(GIT_PROGRAM);44 let mut cmd = std::process::Command::new(GIT_PROGRAM);
45 cmd.env("GIT_CONFIG_SYSTEM", SCOPE_ENV_VALUE);45 cmd.env("GIT_CONFIG_SYSTEM", SCOPE_ENV_VALUE);
46 cmd.env("GIT_CONFIG_GLOBAL", SCOPE_ENV_VALUE);46 cmd.env("GIT_CONFIG_GLOBAL", SCOPE_ENV_VALUE);
47 configure_command(&mut cmd, ["config", "-l", "--show-origin"], temp.path());47 configure_command(
48 &mut cmd,
49 gix_hash::Kind::default(),
50 ["config", "-l", "--show-origin"],
51 temp.path(),
52 );
48 53
49 let output = cmd.output().expect("can run git");54 let output = cmd.output().expect("can run git");
50 let lines: Vec<_> = output55 let lines: Vec<_> = output