@@ -9,9 +9,9 @@ use std::path::{Path, PathBuf};
99
1010#[ cfg_attr( test, automock) ]
1111pub trait PreComputeAppTrait {
12- fn run ( & mut self ) -> Result < ( ) , ReplicateStatusCause > ;
12+ fn run ( & mut self ) -> Result < ( ) , Vec < ReplicateStatusCause > > ;
1313 fn check_output_folder ( & self ) -> Result < ( ) , ReplicateStatusCause > ;
14- fn download_input_files ( & self ) -> Result < ( ) , ReplicateStatusCause > ;
14+ fn download_input_files ( & self ) -> Result < ( ) , Vec < ReplicateStatusCause > > ;
1515 fn save_plain_dataset_file (
1616 & self ,
1717 plain_content : & [ u8 ] ,
@@ -55,17 +55,33 @@ impl PreComputeAppTrait for PreComputeApp {
5555 /// let mut app = PreComputeApp::new("task_id".to_string());
5656 /// app.run();
5757 /// ```
58- fn run ( & mut self ) -> Result < ( ) , ReplicateStatusCause > {
59- // TODO: Collect all errors instead of propagating immediately, and return the list of errors
60- self . pre_compute_args = PreComputeArgs :: read_args ( ) ?;
61- self . check_output_folder ( ) ?;
58+ fn run ( & mut self ) -> Result < ( ) , Vec < ReplicateStatusCause > > {
59+ let ( args, mut exit_causes) = PreComputeArgs :: read_args ( ) ;
60+ self . pre_compute_args = args;
61+
62+ if let Err ( exit_cause) = self . check_output_folder ( ) {
63+ return Err ( vec ! [ exit_cause] ) ;
64+ }
65+
6266 for dataset in self . pre_compute_args . datasets . iter ( ) {
63- let encrypted_content = dataset. download_encrypted_dataset ( & self . chain_task_id ) ?;
64- let plain_content = dataset. decrypt_dataset ( & encrypted_content) ?;
65- self . save_plain_dataset_file ( & plain_content, & dataset. filename ) ?;
67+ if let Err ( exit_cause) = dataset
68+ . download_encrypted_dataset ( & self . chain_task_id )
69+ . and_then ( |encrypted_content| dataset. decrypt_dataset ( & encrypted_content) )
70+ . and_then ( |plain_content| {
71+ self . save_plain_dataset_file ( & plain_content, & dataset. filename )
72+ } )
73+ {
74+ exit_causes. push ( exit_cause) ;
75+ } ;
76+ }
77+ if let Err ( exit_cause) = self . download_input_files ( ) {
78+ exit_causes. extend ( exit_cause) ;
79+ } ;
80+ if !exit_causes. is_empty ( ) {
81+ Err ( exit_causes)
82+ } else {
83+ Ok ( ( ) )
6684 }
67- self . download_input_files ( ) ?;
68- Ok ( ( ) )
6985 }
7086
7187 /// Checks whether the output folder specified in `pre_compute_args` exists.
@@ -105,19 +121,27 @@ impl PreComputeAppTrait for PreComputeApp {
105121 /// This function panics if:
106122 /// - `pre_compute_args` is `None`.
107123 /// - `chain_task_id` is `None`.
108- fn download_input_files ( & self ) -> Result < ( ) , ReplicateStatusCause > {
124+ fn download_input_files ( & self ) -> Result < ( ) , Vec < ReplicateStatusCause > > {
125+ let mut exit_causes: Vec < ReplicateStatusCause > = vec ! [ ] ;
109126 let args = & self . pre_compute_args ;
110127 let chain_task_id: & str = & self . chain_task_id ;
111128
112- for url in & args. input_files {
129+ for ( index , url) in args. input_files . iter ( ) . enumerate ( ) {
113130 info ! ( "Downloading input file [chainTaskId:{chain_task_id}, url:{url}]" ) ;
114131
115132 let filename = sha256 ( url. to_string ( ) ) ;
116133 if download_file ( url, & args. output_dir , & filename) . is_none ( ) {
117- return Err ( ReplicateStatusCause :: PreComputeInputFileDownloadFailed ) ;
134+ exit_causes. push ( ReplicateStatusCause :: PreComputeInputFileDownloadFailed (
135+ index,
136+ ) ) ;
118137 }
119138 }
120- Ok ( ( ) )
139+
140+ if !exit_causes. is_empty ( ) {
141+ Err ( exit_causes)
142+ } else {
143+ Ok ( ( ) )
144+ }
121145 }
122146
123147 /// Saves the decrypted (plain) dataset to disk in the configured output directory.
@@ -293,12 +317,12 @@ mod tests {
293317 let result = app. download_input_files ( ) ;
294318 assert_eq ! (
295319 result. unwrap_err( ) ,
296- ReplicateStatusCause :: PreComputeInputFileDownloadFailed
320+ vec! [ ReplicateStatusCause :: PreComputeInputFileDownloadFailed ( 0 ) ]
297321 ) ;
298322 }
299323
300324 #[ test]
301- fn test_partial_failure_stops_on_first_error ( ) {
325+ fn test_partial_failure_dont_stops_on_first_error ( ) {
302326 let ( _container, json_url, xml_url) = start_container ( ) ;
303327
304328 let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
@@ -307,24 +331,24 @@ mod tests {
307331 vec ! [
308332 & json_url, // This should succeed
309333 "https://invalid-url-that-should-fail.com/file.txt" , // This should fail
310- & xml_url, // This shouldn't be reached
334+ & xml_url, // This should succeed
311335 ] ,
312336 temp_dir. path ( ) . to_str ( ) . unwrap ( ) ,
313337 ) ;
314338
315339 let result = app. download_input_files ( ) ;
316340 assert_eq ! (
317341 result. unwrap_err( ) ,
318- ReplicateStatusCause :: PreComputeInputFileDownloadFailed
342+ vec! [ ReplicateStatusCause :: PreComputeInputFileDownloadFailed ( 1 ) ]
319343 ) ;
320344
321345 // First file should be downloaded with SHA256 filename
322346 let json_hash = sha256 ( json_url) ;
323347 assert ! ( temp_dir. path( ) . join( json_hash) . exists( ) ) ;
324348
325- // Third file should NOT be downloaded (stopped on second failure)
349+ // Third file should be downloaded (not stopped on second failure)
326350 let xml_hash = sha256 ( xml_url) ;
327- assert ! ( ! temp_dir. path( ) . join( xml_hash) . exists( ) ) ;
351+ assert ! ( temp_dir. path( ) . join( xml_hash) . exists( ) ) ;
328352 }
329353 // endregion
330354
0 commit comments