@@ -5,6 +5,7 @@ use crate::ops;
5
5
use crate :: util:: errors:: CargoResult ;
6
6
use crate :: util:: { add_path_args, CargoTestError , Config , Test } ;
7
7
use cargo_util:: ProcessError ;
8
+ use crossbeam_utils:: thread;
8
9
use std:: ffi:: OsString ;
9
10
10
11
pub struct TestOptions {
@@ -76,63 +77,85 @@ fn run_unit_tests(
76
77
compilation : & Compilation < ' _ > ,
77
78
) -> CargoResult < ( Test , Vec < ProcessError > ) > {
78
79
let cwd = config. cwd ( ) ;
79
- let mut errors = Vec :: new ( ) ;
80
+ let mut errors: Vec < ( TargetKind , String , String , anyhow :: Error ) > = Vec :: new ( ) ;
80
81
81
- for UnitOutput {
82
- unit,
83
- path,
84
- script_meta,
85
- } in compilation. tests . iter ( )
86
- {
87
- let test = unit. target . name ( ) . to_string ( ) ;
82
+ thread:: scope ( |s| {
83
+ let mut handles = vec ! [ ] ;
84
+ let parallel = true ;
88
85
89
- let test_path = unit. target . src_path ( ) . path ( ) . unwrap ( ) ;
90
- let exe_display = if let TargetKind :: Test = unit. target . kind ( ) {
91
- format ! (
92
- "{} ({})" ,
93
- test_path
94
- . strip_prefix( unit. pkg. root( ) )
95
- . unwrap_or( test_path)
96
- . display( ) ,
97
- path. strip_prefix( cwd) . unwrap_or( path) . display( )
98
- )
99
- } else {
100
- format ! (
101
- "unittests ({})" ,
102
- path. strip_prefix( cwd) . unwrap_or( path) . display( )
103
- )
104
- } ;
86
+ for UnitOutput {
87
+ unit,
88
+ path,
89
+ script_meta,
90
+ } in compilation. tests . iter ( )
91
+ {
92
+ let test_path = unit. target . src_path ( ) . path ( ) . unwrap ( ) ;
93
+ let exe_display = if let TargetKind :: Test = unit. target . kind ( ) {
94
+ format ! (
95
+ "{} ({})" ,
96
+ test_path
97
+ . strip_prefix( unit. pkg. root( ) )
98
+ . unwrap_or( test_path)
99
+ . display( ) ,
100
+ path. strip_prefix( cwd) . unwrap_or( path) . display( )
101
+ )
102
+ } else {
103
+ format ! (
104
+ "unittests ({})" ,
105
+ path. strip_prefix( cwd) . unwrap_or( path) . display( )
106
+ )
107
+ } ;
105
108
106
- let mut cmd = compilation. target_process ( path, unit. kind , & unit. pkg , * script_meta) ?;
107
- cmd. args ( test_args) ;
108
- if unit. target . harness ( ) && config. shell ( ) . verbosity ( ) == Verbosity :: Quiet {
109
- cmd. arg ( "--quiet" ) ;
110
- }
111
- config
112
- . shell ( )
113
- . concise ( |shell| shell. status ( "Running" , & exe_display) ) ?;
114
- config
115
- . shell ( )
116
- . verbose ( |shell| shell. status ( "Running" , & cmd) ) ?;
109
+ let mut cmd = compilation. target_process ( & path, unit. kind , & unit. pkg , * script_meta) ?;
110
+ cmd. args ( test_args) ;
111
+ if unit. target . harness ( ) && config. shell ( ) . verbosity ( ) == Verbosity :: Quiet {
112
+ cmd. arg ( "--quiet" ) ;
113
+ }
114
+ config
115
+ . shell ( )
116
+ . concise ( |shell| shell. status ( "Running" , & exe_display) ) ?;
117
+ config
118
+ . shell ( )
119
+ . verbose ( |shell| shell. status ( "Running" , & cmd) ) ?;
117
120
118
- let result = cmd. exec ( ) ;
121
+ let pkg_name = unit. pkg . name ( ) . to_string ( ) ;
122
+ let target = & unit. target ;
123
+ let handle = s. spawn ( move |_| {
124
+ cmd. exec ( ) . map_err ( |e| {
125
+ (
126
+ target. kind ( ) . clone ( ) ,
127
+ target. name ( ) . to_string ( ) ,
128
+ pkg_name,
129
+ e,
130
+ )
131
+ } )
132
+ } ) ;
133
+ if parallel {
134
+ handles. push ( handle) ;
135
+ } else {
136
+ let result = handle. join ( ) . unwrap ( ) ;
137
+ if let Err ( err) = result {
138
+ errors. push ( err) ;
139
+ if !options. no_fail_fast {
140
+ break ;
141
+ }
142
+ }
143
+ }
144
+ }
119
145
120
- match result {
121
- Err ( e) => {
122
- let e = e. downcast :: < ProcessError > ( ) ?;
123
- errors. push ( (
124
- unit. target . kind ( ) . clone ( ) ,
125
- test. clone ( ) ,
126
- unit. pkg . name ( ) . to_string ( ) ,
127
- e,
128
- ) ) ;
146
+ for handle in handles {
147
+ let result = handle. join ( ) . unwrap ( ) ;
148
+ if let Err ( err) = result {
149
+ errors. push ( err) ;
129
150
if !options. no_fail_fast {
130
- break ;
151
+ break ; // TODO: we can be clever than this
131
152
}
132
153
}
133
- Ok ( ( ) ) => { }
134
154
}
135
- }
155
+ let out: Result < ( ) , anyhow:: Error > = Ok ( ( ) ) ;
156
+ out
157
+ } )
158
+ . unwrap ( ) ?;
136
159
137
160
if errors. len ( ) == 1 {
138
161
let ( kind, name, pkg_name, e) = errors. pop ( ) . unwrap ( ) ;
@@ -142,13 +165,14 @@ fn run_unit_tests(
142
165
name,
143
166
pkg_name,
144
167
} ,
145
- vec ! [ e] ,
168
+ vec ! [ e. downcast :: < ProcessError > ( ) ? ] ,
146
169
) )
147
170
} else {
148
- Ok ( (
149
- Test :: Multiple ,
150
- errors. into_iter ( ) . map ( |( _, _, _, e) | e) . collect ( ) ,
151
- ) )
171
+ let mut res = vec ! [ ] ;
172
+ for ( _, _, _, e) in errors. into_iter ( ) {
173
+ res. push ( e. downcast :: < ProcessError > ( ) ?) ;
174
+ }
175
+ Ok ( ( Test :: Multiple , res) )
152
176
}
153
177
}
154
178
0 commit comments