1crate::ix!();
3
4impl BatchFileTriple {
5
6 pub async fn move_input_and_output_to_done(
7 &self,
8 ) -> Result<(), FileMoveError> {
9
10 let done_dir = self.get_done_directory();
11 self.maybe_move_input_to_done(&done_dir).await?;
12 self.maybe_move_output_to_done(&done_dir).await?;
13 self.maybe_move_metadata_to_done(&done_dir).await?;
14 Ok(())
15 }
16
17 pub async fn move_input_and_error_to_done(
18 &self,
19 ) -> Result<(), FileMoveError> {
20
21 let done_dir = self.get_done_directory();
22 self.maybe_move_input_to_done(&done_dir).await?;
23 self.maybe_move_error_to_done(&done_dir).await?;
24 self.maybe_move_metadata_to_done(&done_dir).await?;
25 Ok(())
26 }
27
28 pub async fn move_all_to_done(
29 &self,
30 ) -> Result<(), FileMoveError> {
31
32 let done_dir = self.get_done_directory();
33 self.maybe_move_input_to_done(&done_dir).await?;
34 self.maybe_move_output_to_done(&done_dir).await?;
35 self.maybe_move_error_to_done(&done_dir).await?;
36 self.maybe_move_metadata_to_done(&done_dir).await?;
37 Ok(())
38 }
39
40 async fn maybe_move_input_to_done(
42 &self,
43 done_dir: impl AsRef<Path>,
44 ) -> Result<(), FileMoveError> {
45
46 tokio::fs::create_dir_all(done_dir.as_ref()).await.ok();
48
49 if let Some(input_path) = self.input() {
50 if !input_path.exists() {
51 if is_test_mode() {
52 warn!(
53 "Mock scenario (test-only): ignoring rename for missing input file at {:?}",
54 input_path
55 );
56 return Ok(());
57 }
58 }
59 let dest = done_dir.as_ref().join(input_path.file_name().unwrap());
60 trace!("Renaming input_path: {:?} => {:?}", input_path, dest);
61 fs::rename(input_path, &dest).await?;
62 info!("moved batch input file to the done directory");
63 }
64 Ok(())
65 }
66
67 async fn maybe_move_output_to_done(
68 &self,
69 done_dir: impl AsRef<Path>,
70 ) -> Result<(), FileMoveError> {
71
72 tokio::fs::create_dir_all(done_dir.as_ref()).await.ok();
74
75 if let Some(output_path) = self.output() {
76 if !output_path.exists() {
77 if is_test_mode() {
78 warn!(
79 "Mock scenario (test-only): ignoring rename for missing output file at {:?}",
80 output_path
81 );
82 return Ok(());
83 }
84 }
85 let dest = done_dir.as_ref().join(output_path.file_name().unwrap());
86 trace!("Renaming output_path: {:?} => {:?}", output_path, dest);
87 fs::rename(output_path, &dest).await?;
88 info!("moved batch output file to the done directory");
89 }
90 Ok(())
91 }
92
93 async fn maybe_move_error_to_done(
94 &self,
95 done_dir: impl AsRef<Path>,
96 ) -> Result<(), FileMoveError> {
97
98 tokio::fs::create_dir_all(done_dir.as_ref()).await.ok();
100
101 if let Some(error_path) = self.error() {
102 if !error_path.exists() {
103 if is_test_mode() {
104 warn!(
105 "Mock scenario (test-only): ignoring rename for missing error file at {:?}",
106 error_path
107 );
108 return Ok(());
109 }
110 }
111 let dest = done_dir.as_ref().join(error_path.file_name().unwrap());
112 trace!("Renaming error_path: {:?} => {:?}", error_path, dest);
113 fs::rename(error_path, &dest).await?;
114 info!("moved batch error file to the done directory");
115 }
116 Ok(())
117 }
118
119 async fn maybe_move_metadata_to_done(
120 &self,
121 done_dir: impl AsRef<Path>,
122 ) -> Result<(), FileMoveError> {
123
124 tokio::fs::create_dir_all(done_dir.as_ref()).await.ok();
126
127 if let Some(metadata_path) = self.associated_metadata() {
128 if !metadata_path.exists() {
129 if is_test_mode() {
130 warn!(
131 "Mock scenario (test-only): ignoring rename for missing metadata file at {:?}",
132 metadata_path
133 );
134 return Ok(());
135 }
136 }
137 let dest = done_dir.as_ref().join(metadata_path.file_name().unwrap());
138 trace!("Renaming metadata_path: {:?} => {:?}", metadata_path, dest);
139 fs::rename(metadata_path, &dest).await?;
140 info!("moved batch metadata file to the done directory");
141 }
142 Ok(())
143 }
144}
145
146#[cfg(test)]
147mod batch_file_triple_moving_files_exhaustive_tests {
148 use super::*;
149 use tempfile::{NamedTempFile, TempDir};
150 use std::io::Write;
151 use tokio::runtime::Runtime;
152 use tracing::*;
153
154 #[traced_test]
155 async fn move_input_and_output_to_done_moves_correct_files() {
156 trace!("===== BEGIN TEST: move_input_and_output_to_done_moves_correct_files =====");
157 info!("Starting test: move_input_and_output_to_done_moves_correct_files");
158
159 let workspace = MockBatchWorkspace::default();
161 let batch_idx = BatchIndex::Usize(42);
162
163 let input_path = workspace.input_filename(&batch_idx);
165 std::fs::write(&input_path, "fake input contents")
166 .expect("Failed to write to input file");
167
168 let output_path = workspace.output_filename(&batch_idx);
169 std::fs::write(&output_path, "fake output contents")
170 .expect("Failed to write to output file");
171
172 let metadata_path = workspace.metadata_filename(&batch_idx);
173 std::fs::write(&metadata_path, "fake metadata contents")
174 .expect("Failed to write to metadata file");
175
176 let triple = BatchFileTriple::new_direct(
178 &batch_idx,
179 Some(input_path.clone()),
180 Some(output_path.clone()),
181 None,
182 Some(metadata_path.clone()),
183 Arc::new(workspace.clone()),
184 );
185
186 let result = triple.move_input_and_output_to_done().await;
187 debug!("Result of move_input_and_output_to_done: {:?}", result);
188 assert!(
189 result.is_ok(),
190 "Expected success moving input + output to done"
191 );
192
193 assert!(!input_path.exists(), "Input file should have been moved away");
195 assert!(!output_path.exists(), "Output file should have been moved away");
196 assert!(
197 !metadata_path.exists(),
198 "Metadata file should have been moved away"
199 );
200
201 let done_dir = workspace.get_done_directory();
203 trace!("Done directory is: {:?}", done_dir);
204
205 let done_input = done_dir.join(input_path.file_name().unwrap());
206 let done_output = done_dir.join(output_path.file_name().unwrap());
207 let done_metadata = done_dir.join(metadata_path.file_name().unwrap());
208
209 assert!(
210 done_input.exists(),
211 "Input file must be in done directory"
212 );
213 assert!(
214 done_output.exists(),
215 "Output file must be in done directory"
216 );
217 assert!(
218 done_metadata.exists(),
219 "Metadata file must be in done directory"
220 );
221
222 info!("Finished test: move_input_and_output_to_done_moves_correct_files");
223 trace!("===== END TEST: move_input_and_output_to_done_moves_correct_files =====");
224 }
225
226 #[traced_test]
227 async fn move_input_and_error_to_done_moves_correct_files() {
228 trace!("===== BEGIN TEST: move_input_and_error_to_done_moves_correct_files =====");
229 info!("Starting test: move_input_and_error_to_done_moves_correct_files");
230
231 let workspace = MockBatchWorkspace::default();
232 let batch_idx = BatchIndex::Usize(777);
233
234 let input_path = workspace.input_filename(&batch_idx);
235 std::fs::write(&input_path, "fake input contents")
236 .expect("Failed to write to input file");
237
238 let error_path = workspace.error_filename(&batch_idx);
239 std::fs::write(&error_path, "fake error contents")
240 .expect("Failed to write to error file");
241
242 let metadata_path = workspace.metadata_filename(&batch_idx);
243 std::fs::write(&metadata_path, "fake metadata contents")
244 .expect("Failed to write to metadata file");
245
246 let triple = BatchFileTriple::new_direct(
247 &batch_idx,
248 Some(input_path.clone()),
249 None,
250 Some(error_path.clone()),
251 Some(metadata_path.clone()),
252 Arc::new(workspace.clone()),
253 );
254
255 let result = triple.move_input_and_error_to_done().await;
256 debug!("Result of move_input_and_error_to_done: {:?}", result);
257 assert!(
258 result.is_ok(),
259 "Expected success moving input + error to done"
260 );
261
262 assert!(!input_path.exists(), "Input file should have been moved away");
263 assert!(!error_path.exists(), "Error file should have been moved away");
264 assert!(
265 !metadata_path.exists(),
266 "Metadata file should have been moved away"
267 );
268
269 let done_dir = workspace.get_done_directory();
270 trace!("Done directory is: {:?}", done_dir);
271
272 let done_input = done_dir.join(input_path.file_name().unwrap());
273 let done_error = done_dir.join(error_path.file_name().unwrap());
274 let done_metadata = done_dir.join(metadata_path.file_name().unwrap());
275
276 assert!(
277 done_input.exists(),
278 "Input file must be in done directory"
279 );
280 assert!(
281 done_error.exists(),
282 "Error file must be in done directory"
283 );
284 assert!(
285 done_metadata.exists(),
286 "Metadata file must be in done directory"
287 );
288
289 info!("Finished test: move_input_and_error_to_done_moves_correct_files");
290 trace!("===== END TEST: move_input_and_error_to_done_moves_correct_files =====");
291 }
292
293 #[traced_test]
294 async fn move_all_to_done_moves_input_output_error_and_metadata() {
295 trace!("===== BEGIN TEST: move_all_to_done_moves_input_output_error_and_metadata =====");
296 info!("Starting test: move_all_to_done_moves_input_output_error_and_metadata");
297
298 let workspace = MockBatchWorkspace::default();
299 let batch_idx = BatchIndex::Usize(5);
300
301 let input_path = workspace.input_filename(&batch_idx);
302 std::fs::write(&input_path, "some input content")
303 .expect("Failed to write to input file");
304
305 let output_path = workspace.output_filename(&batch_idx);
306 std::fs::write(&output_path, "some output content")
307 .expect("Failed to write to output file");
308
309 let error_path = workspace.error_filename(&batch_idx);
310 std::fs::write(&error_path, "some error content")
311 .expect("Failed to write to error file");
312
313 let metadata_path = workspace.metadata_filename(&batch_idx);
314 std::fs::write(&metadata_path, "some metadata content")
315 .expect("Failed to write to metadata file");
316
317 let triple = BatchFileTriple::new_direct(
318 &batch_idx,
319 Some(input_path.clone()),
320 Some(output_path.clone()),
321 Some(error_path.clone()),
322 Some(metadata_path.clone()),
323 Arc::new(workspace.clone()),
324 );
325
326 debug!("Constructed triple for test: {:?}", triple);
327
328 let result = triple.move_all_to_done().await;
329 debug!("Result of move_all_to_done: {:?}", result);
330 assert!(
331 result.is_ok(),
332 "Expected success moving all files to done"
333 );
334
335 assert!(!input_path.exists(), "Input file should be moved away");
336 assert!(!output_path.exists(), "Output file should be moved away");
337 assert!(!error_path.exists(), "Error file should be moved away");
338 assert!(
339 !metadata_path.exists(),
340 "Metadata file should be moved away"
341 );
342
343 let done_dir = workspace.get_done_directory();
344 trace!("Done directory is: {:?}", done_dir);
345
346 let done_input = done_dir.join(input_path.file_name().unwrap());
347 let done_output = done_dir.join(output_path.file_name().unwrap());
348 let done_error = done_dir.join(error_path.file_name().unwrap());
349 let done_metadata = done_dir.join(metadata_path.file_name().unwrap());
350
351 assert!(done_input.exists(), "Input must be in done directory now");
352 assert!(done_output.exists(), "Output must be in done directory now");
353 assert!(done_error.exists(), "Error must be in done directory now");
354 assert!(
355 done_metadata.exists(),
356 "Metadata must be in done directory now"
357 );
358
359 info!("Finished test: move_all_to_done_moves_input_output_error_and_metadata");
360 trace!("===== END TEST: move_all_to_done_moves_input_output_error_and_metadata =====");
361 }
362}