@@ -5,91 +5,189 @@ 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" ;
28+
29+ async fn get_valgrind_executor ( ) -> & ' static ValgrindExecutor {
30+ static VALGRIND_EXECUTOR : OnceCell < ValgrindExecutor > = OnceCell :: const_new ( ) ;
2231
23- const BENCHMARK_COMMANDS : [ & str ; 5 ] = [
24- "echo 'Hello, World!'" ,
25- MULTILINE_ECHO_WITH_SEMICOLONS ,
26- MULTILINE_ECHO_WITH_SEMICOLONS ,
27- MULTILINE_ECHO_SCRIPT ,
28- DIRECTORY_CHECK_SCRIPT ,
29- ] ;
32+ VALGRIND_EXECUTOR
33+ . get_or_init ( || async {
34+ let executor = ValgrindExecutor ;
35+ let system_info = SystemInfo :: new ( ) . unwrap ( ) ;
36+ executor. setup ( & system_info) . await . unwrap ( ) ;
37+ executor
38+ } )
39+ . await
40+ }
41+
42+ async fn get_walltime_executor ( ) -> ( SemaphorePermit < ' static > , WallTimeExecutor ) {
43+ static WALLTIME_INIT : OnceCell < ( ) > = OnceCell :: const_new ( ) ;
44+ static WALLTIME_SEMAPHORE : OnceCell < Semaphore > = OnceCell :: const_new ( ) ;
45+
46+ WALLTIME_INIT
47+ . get_or_init ( || async {
48+ let executor = WallTimeExecutor :: new ( ) ;
49+ let system_info = SystemInfo :: new ( ) . unwrap ( ) ;
50+ executor. setup ( & system_info) . await . unwrap ( ) ;
51+ } )
52+ . await ;
53+
54+ // We can't execute multiple walltime executors in parallel because perf isn't thread-safe (yet). We have to
55+ // use a semaphore to limit concurrent access.
56+ let semaphore = WALLTIME_SEMAPHORE
57+ . get_or_init ( || async { Semaphore :: new ( 1 ) } )
58+ . await ;
59+ let permit = semaphore. acquire ( ) . await . unwrap ( ) ;
60+
61+ ( permit, WallTimeExecutor :: new ( ) )
62+ }
3063
3164async fn create_test_setup ( ) -> ( SystemInfo , RunData , TempDir ) {
3265 let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
3366
34- let system_info = SystemInfo :: test ( ) ;
67+ let system_info = SystemInfo :: new ( ) . unwrap ( ) ;
3568 let run_data = RunData {
3669 profile_folder : temp_dir. path ( ) . to_path_buf ( ) ,
3770 } ;
3871
3972 ( system_info, run_data, temp_dir)
4073}
4174
75+ #[ rstest:: rstest]
76+ #[ case( SIMPLE_ECHO_SCRIPT ) ]
77+ #[ case( MULTILINE_ECHO_WITH_SEMICOLONS ) ]
78+ #[ case( MULTILINE_ECHO_SCRIPT ) ]
79+ #[ case( DIRECTORY_CHECK_SCRIPT ) ]
4280#[ tokio:: test]
43- async fn test_valgrind_executor ( ) {
81+ async fn test_valgrind_executor ( # [ case ] cmd : & str ) {
4482 let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
83+ let executor = get_valgrind_executor ( ) . await ;
84+
85+ eprintln ! ( "Running command: {cmd}" ) ;
86+
87+ let config = Config {
88+ mode : RunnerMode :: Instrumentation ,
89+ command : cmd. to_string ( ) ,
90+ ..Config :: test ( )
91+ } ;
92+
93+ executor
94+ . run ( & config, & system_info, & run_data, & None )
95+ . await
96+ . unwrap ( ) ;
97+ executor
98+ . teardown ( & config, & system_info, & run_data)
99+ . await
100+ . unwrap ( ) ;
101+ }
102+
103+ #[ rstest:: rstest]
104+ #[ case( SIMPLE_ECHO_SCRIPT , false ) ]
105+ #[ case( SIMPLE_ECHO_SCRIPT , true ) ]
106+ #[ case( MULTILINE_ECHO_WITH_SEMICOLONS , false ) ]
107+ #[ case( MULTILINE_ECHO_WITH_SEMICOLONS , true ) ]
108+ #[ case( MULTILINE_ECHO_SCRIPT , false ) ]
109+ #[ case( MULTILINE_ECHO_SCRIPT , true ) ]
110+ #[ case( DIRECTORY_CHECK_SCRIPT , false ) ]
111+ #[ case( DIRECTORY_CHECK_SCRIPT , true ) ]
112+ #[ tokio:: test]
113+ async fn test_walltime_executor ( #[ case] cmd : & str , #[ case] enable_perf : bool ) {
114+ let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
115+ let ( _permit, executor) = get_walltime_executor ( ) . await ;
116+ let executor = executor;
117+
118+ eprintln ! ( "Running command: {cmd}" ) ;
119+
120+ let config = Config {
121+ mode : RunnerMode :: Walltime ,
122+ command : cmd. to_string ( ) ,
123+ enable_perf,
124+ ..Config :: test ( )
125+ } ;
126+
127+ executor
128+ . run ( & config, & system_info, & run_data, & None )
129+ . await
130+ . unwrap ( ) ;
45131
46- let executor = ValgrindExecutor ;
47- executor. setup ( & system_info) . await . unwrap ( ) ;
132+ // Don't execute teardown since the cmds dont use the FIFO to set the integration metadata.
133+ }
134+
135+ #[ rstest:: rstest]
136+ #[ case( "MY_ENV_VAR" , "Hello" , ENV_VAR_VALIDATION_SCRIPT ) ]
137+ #[ tokio:: test]
138+ async fn test_valgrind_executor_with_env (
139+ #[ case] env_var : & str ,
140+ #[ case] env_value : & str ,
141+ #[ case] cmd : & str ,
142+ ) {
143+ let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
144+ let executor = get_valgrind_executor ( ) . await ;
48145
49- for cmd in BENCHMARK_COMMANDS {
50- eprintln ! ( "Running command: {cmd}" ) ;
146+ let config = Config {
147+ mode : RunnerMode :: Instrumentation ,
148+ command : cmd. to_string ( ) ,
149+ ..Config :: test ( )
150+ } ;
51151
52- let config = Config {
53- mode : RunnerMode :: Instrumentation ,
54- command : cmd. to_string ( ) ,
55- ..Config :: test ( )
56- } ;
152+ eprintln ! ( "Running command: {cmd}" ) ;
57153
154+ temp_env:: async_with_vars ( & [ ( env_var, Some ( env_value) ) ] , async {
58155 executor
59156 . run ( & config, & system_info, & run_data, & None )
60157 . await
61158 . unwrap ( ) ;
62- executor
63- . teardown ( & config, & system_info, & run_data)
64- . await
65- . unwrap ( ) ;
66- }
159+ } )
160+ . await ;
67161}
68162
163+ #[ rstest:: rstest]
164+ #[ case( "MY_ENV_VAR" , "Hello" , ENV_VAR_VALIDATION_SCRIPT , false ) ]
165+ #[ case( "MY_ENV_VAR" , "Hello" , ENV_VAR_VALIDATION_SCRIPT , true ) ]
69166#[ tokio:: test]
70- async fn test_walltime_executor ( ) {
167+ async fn test_walltime_executor_with_env (
168+ #[ case] env_var : & str ,
169+ #[ case] env_value : & str ,
170+ #[ case] cmd : & str ,
171+ #[ case] enable_perf : bool ,
172+ ) {
71173 let ( system_info, run_data, _temp_dir) = create_test_setup ( ) . await ;
174+ let ( _permit, executor) = get_walltime_executor ( ) . await ;
175+ let executor = executor;
176+
177+ let config = Config {
178+ mode : RunnerMode :: Walltime ,
179+ command : cmd. to_string ( ) ,
180+ enable_perf,
181+ ..Config :: test ( )
182+ } ;
72183
73- let executor = WallTimeExecutor :: new ( ) ;
74- executor. setup ( & system_info) . await . unwrap ( ) ;
75-
76- for enable_perf in [ false , true ] {
77- for cmd in BENCHMARK_COMMANDS {
78- eprintln ! ( "Running command: {cmd}" ) ;
79-
80- let config = Config {
81- mode : RunnerMode :: Walltime ,
82- command : cmd. to_string ( ) ,
83- enable_perf,
84- ..Config :: test ( )
85- } ;
86-
87- executor
88- . run ( & config, & system_info, & run_data, & None )
89- . await
90- . unwrap ( ) ;
184+ eprintln ! ( "Running command: {cmd}" ) ;
91185
92- // Don't execute teardown since the cmds dont use the FIFO to set the integration metadata.
93- }
94- }
186+ temp_env:: async_with_vars ( & [ ( env_var, Some ( env_value) ) ] , async {
187+ executor
188+ . run ( & config, & system_info, & run_data, & None )
189+ . await
190+ . unwrap ( ) ;
191+ } )
192+ . await ;
95193}
0 commit comments