rocketmq_remoting/protocol/header/
query_topics_by_consumer_request_header.rs1use cheetah_string::CheetahString;
16use rocketmq_macros::RequestHeaderCodecV2;
17use serde::Deserialize;
18use serde::Serialize;
19
20use crate::rpc::rpc_request_header::RpcRequestHeader;
21
22#[derive(Serialize, Deserialize, Debug, RequestHeaderCodecV2, Default)]
23pub struct QueryTopicsByConsumerRequestHeader {
24 #[required]
25 #[serde(rename = "group")]
26 pub group: CheetahString,
27
28 #[serde(flatten)]
29 pub rpc_request_header: Option<RpcRequestHeader>,
30}
31
32impl QueryTopicsByConsumerRequestHeader {
33 pub fn new(group: impl Into<CheetahString>) -> Self {
34 Self {
35 group: group.into(),
36 rpc_request_header: None,
37 }
38 }
39
40 pub fn get_group(&self) -> &CheetahString {
41 &self.group
42 }
43
44 pub fn set_group(&mut self, group: CheetahString) {
45 self.group = group;
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use std::collections::HashMap;
52
53 use super::*;
54 use crate::protocol::command_custom_header::FromMap;
55
56 #[test]
57 fn query_topics_by_consumer_request_header_default() {
58 let header = QueryTopicsByConsumerRequestHeader::default();
59 assert_eq!(header.get_group(), "");
60 assert!(header.rpc_request_header.is_none());
61 }
62
63 #[test]
64 fn query_topics_by_consumer_request_header_new() {
65 let mut header = QueryTopicsByConsumerRequestHeader::new("group1");
66 assert_eq!(header.get_group(), "group1");
67 assert!(header.rpc_request_header.is_none());
68 header.set_group(CheetahString::from("group2"));
69 assert_eq!(header.get_group(), "group2");
70 }
71
72 #[test]
73 fn query_topics_by_consumer_request_header_serialization() {
74 let header = QueryTopicsByConsumerRequestHeader {
75 group: CheetahString::from("group1"),
76 rpc_request_header: Some(RpcRequestHeader {
77 broker_name: Some(CheetahString::from("broker")),
78 ..Default::default()
79 }),
80 };
81 let json = serde_json::to_string(&header).unwrap();
82 assert!(json.contains("\"group\":\"group1\""));
83 assert!(json.contains("\"brokerName\":\"broker\""));
84 }
85
86 #[test]
87 fn query_topics_by_consumer_request_header_deserialization() {
88 let json = r#"{"group":"group1","brokerName":"broker"}"#;
89 let header: QueryTopicsByConsumerRequestHeader = serde_json::from_str(json).unwrap();
90 assert_eq!(header.group, "group1");
91 assert_eq!(
92 header.rpc_request_header.unwrap().broker_name,
93 Some(CheetahString::from("broker"))
94 );
95 }
96
97 #[test]
98 fn query_topics_by_consumer_request_header_from_map() {
99 let mut map = HashMap::new();
100 map.insert(CheetahString::from("group"), CheetahString::from("group1"));
101 map.insert(CheetahString::from("brokerName"), CheetahString::from("broker1"));
102
103 let header = <QueryTopicsByConsumerRequestHeader as FromMap>::from(&map).unwrap();
104 assert_eq!(header.group, "group1");
105 assert_eq!(
106 header.rpc_request_header.unwrap().broker_name,
107 Some(CheetahString::from("broker1"))
108 );
109 }
110
111 #[test]
112 fn debug_impl_contains_group() {
113 let header = QueryTopicsByConsumerRequestHeader::new("dbg_group");
114 let s = format!("{:?}", header);
115 assert!(s.contains("group"));
116 assert!(s.contains("dbg_group"));
117 }
118
119 #[test]
120 fn getter_setter_multiple_calls() {
121 let mut header = QueryTopicsByConsumerRequestHeader::new("g1");
122 assert_eq!(header.get_group(), "g1");
123 header.set_group(CheetahString::from("g2"));
124 assert_eq!(header.get_group(), "g2");
125 header.set_group(CheetahString::from("g3"));
126 assert_eq!(header.get_group(), "g3");
127 }
128
129 #[test]
130 fn serde_deserialize_missing_required_field_errors() {
131 let json = r#"{}"#;
132 let res: Result<QueryTopicsByConsumerRequestHeader, _> = serde_json::from_str(json);
133 assert!(res.is_err());
134 }
135
136 #[test]
137 fn serialization_includes_group_and_flattened_none() {
138 let header = QueryTopicsByConsumerRequestHeader::new("");
139 let json = serde_json::to_string(&header).unwrap();
140 assert!(json.contains("\"group\":"));
141 assert!(!json.contains("brokerName"));
143 }
144
145 #[test]
146 fn serialization_with_rpc_request_header_some() {
147 let header = QueryTopicsByConsumerRequestHeader {
148 group: CheetahString::from("g_with_rpc"),
149 rpc_request_header: Some(RpcRequestHeader {
150 broker_name: Some(CheetahString::from("brokerX")),
151 ..Default::default()
152 }),
153 };
154 let json = serde_json::to_string(&header).unwrap();
155 assert!(json.contains("\"group\":\"g_with_rpc\""));
156 assert!(json.contains("\"brokerName\":\"brokerX\""));
157 }
158
159 #[test]
160 fn deserialization_with_extra_fields_ignored() {
161 let json = r#"{"group":"gextra","unknownField":"x"}"#;
162 let header: QueryTopicsByConsumerRequestHeader = serde_json::from_str(json).unwrap();
163 assert_eq!(header.group, "gextra");
164 }
165
166 #[test]
167 fn round_trip_serialization_deserialization() {
168 let header = QueryTopicsByConsumerRequestHeader {
169 group: CheetahString::from("round"),
170 rpc_request_header: Some(RpcRequestHeader {
171 broker_name: Some(CheetahString::from("rb")),
172 ..Default::default()
173 }),
174 };
175 let json = serde_json::to_string(&header).unwrap();
176 let header2: QueryTopicsByConsumerRequestHeader = serde_json::from_str(&json).unwrap();
177 assert_eq!(header2.group, "round");
178 assert_eq!(
179 header2.rpc_request_header.unwrap().broker_name,
180 Some(CheetahString::from("rb"))
181 );
182 }
183
184 #[test]
185 fn nested_rpc_request_header_access_none_and_some() {
186 let header_none = QueryTopicsByConsumerRequestHeader::new("g_none");
187 assert!(header_none
188 .rpc_request_header
189 .as_ref()
190 .and_then(|h| h.broker_name.clone())
191 .is_none());
192
193 let header_some = QueryTopicsByConsumerRequestHeader {
194 group: CheetahString::from("g_some"),
195 rpc_request_header: Some(RpcRequestHeader {
196 broker_name: Some(CheetahString::from("bk1")),
197 ..Default::default()
198 }),
199 };
200 assert_eq!(
201 header_some
202 .rpc_request_header
203 .as_ref()
204 .and_then(|h| h.broker_name.clone()),
205 Some(CheetahString::from("bk1"))
206 );
207 }
208
209 #[test]
210 fn special_characters_and_long_group_names() {
211 let special = "g-💖-\n-\u{2764}";
212 let header = QueryTopicsByConsumerRequestHeader::new(special);
213 let json = serde_json::to_string(&header).unwrap();
214 let header2: QueryTopicsByConsumerRequestHeader = serde_json::from_str(&json).unwrap();
215 assert_eq!(header2.group, special);
216
217 let long = "a".repeat(5000);
218 let header_long = QueryTopicsByConsumerRequestHeader::new(long.clone());
219 let json_long = serde_json::to_string(&header_long).unwrap();
220 let header_long2: QueryTopicsByConsumerRequestHeader = serde_json::from_str(&json_long).unwrap();
221 assert_eq!(header_long2.group, long.as_str());
222 }
223
224 #[test]
225 fn malformed_json_and_wrong_field_types_error() {
226 let bad = "{";
227 let res: Result<QueryTopicsByConsumerRequestHeader, _> = serde_json::from_str(bad);
228 assert!(res.is_err());
229
230 let wrong_type = r#"{"group":123}"#;
231 let res2: Result<QueryTopicsByConsumerRequestHeader, _> = serde_json::from_str(wrong_type);
232 assert!(res2.is_err());
233 }
234
235 #[test]
236 fn struct_size_check_and_empty_group_behavior() {
237 use std::mem;
238 let _sz = mem::size_of::<QueryTopicsByConsumerRequestHeader>();
239 assert!(_sz > 0);
240
241 let header_empty = QueryTopicsByConsumerRequestHeader::new("");
242 let json = serde_json::to_string(&header_empty).unwrap();
243 assert!(json.contains("\"group\":\"\""));
244 let header2: QueryTopicsByConsumerRequestHeader = serde_json::from_str(&json).unwrap();
245 assert_eq!(header2.group, "");
246 }
247}