1use serde::{Deserialize, Serialize};
2use uuid::Uuid;
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
20pub struct Message {
21 pub id: Uuid,
23 pub body: String,
25 pub state: MessageState,
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub lock_until: Option<u64>,
30 pub retry_count: u32,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
58#[serde(rename_all = "PascalCase")]
59pub enum MessageState {
60 Ready,
62 Processing,
64}
65
66impl Message {
67 pub fn new(body: String) -> Self {
91 Self {
92 id: Uuid::now_v7(),
93 body,
94 state: MessageState::Ready,
95 lock_until: None,
96 retry_count: 0,
97 }
98 }
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
106pub struct QueueStats {
107 pub ready: u64,
109 pub processing: u64,
111 pub dead: u64,
113}
114
115#[derive(Debug, Serialize)]
119pub struct AddMessageRequest {
120 pub body: String,
121}
122
123#[derive(Debug, Serialize)]
125pub struct GetMessagesRequest {
126 pub count: u32,
127}
128
129#[derive(Debug, Serialize)]
131pub struct DeleteMessagesRequest {
132 pub ids: Vec<Uuid>,
133}
134
135#[derive(Debug, Serialize)]
137pub struct RetryMessagesRequest {
138 pub ids: Vec<Uuid>,
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use serde_json;
145
146 #[test]
147 fn test_message_creation() {
148 let message = Message::new("Test message".to_string());
149
150 assert_eq!(message.body, "Test message");
151 assert_eq!(message.state, MessageState::Ready);
152 assert_eq!(message.retry_count, 0);
153
154 assert!(!message.id.to_string().is_empty());
156 }
157
158 #[test]
159 fn test_message_state_serialization() {
160 assert_eq!(
162 serde_json::to_string(&MessageState::Ready).unwrap(),
163 "\"Ready\""
164 );
165 assert_eq!(
166 serde_json::to_string(&MessageState::Processing).unwrap(),
167 "\"Processing\""
168 );
169 }
170
171 #[test]
172 fn test_message_state_deserialization() {
173 assert_eq!(
175 serde_json::from_str::<MessageState>("\"Ready\"").unwrap(),
176 MessageState::Ready
177 );
178 assert_eq!(
179 serde_json::from_str::<MessageState>("\"Processing\"").unwrap(),
180 MessageState::Processing
181 );
182 }
183
184 #[test]
185 fn test_message_state_invalid_deserialization() {
186 let result = serde_json::from_str::<MessageState>("\"Invalid\"");
188 assert!(result.is_err());
189
190 let result = serde_json::from_str::<MessageState>("\"ready\""); assert!(result.is_err());
192
193 let result = serde_json::from_str::<MessageState>("\"READY\""); assert!(result.is_err());
195 }
196
197 #[test]
198 fn test_message_serialization() {
199 let message = Message::new("test body".to_string());
200
201 let json = serde_json::to_string(&message).unwrap();
202
203 assert!(json.contains("\"id\":"));
205 assert!(json.contains("\"body\":\"test body\""));
206 assert!(json.contains("\"state\":\"Ready\""));
207 assert!(json.contains("\"retry_count\":0"));
208
209 let deserialized: Message = serde_json::from_str(&json).unwrap();
211 assert_eq!(deserialized.body, message.body);
212 assert_eq!(deserialized.state, message.state);
213 assert_eq!(deserialized.retry_count, message.retry_count);
214 assert_eq!(deserialized.id, message.id);
215 }
216
217 #[test]
218 fn test_message_with_special_characters() {
219 let special_body = "Test with 🦀 emojis and \"quotes\" and \n newlines \t tabs";
220 let message = Message::new(special_body.to_string());
221
222 assert_eq!(message.body, special_body);
223
224 let json = serde_json::to_string(&message).unwrap();
226 let deserialized: Message = serde_json::from_str(&json).unwrap();
227 assert_eq!(deserialized.body, special_body);
228 }
229
230 #[test]
231 fn test_message_with_very_long_body() {
232 let long_body = "a".repeat(100_000);
233 let message = Message::new(long_body.clone());
234
235 assert_eq!(message.body, long_body);
236 assert_eq!(message.body.len(), 100_000);
237 }
238
239 #[test]
240 fn test_message_with_empty_body() {
241 let message = Message::new("".to_string());
242
243 assert_eq!(message.body, "");
244 assert_eq!(message.state, MessageState::Ready);
245 assert_eq!(message.retry_count, 0);
246 }
247
248 #[test]
249 fn test_request_response_structures() {
250 let add_req = AddMessageRequest {
252 body: "test message".to_string(),
253 };
254 let json = serde_json::to_string(&add_req).unwrap();
255 assert!(json.contains("\"body\":\"test message\""));
256
257 let get_req = GetMessagesRequest { count: 5 };
259 let json = serde_json::to_string(&get_req).unwrap();
260 assert!(json.contains("\"count\":5"));
261
262 use uuid::Uuid;
264 let id1 = Uuid::now_v7();
265 let id2 = Uuid::now_v7();
266 let delete_req = DeleteMessagesRequest {
267 ids: vec![id1, id2],
268 };
269 let json = serde_json::to_string(&delete_req).unwrap();
270 assert!(json.contains("\"ids\":"));
271
272 let retry_req = RetryMessagesRequest { ids: vec![id1] };
274 let json = serde_json::to_string(&retry_req).unwrap();
275 assert!(json.contains("\"ids\":"));
276 }
277
278 #[test]
279 fn test_response_deserialization() {
280 let message_json = r#"{"id":"0198fbd8-344e-7b70-841f-3fbd4b371e4c","body":"test","state":"Ready","lock_until":null,"retry_count":0}"#;
282 let message: Message = serde_json::from_str(message_json).unwrap();
283 assert_eq!(message.body, "test");
284 assert_eq!(message.state, MessageState::Ready);
285 assert_eq!(message.retry_count, 0);
286 assert_eq!(message.lock_until, None);
287
288 let messages_json = r#"[{"id":"0198fbd8-344e-7b70-841f-3fbd4b371e4c","body":"test1","state":"Processing","lock_until":null,"retry_count":1}]"#;
290 let messages: Vec<Message> = serde_json::from_str(messages_json).unwrap();
291 assert_eq!(messages.len(), 1);
292 assert_eq!(messages[0].body, "test1");
293 assert_eq!(messages[0].state, MessageState::Processing);
294
295 let locked_json = r#"{"id":"0198fbd8-344e-7b70-841f-3fbd4b371e4c","body":"locked","state":"Processing","lock_until":1700000000000,"retry_count":1}"#;
297 let locked: Message = serde_json::from_str(locked_json).unwrap();
298 assert_eq!(locked.lock_until, Some(1700000000000u64));
299 assert_eq!(locked.state, MessageState::Processing);
300
301 let success_response: String = serde_json::from_str(r#""Success""#).unwrap();
303 assert_eq!(success_response, "Success");
304
305 let health_response: String = serde_json::from_str(r#""Hello World""#).unwrap();
307 assert_eq!(health_response, "Hello World");
308 }
309
310 #[test]
311 fn test_malformed_response_deserialization() {
312 let malformed_json = r#"{"id": invalid}"#;
314 let result = serde_json::from_str::<Message>(malformed_json);
315 assert!(result.is_err());
316
317 let incomplete_json = r#"{"id":"0198fbd8-344e-7b70-841f-3fbd4b371e4c","body":"test"}"#; let result = serde_json::from_str::<Message>(incomplete_json);
320 assert!(result.is_err());
321
322 let wrong_type_json = r#"{"id":"0198fbd8-344e-7b70-841f-3fbd4b371e4c","body":"test","state":"Ready","retry_count":"not_a_number"}"#;
324 let result = serde_json::from_str::<Message>(wrong_type_json);
325 assert!(result.is_err());
326
327 let bad_uuid_json = r#"{"id":"invalid-uuid","body":"test","state":"Ready","lock_until":null,"retry_count":0}"#;
329 let result = serde_json::from_str::<Message>(bad_uuid_json);
330 assert!(result.is_err()); let bad_array_json = r#"[{"id":"invalid"}]"#;
334 let result = serde_json::from_str::<Vec<Message>>(bad_array_json);
335 assert!(result.is_err());
336 }
337
338 #[test]
339 fn test_queue_stats_deserialization() {
340 let json = r#"{"ready":10,"processing":5,"dead":2}"#;
341 let stats: QueueStats = serde_json::from_str(json).unwrap();
342 assert_eq!(stats.ready, 10);
343 assert_eq!(stats.processing, 5);
344 assert_eq!(stats.dead, 2);
345 }
346
347 #[test]
348 fn test_queue_stats_serialization() {
349 let stats = QueueStats {
350 ready: 3,
351 processing: 1,
352 dead: 0,
353 };
354 let json = serde_json::to_string(&stats).unwrap();
355 let deserialized: QueueStats = serde_json::from_str(&json).unwrap();
356 assert_eq!(stats, deserialized);
357 }
358}