--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/rust/hg-core/src/utils/debug.rs Thu Mar 02 19:02:52 2023 +0100
@@ -0,0 +1,87 @@
+//! Utils for debugging hg-core
+
+use crate::config::Config;
+
+/// Write the file path given by the config option `devel.<config_option>` with
+/// the suffix `.waiting`, then wait for the file path given by the
+/// config option `devel.<config_option>` to appear on disk
+/// up to `devel.<config_option>-timeout` seconds.
+/// Note that the timeout may be higher because we scale it if global
+/// `run-tests` timeouts are raised to prevent flakiness on slower hardware.
+///
+/// Useful for testing race conditions.
+pub fn debug_wait_for_file(
+ config: &Config,
+ config_option: &str,
+) -> Result<(), String> {
+ let path_opt = format!("sync.{config_option}");
+ let file_path = match config.get_str(b"devel", path_opt.as_bytes()).ok() {
+ Some(Some(file_path)) => file_path,
+ _ => return Ok(()),
+ };
+
+ // TODO make it so `configitems` is shared between Rust and Python so that
+ // defaults work out of the box, etc.
+ let default_timeout = 2;
+ let timeout_opt = format!("sync.{config_option}-timeout");
+ let timeout_seconds =
+ match config.get_u32(b"devel", timeout_opt.as_bytes()) {
+ Ok(Some(timeout)) => timeout,
+ Err(e) => {
+ log::debug!("{e}");
+ default_timeout
+ }
+ _ => default_timeout,
+ };
+ let timeout_seconds = timeout_seconds as u64;
+
+ log::debug!(
+ "Config option `{config_option}` found, \
+ waiting for file `{file_path}` to be created"
+ );
+ std::fs::File::create(format!("{file_path}.waiting")).ok();
+ // If the test timeout have been extended, scale the timer relative
+ // to the normal timing.
+ let global_default_timeout: u64 = std::env::var("HGTEST_TIMEOUT_DEFAULT")
+ .map(|t| t.parse())
+ .unwrap_or(Ok(0))
+ .unwrap();
+ let global_timeout_override: u64 = std::env::var("HGTEST_TIMEOUT")
+ .map(|t| t.parse())
+ .unwrap_or(Ok(0))
+ .unwrap();
+ let timeout_seconds = if global_default_timeout < global_timeout_override {
+ timeout_seconds * global_timeout_override / global_default_timeout
+ } else {
+ timeout_seconds
+ };
+ let timeout = std::time::Duration::from_secs(timeout_seconds);
+
+ let start = std::time::Instant::now();
+ let path = std::path::Path::new(file_path);
+ let mut found = false;
+ while start.elapsed() < timeout {
+ if path.exists() {
+ log::debug!("File `{file_path}` was created");
+ found = true;
+ break;
+ } else {
+ std::thread::sleep(std::time::Duration::from_millis(10));
+ }
+ }
+ if !found {
+ let msg = format!(
+ "File `{file_path}` set by `{config_option}` was not found \
+ within the allocated {timeout_seconds} seconds timeout"
+ );
+ Err(msg)
+ } else {
+ Ok(())
+ }
+}
+
+pub fn debug_wait_for_file_or_print(config: &Config, config_option: &str) {
+ if let Err(e) = debug_wait_for_file(config, config_option) {
+ eprintln!("{e}");
+ };
+}