rocketmq_remoting/protocol/header/
heartbeat_request_header.rs1use rocketmq_macros::RequestHeaderCodecV2;
16use serde::Deserialize;
17use serde::Serialize;
18
19use crate::rpc::rpc_request_header::RpcRequestHeader;
20
21#[derive(Serialize, Deserialize, Debug, Default, RequestHeaderCodecV2)]
22#[serde(rename_all = "camelCase")]
23pub struct HeartbeatRequestHeader {
24 #[serde(flatten)]
25 pub rpc_request: Option<RpcRequestHeader>,
26}
27
28#[cfg(test)]
29mod tests {
30 use std::collections::HashMap;
31
32 use cheetah_string::CheetahString;
33
34 use super::*;
35 use crate::protocol::command_custom_header::FromMap;
36
37 #[test]
38 fn default_initialization_creates_empty_struct() {
39 let header = HeartbeatRequestHeader::default();
40 assert!(header.rpc_request.is_none());
41 }
42
43 #[test]
44 fn serialization_with_none_rpc_request() {
45 let header = HeartbeatRequestHeader { rpc_request: None };
46 let json = serde_json::to_string(&header).unwrap();
47 assert_eq!(json, "{}");
48 }
49
50 #[test]
51 fn serialization_with_some_rpc_request() {
52 let header = HeartbeatRequestHeader {
53 rpc_request: Some(RpcRequestHeader {
54 namespace: Some(CheetahString::from("test_namespace")),
55 namespaced: Some(true),
56 broker_name: Some(CheetahString::from("test_broker")),
57 oneway: Some(false),
58 }),
59 };
60 let json = serde_json::to_string(&header).unwrap();
61 assert!(json.contains("\"namespace\":\"test_namespace\""));
62 assert!(json.contains("\"namespaced\":true"));
63 assert!(json.contains("\"brokerName\":\"test_broker\""));
64 assert!(json.contains("\"oneway\":false"));
65
66 assert!(!json.contains("rpcRequest"));
68 assert!(!json.contains("rpc_request"));
69 }
70
71 #[test]
72 fn deserialization_with_empty_json() {
73 let json = "{}";
74 let header: HeartbeatRequestHeader = serde_json::from_str(json).unwrap();
75 assert!(header.rpc_request.is_some());
77 let rpc = header.rpc_request.unwrap();
78 assert!(rpc.namespace.is_none());
79 assert!(rpc.namespaced.is_none());
80 assert!(rpc.broker_name.is_none());
81 assert!(rpc.oneway.is_none());
82 }
83
84 #[test]
85 fn deserialization_with_rpc_request_fields() {
86 let json = r#"{
87 "namespace": "test_namespace",
88 "namespaced": true,
89 "brokerName": "test_broker",
90 "oneway": false
91 }"#;
92 let header: HeartbeatRequestHeader = serde_json::from_str(json).unwrap();
93 assert!(header.rpc_request.is_some());
94 let rpc = header.rpc_request.unwrap();
95 assert_eq!(rpc.namespace.unwrap(), "test_namespace");
96 assert!(rpc.namespaced.unwrap());
97 assert_eq!(rpc.broker_name.unwrap(), "test_broker");
98 assert!(!rpc.oneway.unwrap());
99 }
100
101 #[test]
102 fn deserialization_with_partial_rpc_request_fields() {
103 let json = r#"{
104 "namespace": "test_namespace",
105 "brokerName": "test_broker"
106 }"#;
107 let header: HeartbeatRequestHeader = serde_json::from_str(json).unwrap();
108 assert!(header.rpc_request.is_some());
109 let rpc = header.rpc_request.unwrap();
110 assert_eq!(rpc.namespace.unwrap(), "test_namespace");
111 assert_eq!(rpc.broker_name.unwrap(), "test_broker");
112 assert!(rpc.namespaced.is_none());
113 assert!(rpc.oneway.is_none());
114 }
115
116 #[test]
117 fn serialization_deserialization_roundtrip_with_none() {
118 let original = HeartbeatRequestHeader { rpc_request: None };
119 let json = serde_json::to_string(&original).unwrap();
120 let deserialized: HeartbeatRequestHeader = serde_json::from_str(&json).unwrap();
121 assert!(deserialized.rpc_request.is_some());
123 let rpc = deserialized.rpc_request.unwrap();
124 assert!(rpc.namespace.is_none());
125 assert!(rpc.namespaced.is_none());
126 assert!(rpc.broker_name.is_none());
127 assert!(rpc.oneway.is_none());
128 }
129
130 #[test]
131 fn serialization_deserialization_roundtrip_with_some() {
132 let original = HeartbeatRequestHeader {
133 rpc_request: Some(RpcRequestHeader {
134 namespace: Some(CheetahString::from("test_namespace")),
135 namespaced: Some(true),
136 broker_name: Some(CheetahString::from("test_broker")),
137 oneway: Some(false),
138 }),
139 };
140 let json = serde_json::to_string(&original).unwrap();
141 let deserialized: HeartbeatRequestHeader = serde_json::from_str(&json).unwrap();
142
143 assert!(deserialized.rpc_request.is_some());
144 let rpc = deserialized.rpc_request.unwrap();
145 assert_eq!(rpc.namespace.unwrap(), "test_namespace");
146 assert!(rpc.namespaced.unwrap());
147 assert_eq!(rpc.broker_name.unwrap(), "test_broker");
148 assert!(!rpc.oneway.unwrap());
149 }
150
151 #[test]
152 fn serialization_deserialization_roundtrip_with_partial_fields() {
153 let original = HeartbeatRequestHeader {
154 rpc_request: Some(RpcRequestHeader {
155 namespace: Some(CheetahString::from("test_namespace")),
156 namespaced: None,
157 broker_name: Some(CheetahString::from("test_broker")),
158 oneway: None,
159 }),
160 };
161 let json = serde_json::to_string(&original).unwrap();
162 let deserialized: HeartbeatRequestHeader = serde_json::from_str(&json).unwrap();
163
164 assert!(deserialized.rpc_request.is_some());
165 let rpc = deserialized.rpc_request.unwrap();
166 assert_eq!(rpc.namespace.unwrap(), "test_namespace");
167 assert_eq!(rpc.broker_name.unwrap(), "test_broker");
168 assert!(rpc.namespaced.is_none());
169 assert!(rpc.oneway.is_none());
170 }
171
172 #[test]
173 fn flattened_serde_attribute_works_correctly() {
174 let header = HeartbeatRequestHeader {
175 rpc_request: Some(RpcRequestHeader {
176 namespace: Some(CheetahString::from("ns")),
177 namespaced: Some(true),
178 broker_name: Some(CheetahString::from("broker")),
179 oneway: Some(true),
180 }),
181 };
182 let json = serde_json::to_string(&header).unwrap();
183 let value: serde_json::Value = serde_json::from_str(&json).unwrap();
184
185 assert!(value.get("namespace").is_some());
187 assert!(value.get("namespaced").is_some());
188 assert!(value.get("brokerName").is_some());
189 assert!(value.get("oneway").is_some());
190
191 assert!(value.get("rpcRequest").is_none());
193 assert!(value.get("rpc_request").is_none());
194 }
195
196 #[test]
197 fn from_map_with_empty_map() {
198 let map = HashMap::new();
199 let header = <HeartbeatRequestHeader as FromMap>::from(&map).unwrap();
200
201 assert!(header.rpc_request.is_some());
202 let rpc = header.rpc_request.unwrap();
203
204 assert!(rpc.namespace.is_none());
205 assert!(rpc.namespaced.is_none());
206 assert!(rpc.broker_name.is_none());
207 assert!(rpc.oneway.is_none());
208 }
209
210 #[test]
211 fn from_map_with_rpc_request_fields() {
212 let mut map = HashMap::new();
213 map.insert(CheetahString::from("namespace"), CheetahString::from("test_namespace"));
214 map.insert(CheetahString::from("namespaced"), CheetahString::from("true"));
215 map.insert(CheetahString::from("brokerName"), CheetahString::from("test_broker"));
216 map.insert(CheetahString::from("oneway"), CheetahString::from("false"));
217
218 let header = <HeartbeatRequestHeader as FromMap>::from(&map).unwrap();
219
220 assert!(header.rpc_request.is_some());
221 let rpc = header.rpc_request.unwrap();
222 assert_eq!(rpc.namespace.unwrap(), "test_namespace");
223 assert!(rpc.namespaced.unwrap());
224 assert_eq!(rpc.broker_name.unwrap(), "test_broker");
225 assert!(!rpc.oneway.unwrap());
226 }
227
228 #[test]
229 fn from_map_with_partial_fields() {
230 let mut map = HashMap::new();
231 map.insert(CheetahString::from("namespace"), CheetahString::from("test_namespace"));
232
233 let header = <HeartbeatRequestHeader as FromMap>::from(&map).unwrap();
234
235 assert!(header.rpc_request.is_some());
236 let rpc = header.rpc_request.unwrap();
237 assert_eq!(rpc.namespace.unwrap(), "test_namespace");
238 assert!(rpc.namespaced.is_none());
239 assert!(rpc.broker_name.is_none());
240 assert!(rpc.oneway.is_none());
241 }
242
243 #[test]
244 fn debug_trait_implementation() {
245 let header = HeartbeatRequestHeader {
246 rpc_request: Some(RpcRequestHeader {
247 namespace: Some(CheetahString::from("test_namespace")),
248 namespaced: Some(true),
249 broker_name: Some(CheetahString::from("test_broker")),
250 oneway: Some(false),
251 }),
252 };
253 let debug_string = format!("{:?}", header);
254
255 assert!(debug_string.contains("HeartbeatRequestHeader"));
256 assert!(debug_string.contains("rpc_request"));
257 }
258
259 #[test]
260 fn debug_trait_with_none() {
261 let header = HeartbeatRequestHeader { rpc_request: None };
262 let debug_string = format!("{:?}", header);
263
264 assert!(debug_string.contains("HeartbeatRequestHeader"));
265 assert!(debug_string.contains("None"));
266 }
267
268 #[test]
269 fn default_trait_implementation() {
270 let header = HeartbeatRequestHeader::default();
271 assert!(header.rpc_request.is_none());
272
273 let manual_header = HeartbeatRequestHeader { rpc_request: None };
275 let default_json = serde_json::to_string(&header).unwrap();
276 let manual_json = serde_json::to_string(&manual_header).unwrap();
277
278 assert_eq!(default_json, manual_json);
279 }
280
281 #[test]
282 fn complete_rpc_request_header_structure() {
283 let rpc_header = RpcRequestHeader {
284 namespace: Some(CheetahString::from("production")),
285 namespaced: Some(true),
286 broker_name: Some(CheetahString::from("broker-master")),
287 oneway: Some(false),
288 };
289
290 let header = HeartbeatRequestHeader {
291 rpc_request: Some(rpc_header),
292 };
293
294 let json = serde_json::to_string(&header).unwrap();
295 let deserialized: HeartbeatRequestHeader = serde_json::from_str(&json).unwrap();
296
297 let rpc = deserialized.rpc_request.unwrap();
298 assert_eq!(rpc.namespace.unwrap(), "production");
299 assert!(rpc.namespaced.unwrap());
300 assert_eq!(rpc.broker_name.unwrap(), "broker-master");
301 assert!(!rpc.oneway.unwrap());
302 }
303
304 #[test]
305 fn rpc_request_header_namespace_field() {
306 let header = HeartbeatRequestHeader {
307 rpc_request: Some(RpcRequestHeader {
308 namespace: Some(CheetahString::from("test_ns")),
309 namespaced: None,
310 broker_name: None,
311 oneway: None,
312 }),
313 };
314
315 assert!(header.rpc_request.is_some());
316 assert_eq!(
317 header.rpc_request.as_ref().unwrap().namespace.as_ref().unwrap(),
318 "test_ns"
319 );
320 }
321
322 #[test]
323 fn rpc_request_header_namespaced_field() {
324 let header = HeartbeatRequestHeader {
325 rpc_request: Some(RpcRequestHeader {
326 namespace: None,
327 namespaced: Some(true),
328 broker_name: None,
329 oneway: None,
330 }),
331 };
332
333 assert!(header.rpc_request.is_some());
334 assert!(header.rpc_request.as_ref().unwrap().namespaced.unwrap());
335 }
336
337 #[test]
338 fn rpc_request_header_broker_name_field() {
339 let header = HeartbeatRequestHeader {
340 rpc_request: Some(RpcRequestHeader {
341 namespace: None,
342 namespaced: None,
343 broker_name: Some(CheetahString::from("my_broker")),
344 oneway: None,
345 }),
346 };
347
348 assert!(header.rpc_request.is_some());
349 assert_eq!(
350 header.rpc_request.as_ref().unwrap().broker_name.as_ref().unwrap(),
351 "my_broker"
352 );
353 }
354
355 #[test]
356 fn rpc_request_header_oneway_field() {
357 let header = HeartbeatRequestHeader {
358 rpc_request: Some(RpcRequestHeader {
359 namespace: None,
360 namespaced: None,
361 broker_name: None,
362 oneway: Some(true),
363 }),
364 };
365
366 assert!(header.rpc_request.is_some());
367 assert!(header.rpc_request.as_ref().unwrap().oneway.unwrap());
368 }
369
370 #[test]
371 fn camel_case_field_names_in_json() {
372 let header = HeartbeatRequestHeader {
373 rpc_request: Some(RpcRequestHeader {
374 namespace: Some(CheetahString::from("ns")),
375 namespaced: Some(false),
376 broker_name: Some(CheetahString::from("broker")),
377 oneway: Some(true),
378 }),
379 };
380
381 let json = serde_json::to_string(&header).unwrap();
382
383 assert!(json.contains("brokerName"));
385 assert!(!json.contains("broker_name"));
386 assert!(json.contains("namespace"));
387 assert!(json.contains("namespaced"));
388 assert!(json.contains("oneway"));
389 }
390}