@@ -3,8 +3,9 @@ use clap::{CommandFactory, Parser, Subcommand};
3
3
use slog:: { Drain , Level , Logger } ;
4
4
use slog_scope:: { error, info, warn} ;
5
5
use std:: {
6
- fs,
6
+ fmt , fs,
7
7
path:: { Path , PathBuf } ,
8
+ process:: { ExitCode , Termination } ,
8
9
sync:: Arc ,
9
10
time:: Duration ,
10
11
} ;
@@ -18,6 +19,7 @@ use mithril_common::StdResult;
18
19
use mithril_doc:: GenerateDocCommands ;
19
20
use mithril_end_to_end:: {
20
21
Devnet , DevnetBootstrapArgs , MithrilInfrastructure , MithrilInfrastructureConfig , RunOnly , Spec ,
22
+ UnrecoverableDevnetError ,
21
23
} ;
22
24
23
25
/// Tests args
@@ -152,8 +154,16 @@ enum EndToEndCommands {
152
154
GenerateDoc ( GenerateDocCommands ) ,
153
155
}
154
156
155
- #[ tokio:: main]
156
- async fn main ( ) -> StdResult < ( ) > {
157
+ fn main ( ) -> AppResult {
158
+ tokio:: runtime:: Builder :: new_multi_thread ( )
159
+ . enable_all ( )
160
+ . build ( )
161
+ . unwrap ( )
162
+ . block_on ( async { main_exec ( ) . await } )
163
+ . into ( )
164
+ }
165
+
166
+ async fn main_exec ( ) -> StdResult < ( ) > {
157
167
let args = Args :: parse ( ) ;
158
168
let _guard = slog_scope:: set_global_logger ( build_logger ( & args) ) ;
159
169
@@ -198,9 +208,66 @@ async fn main() -> StdResult<()> {
198
208
199
209
app_stopper. stop ( ) . await ;
200
210
join_set. shutdown ( ) . await ;
211
+
201
212
res
202
213
}
203
214
215
+ #[ derive( Debug ) ]
216
+ enum AppResult {
217
+ Success ( ) ,
218
+ UnretryableError ( anyhow:: Error ) ,
219
+ RetryableError ( anyhow:: Error ) ,
220
+ }
221
+
222
+ impl AppResult {
223
+ fn exit_code ( & self ) -> ExitCode {
224
+ match self {
225
+ AppResult :: Success ( ) => ExitCode :: SUCCESS ,
226
+ AppResult :: UnretryableError ( _) => ExitCode :: FAILURE ,
227
+ AppResult :: RetryableError ( _) => ExitCode :: from ( 2 ) ,
228
+ }
229
+ }
230
+ }
231
+
232
+ impl fmt:: Display for AppResult {
233
+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
234
+ match self {
235
+ AppResult :: Success ( ) => write ! ( f, "Success" ) ,
236
+ AppResult :: UnretryableError ( error) => write ! ( f, "Error(Unretryable): {error:?}" ) ,
237
+ AppResult :: RetryableError ( error) => write ! ( f, "Error(Retryable): {error:?}" ) ,
238
+ }
239
+ }
240
+ }
241
+
242
+ impl Termination for AppResult {
243
+ fn report ( self ) -> ExitCode {
244
+ let exit_code = self . exit_code ( ) ;
245
+ println ! ( " " ) ;
246
+ println ! ( "----------------------------------------------------------------------------------------------------" ) ;
247
+ println ! ( "Mithril End to End test outcome:" ) ;
248
+ println ! ( "----------------------------------------------------------------------------------------------------" ) ;
249
+ println ! ( "{self}" ) ;
250
+ println ! ( "{exit_code:?}" ) ;
251
+
252
+ exit_code
253
+ }
254
+ }
255
+
256
+ impl From < StdResult < ( ) > > for AppResult {
257
+ fn from ( result : StdResult < ( ) > ) -> Self {
258
+ match result {
259
+ Ok ( ( ) ) => AppResult :: Success ( ) ,
260
+ Err ( error) => {
261
+ if error. is :: < UnrecoverableDevnetError > ( ) {
262
+ AppResult :: RetryableError ( error)
263
+ } else {
264
+ AppResult :: UnretryableError ( error)
265
+ }
266
+ }
267
+ }
268
+ }
269
+ }
270
+
204
271
struct App {
205
272
devnet : Arc < Mutex < Option < Devnet > > > ,
206
273
infrastructure : Arc < Mutex < Option < MithrilInfrastructure > > > ,
@@ -366,3 +433,49 @@ fn with_gracefull_shutdown(join_set: &mut JoinSet<StdResult<()>>) {
366
433
. inspect ( |( ) | warn ! ( "Received SIGQUIT" ) )
367
434
} ) ;
368
435
}
436
+
437
+ #[ cfg( test) ]
438
+ mod tests {
439
+ use super :: * ;
440
+
441
+ #[ test]
442
+ fn app_result_exit_code ( ) {
443
+ let expected_exit_code = ExitCode :: SUCCESS ;
444
+ let exit_code = AppResult :: Success ( ) . exit_code ( ) ;
445
+ assert_eq ! (
446
+ format!( "{:?}" , expected_exit_code) ,
447
+ format!( "{:?}" , exit_code)
448
+ ) ;
449
+
450
+ let expected_exit_code = ExitCode :: FAILURE ;
451
+ let exit_code = AppResult :: UnretryableError ( anyhow:: anyhow!( "an error" ) ) . exit_code ( ) ;
452
+ assert_eq ! (
453
+ format!( "{:?}" , expected_exit_code) ,
454
+ format!( "{:?}" , exit_code)
455
+ ) ;
456
+
457
+ let expected_exit_code = ExitCode :: from ( 2 ) ;
458
+ let exit_code = AppResult :: RetryableError ( anyhow:: anyhow!( "an error" ) ) . exit_code ( ) ;
459
+ assert_eq ! (
460
+ format!( "{:?}" , expected_exit_code) ,
461
+ format!( "{:?}" , exit_code)
462
+ ) ;
463
+ }
464
+
465
+ #[ test]
466
+ fn app_result_conversion ( ) {
467
+ assert ! ( matches!( AppResult :: from( Ok ( ( ) ) ) , AppResult :: Success ( ) ) ) ;
468
+
469
+ assert ! ( matches!(
470
+ AppResult :: from( Err ( anyhow!( UnrecoverableDevnetError (
471
+ "an error" . to_string( )
472
+ ) ) ) ) ,
473
+ AppResult :: RetryableError ( _)
474
+ ) ) ;
475
+
476
+ assert ! ( matches!(
477
+ AppResult :: from( Err ( anyhow!( "an error" ) ) ) ,
478
+ AppResult :: UnretryableError ( _)
479
+ ) ) ;
480
+ }
481
+ }
0 commit comments