@@ -12,7 +12,7 @@ use futures::StreamExt;
1212use rayon:: prelude:: { IntoParallelRefIterator , ParallelIterator } ;
1313use running:: blocking_run_from_test;
1414use serde:: Deserialize ;
15- use tokio:: sync:: mpsc:: channel;
15+ use tokio:: sync:: mpsc:: { channel, Sender } ;
1616
1717use std:: sync:: Arc ;
1818use test_case_summary:: TestCaseSummary ;
@@ -366,7 +366,7 @@ pub async fn run(
366366 . await ?;
367367
368368 fuzzing_happened |= was_fuzzed;
369- summaries. push ( summary. clone ( ) ) ;
369+ summaries. push ( summary) ;
370370 }
371371
372372 pretty_printing:: print_test_summary ( & summaries) ;
@@ -397,6 +397,17 @@ async fn run_tests_from_crate(
397397 let mut tasks = FuturesUnordered :: new ( ) ;
398398 let test_cases = & tests. test_cases ;
399399
400+ // Initiate two channels to manage the `--exit-first` flag.
401+ // Owing to `cheatnet` fork's utilization of its own Tokio runtime for RPC requests,
402+ // test execution must occur within a `tokio::spawn_blocking`.
403+ // As `spawn_blocking` can't be prematurely cancelled (refer: https://dtantsur.github.io/rust-openstack/tokio/task/fn.spawn_blocking.html),
404+ // a channel is used to signal the task that test processing is no longer necessary.
405+ let ( send, mut rec) = channel ( 1 ) ;
406+
407+ // The second channel serves as a hold point to ensure all tasks complete
408+ // their shutdown procedures before moving forward (more info: https://tokio.rs/tokio/topics/shutdown)
409+ let ( send_shut_down, mut rec_shut_down) = channel ( 1 ) ;
410+
400411 for case in test_cases. iter ( ) {
401412 let case_name = case. name . as_str ( ) ;
402413
@@ -414,6 +425,8 @@ async fn run_tests_from_crate(
414425 runner_config. clone ( ) ,
415426 runner_params. clone ( ) ,
416427 cancellation_tokens. clone ( ) ,
428+ & send,
429+ & send_shut_down,
417430 ) ) ;
418431 }
419432
@@ -431,6 +444,12 @@ async fn run_tests_from_crate(
431444 results. push ( result) ;
432445 }
433446
447+ rec. close ( ) ;
448+
449+ // Waiting for things to finish shutting down
450+ drop ( send_shut_down) ;
451+ let _ = rec_shut_down. recv ( ) . await ;
452+
434453 Ok ( (
435454 TestCrateSummary {
436455 test_case_summaries : results,
@@ -441,13 +460,16 @@ async fn run_tests_from_crate(
441460 ) )
442461}
443462
463+ #[ allow( clippy:: too_many_arguments) ]
444464fn choose_test_strategy_and_run (
445465 args : Vec < ConcreteTypeId > ,
446466 case : Arc < TestCase > ,
447467 runner : Arc < SierraCasmRunner > ,
448468 runner_config : Arc < RunnerConfig > ,
449469 runner_params : Arc < RunnerParams > ,
450470 cancellation_tokens : Arc < CancellationTokens > ,
471+ send : & Sender < ( ) > ,
472+ send_shut_down : & Sender < ( ) > ,
451473) -> JoinHandle < Result < TestCaseSummary > > {
452474 if args. is_empty ( ) {
453475 run_single_test (
@@ -456,6 +478,8 @@ fn choose_test_strategy_and_run(
456478 runner_config,
457479 runner_params,
458480 cancellation_tokens,
481+ send. clone ( ) ,
482+ send_shut_down. clone ( ) ,
459483 )
460484 } else {
461485 run_with_fuzzing (
@@ -465,6 +489,7 @@ fn choose_test_strategy_and_run(
465489 runner_config,
466490 runner_params,
467491 cancellation_tokens,
492+ send_shut_down. clone ( ) ,
468493 )
469494 }
470495}
@@ -475,6 +500,8 @@ fn run_single_test(
475500 runner_config : Arc < RunnerConfig > ,
476501 runner_params : Arc < RunnerParams > ,
477502 cancellation_tokens : Arc < CancellationTokens > ,
503+ send : Sender < ( ) > ,
504+ send_shut_down : Sender < ( ) > ,
478505) -> JoinHandle < Result < TestCaseSummary > > {
479506 let exit_first = runner_config. exit_first ;
480507 tokio:: task:: spawn ( async move {
@@ -489,8 +516,8 @@ fn run_single_test(
489516 // one of a test returns Err
490517 Ok ( TestCaseSummary :: Interrupted { } )
491518 } ,
492- result = blocking_run_from_test( vec![ ] , case. clone( ) , runner, runner_config. clone( ) , runner_params. clone( ) , None ) => {
493- match result {
519+ result = blocking_run_from_test( vec![ ] , case. clone( ) , runner, runner_config. clone( ) , runner_params. clone( ) , send . clone ( ) , send_shut_down . clone ( ) ) => {
520+ match result? {
494521 Ok ( result) => {
495522 if exit_first {
496523 if let TestCaseSummary :: Failed { .. } = & result {
@@ -516,10 +543,11 @@ fn run_with_fuzzing(
516543 runner_config : Arc < RunnerConfig > ,
517544 runner_params : Arc < RunnerParams > ,
518545 cancellation_tokens : Arc < CancellationTokens > ,
546+ send_shut_down : Sender < ( ) > ,
519547) -> JoinHandle < Result < TestCaseSummary > > {
520548 tokio:: task:: spawn ( async move {
521549 let token = CancellationToken :: new ( ) ;
522-
550+ let ( send , mut rec ) = channel ( 1 ) ;
523551 let args = args
524552 . iter ( )
525553 . map ( |arg| {
@@ -540,9 +568,6 @@ fn run_with_fuzzing(
540568 let mut fuzzer = RandomFuzzer :: create ( fuzzer_seed, fuzzer_runs, & args) ?;
541569
542570 let mut tasks = FuturesUnordered :: new ( ) ;
543- // Pattern in order to waiting for things to finish shutting down
544- // https://tokio.rs/tokio/topics/shutdown
545- let ( send, mut recv) = channel ( 1 ) ;
546571
547572 for _ in 1 ..=fuzzer_runs {
548573 let args = fuzzer. next_args ( ) ;
@@ -556,14 +581,12 @@ fn run_with_fuzzing(
556581 cancellation_tokens. clone ( ) ,
557582 token. clone ( ) ,
558583 send. clone ( ) ,
584+ send_shut_down. clone ( ) ,
559585 ) ) ;
560586 }
561587
562588 let mut results = vec ! [ ] ;
563589
564- // Graceful Shutdown Pattern
565- drop ( send) ;
566-
567590 while let Some ( task) = tasks. next ( ) . await {
568591 let result = task??;
569592 results. push ( result. clone ( ) ) ;
@@ -576,7 +599,7 @@ fn run_with_fuzzing(
576599 }
577600 }
578601
579- let _ = recv . recv ( ) . await ;
602+ rec . close ( ) ;
580603
581604 let runs = u32:: try_from (
582605 results
@@ -627,7 +650,8 @@ fn run_fuzzing_subtest(
627650 runner_params : Arc < RunnerParams > ,
628651 cancellation_tokens : Arc < CancellationTokens > ,
629652 cancellation_fuzzing_token : CancellationToken ,
630- send : tokio:: sync:: mpsc:: Sender < ( ) > ,
653+ send : Sender < ( ) > ,
654+ send_shut_down : Sender < ( ) > ,
631655) -> JoinHandle < Result < TestCaseSummary > > {
632656 let c = case. clone ( ) ;
633657 task:: spawn ( async move {
@@ -654,9 +678,10 @@ fn run_fuzzing_subtest(
654678 runner,
655679 runner_config. clone( ) ,
656680 runner_params. clone( ) ,
657- Some ( send) ,
681+ send. clone( ) ,
682+ send_shut_down. clone( )
658683 ) => {
659- match result {
684+ match result? {
660685 Ok ( result) => {
661686 if let TestCaseSummary :: Failed { .. } = & result {
662687 if runner_config. exit_first {
0 commit comments