@@ -5,91 +5,183 @@ use crate::run::runner::interfaces::RunData;
55use crate :: run:: runner:: valgrind:: executor:: ValgrindExecutor ;
66use crate :: run:: { RunnerMode , runner:: wall_time:: executor:: WallTimeExecutor } ;
77use tempfile:: TempDir ;
8+ use tokio:: sync:: { OnceCell , Semaphore , SemaphorePermit } ;
89
10+ const SIMPLE_ECHO_SCRIPT : & str = "echo 'Hello, World!'" ;
911const MULTILINE_ECHO_SCRIPT : & str = "echo \" Working\"
1012echo \" with\"
1113echo \" multiple lines\" " ;
12-
1314const MULTILINE_ECHO_WITH_SEMICOLONS : & str = "echo \" Working\" ;
1415echo \" with\" ;
1516echo \" multiple lines\" ;" ;
16-
1717const DIRECTORY_CHECK_SCRIPT : & str = "cd /tmp
1818# Check that the directory is actually changed
1919if [ $(basename $(pwd)) != \" tmp\" ]; then
2020 exit 1
2121fi" ;
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" ;
2228
23- const BENCHMARK_COMMANDS : [ & str ; 5 ] = [
24- "echo 'Hello, World!'" ,
25- MULTILINE_ECHO_WITH_SEMICOLONS ,
26- MULTILINE_ECHO_WITH_SEMICOLONS ,
29+ const TESTS : [ & str ; 5 ] = [
30+ SIMPLE_ECHO_SCRIPT ,
2731 MULTILINE_ECHO_SCRIPT ,
32+ MULTILINE_ECHO_WITH_SEMICOLONS ,
2833 DIRECTORY_CHECK_SCRIPT ,
34+ ENV_VAR_VALIDATION_SCRIPT ,
2935] ;
3036
3137async fn create_test_setup ( ) -> ( SystemInfo , RunData , TempDir ) {
32- let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
38+ let system_info = SystemInfo :: new ( ) . unwrap ( ) ;
3339
34- let system_info = SystemInfo :: test ( ) ;
40+ let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
3541 let run_data = RunData {
3642 profile_folder : temp_dir. path ( ) . to_path_buf ( ) ,
3743 } ;
38-
3944 ( system_info, run_data, temp_dir)
4045}
4146
42- #[ tokio:: test]
43- async fn test_valgrind_executor ( ) {
44- let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
47+ mod valgrind {
48+ use super :: * ;
4549
46- let executor = ValgrindExecutor ;
47- executor . setup ( & system_info ) . await . unwrap ( ) ;
50+ async fn get_valgrind_executor ( ) -> & ' static ValgrindExecutor {
51+ static VALGRIND_EXECUTOR : OnceCell < ValgrindExecutor > = OnceCell :: const_new ( ) ;
4852
49- for cmd in BENCHMARK_COMMANDS {
50- eprintln ! ( "Running command: {cmd}" ) ;
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+ }
5162
52- let config = Config {
63+ fn valgrind_config ( command : & str ) -> Config {
64+ Config {
5365 mode : RunnerMode :: Instrumentation ,
54- command : cmd . to_string ( ) ,
66+ command : command . to_string ( ) ,
5567 ..Config :: test ( )
56- } ;
68+ }
69+ }
5770
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) ;
5882 executor
5983 . run ( & config, & system_info, & run_data, & None )
6084 . await
6185 . unwrap ( ) ;
62- executor
63- . teardown ( & config, & system_info, & run_data)
64- . await
65- . unwrap ( ) ;
6686 }
67- }
6887
69- #[ tokio:: test]
70- async fn test_walltime_executor ( ) {
71- let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
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+ }
72109
73- let executor = WallTimeExecutor :: new ( ) ;
74- executor. setup ( & system_info) . await . unwrap ( ) ;
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+ }
75134
76- for enable_perf in [ false , true ] {
77- for cmd in BENCHMARK_COMMANDS {
78- eprintln ! ( "Running command: {cmd}" ) ;
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+ }
79143
80- let config = Config {
81- mode : RunnerMode :: Walltime ,
82- command : cmd. to_string ( ) ,
83- enable_perf,
84- ..Config :: test ( )
85- } ;
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+ }
86164
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) ;
87180 executor
88181 . run ( & config, & system_info, & run_data, & None )
89182 . await
90183 . unwrap ( ) ;
91-
92- // Don't execute teardown since the cmds dont use the FIFO to set the integration metadata.
93- }
184+ } )
185+ . await ;
94186 }
95187}
0 commit comments