@@ -175,14 +175,9 @@ async fn run_tests(run_opts: &RunOptions) -> anyhow::Result<ExecutionStats> {
175175
176176 let mut runners = Vec :: new ( ) ;
177177
178- // Create up to parallelism collections of PHD framework settings. For the
179- // most part we can reuse the same settings for all test-running tasks -
180- // state is not mutably shared. The important exception is port ranges for
181- // servers PHD will run, where we want non-overlapping port ranges to ensure
182- // that concurrent tests don't accidentally use a neighbor's servers.
183- for i in 0 ..parallelism {
184- let port_range = ( 9000 + PORT_RANGE_PER_RUNNER * i)
185- ..( 9000 + PORT_RANGE_PER_RUNNER * ( i + 1 ) ) ;
178+ if parallelism == 1 {
179+ // If there's only one test runner, the provided config is by definition
180+ // not going to have issues with parallelism. Consume it directly.
186181 let ctx_params = FrameworkParameters {
187182 propolis_server_path : run_opts. propolis_server_cmd . clone ( ) ,
188183 crucible_downstairs : run_opts. crucible_downstairs ( ) ?,
@@ -195,7 +190,7 @@ async fn run_tests(run_opts: &RunOptions) -> anyhow::Result<ExecutionStats> {
195190 default_guest_memory_mib : run_opts. default_guest_memory_mib ,
196191 default_guest_os_artifact : run_opts. default_guest_artifact . clone ( ) ,
197192 default_bootrom_artifact : run_opts. default_bootrom_artifact . clone ( ) ,
198- port_range,
193+ port_range : 9000 .. ( 9000 + PORT_RANGE_PER_RUNNER ) ,
199194 max_buildomat_wait : Duration :: from_secs (
200195 run_opts. max_buildomat_wait_secs ,
201196 ) ,
@@ -209,6 +204,71 @@ async fn run_tests(run_opts: &RunOptions) -> anyhow::Result<ExecutionStats> {
209204
210205 let fixtures = TestFixtures :: new ( ctx. clone ( ) ) . unwrap ( ) ;
211206 runners. push ( ( ctx, fixtures) ) ;
207+ } else {
208+ // Create up to parallelism collections of PHD framework settings. Many
209+ // settings can be reused directly, but some describe state the
210+ // framework will mutate (causing ports to be allocated, fetching
211+ // artifacts, etc). Take the provided config and make it safe for
212+ // Frameworks to use independently.
213+ //
214+ // This implies downloading artifacts {parallelism} times, extracting
215+ // artifacts redundantly for the different artifact directories, makes
216+ // terrible use of the port range. It'd be much better to accept some
217+ // owner of the shared state that each Framework can take as a
218+ // parameter.
219+
220+ // We'll separate directories by which Framework they're for in some
221+ // cases, below. Those uniquifying names will be padded to all be the
222+ // length of the longest uniquifier to help make it kind of legible..
223+ let pad_size = format ! ( "{}" , parallelism - 1 ) . len ( ) ;
224+
225+ for i in 0 ..parallelism {
226+ let port_range = ( 9000 + PORT_RANGE_PER_RUNNER * i)
227+ ..( 9000 + PORT_RANGE_PER_RUNNER * ( i + 1 ) ) ;
228+ let mut unshared_tmp_dir = run_opts. tmp_directory . clone ( ) ;
229+ unshared_tmp_dir. push ( format ! ( "runner-{:pad_size$}" , i) ) ;
230+
231+ let mut unshared_artifacts_dir =
232+ run_opts. artifact_directory ( ) . clone ( ) ;
233+ unshared_artifacts_dir. push ( format ! ( "runner-{:pad_size$}" , i) ) ;
234+
235+ // The runner directories may well not exist, we just invented them
236+ // after all. Create them so phd-runner can use them. This is awful.
237+ // Sorry.
238+ let _ = std:: fs:: create_dir ( & unshared_tmp_dir) ;
239+ let _ = std:: fs:: create_dir ( & unshared_artifacts_dir) ;
240+
241+ let ctx_params = FrameworkParameters {
242+ propolis_server_path : run_opts. propolis_server_cmd . clone ( ) ,
243+ crucible_downstairs : run_opts. crucible_downstairs ( ) ?,
244+ base_propolis : run_opts. base_propolis ( ) ,
245+ tmp_directory : unshared_tmp_dir,
246+ artifact_directory : unshared_artifacts_dir,
247+ artifact_toml : run_opts. artifact_toml_path . clone ( ) ,
248+ server_log_mode : run_opts. server_logging_mode ,
249+ default_guest_cpus : run_opts. default_guest_cpus ,
250+ default_guest_memory_mib : run_opts. default_guest_memory_mib ,
251+ default_guest_os_artifact : run_opts
252+ . default_guest_artifact
253+ . clone ( ) ,
254+ default_bootrom_artifact : run_opts
255+ . default_bootrom_artifact
256+ . clone ( ) ,
257+ port_range,
258+ max_buildomat_wait : Duration :: from_secs (
259+ run_opts. max_buildomat_wait_secs ,
260+ ) ,
261+ } ;
262+
263+ let ctx = Arc :: new (
264+ Framework :: new ( ctx_params)
265+ . await
266+ . expect ( "should be able to set up a test context" ) ,
267+ ) ;
268+
269+ let fixtures = TestFixtures :: new ( ctx. clone ( ) ) . unwrap ( ) ;
270+ runners. push ( ( ctx, fixtures) ) ;
271+ }
212272 }
213273
214274 // Run the tests and print results.
0 commit comments