rocketmq_protocol/protocol/header/
reply_message_request_header.rs1use cheetah_string::CheetahString;
16use rocketmq_macros::RequestHeaderCodec;
17use serde::Deserialize;
18use serde::Serialize;
19
20use crate::protocol::header::namesrv::topic_operation_header::TopicRequestHeader;
21
22#[derive(Serialize, Deserialize, Debug, Default, RequestHeaderCodec)]
24#[header(
25 type_id = "rocketmq_protocol::protocol::header::reply_message_request_header::ReplyMessageRequestHeader",
26 java_class = "org.apache.rocketmq.remoting.protocol.header.ReplyMessageRequestHeader"
27)]
28#[serde(rename_all = "camelCase")]
29pub struct ReplyMessageRequestHeader {
30 #[header(required)]
32 pub producer_group: CheetahString,
33
34 #[header(required)]
36 pub topic: CheetahString,
37
38 #[header(required)]
40 pub default_topic: CheetahString,
41
42 #[header(required)]
44 pub default_topic_queue_nums: i32,
45
46 #[header(required)]
48 pub queue_id: i32,
49
50 #[header(required)]
52 pub sys_flag: i32,
53
54 #[header(required)]
56 pub born_timestamp: i64,
57
58 #[header(required)]
60 pub flag: i32,
61
62 pub properties: Option<CheetahString>,
64
65 pub reconsume_times: Option<i32>,
67
68 #[serde(default = "default_unit_mode")]
70 #[header(default_with = "default_unit_mode", default_semantic = "literal:false")]
71 pub unit_mode: Option<bool>,
72
73 #[header(required)]
75 pub born_host: CheetahString,
76
77 #[header(required)]
79 pub store_host: CheetahString,
80
81 #[header(required)]
83 pub store_timestamp: i64,
84
85 #[serde(flatten)]
86 #[header(flatten, presence = "always")]
87 pub topic_request: Option<TopicRequestHeader>,
88}
89
90fn default_unit_mode() -> Option<bool> {
91 Some(false)
92}
93
94#[cfg(test)]
95mod reply_message_request_header_tests {
96 use std::collections::HashMap;
97
98 use super::*;
99 use crate::protocol::command_custom_header::CommandCustomHeader;
100 use crate::protocol::command_custom_header::FromMap;
101 #[test]
102 fn deserialize_from_map_with_all_fields_populates_struct_correctly() {
103 let mut map: HashMap<CheetahString, CheetahString> = HashMap::new();
104 map.insert("producerGroup".into(), "test_producer_group".into());
105 map.insert("topic".into(), "test_topic".into());
106 map.insert("defaultTopic".into(), "test_default_topic".into());
107 map.insert("defaultTopicQueueNums".into(), "10".into());
108 map.insert("queueId".into(), "1".into());
109 map.insert("sysFlag".into(), "0".into());
110 map.insert("flag".into(), "0".into());
111 map.insert("bornTimestamp".into(), "1622547800".into());
112 map.insert("bornHost".into(), "test_born_host".into());
113 map.insert("storeHost".into(), "test_store_host".into());
114 map.insert("storeTimestamp".into(), "1622547800".into());
115 map.insert("unitMode".into(), "true".into());
116
117 let header: ReplyMessageRequestHeader = <ReplyMessageRequestHeader as FromMap>::from(&map).unwrap();
118
119 assert_eq!(header.topic, "test_topic");
120 assert_eq!(header.producer_group, "test_producer_group");
121 assert_eq!(header.default_topic, "test_default_topic");
122 assert_eq!(header.default_topic_queue_nums, 10);
123 assert_eq!(header.queue_id, 1);
124 assert_eq!(header.sys_flag, 0);
125 assert_eq!(header.flag, 0);
126 assert_eq!(header.born_timestamp, 1622547800);
127 assert_eq!(header.born_host, "test_born_host");
128 assert_eq!(header.store_host, "test_store_host");
129 assert_eq!(header.store_timestamp, 1622547800);
130 assert_eq!(header.properties, None);
131 assert_eq!(header.reconsume_times, None);
132 assert_eq!(header.unit_mode, Some(true));
133 }
134
135 #[test]
136 fn deserialize_from_map_with_invalid_number_fields_returns_none() {
137 let mut map = HashMap::new();
138 map.insert("producerGroup".into(), "test_producer_group".into());
139 map.insert("topic".into(), "test_topic".into());
140 map.insert("defaultTopic".into(), "test_default_topic".into());
141 map.insert("defaultTopicQueueNums".into(), "invalid".into());
142 let header: Result<ReplyMessageRequestHeader, rocketmq_error::Error> =
143 <ReplyMessageRequestHeader as FromMap>::from(&map);
144 assert!(header.is_err());
145 }
146
147 #[test]
148 fn serialize_header_to_map() {
149 let header = ReplyMessageRequestHeader {
150 topic: "test_topic".into(),
151 producer_group: "test_producer_group".into(),
152 default_topic: "test_default_topic".into(),
153 default_topic_queue_nums: 10,
154 queue_id: 1,
155 flag: 2,
156 sys_flag: 0,
157 born_timestamp: 1622547800,
158 born_host: "test_born_host".into(),
159 store_host: "test_store_host".into(),
160 store_timestamp: 1622547800,
161 properties: Some("test_properties".into()),
162 reconsume_times: Some(1),
163 unit_mode: Some(true),
164 topic_request: None,
165 };
166 let map: HashMap<CheetahString, CheetahString> = header.to_map().unwrap();
167
168 assert_eq!(map.get("topic").unwrap(), "test_topic");
169 assert_eq!(map.get("producerGroup").unwrap(), "test_producer_group");
170 assert_eq!(map.get("defaultTopicQueueNums").unwrap(), "10");
171 assert_eq!(map.get("bornTimestamp").unwrap(), "1622547800");
172 assert!(!map.contains_key("topicRequest"));
173 assert_eq!(map.get("queueId").unwrap(), "1");
174 assert_eq!(map.get("sysFlag").unwrap(), "0");
175 assert_eq!(map.get("bornHost").unwrap(), "test_born_host");
176 assert_eq!(map.get("storeHost").unwrap(), "test_store_host");
177 assert_eq!(map.get("storeTimestamp").unwrap(), "1622547800");
178 assert_eq!(map.get("flag").unwrap(), "2");
179 assert_eq!(map.get("properties").unwrap(), "test_properties");
180 assert_eq!(map.get("reconsumeTimes").unwrap(), "1");
181 assert_eq!(map.get("unitMode").unwrap(), "true");
182 }
183
184 #[test]
185 fn serialize_header_to_map_with_topic_request_header_includes_nested_fields() {
186 let topic_request_header = TopicRequestHeader::default();
187 let header = ReplyMessageRequestHeader {
188 topic: "test_topic".into(),
189 producer_group: "test_producer_group".into(),
190 default_topic: "test_default_topic".into(),
191 default_topic_queue_nums: 10,
192 queue_id: 1,
193 flag: 2,
194 sys_flag: 0,
195 born_timestamp: 1622547800,
196 born_host: "test_born_host".into(),
197 store_host: "test_store_host".into(),
198 store_timestamp: 1622547800,
199 properties: Some("test_properties".into()),
200 reconsume_times: Some(1),
201 unit_mode: Some(true),
202 topic_request: Some(topic_request_header),
203 };
204 let map: HashMap<CheetahString, CheetahString> = header.to_map().unwrap();
205 assert!(!map.contains_key("nestedField"));
206 }
207}