batch_mode_batch_metadata/
metadata.rs1crate::ix!();
3
4#[derive(Builder,Debug,Clone,Serialize,Deserialize)]
5#[builder(setter(into))]
6pub struct BatchMetadata {
7 batch_id: String,
8 input_file_id: String,
9
10 #[builder(default)]
11 output_file_id: Option<String>,
12
13 #[builder(default)]
14 error_file_id: Option<String>,
15}
16
17impl BatchMetadata {
18
19 pub fn with_input_id_and_batch_id(input_id: &str, batch_id: &str) -> Self {
20 Self {
21 batch_id: batch_id.to_string(),
22 input_file_id: input_id.to_string(),
23 output_file_id: None,
24 error_file_id: None,
25 }
26 }
27
28 pub fn batch_id(&self) -> &str {
29 &self.batch_id
30 }
31
32 pub fn input_file_id(&self) -> &str {
33 self.input_file_id.as_ref()
34 }
35
36 pub fn output_file_id(&self) -> Result<&str,BatchMetadataError> {
37 let output_file_id = self.output_file_id.as_ref()
38 .ok_or(BatchMetadataError::MissingOutputFileId)?;
39 Ok(output_file_id)
40 }
41
42 pub fn error_file_id(&self) -> Result<&str,BatchMetadataError> {
43 let error_file_id = self.error_file_id.as_ref()
44 .ok_or(BatchMetadataError::MissingErrorFileId)?;
45 Ok(error_file_id)
46 }
47
48 pub fn set_output_file_id(&mut self, new_id: Option<String>) {
49 self.output_file_id = new_id;
50 }
51
52 pub fn set_error_file_id(&mut self, new_id: Option<String>) {
53 self.error_file_id = new_id;
54 }
55}
56
57#[async_trait]
58impl SaveToFile for BatchMetadata {
59
60 type Error = BatchMetadataError;
61
62 async fn save_to_file(
63 &self,
64 metadata_filename: impl AsRef<Path> + Send,
65
66 ) -> Result<(), Self::Error> {
67
68 info!("saving batch metadata to file {:?}", metadata_filename.as_ref());
69
70 let metadata_json = serde_json::to_string(&self)?;
71
72 std::fs::write(metadata_filename, metadata_json)?;
73
74 Ok(())
75 }
76}
77
78#[async_trait]
79impl LoadFromFile for BatchMetadata {
80
81 type Error = BatchMetadataError;
82
83 async fn load_from_file(metadata_filename: impl AsRef<Path> + Send)
84 -> Result<Self, Self::Error>
85 {
86 info!("loading batch metadata from file {:?}", metadata_filename.as_ref());
87
88 let metadata_json = std::fs::read_to_string(metadata_filename)?;
89 let metadata = serde_json::from_str(&metadata_json)?;
90
91 Ok(metadata)
92 }
93}
94
95#[cfg(test)]
96mod batch_metadata_exhaustive_tests {
97 use super::*;
98
99 #[traced_test]
100 fn with_input_id_and_batch_id_sets_expected_fields() {
101 trace!("===== BEGIN TEST: with_input_id_and_batch_id_sets_expected_fields =====");
102 let input_id = "some_input_id";
103 let batch_id = "some_batch_id";
104 let metadata = BatchMetadata::with_input_id_and_batch_id(input_id, batch_id);
105 debug!("Constructed metadata: {:?}", metadata);
106
107 pretty_assert_eq!(
108 metadata.batch_id(),
109 batch_id,
110 "batch_id should match the provided value"
111 );
112 pretty_assert_eq!(
113 metadata.input_file_id(),
114 input_id,
115 "input_file_id should match the provided value"
116 );
117 assert!(metadata.output_file_id.is_none(), "output_file_id should be None initially");
118 assert!(metadata.error_file_id.is_none(), "error_file_id should be None initially");
119
120 trace!("===== END TEST: with_input_id_and_batch_id_sets_expected_fields =====");
121 }
122
123 #[traced_test]
124 fn set_output_file_id_and_retrieve_it_successfully() {
125 trace!("===== BEGIN TEST: set_output_file_id_and_retrieve_it_successfully =====");
126 let mut metadata = BatchMetadata::with_input_id_and_batch_id("input_1", "batch_1");
127 let new_output_id = Some("output_file_xyz".to_string());
128 trace!("Assigning output_file_id={:?}", new_output_id);
129 metadata.set_output_file_id(new_output_id);
130
131 match metadata.output_file_id() {
132 Ok(id) => {
133 debug!("Retrieved output_file_id: {}", id);
134 pretty_assert_eq!(id, "output_file_xyz");
135 },
136 Err(_) => {
137 error!("Expected output_file_id to be set, but got an error");
138 panic!("Mismatch in output_file_id retrieval");
139 }
140 }
141 trace!("===== END TEST: set_output_file_id_and_retrieve_it_successfully =====");
142 }
143
144 #[traced_test]
145 fn set_output_file_id_to_none_and_verify_error() {
146 trace!("===== BEGIN TEST: set_output_file_id_to_none_and_verify_error =====");
147 let mut metadata = BatchMetadata::with_input_id_and_batch_id("input_2", "batch_2");
148 metadata.set_output_file_id(None);
149 trace!("Set output_file_id to None");
150
151 let result = metadata.output_file_id();
152 debug!("Attempting to retrieve output_file_id -> {:?}", result);
153 assert!(result.is_err(), "Should fail when output_file_id is None");
154 trace!("===== END TEST: set_output_file_id_to_none_and_verify_error =====");
155 }
156
157 #[traced_test]
158 fn set_error_file_id_and_retrieve_it_successfully() {
159 trace!("===== BEGIN TEST: set_error_file_id_and_retrieve_it_successfully =====");
160 let mut metadata = BatchMetadata::with_input_id_and_batch_id("input_3", "batch_3");
161 let new_error_id = Some("error_file_abc".to_string());
162 trace!("Assigning error_file_id={:?}", new_error_id);
163 metadata.set_error_file_id(new_error_id);
164
165 match metadata.error_file_id() {
166 Ok(id) => {
167 debug!("Retrieved error_file_id: {}", id);
168 pretty_assert_eq!(id, "error_file_abc");
169 },
170 Err(_) => {
171 error!("Expected error_file_id to be set, but got an error");
172 panic!("Mismatch in error_file_id retrieval");
173 }
174 }
175 trace!("===== END TEST: set_error_file_id_and_retrieve_it_successfully =====");
176 }
177
178 #[traced_test]
179 fn set_error_file_id_to_none_and_verify_error() {
180 trace!("===== BEGIN TEST: set_error_file_id_to_none_and_verify_error =====");
181 let mut metadata = BatchMetadata::with_input_id_and_batch_id("input_4", "batch_4");
182 metadata.set_error_file_id(None);
183 trace!("Set error_file_id to None");
184
185 let result = metadata.error_file_id();
186 debug!("Attempting to retrieve error_file_id -> {:?}", result);
187 assert!(result.is_err(), "Should fail when error_file_id is None");
188 trace!("===== END TEST: set_error_file_id_to_none_and_verify_error =====");
189 }
190
191 #[traced_test]
192 async fn save_to_file_and_load_from_file_round_trip() -> Result<(),BatchMetadataError> {
193
194 trace!("===== BEGIN TEST: save_to_file_and_load_from_file_round_trip =====");
195
196 let temp_dir = std::env::temp_dir();
198 let filename = temp_dir.join("test_batch_metadata.json");
199 debug!("Temporary file for metadata: {:?}", filename);
200
201 let mut original = BatchMetadata::with_input_id_and_batch_id("in_10", "batch_10");
202 original.set_output_file_id(Some("out_10".into()));
203 original.set_error_file_id(Some("err_10".into()));
204 trace!("Original metadata: {:?}", original);
205
206 let save_res = original.save_to_file(&filename).await;
208 debug!("save_to_file result: {:?}", save_res);
209 assert!(save_res.is_ok(), "Saving metadata should succeed");
210
211 let loaded = BatchMetadata::load_from_file(&filename).await
213 .expect("Loading metadata from file should succeed");
214 debug!("Loaded metadata: {:?}", loaded);
215
216 if let Err(e) = fs::remove_file(&filename).await {
218 warn!("Failed to remove temp file: {:?}", e);
219 }
220
221 pretty_assert_eq!(loaded.batch_id(), original.batch_id());
223 pretty_assert_eq!(loaded.input_file_id(), original.input_file_id());
224 pretty_assert_eq!(loaded.output_file_id().unwrap(), original.output_file_id().unwrap());
226 pretty_assert_eq!(loaded.error_file_id().unwrap(), original.error_file_id().unwrap());
227
228 trace!("===== END TEST: save_to_file_and_load_from_file_round_trip =====");
229 Ok(())
230 }
231}