rocketmq_remoting/protocol/header/
query_message_response_header.rs1use rocketmq_macros::RequestHeaderCodecV2;
16use serde::Deserialize;
17use serde::Serialize;
18
19#[derive(Debug, Clone, Serialize, Deserialize, RequestHeaderCodecV2, Default, PartialEq)]
20#[serde(rename_all = "camelCase")]
21pub struct QueryMessageResponseHeader {
22 pub index_last_update_timestamp: i64,
23 pub index_last_update_phyoffset: i64,
24}
25
26#[cfg(test)]
27mod tests {
28 use std::collections::HashMap;
29 use std::mem;
30
31 use crate::protocol::remoting_command::RemotingCommand;
32 use crate::CommandCustomHeader;
33 use cheetah_string::CheetahString;
34
35 use super::*;
36
37 #[test]
38 fn explicit_construction_sets_fields_correctly() {
39 let header = QueryMessageResponseHeader {
40 index_last_update_timestamp: 10,
41 index_last_update_phyoffset: 20,
42 };
43
44 assert_eq!(header.index_last_update_timestamp, 10);
45 assert_eq!(header.index_last_update_phyoffset, 20);
46 }
47
48 #[test]
49 fn query_message_response_header_default_values_are_zero() {
50 let header = QueryMessageResponseHeader::default();
51
52 assert_eq!(header.index_last_update_timestamp, 0);
53 assert_eq!(header.index_last_update_phyoffset, 0);
54 }
55
56 #[test]
57 fn clone_creates_independent_copy() {
58 let original = QueryMessageResponseHeader {
59 index_last_update_timestamp: 100,
60 index_last_update_phyoffset: 200,
61 };
62
63 let mut cloned = original.clone();
64 cloned.index_last_update_timestamp = 999;
65
66 assert_eq!(original.index_last_update_timestamp, 100);
67 assert_eq!(cloned.index_last_update_timestamp, 999);
68
69 assert_eq!(cloned.index_last_update_phyoffset, 200);
70 }
71
72 #[test]
73 fn debug_format_contains_field_names_and_values() {
74 let header = QueryMessageResponseHeader {
75 index_last_update_timestamp: 1,
76 index_last_update_phyoffset: 2,
77 };
78
79 let debug_output = format!("{:?}", header);
80
81 assert!(debug_output.contains("index_last_update_timestamp"));
82 assert!(debug_output.contains("index_last_update_phyoffset"));
83 assert!(debug_output.contains("1"));
84 assert!(debug_output.contains("2"));
85 }
86
87 #[test]
88 fn timestamp_with_positive_value() {
89 let header = QueryMessageResponseHeader {
90 index_last_update_phyoffset: 0,
91 index_last_update_timestamp: 42,
92 };
93
94 assert_eq!(header.index_last_update_timestamp, 42);
95
96 let map = header.to_map().unwrap();
97
98 assert_eq!(
99 map.get(&CheetahString::from_static_str("indexLastUpdateTimestamp"))
100 .unwrap(),
101 "42"
102 );
103 }
104
105 #[test]
106 fn timestamp_with_zero() {
107 let header = QueryMessageResponseHeader {
108 index_last_update_timestamp: 0,
109 index_last_update_phyoffset: 0,
110 };
111
112 let map = header.to_map().unwrap();
113
114 assert_eq!(
115 map.get(&CheetahString::from_static_str("indexLastUpdateTimestamp"))
116 .unwrap(),
117 "0"
118 );
119 }
120
121 #[test]
122 fn timestamp_with_negative_value() {
123 let header = QueryMessageResponseHeader {
124 index_last_update_timestamp: -456,
125 index_last_update_phyoffset: 0,
126 };
127
128 let map = header.to_map().unwrap();
129
130 assert_eq!(
131 map.get(&CheetahString::from_static_str("indexLastUpdateTimestamp"))
132 .unwrap(),
133 "-456"
134 );
135 }
136
137 #[test]
138 fn timestamp_with_i64_min() {
139 let header = QueryMessageResponseHeader {
140 index_last_update_timestamp: i64::MIN,
141 index_last_update_phyoffset: 0,
142 };
143
144 let map = header.to_map().unwrap();
145
146 assert_eq!(
147 map.get(&CheetahString::from_static_str("indexLastUpdateTimestamp"))
148 .unwrap()
149 .to_string(),
150 i64::MIN.to_string()
151 );
152 }
153
154 #[test]
155 fn phyoffset_with_positive_value() {
156 let header = QueryMessageResponseHeader {
157 index_last_update_phyoffset: 123,
158 index_last_update_timestamp: 0,
159 };
160
161 let map = header.to_map().unwrap();
162
163 assert_eq!(
164 map.get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
165 .unwrap(),
166 "123"
167 );
168 }
169
170 #[test]
171 fn phyoffset_with_zero() {
172 let header = QueryMessageResponseHeader {
173 index_last_update_phyoffset: 0,
174 index_last_update_timestamp: 0,
175 };
176
177 let map = header.to_map().unwrap();
178
179 assert_eq!(
180 map.get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
181 .unwrap(),
182 "0"
183 );
184 }
185
186 #[test]
187 fn phyoffset_with_negative_value() {
188 let header = QueryMessageResponseHeader {
189 index_last_update_phyoffset: -456,
190 index_last_update_timestamp: 0,
191 };
192
193 let map = header.to_map().unwrap();
194
195 assert_eq!(
196 map.get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
197 .unwrap(),
198 "-456"
199 );
200 }
201
202 #[test]
203 fn phyoffset_with_i64_min() {
204 let header = QueryMessageResponseHeader {
205 index_last_update_phyoffset: i64::MIN,
206 index_last_update_timestamp: 0,
207 };
208
209 let map = header.to_map().unwrap();
210
211 assert_eq!(
212 map.get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
213 .unwrap()
214 .to_string(),
215 i64::MIN.to_string()
216 );
217 }
218
219 #[test]
220 fn phyoffset_with_i64_max() {
221 let header = QueryMessageResponseHeader {
222 index_last_update_phyoffset: i64::MAX,
223 index_last_update_timestamp: 0,
224 };
225
226 let map = header.to_map().unwrap();
227
228 assert_eq!(
229 map.get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
230 .unwrap()
231 .to_string(),
232 i64::MAX.to_string()
233 );
234 }
235
236 #[test]
237 fn serde_json_serialization() {
238 let header = QueryMessageResponseHeader {
239 index_last_update_timestamp: 131415,
240 index_last_update_phyoffset: 131496,
241 };
242
243 let json = serde_json::to_string(&header).unwrap();
244 assert_eq!(
245 json,
246 r#"{"indexLastUpdateTimestamp":131415,"indexLastUpdatePhyoffset":131496}"#
247 );
248 }
249
250 #[test]
251 fn serde_json_deserialization() {
252 let json = r#"{"indexLastUpdateTimestamp":131415,"indexLastUpdatePhyoffset":131496}"#;
253 let header: QueryMessageResponseHeader = serde_json::from_str(json).unwrap();
254
255 assert_eq!(header.index_last_update_timestamp, 131415);
256 assert_eq!(header.index_last_update_phyoffset, 131496);
257 }
258
259 #[test]
260 fn serde_json_round_trip() {
261 let header = QueryMessageResponseHeader {
262 index_last_update_timestamp: 131415,
263 index_last_update_phyoffset: 131496,
264 };
265
266 let json = serde_json::to_string(&header).unwrap();
267 let deserialized_header: QueryMessageResponseHeader = serde_json::from_str(&json).unwrap();
268
269 assert_eq!(header, deserialized_header);
270 }
271
272 #[test]
273 fn serde_json_deserialization_with_missing_fields() {
274 let json = "{}";
275 let result: Result<QueryMessageResponseHeader, _> = serde_json::from_str(json);
276 assert!(result.is_err());
277 }
278
279 #[test]
280 fn serde_json_deserialization_with_extra_fields() {
281 let json = r#"{"indexLastUpdateTimestamp":131415,"indexLastUpdatePhyoffset":131496,"extraField":"extraValue"}"#;
282 let header: QueryMessageResponseHeader = serde_json::from_str(json).unwrap();
283
284 assert_eq!(header.index_last_update_timestamp, 131415);
285 assert_eq!(header.index_last_update_phyoffset, 131496);
286 }
287
288 #[test]
289 fn test_encoding_of_the_header_to_remoting_command_format() {
290 let header = QueryMessageResponseHeader {
291 index_last_update_timestamp: 131415,
292 index_last_update_phyoffset: 131496,
293 };
294
295 let mut command = RemotingCommand::default();
296 command.set_command_custom_header_ref(header);
297 command.make_custom_header_to_net();
298
299 let ext_fields = command.ext_fields().unwrap();
300
301 assert_eq!(
302 ext_fields
303 .get(&CheetahString::from_static_str("indexLastUpdateTimestamp"))
304 .unwrap(),
305 "131415"
306 );
307 assert_eq!(
308 ext_fields
309 .get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
310 .unwrap(),
311 "131496"
312 )
313 }
314
315 #[test]
316 fn test_decoding_of_the_header_from_remoting_command_format() {
317 let mut command = RemotingCommand::default().set_ext_fields(HashMap::new());
318 command.add_ext_field("indexLastUpdateTimestamp", "131415");
319 command.add_ext_field("indexLastUpdatePhyoffset", "131496");
320
321 let header: QueryMessageResponseHeader = command.decode_command_custom_header().unwrap();
322
323 assert_eq!(header.index_last_update_timestamp, 131415);
324 assert_eq!(header.index_last_update_phyoffset, 131496);
325 }
326
327 #[test]
328 fn test_codec_compatibility_with_query_message_response() {
329 let mut command = RemotingCommand::default().set_ext_fields(HashMap::new());
330 command.add_ext_field("indexLastUpdateTimestamp", "131415");
331 command.add_ext_field("indexLastUpdatePhyoffset", "131496");
332
333 let header_fast: QueryMessageResponseHeader = command.decode_command_custom_header_fast().unwrap();
334
335 let header_normal: QueryMessageResponseHeader = command.decode_command_custom_header().unwrap();
336
337 assert_eq!(header_fast, header_normal);
338 assert_eq!(header_fast.index_last_update_timestamp, 131415);
339 assert_eq!(header_fast.index_last_update_phyoffset, 131496);
340 }
341 #[test]
342 fn test_codec_behavior_with_various_timestamp_and_offset_values() {
343 let test_cases = vec![
344 (0, 0),
345 (-1, -1),
346 (i64::MAX, i64::MAX),
347 (i64::MIN, i64::MIN),
348 (1234567890, 987654321),
349 (-1234567890, -987654321),
350 ];
351
352 for (timestamp, offset) in test_cases {
353 let mut command = RemotingCommand::default().set_ext_fields(HashMap::new());
354 command.add_ext_field("indexLastUpdateTimestamp", timestamp.to_string());
355 command.add_ext_field("indexLastUpdatePhyoffset", offset.to_string());
356
357 let header: QueryMessageResponseHeader = command.decode_command_custom_header_fast().unwrap();
358
359 assert_eq!(header.index_last_update_timestamp, timestamp);
360 assert_eq!(header.index_last_update_phyoffset, offset);
361 }
362 }
363
364 #[test]
365 fn query_message_response_header_deserialization_malformed_json() {
366 let json = r#"{"indexLastUpdateTimestamp":"not_a_number"}"#;
367 let result: Result<QueryMessageResponseHeader, _> = serde_json::from_str(json);
368 assert!(result.is_err());
369 }
370
371 #[test]
372 fn query_message_response_header_deserialization_with_wrong_data_type_for_timestamp() {
373 let json = r#"{"indexLastUpdateTimestamp":true,"indexLastUpdatePhyoffset":131496}"#;
374 let result: Result<QueryMessageResponseHeader, _> = serde_json::from_str(json);
375 assert!(result.is_err());
376 }
377
378 #[test]
379 fn query_message_response_header_deserialization_with_wrong_data_type_for_phyoffset() {
380 let json = r#"{"indexLastUpdateTimestamp":131415,"indexLastUpdatePhyoffset":"string_instead_of_number"}"#;
381 let result: Result<QueryMessageResponseHeader, _> = serde_json::from_str(json);
382 assert!(result.is_err());
383 }
384
385 #[test]
386 fn query_message_response_header_struct_size() {
387 assert_eq!(mem::size_of::<QueryMessageResponseHeader>(), 16);
389 }
390
391 #[test]
392 fn test_compatibility_with_brokers_query_message_processor_usage() {
393 let header = QueryMessageResponseHeader {
394 index_last_update_timestamp: 123456789,
395 index_last_update_phyoffset: 987654321,
396 };
397
398 let mut command = RemotingCommand::create_response_command_with_header(header);
399 command.make_custom_header_to_net();
400
401 let ext_fields = command.ext_fields().unwrap();
402 assert_eq!(
403 ext_fields
404 .get(&CheetahString::from_static_str("indexLastUpdateTimestamp"))
405 .unwrap(),
406 "123456789"
407 );
408 assert_eq!(
409 ext_fields
410 .get(&CheetahString::from_static_str("indexLastUpdatePhyoffset"))
411 .unwrap(),
412 "987654321"
413 );
414 }
415
416 #[test]
417 fn test_usage_in_remoting_command_create_response_command_with_header() {
418 let header = QueryMessageResponseHeader {
419 index_last_update_timestamp: 11111,
420 index_last_update_phyoffset: 22222,
421 };
422
423 let command = RemotingCommand::create_response_command_with_header(header);
424
425 let extracted_header = command.read_custom_header_ref::<QueryMessageResponseHeader>().unwrap();
426
427 assert_eq!(extracted_header.index_last_update_timestamp, 11111);
428 assert_eq!(extracted_header.index_last_update_phyoffset, 22222);
429 }
430
431 #[test]
432 fn test_read_custom_header_mut_integration() {
433 let header = QueryMessageResponseHeader {
434 index_last_update_timestamp: 100,
435 index_last_update_phyoffset: 200,
436 };
437
438 let mut command = RemotingCommand::create_response_command_with_header(header);
439
440 if let Some(mut_header) = command.read_custom_header_mut::<QueryMessageResponseHeader>() {
441 mut_header.index_last_update_timestamp = 300;
442 mut_header.index_last_update_phyoffset = 400;
443 }
444
445 let extracted_header = command.read_custom_header_ref::<QueryMessageResponseHeader>().unwrap();
446 assert_eq!(extracted_header.index_last_update_timestamp, 300);
447 assert_eq!(extracted_header.index_last_update_phyoffset, 400);
448 }
449
450 #[test]
451 fn test_default_usage_in_response_creation() {
452 let header = QueryMessageResponseHeader::default();
453 let mut command = RemotingCommand::create_response_command_with_header(header);
454
455 let extracted_header = command.read_custom_header_ref::<QueryMessageResponseHeader>().unwrap();
456 assert_eq!(extracted_header.index_last_update_timestamp, 0);
457 assert_eq!(extracted_header.index_last_update_phyoffset, 0);
458
459 if let Some(mut_header) = command.read_custom_header_mut::<QueryMessageResponseHeader>() {
460 mut_header.index_last_update_timestamp = 1314;
461 }
462
463 let updated_header = command.read_custom_header_ref::<QueryMessageResponseHeader>().unwrap();
464 assert_eq!(updated_header.index_last_update_timestamp, 1314);
465 assert_eq!(updated_header.index_last_update_phyoffset, 0);
466 }
467
468 #[test]
470 fn test_both_fields_set_to_same_value() {
471 let header = QueryMessageResponseHeader {
472 index_last_update_timestamp: 12345,
473 index_last_update_phyoffset: 12345,
474 };
475 assert_eq!(header.index_last_update_timestamp, header.index_last_update_phyoffset);
476 }
477
478 #[test]
479 fn test_timestamp_greater_than_phyoffset_normal_case() {
480 let header = QueryMessageResponseHeader {
481 index_last_update_timestamp: 1684300000000,
482 index_last_update_phyoffset: 50000,
483 };
484 assert!(header.index_last_update_timestamp > header.index_last_update_phyoffset);
485 }
486
487 #[test]
488 fn test_timestamp_less_than_phyoffset() {
489 let header = QueryMessageResponseHeader {
490 index_last_update_timestamp: 1000,
491 index_last_update_phyoffset: 999999999,
492 };
493 assert!(header.index_last_update_timestamp < header.index_last_update_phyoffset);
494 }
495
496 #[test]
497 fn test_both_fields_set_to_zero_initial_state() {
498 let header = QueryMessageResponseHeader {
499 index_last_update_timestamp: 0,
500 index_last_update_phyoffset: 0,
501 };
502 assert_eq!(header.index_last_update_timestamp, 0);
503 assert_eq!(header.index_last_update_phyoffset, 0);
504
505 let default_header = QueryMessageResponseHeader::default();
506 assert_eq!(header, default_header);
507 }
508
509 #[test]
510 fn test_updating_index_last_update_timestamp_after_creation() {
511 let mut header = QueryMessageResponseHeader {
512 index_last_update_timestamp: 100,
513 index_last_update_phyoffset: 0,
514 };
515
516 header.index_last_update_timestamp = 500;
517 assert_eq!(header.index_last_update_timestamp, 500);
518 assert_eq!(header.index_last_update_phyoffset, 0);
519 }
520
521 #[test]
522 fn test_updating_index_last_update_phyoffset_after_creation() {
523 let mut header = QueryMessageResponseHeader {
524 index_last_update_timestamp: 0,
525 index_last_update_phyoffset: 200,
526 };
527
528 header.index_last_update_phyoffset = 800;
529 assert_eq!(header.index_last_update_phyoffset, 800);
530 assert_eq!(header.index_last_update_timestamp, 0);
531 }
532
533 #[test]
534 fn test_updating_both_fields_simultaneously() {
535 let mut header = QueryMessageResponseHeader {
536 index_last_update_timestamp: 10,
537 index_last_update_phyoffset: 20,
538 };
539
540 header.index_last_update_timestamp = 999;
541 header.index_last_update_phyoffset = 888;
542
543 assert_eq!(header.index_last_update_timestamp, 999);
544 assert_eq!(header.index_last_update_phyoffset, 888);
545 }
546}