1extern crate alloc;
2
3use alloc::string::{String, ToString};
4use alloc::vec::Vec;
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum SelfCheckStage {
12 RequestPreparation,
14 WireFunctionTest,
16 CapabilityVerification,
18 ResponseValidation,
20}
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case")]
25pub enum SelfCheckStatus {
26 Success,
28 Failure,
30}
31
32#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
34#[serde(deny_unknown_fields)]
35pub struct SelfCheckFailure {
36 pub stage: SelfCheckStage,
38 pub message: String,
40}
41
42#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
47#[serde(deny_unknown_fields)]
48pub struct SelfCheckRequest {
49 pub functions_to_test: Vec<String>,
51 pub initiated_at: i64,
53}
54
55#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(deny_unknown_fields)]
60pub struct SelfCheckResponse {
61 pub status: SelfCheckStatus,
63 pub failures: Vec<SelfCheckFailure>,
65 pub completed_at: i64,
67}
68
69#[derive(Debug, Clone, Error, PartialEq, Eq)]
71pub enum SelfCheckError {
72 #[error("self-check request is empty (no functions to test)")]
73 EmptyRequest,
74
75 #[error(
76 "self-check function list exceeds maximum of {}",
77 crate::limits::IMPLEMENTED_FUNCTIONS_MAX
78 )]
79 TooManyFunctions,
80
81 #[error("invalid timestamp: {0}")]
82 InvalidTimestamp(String),
83
84 #[error("self-check response serialization failed: {0}")]
85 SerializationFailed(String),
86}
87
88impl SelfCheckRequest {
89 pub fn validate(&self) -> Result<(), SelfCheckError> {
91 if self.functions_to_test.is_empty() {
92 return Err(SelfCheckError::EmptyRequest);
93 }
94
95 if self.functions_to_test.len() > crate::limits::IMPLEMENTED_FUNCTIONS_MAX {
96 return Err(SelfCheckError::TooManyFunctions);
97 }
98
99 if self.initiated_at <= 0 {
100 return Err(SelfCheckError::InvalidTimestamp(
101 "initiated_at must be positive".to_string(),
102 ));
103 }
104
105 Ok(())
106 }
107}
108
109impl SelfCheckResponse {
110 pub fn validate(&self) -> Result<(), SelfCheckError> {
112 if self.completed_at <= 0 {
113 return Err(SelfCheckError::InvalidTimestamp(
114 "completed_at must be positive".to_string(),
115 ));
116 }
117
118 if self.failures.len() > crate::limits::IMPLEMENTED_FUNCTIONS_MAX {
119 return Err(SelfCheckError::TooManyFunctions);
120 }
121
122 Ok(())
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use alloc::format;
130 use alloc::vec;
131
132 #[test]
133 fn test_self_check_stage_serde() {
134 let stages = [
135 SelfCheckStage::RequestPreparation,
136 SelfCheckStage::WireFunctionTest,
137 SelfCheckStage::CapabilityVerification,
138 SelfCheckStage::ResponseValidation,
139 ];
140
141 for stage in &stages {
142 let json = serde_json::to_string(stage).unwrap();
143 let deserialized: SelfCheckStage = serde_json::from_str(&json).unwrap();
144 assert_eq!(*stage, deserialized);
145 }
146 }
147
148 #[test]
149 fn test_self_check_status_serde() {
150 let statuses = [SelfCheckStatus::Success, SelfCheckStatus::Failure];
151
152 for status in &statuses {
153 let json = serde_json::to_string(status).unwrap();
154 let deserialized: SelfCheckStatus = serde_json::from_str(&json).unwrap();
155 assert_eq!(*status, deserialized);
156 }
157 }
158
159 #[test]
160 fn test_self_check_failure_serde() {
161 let failure = SelfCheckFailure {
162 stage: SelfCheckStage::WireFunctionTest,
163 message: "test failed".to_string(),
164 };
165
166 let json = serde_json::to_string(&failure).unwrap();
167 let deserialized: SelfCheckFailure = serde_json::from_str(&json).unwrap();
168 assert_eq!(failure, deserialized);
169 }
170
171 #[test]
172 fn test_self_check_failure_deny_unknown_fields() {
173 let json = r#"{"stage":"wire_function_test","message":"test","unknown":"field"}"#;
174 let result: Result<SelfCheckFailure, _> = serde_json::from_str(json);
175 assert!(result.is_err());
176 }
177
178 #[test]
179 fn test_self_check_request_valid() {
180 let request = SelfCheckRequest {
181 functions_to_test: vec!["route".to_string(), "observe".to_string()],
182 initiated_at: 1000,
183 };
184 assert!(request.validate().is_ok());
185 }
186
187 #[test]
188 fn test_self_check_request_empty() {
189 let request = SelfCheckRequest {
190 functions_to_test: vec![],
191 initiated_at: 1000,
192 };
193 assert_eq!(request.validate(), Err(SelfCheckError::EmptyRequest));
194 }
195
196 #[test]
197 fn test_self_check_request_too_many_functions() {
198 let mut functions = Vec::new();
199 for i in 0..=crate::limits::IMPLEMENTED_FUNCTIONS_MAX {
200 functions.push(format!("func_{}", i));
201 }
202
203 let request = SelfCheckRequest {
204 functions_to_test: functions,
205 initiated_at: 1000,
206 };
207 assert_eq!(request.validate(), Err(SelfCheckError::TooManyFunctions));
208 }
209
210 #[test]
211 fn test_self_check_request_invalid_timestamp() {
212 let request = SelfCheckRequest {
213 functions_to_test: vec!["route".to_string()],
214 initiated_at: 0,
215 };
216 assert!(request.validate().is_err());
217
218 let request2 = SelfCheckRequest {
219 functions_to_test: vec!["route".to_string()],
220 initiated_at: -100,
221 };
222 assert!(request2.validate().is_err());
223 }
224
225 #[test]
226 fn test_self_check_request_serde() {
227 let request = SelfCheckRequest {
228 functions_to_test: vec!["route".to_string(), "observe".to_string()],
229 initiated_at: 1234567890,
230 };
231
232 let json = serde_json::to_string(&request).unwrap();
233 let deserialized: SelfCheckRequest = serde_json::from_str(&json).unwrap();
234 assert_eq!(request, deserialized);
235 }
236
237 #[test]
238 fn test_self_check_request_deny_unknown_fields() {
239 let json = r#"{"functions_to_test":["route"],"initiated_at":1000,"unknown":"field"}"#;
240 let result: Result<SelfCheckRequest, _> = serde_json::from_str(json);
241 assert!(result.is_err());
242 }
243
244 #[test]
245 fn test_self_check_response_success() {
246 let response = SelfCheckResponse {
247 status: SelfCheckStatus::Success,
248 failures: vec![],
249 completed_at: 2000,
250 };
251 assert!(response.validate().is_ok());
252 }
253
254 #[test]
255 fn test_self_check_response_with_failures() {
256 let response = SelfCheckResponse {
257 status: SelfCheckStatus::Failure,
258 failures: vec![SelfCheckFailure {
259 stage: SelfCheckStage::WireFunctionTest,
260 message: "function not found".to_string(),
261 }],
262 completed_at: 2000,
263 };
264 assert!(response.validate().is_ok());
265 }
266
267 #[test]
268 fn test_self_check_response_invalid_timestamp() {
269 let response = SelfCheckResponse {
270 status: SelfCheckStatus::Success,
271 failures: vec![],
272 completed_at: 0,
273 };
274 assert!(response.validate().is_err());
275 }
276
277 #[test]
278 fn test_self_check_response_serde() {
279 let response = SelfCheckResponse {
280 status: SelfCheckStatus::Success,
281 failures: vec![],
282 completed_at: 1234567890,
283 };
284
285 let json = serde_json::to_string(&response).unwrap();
286 let deserialized: SelfCheckResponse = serde_json::from_str(&json).unwrap();
287 assert_eq!(response, deserialized);
288 }
289
290 #[test]
291 fn test_self_check_response_deny_unknown_fields() {
292 let json = r#"{"status":"success","failures":[],"completed_at":2000,"unknown":"field"}"#;
293 let result: Result<SelfCheckResponse, _> = serde_json::from_str(json);
294 assert!(result.is_err());
295 }
296
297 #[test]
298 fn test_status_snake_case_names() {
299 assert_eq!(
300 serde_json::to_string(&SelfCheckStatus::Success).unwrap(),
301 "\"success\""
302 );
303 assert_eq!(
304 serde_json::to_string(&SelfCheckStatus::Failure).unwrap(),
305 "\"failure\""
306 );
307 }
308
309 #[test]
310 fn test_stage_snake_case_names() {
311 assert_eq!(
312 serde_json::to_string(&SelfCheckStage::RequestPreparation).unwrap(),
313 "\"request_preparation\""
314 );
315 assert_eq!(
316 serde_json::to_string(&SelfCheckStage::WireFunctionTest).unwrap(),
317 "\"wire_function_test\""
318 );
319 }
320}