1use cheetah_string::CheetahString;
16use rocketmq_macros::RequestHeaderCodecV2;
17use serde::Deserialize;
18use serde::Serialize;
19
20use crate::rpc::rpc_request_header::RpcRequestHeader;
21
22#[derive(Clone, Debug, Serialize, Deserialize, Default, RequestHeaderCodecV2)]
23#[serde(rename_all = "camelCase")]
24pub struct EndTransactionRequestHeader {
25 #[required]
26 pub topic: CheetahString,
27
28 #[required]
29 pub producer_group: CheetahString,
30
31 #[required]
33 pub tran_state_table_offset: i64,
34
35 #[required]
37 pub commit_log_offset: i64,
38
39 #[required]
41 pub commit_or_rollback: i32,
42
43 #[required]
45 pub from_transaction_check: bool,
46
47 #[required]
48 pub msg_id: CheetahString,
49
50 pub transaction_id: Option<CheetahString>,
51
52 #[serde(flatten)]
53 pub rpc_request_header: RpcRequestHeader,
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn end_transaction_request_header_default() {
62 let header = EndTransactionRequestHeader::default();
63 assert_eq!(header.topic, "");
64 assert_eq!(header.producer_group, "");
65 assert_eq!(header.tran_state_table_offset, 0);
66 assert_eq!(header.commit_log_offset, 0);
67 assert_eq!(header.commit_or_rollback, 0);
68 assert!(!header.from_transaction_check);
69 assert_eq!(header.msg_id, "");
70 assert!(header.transaction_id.is_none());
71 }
72
73 #[test]
74 fn end_transaction_request_header_clone() {
75 let header = EndTransactionRequestHeader {
76 topic: CheetahString::from("topic1"),
77 producer_group: CheetahString::from("group1"),
78 tran_state_table_offset: 123,
79 commit_log_offset: 456,
80 commit_or_rollback: 1,
81 from_transaction_check: true,
82 msg_id: CheetahString::from("msg1"),
83 transaction_id: Some(CheetahString::from("tran1")),
84 rpc_request_header: RpcRequestHeader::default(),
85 };
86 let cloned_header = header.clone();
87 assert_eq!(cloned_header.topic, "topic1");
88 assert_eq!(cloned_header.producer_group, "group1");
89 assert_eq!(cloned_header.tran_state_table_offset, 123);
90 assert_eq!(cloned_header.commit_log_offset, 456);
91 assert_eq!(cloned_header.commit_or_rollback, 1);
92 assert!(cloned_header.from_transaction_check);
93 assert_eq!(cloned_header.msg_id, "msg1");
94 assert_eq!(cloned_header.transaction_id.as_ref().unwrap(), "tran1");
95 }
96
97 #[test]
98 fn end_transaction_request_header_serialization() {
99 let header = EndTransactionRequestHeader {
100 topic: CheetahString::from("topic1"),
101 producer_group: CheetahString::from("group1"),
102 tran_state_table_offset: 123,
103 commit_log_offset: 456,
104 commit_or_rollback: 1,
105 from_transaction_check: true,
106 msg_id: CheetahString::from("msg1"),
107 transaction_id: Some(CheetahString::from("tran1")),
108 rpc_request_header: RpcRequestHeader {
109 broker_name: Some(CheetahString::from("broker1")),
110 ..Default::default()
111 },
112 };
113 let json = serde_json::to_string(&header).unwrap();
114 assert!(json.contains("\"topic\":\"topic1\""));
115 assert!(json.contains("\"producerGroup\":\"group1\""));
116 assert!(json.contains("\"tranStateTableOffset\":123"));
117 assert!(json.contains("\"commitLogOffset\":456"));
118 assert!(json.contains("\"commitOrRollback\":1"));
119 assert!(json.contains("\"fromTransactionCheck\":true"));
120 assert!(json.contains("\"msgId\":\"msg1\""));
121 assert!(json.contains("\"transactionId\":\"tran1\""));
122 assert!(json.contains("\"brokerName\":\"broker1\""));
123 }
124
125 #[test]
126 fn end_transaction_request_header_deserialization() {
127 let json = r#"{"topic":"topic1","producerGroup":"group1","tranStateTableOffset":123,"commitLogOffset":456,"commitOrRollback":1,"fromTransactionCheck":true,"msgId":"msg1","transactionId":"tran1","brokerName":"broker1"}"#;
128 let header: EndTransactionRequestHeader = serde_json::from_str(json).unwrap();
129 assert_eq!(header.topic, "topic1");
130 assert_eq!(header.producer_group, "group1");
131 assert_eq!(header.tran_state_table_offset, 123);
132 assert_eq!(header.commit_log_offset, 456);
133 assert_eq!(header.commit_or_rollback, 1);
134 assert!(header.from_transaction_check);
135 assert_eq!(header.msg_id, "msg1");
136 assert_eq!(header.transaction_id.as_ref().unwrap(), "tran1");
137 assert_eq!(header.rpc_request_header.broker_name.as_ref().unwrap(), "broker1");
138 }
139 #[test]
140 fn end_transaction_request_header_required_fields() {
141 let json = r#"{"topic":"topic1","producerGroup":"group1","tranStateTableOffset":123,"commitLogOffset":456,"commitOrRollback":1,"fromTransactionCheck":true,"msgId":"msg1"}"#;
142 let header: EndTransactionRequestHeader = serde_json::from_str(json).unwrap();
143 assert_eq!(header.topic, "topic1");
144 assert_eq!(header.producer_group, "group1");
145 assert_eq!(header.tran_state_table_offset, 123);
146 assert_eq!(header.commit_log_offset, 456);
147 assert_eq!(header.commit_or_rollback, 1);
148 assert!(header.from_transaction_check);
149 assert_eq!(header.msg_id, "msg1");
150 assert!(header.transaction_id.is_none());
151 }
152
153 #[test]
154 fn end_transaction_request_header_rpc_request_header() {
155 let header = EndTransactionRequestHeader {
156 topic: CheetahString::from("topic1"),
157 producer_group: CheetahString::from("group1"),
158 tran_state_table_offset: 123,
159 commit_log_offset: 456,
160 commit_or_rollback: 1,
161 from_transaction_check: true,
162 msg_id: CheetahString::from("msg1"),
163 transaction_id: Some(CheetahString::from("tran1")),
164 rpc_request_header: RpcRequestHeader {
165 namespace: Some(CheetahString::from("namespace1")),
166 namespaced: Some(true),
167 broker_name: Some(CheetahString::from("broker1")),
168 oneway: Some(false),
169 },
170 };
171 assert_eq!(header.rpc_request_header.namespace.as_ref().unwrap(), "namespace1");
172 assert!(header.rpc_request_header.namespaced.unwrap());
173 assert_eq!(header.rpc_request_header.broker_name.as_ref().unwrap(), "broker1");
174 assert!(!header.rpc_request_header.oneway.unwrap());
175 }
176
177 #[test]
178 fn end_transaction_request_header_to_map() {
179 use crate::protocol::command_custom_header::CommandCustomHeader;
180
181 let header = EndTransactionRequestHeader {
182 topic: CheetahString::from("topic1"),
183 producer_group: CheetahString::from("group1"),
184 tran_state_table_offset: 123,
185 commit_log_offset: 456,
186 commit_or_rollback: 1,
187 from_transaction_check: true,
188 msg_id: CheetahString::from("msg1"),
189 transaction_id: Some(CheetahString::from("tran1")),
190 rpc_request_header: RpcRequestHeader::default(),
191 };
192
193 let map = header.to_map().unwrap();
194 assert_eq!(
195 map.get(&CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC))
196 .unwrap(),
197 "topic1"
198 );
199 assert_eq!(
200 map.get(&CheetahString::from_static_str(
201 EndTransactionRequestHeader::PRODUCER_GROUP
202 ))
203 .unwrap(),
204 "group1"
205 );
206 assert_eq!(
207 map.get(&CheetahString::from_static_str(
208 EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET
209 ))
210 .unwrap(),
211 "123"
212 );
213 assert_eq!(
214 map.get(&CheetahString::from_static_str(
215 EndTransactionRequestHeader::COMMIT_LOG_OFFSET
216 ))
217 .unwrap(),
218 "456"
219 );
220 assert_eq!(
221 map.get(&CheetahString::from_static_str(
222 EndTransactionRequestHeader::COMMIT_OR_ROLLBACK
223 ))
224 .unwrap(),
225 "1"
226 );
227 assert_eq!(
228 map.get(&CheetahString::from_static_str(
229 EndTransactionRequestHeader::FROM_TRANSACTION_CHECK
230 ))
231 .unwrap(),
232 "true"
233 );
234 assert_eq!(
235 map.get(&CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID))
236 .unwrap(),
237 "msg1"
238 );
239 assert_eq!(
240 map.get(&CheetahString::from_static_str(
241 EndTransactionRequestHeader::TRANSACTION_ID
242 ))
243 .unwrap(),
244 "tran1"
245 );
246 }
247
248 #[test]
249 fn end_transaction_request_header_to_map_without_transaction_id() {
250 use crate::protocol::command_custom_header::CommandCustomHeader;
251
252 let header = EndTransactionRequestHeader {
253 topic: CheetahString::from("topic1"),
254 producer_group: CheetahString::from("group1"),
255 tran_state_table_offset: 123,
256 commit_log_offset: 456,
257 commit_or_rollback: 1,
258 from_transaction_check: true,
259 msg_id: CheetahString::from("msg1"),
260 transaction_id: None,
261 rpc_request_header: RpcRequestHeader::default(),
262 };
263
264 let map = header.to_map().unwrap();
265 assert_eq!(
266 map.get(&CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC))
267 .unwrap(),
268 "topic1"
269 );
270 assert!(!map.contains_key(&CheetahString::from_static_str(
271 EndTransactionRequestHeader::TRANSACTION_ID
272 )));
273 }
274
275 #[test]
276 fn end_transaction_request_header_from_map() {
277 use crate::protocol::command_custom_header::FromMap;
278 use std::collections::HashMap;
279
280 let mut map = HashMap::new();
281 map.insert(
282 CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC),
283 CheetahString::from_static_str("topic1"),
284 );
285 map.insert(
286 CheetahString::from_static_str(EndTransactionRequestHeader::PRODUCER_GROUP),
287 CheetahString::from_static_str("group1"),
288 );
289 map.insert(
290 CheetahString::from_static_str(EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET),
291 CheetahString::from_static_str("123"),
292 );
293 map.insert(
294 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_LOG_OFFSET),
295 CheetahString::from_static_str("456"),
296 );
297 map.insert(
298 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_OR_ROLLBACK),
299 CheetahString::from_static_str("1"),
300 );
301 map.insert(
302 CheetahString::from_static_str(EndTransactionRequestHeader::FROM_TRANSACTION_CHECK),
303 CheetahString::from_static_str("true"),
304 );
305 map.insert(
306 CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID),
307 CheetahString::from_static_str("msg1"),
308 );
309 map.insert(
310 CheetahString::from_static_str(EndTransactionRequestHeader::TRANSACTION_ID),
311 CheetahString::from_static_str("tran1"),
312 );
313
314 let header = <EndTransactionRequestHeader as FromMap>::from(&map).unwrap();
315 assert_eq!(header.topic, "topic1");
316 assert_eq!(header.producer_group, "group1");
317 assert_eq!(header.tran_state_table_offset, 123);
318 assert_eq!(header.commit_log_offset, 456);
319 assert_eq!(header.commit_or_rollback, 1);
320 assert!(header.from_transaction_check);
321 assert_eq!(header.msg_id, "msg1");
322 assert_eq!(header.transaction_id.unwrap(), "tran1");
323 }
324
325 #[test]
326 fn end_transaction_request_header_preserves_java_signed_long_offsets() {
327 use crate::protocol::command_custom_header::CommandCustomHeader;
328 use crate::protocol::command_custom_header::FromMap;
329 use std::collections::HashMap;
330
331 let header = EndTransactionRequestHeader {
332 topic: CheetahString::from("topic1"),
333 producer_group: CheetahString::from("group1"),
334 tran_state_table_offset: -123,
335 commit_log_offset: -456,
336 commit_or_rollback: 1,
337 from_transaction_check: true,
338 msg_id: CheetahString::from("msg1"),
339 transaction_id: None,
340 rpc_request_header: RpcRequestHeader::default(),
341 };
342 let map = header.to_map().unwrap();
343 assert_eq!(
344 map.get(&CheetahString::from_static_str(
345 EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET
346 )),
347 Some(&CheetahString::from_static_str("-123"))
348 );
349 assert_eq!(
350 map.get(&CheetahString::from_static_str(
351 EndTransactionRequestHeader::COMMIT_LOG_OFFSET
352 )),
353 Some(&CheetahString::from_static_str("-456"))
354 );
355
356 let restored = <EndTransactionRequestHeader as FromMap>::from(&HashMap::from([
357 (
358 CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC),
359 CheetahString::from_static_str("topic1"),
360 ),
361 (
362 CheetahString::from_static_str(EndTransactionRequestHeader::PRODUCER_GROUP),
363 CheetahString::from_static_str("group1"),
364 ),
365 (
366 CheetahString::from_static_str(EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET),
367 CheetahString::from_static_str("-123"),
368 ),
369 (
370 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_LOG_OFFSET),
371 CheetahString::from_static_str("-456"),
372 ),
373 (
374 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_OR_ROLLBACK),
375 CheetahString::from_static_str("1"),
376 ),
377 (
378 CheetahString::from_static_str(EndTransactionRequestHeader::FROM_TRANSACTION_CHECK),
379 CheetahString::from_static_str("true"),
380 ),
381 (
382 CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID),
383 CheetahString::from_static_str("msg1"),
384 ),
385 ]))
386 .unwrap();
387
388 assert_eq!(restored.tran_state_table_offset, -123);
389 assert_eq!(restored.commit_log_offset, -456);
390 }
391
392 #[test]
393 fn end_transaction_request_header_from_map_without_transaction_id() {
394 use crate::protocol::command_custom_header::FromMap;
395 use std::collections::HashMap;
396
397 let mut map = HashMap::new();
398 map.insert(
399 CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC),
400 CheetahString::from_static_str("topic1"),
401 );
402 map.insert(
403 CheetahString::from_static_str(EndTransactionRequestHeader::PRODUCER_GROUP),
404 CheetahString::from_static_str("group1"),
405 );
406 map.insert(
407 CheetahString::from_static_str(EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET),
408 CheetahString::from_static_str("123"),
409 );
410 map.insert(
411 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_LOG_OFFSET),
412 CheetahString::from_static_str("456"),
413 );
414 map.insert(
415 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_OR_ROLLBACK),
416 CheetahString::from_static_str("1"),
417 );
418 map.insert(
419 CheetahString::from_static_str(EndTransactionRequestHeader::FROM_TRANSACTION_CHECK),
420 CheetahString::from_static_str("true"),
421 );
422 map.insert(
423 CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID),
424 CheetahString::from_static_str("msg1"),
425 );
426
427 let header = <EndTransactionRequestHeader as FromMap>::from(&map).unwrap();
428 assert_eq!(header.topic, "topic1");
429 assert_eq!(header.producer_group, "group1");
430 assert_eq!(header.tran_state_table_offset, 123);
431 assert_eq!(header.commit_log_offset, 456);
432 assert_eq!(header.commit_or_rollback, 1);
433 assert!(header.from_transaction_check);
434 assert_eq!(header.msg_id, "msg1");
435 assert!(header.transaction_id.is_none());
436 }
437
438 #[test]
439 fn end_transaction_request_header_from_map_missing_required_field() {
440 use crate::protocol::command_custom_header::FromMap;
441 use std::collections::HashMap;
442
443 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
444 enum RequiredField {
445 Topic,
446 ProducerGroup,
447 TranStateTableOffset,
448 CommitLogOffset,
449 CommitOrRollback,
450 FromTransactionCheck,
451 MsgId,
452 }
453
454 impl RequiredField {
455 fn as_str(&self) -> &'static str {
456 match self {
457 RequiredField::Topic => EndTransactionRequestHeader::TOPIC,
458 RequiredField::ProducerGroup => EndTransactionRequestHeader::PRODUCER_GROUP,
459 RequiredField::TranStateTableOffset => EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET,
460 RequiredField::CommitLogOffset => EndTransactionRequestHeader::COMMIT_LOG_OFFSET,
461 RequiredField::CommitOrRollback => EndTransactionRequestHeader::COMMIT_OR_ROLLBACK,
462 RequiredField::FromTransactionCheck => EndTransactionRequestHeader::FROM_TRANSACTION_CHECK,
463 RequiredField::MsgId => EndTransactionRequestHeader::MSG_ID,
464 }
465 }
466
467 fn test_value(&self) -> &'static str {
468 match self {
469 RequiredField::Topic => "topic1",
470 RequiredField::ProducerGroup => "group1",
471 RequiredField::TranStateTableOffset => "123",
472 RequiredField::CommitLogOffset => "456",
473 RequiredField::CommitOrRollback => "1",
474 RequiredField::FromTransactionCheck => "true",
475 RequiredField::MsgId => "msg1",
476 }
477 }
478 }
479
480 let all_required_fields: &[RequiredField] = &[
481 RequiredField::Topic,
482 RequiredField::ProducerGroup,
483 RequiredField::TranStateTableOffset,
484 RequiredField::CommitLogOffset,
485 RequiredField::CommitOrRollback,
486 RequiredField::FromTransactionCheck,
487 RequiredField::MsgId,
488 ];
489
490 for &missing_field in all_required_fields {
491 let mut map = HashMap::new();
492 for &field in all_required_fields {
493 if field != missing_field {
494 map.insert(
495 CheetahString::from_static_str(field.as_str()),
496 CheetahString::from_static_str(field.test_value()),
497 );
498 }
499 }
500
501 let result = <EndTransactionRequestHeader as FromMap>::from(&map);
502 assert!(
503 result.is_err(),
504 "Expected failure when missing required field: {:?}",
505 missing_field
506 );
507 }
508 }
509
510 #[test]
511 fn end_transaction_request_header_from_map_invalid_numeric_field() {
512 use crate::protocol::command_custom_header::FromMap;
513 use std::collections::HashMap;
514
515 let mut map = HashMap::new();
516 map.insert(
517 CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC),
518 CheetahString::from_static_str("topic1"),
519 );
520 map.insert(
521 CheetahString::from_static_str(EndTransactionRequestHeader::PRODUCER_GROUP),
522 CheetahString::from_static_str("group1"),
523 );
524 map.insert(
525 CheetahString::from_static_str(EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET),
526 CheetahString::from_static_str("invalid"),
527 );
528 map.insert(
529 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_LOG_OFFSET),
530 CheetahString::from_static_str("456"),
531 );
532 map.insert(
533 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_OR_ROLLBACK),
534 CheetahString::from_static_str("1"),
535 );
536 map.insert(
537 CheetahString::from_static_str(EndTransactionRequestHeader::FROM_TRANSACTION_CHECK),
538 CheetahString::from_static_str("true"),
539 );
540 map.insert(
541 CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID),
542 CheetahString::from_static_str("msg1"),
543 );
544
545 let result = <EndTransactionRequestHeader as FromMap>::from(&map);
546 assert!(result.is_err());
547 }
548
549 #[test]
550 fn end_transaction_request_header_from_map_invalid_bool_field() {
551 use crate::protocol::command_custom_header::FromMap;
552 use std::collections::HashMap;
553
554 let mut map = HashMap::new();
555 map.insert(
556 CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC),
557 CheetahString::from_static_str("topic1"),
558 );
559 map.insert(
560 CheetahString::from_static_str(EndTransactionRequestHeader::PRODUCER_GROUP),
561 CheetahString::from_static_str("group1"),
562 );
563 map.insert(
564 CheetahString::from_static_str(EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET),
565 CheetahString::from_static_str("123"),
566 );
567 map.insert(
568 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_LOG_OFFSET),
569 CheetahString::from_static_str("456"),
570 );
571 map.insert(
572 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_OR_ROLLBACK),
573 CheetahString::from_static_str("1"),
574 );
575 map.insert(
576 CheetahString::from_static_str(EndTransactionRequestHeader::FROM_TRANSACTION_CHECK),
577 CheetahString::from_static_str("invalid"),
578 );
579 map.insert(
580 CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID),
581 CheetahString::from_static_str("msg1"),
582 );
583
584 let result = <EndTransactionRequestHeader as FromMap>::from(&map);
585 assert!(result.is_err());
586 }
587
588 #[test]
589 fn end_transaction_request_header_from_map_transaction_state_values() {
590 use crate::protocol::command_custom_header::FromMap;
591 use rocketmq_common::common::sys_flag::message_sys_flag::MessageSysFlag;
592 use std::collections::HashMap;
593
594 struct TestCase {
595 value: i32,
596 }
597
598 let test_cases = &[
599 TestCase {
600 value: MessageSysFlag::TRANSACTION_NOT_TYPE,
601 },
602 TestCase {
603 value: MessageSysFlag::TRANSACTION_COMMIT_TYPE,
604 },
605 TestCase {
606 value: MessageSysFlag::TRANSACTION_ROLLBACK_TYPE,
607 },
608 ];
609
610 for case in test_cases {
611 let mut map = HashMap::new();
612 map.insert(
613 CheetahString::from_static_str(EndTransactionRequestHeader::TOPIC),
614 CheetahString::from_static_str("topic1"),
615 );
616 map.insert(
617 CheetahString::from_static_str(EndTransactionRequestHeader::PRODUCER_GROUP),
618 CheetahString::from_static_str("group1"),
619 );
620 map.insert(
621 CheetahString::from_static_str(EndTransactionRequestHeader::TRAN_STATE_TABLE_OFFSET),
622 CheetahString::from_static_str("123"),
623 );
624 map.insert(
625 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_LOG_OFFSET),
626 CheetahString::from_static_str("456"),
627 );
628 map.insert(
629 CheetahString::from_static_str(EndTransactionRequestHeader::COMMIT_OR_ROLLBACK),
630 CheetahString::from(case.value.to_string()),
631 );
632 map.insert(
633 CheetahString::from_static_str(EndTransactionRequestHeader::FROM_TRANSACTION_CHECK),
634 CheetahString::from_static_str("true"),
635 );
636 map.insert(
637 CheetahString::from_static_str(EndTransactionRequestHeader::MSG_ID),
638 CheetahString::from_static_str("msg1"),
639 );
640
641 let result = <EndTransactionRequestHeader as FromMap>::from(&map);
642 assert!(
643 result.is_ok(),
644 "commit_or_rollback={} should parse successfully but got {:?}",
645 case.value,
646 result
647 );
648 let header = result.unwrap();
649 assert_eq!(
650 header.commit_or_rollback, case.value,
651 "commit_or_rollback should be {}",
652 case.value
653 );
654 }
655 }
656
657 #[test]
658 fn end_transaction_request_header_roundtrip() {
659 use crate::protocol::command_custom_header::CommandCustomHeader;
660 use crate::protocol::command_custom_header::FromMap;
661 use rocketmq_common::common::sys_flag::message_sys_flag::MessageSysFlag;
662
663 let original = EndTransactionRequestHeader {
664 topic: CheetahString::from("topic1"),
665 producer_group: CheetahString::from("group1"),
666 tran_state_table_offset: 123,
667 commit_log_offset: 456,
668 commit_or_rollback: MessageSysFlag::TRANSACTION_COMMIT_TYPE,
669 from_transaction_check: true,
670 msg_id: CheetahString::from("msg1"),
671 transaction_id: Some(CheetahString::from("tran1")),
672 rpc_request_header: RpcRequestHeader::default(),
673 };
674
675 let map = original.to_map().unwrap();
676 let restored = <EndTransactionRequestHeader as FromMap>::from(&map).unwrap();
677
678 assert_eq!(original.topic, restored.topic);
679 assert_eq!(original.producer_group, restored.producer_group);
680 assert_eq!(original.tran_state_table_offset, restored.tran_state_table_offset);
681 assert_eq!(original.commit_log_offset, restored.commit_log_offset);
682 assert_eq!(original.commit_or_rollback, restored.commit_or_rollback);
683 assert_eq!(original.from_transaction_check, restored.from_transaction_check);
684 assert_eq!(original.msg_id, restored.msg_id);
685 assert_eq!(original.transaction_id, restored.transaction_id);
686 }
687
688 #[test]
689 fn end_transaction_request_header_via_remoting_command() {
690 use crate::code::request_code::RequestCode;
691 use crate::protocol::remoting_command::RemotingCommand;
692 use bytes::BytesMut;
693 use rocketmq_common::common::sys_flag::message_sys_flag::MessageSysFlag;
694
695 let original = EndTransactionRequestHeader {
696 topic: CheetahString::from("topic1"),
697 producer_group: CheetahString::from("group1"),
698 tran_state_table_offset: 123,
699 commit_log_offset: 456,
700 commit_or_rollback: MessageSysFlag::TRANSACTION_COMMIT_TYPE,
701 from_transaction_check: true,
702 msg_id: CheetahString::from("msg1"),
703 transaction_id: Some(CheetahString::from("tran1")),
704 rpc_request_header: RpcRequestHeader::default(),
705 };
706
707 let mut command = RemotingCommand::create_request_command(RequestCode::EndTransaction, original);
708 let header_bytes = command.encode_header().expect("Failed to encode header");
709
710 let mut buf = BytesMut::from(header_bytes);
711 let decoded_command = RemotingCommand::decode(&mut buf).expect("Failed to decode command");
712 let decoded_command = decoded_command.expect("Decoded command is None");
713
714 assert_eq!(decoded_command.code(), RequestCode::EndTransaction as i32);
715
716 let decoded_header = decoded_command
717 .decode_command_custom_header::<EndTransactionRequestHeader>()
718 .expect("Failed to decode header");
719
720 assert_eq!(decoded_header.topic, "topic1");
721 assert_eq!(decoded_header.producer_group, "group1");
722 assert_eq!(decoded_header.tran_state_table_offset, 123);
723 assert_eq!(decoded_header.commit_log_offset, 456);
724 assert_eq!(
725 decoded_header.commit_or_rollback,
726 MessageSysFlag::TRANSACTION_COMMIT_TYPE
727 );
728 assert!(decoded_header.from_transaction_check);
729 assert_eq!(decoded_header.msg_id, "msg1");
730 assert_eq!(decoded_header.transaction_id.unwrap(), "tran1");
731 }
732}