Skip to content

Commit fe4de63

Browse files
committed
chore: add executor tests
1 parent 526f1a8 commit fe4de63

4 files changed

Lines changed: 245 additions & 0 deletions

File tree

Cargo.lock

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ procfs = "0.17.0"
6262
temp-env = { version = "0.3.6", features = ["async_closure"] }
6363
insta = { version = "1.29.0", features = ["json", "redactions"] }
6464
test-with = { version = "0.15", default-features = false, features = [] }
65+
rstest = { version = "0.25.0", default-features = false }
6566

6667
[workspace.metadata.release]
6768
sign-tag = true

src/run/runner/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use super::{RunnerMode, config::Config};
77
mod executor;
88
mod helpers;
99
mod interfaces;
10+
#[cfg(test)]
11+
mod tests;
1012
mod valgrind;
1113
mod wall_time;
1214

src/run/runner/tests.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
use crate::run::check_system::SystemInfo;
2+
use crate::run::config::Config;
3+
use crate::run::runner::executor::Executor;
4+
use crate::run::runner::interfaces::RunData;
5+
use crate::run::runner::valgrind::executor::ValgrindExecutor;
6+
use crate::run::{RunnerMode, runner::wall_time::executor::WallTimeExecutor};
7+
use tempfile::TempDir;
8+
use tokio::sync::{OnceCell, Semaphore, SemaphorePermit};
9+
10+
const SIMPLE_ECHO_SCRIPT: &str = "echo 'Hello, World!'";
11+
const MULTILINE_ECHO_SCRIPT: &str = "echo \"Working\"
12+
echo \"with\"
13+
echo \"multiple lines\"";
14+
const MULTILINE_ECHO_WITH_SEMICOLONS: &str = "echo \"Working\";
15+
echo \"with\";
16+
echo \"multiple lines\";";
17+
const DIRECTORY_CHECK_SCRIPT: &str = "cd /tmp
18+
# Check that the directory is actually changed
19+
if [ $(basename $(pwd)) != \"tmp\" ]; then
20+
exit 1
21+
fi";
22+
const ENV_VAR_VALIDATION_SCRIPT: &str = "
23+
output=$(echo \"$MY_ENV_VAR\")
24+
if [ \"$output\" != \"Hello\" ]; then
25+
echo \"Assertion failed: Expected 'Hello' but got '$output'\"
26+
exit 1
27+
fi";
28+
29+
const TESTS: [&str; 5] = [
30+
SIMPLE_ECHO_SCRIPT,
31+
MULTILINE_ECHO_SCRIPT,
32+
MULTILINE_ECHO_WITH_SEMICOLONS,
33+
DIRECTORY_CHECK_SCRIPT,
34+
ENV_VAR_VALIDATION_SCRIPT,
35+
];
36+
37+
async fn create_test_setup() -> (SystemInfo, RunData, TempDir) {
38+
let system_info = SystemInfo::new().unwrap();
39+
40+
let temp_dir = TempDir::new().unwrap();
41+
let run_data = RunData {
42+
profile_folder: temp_dir.path().to_path_buf(),
43+
};
44+
(system_info, run_data, temp_dir)
45+
}
46+
47+
mod valgrind {
48+
use super::*;
49+
50+
async fn get_valgrind_executor() -> &'static ValgrindExecutor {
51+
static VALGRIND_EXECUTOR: OnceCell<ValgrindExecutor> = OnceCell::const_new();
52+
53+
VALGRIND_EXECUTOR
54+
.get_or_init(|| async {
55+
let executor = ValgrindExecutor;
56+
let system_info = SystemInfo::new().unwrap();
57+
executor.setup(&system_info).await.unwrap();
58+
executor
59+
})
60+
.await
61+
}
62+
63+
fn valgrind_config(command: &str) -> Config {
64+
Config {
65+
mode: RunnerMode::Instrumentation,
66+
command: command.to_string(),
67+
..Config::test()
68+
}
69+
}
70+
71+
#[rstest::rstest]
72+
#[case(TESTS[0])]
73+
#[case(TESTS[1])]
74+
#[case(TESTS[2])]
75+
#[case(TESTS[3])]
76+
#[tokio::test]
77+
async fn test_valgrind_executor(#[case] cmd: &str) {
78+
let (system_info, run_data, _temp_dir) = create_test_setup().await;
79+
let executor = get_valgrind_executor().await;
80+
81+
let config = valgrind_config(cmd);
82+
executor
83+
.run(&config, &system_info, &run_data, &None)
84+
.await
85+
.unwrap();
86+
}
87+
88+
#[rstest::rstest]
89+
#[case("MY_ENV_VAR", "Hello", ENV_VAR_VALIDATION_SCRIPT)]
90+
#[tokio::test]
91+
async fn test_valgrind_executor_with_env(
92+
#[case] env_var: &str,
93+
#[case] env_value: &str,
94+
#[case] cmd: &str,
95+
) {
96+
let (system_info, run_data, _temp_dir) = create_test_setup().await;
97+
let executor = get_valgrind_executor().await;
98+
99+
temp_env::async_with_vars(&[(env_var, Some(env_value))], async {
100+
let config = valgrind_config(cmd);
101+
executor
102+
.run(&config, &system_info, &run_data, &None)
103+
.await
104+
.unwrap();
105+
})
106+
.await;
107+
}
108+
}
109+
110+
mod walltime {
111+
use super::*;
112+
113+
async fn get_walltime_executor() -> (SemaphorePermit<'static>, WallTimeExecutor) {
114+
static WALLTIME_INIT: OnceCell<()> = OnceCell::const_new();
115+
static WALLTIME_SEMAPHORE: OnceCell<Semaphore> = OnceCell::const_new();
116+
117+
WALLTIME_INIT
118+
.get_or_init(|| async {
119+
let executor = WallTimeExecutor::new();
120+
let system_info = SystemInfo::new().unwrap();
121+
executor.setup(&system_info).await.unwrap();
122+
})
123+
.await;
124+
125+
// We can't execute multiple walltime executors in parallel because perf isn't thread-safe (yet). We have to
126+
// use a semaphore to limit concurrent access.
127+
let semaphore = WALLTIME_SEMAPHORE
128+
.get_or_init(|| async { Semaphore::new(1) })
129+
.await;
130+
let permit = semaphore.acquire().await.unwrap();
131+
132+
(permit, WallTimeExecutor::new())
133+
}
134+
135+
fn walltime_config(command: &str, enable_perf: bool) -> Config {
136+
Config {
137+
mode: RunnerMode::Walltime,
138+
command: command.to_string(),
139+
enable_perf,
140+
..Config::test()
141+
}
142+
}
143+
144+
#[rstest::rstest]
145+
#[case(TESTS[0], false)]
146+
#[case(TESTS[0], true)]
147+
#[case(TESTS[1], false)]
148+
#[case(TESTS[1], true)]
149+
#[case(TESTS[2], false)]
150+
#[case(TESTS[2], true)]
151+
#[case(TESTS[3], false)]
152+
#[case(TESTS[3], true)]
153+
#[tokio::test]
154+
async fn test_walltime_executor(#[case] cmd: &str, #[case] enable_perf: bool) {
155+
let (system_info, run_data, _temp_dir) = create_test_setup().await;
156+
let (_permit, executor) = get_walltime_executor().await;
157+
158+
let config = walltime_config(cmd, enable_perf);
159+
executor
160+
.run(&config, &system_info, &run_data, &None)
161+
.await
162+
.unwrap();
163+
}
164+
165+
#[rstest::rstest]
166+
#[case("MY_ENV_VAR", "Hello", ENV_VAR_VALIDATION_SCRIPT, false)]
167+
#[case("MY_ENV_VAR", "Hello", ENV_VAR_VALIDATION_SCRIPT, true)]
168+
#[tokio::test]
169+
async fn test_walltime_executor_with_env(
170+
#[case] env_var: &str,
171+
#[case] env_value: &str,
172+
#[case] cmd: &str,
173+
#[case] enable_perf: bool,
174+
) {
175+
let (system_info, run_data, _temp_dir) = create_test_setup().await;
176+
let (_permit, executor) = get_walltime_executor().await;
177+
178+
temp_env::async_with_vars(&[(env_var, Some(env_value))], async {
179+
let config = walltime_config(cmd, enable_perf);
180+
executor
181+
.run(&config, &system_info, &run_data, &None)
182+
.await
183+
.unwrap();
184+
})
185+
.await;
186+
}
187+
}

0 commit comments

Comments
 (0)