##// END OF EJS Templates
testing: introduce util function to synchronize concurrent commands on files...
Raphaël Gomès -
r51109:8e0d823e stable
parent child Browse files
Show More
@@ -0,0 +1,81 b''
1 //! Utils for debugging hg-core
2
3 use crate::config::Config;
4
5 /// Write the file path given by the config option `devel.<config_option>` with
6 /// the suffix `.waiting`, then wait for the file path given by the
7 /// config option `devel.<config_option>` to appear on disk
8 /// up to `devel.<config_option>-timeout` seconds.
9 /// Note that the timeout may be higher because we scale it if global
10 /// `run-tests` timeouts are raised to prevent flakiness on slower hardware.
11 ///
12 /// Useful for testing race conditions.
13 pub fn debug_wait_for_file(
14 config: &Config,
15 config_option: &str,
16 ) -> Result<(), String> {
17 let path_opt = format!("sync.{config_option}");
18 let file_path = match config.get_str(b"devel", path_opt.as_bytes()).ok() {
19 Some(Some(file_path)) => file_path,
20 _ => return Ok(()),
21 };
22
23 // TODO make it so `configitems` is shared between Rust and Python so that
24 // defaults work out of the box, etc.
25 let default_timeout = 2;
26 let timeout_opt = format!("sync.{config_option}-timeout");
27 let timeout_seconds =
28 match config.get_u32(b"devel", timeout_opt.as_bytes()) {
29 Ok(Some(timeout)) => timeout,
30 Err(e) => {
31 log::debug!("{e}");
32 default_timeout
33 }
34 _ => default_timeout,
35 };
36 let timeout_seconds = timeout_seconds as u64;
37
38 log::debug!(
39 "Config option `{config_option}` found, \
40 waiting for file `{file_path}` to be created"
41 );
42 std::fs::File::create(format!("{file_path}.waiting")).ok();
43 // If the test timeout have been extended, scale the timer relative
44 // to the normal timing.
45 let global_default_timeout: u64 = std::env::var("HGTEST_TIMEOUT_DEFAULT")
46 .map(|t| t.parse())
47 .unwrap_or(Ok(0))
48 .unwrap();
49 let global_timeout_override: u64 = std::env::var("HGTEST_TIMEOUT")
50 .map(|t| t.parse())
51 .unwrap_or(Ok(0))
52 .unwrap();
53 let timeout_seconds = if global_default_timeout < global_timeout_override {
54 timeout_seconds * global_timeout_override / global_default_timeout
55 } else {
56 timeout_seconds
57 };
58 let timeout = std::time::Duration::from_secs(timeout_seconds);
59
60 let start = std::time::Instant::now();
61 let path = std::path::Path::new(file_path);
62 let mut found = false;
63 while start.elapsed() < timeout {
64 if path.exists() {
65 log::debug!("File `{file_path}` was created");
66 found = true;
67 break;
68 } else {
69 std::thread::sleep(std::time::Duration::from_millis(10));
70 }
71 }
72 if !found {
73 let msg = format!(
74 "File `{file_path}` set by `{config_option}` was not found \
75 within the allocated {timeout_seconds} seconds timeout"
76 );
77 Err(msg)
78 } else {
79 Ok(())
80 }
81 }
@@ -9,6 +9,21 b' import time'
9 environ = getattr(os, 'environ')
9 environ = getattr(os, 'environ')
10
10
11
11
12 def wait_on_cfg(ui, cfg, timeout=10):
13 """synchronize on the `cfg` config path
14
15 Use this to synchronize commands during race tests.
16 """
17 full_config = b'sync.' + cfg
18 wait_config = full_config + b'-timeout'
19 sync_path = ui.config(b'devel', full_config)
20 if sync_path is not None:
21 timeout = ui.config(b'devel', wait_config)
22 ready_path = sync_path + b'.waiting'
23 write_file(ready_path)
24 wait_file(sync_path, timeout=timeout)
25
26
12 def _timeout_factor():
27 def _timeout_factor():
13 """return the current modification to timeout"""
28 """return the current modification to timeout"""
14 default = int(environ.get('HGTEST_TIMEOUT_DEFAULT', 360))
29 default = int(environ.get('HGTEST_TIMEOUT_DEFAULT', 360))
@@ -15,6 +15,7 b' use std::cell::Cell;'
15 use std::fmt;
15 use std::fmt;
16 use std::{io::Write, ops::Deref};
16 use std::{io::Write, ops::Deref};
17
17
18 pub mod debug;
18 pub mod files;
19 pub mod files;
19 pub mod hg_path;
20 pub mod hg_path;
20 pub mod path_auditor;
21 pub mod path_auditor;
General Comments 0
You need to be logged in to leave comments. Login now