1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #[macro_export]
15 macro_rules! async_client_test_case {
16     (
17         HTTPS;
18         ServeFnName: $server_fn_name: ident,
19         RootCA: $ca_file: expr,
20         RuntimeThreads: $thread_num: expr,
21         $(ClientNum: $client_num: expr,)?
22         $(Request: {
23             Method: $method: expr,
24             Host: $host: expr,
25             $(
26                 Header: $req_n: expr, $req_v: expr,
27             )*
28             Body: $req_body: expr,
29         },
30         Response: {
31             Status: $status: expr,
32             Version: $version: expr,
33             $(
34                 Header: $resp_n: expr, $resp_v: expr,
35             )*
36             Body: $resp_body: expr,
37         },)*
38     ) => {{
39         define_service_handle!(HTTPS;);
40         set_server_fn!(
41             ASYNC;
42             $server_fn_name,
43             $(Request: {
44                 Method: $method,
45                 $(
46                     Header: $req_n, $req_v,
47                 )*
48                 Body: $req_body,
49             },
50             Response: {
51                 Status: $status,
52                 Version: $version,
53                 $(
54                     Header: $resp_n, $resp_v,
55                 )*
56                 Body: $resp_body,
57             },)*
58         );
59 
60         let runtime = init_test_work_runtime($thread_num);
61         // The number of servers may be variable based on the number of servers set by the user.
62         // However, clippy checks that the variable does not need to be variable.
63         #[allow(unused_mut, unused_assignments)]
64         let mut server_num = 1;
65         $(server_num = $client_num;)?
66 
67         let mut handles_vec = vec![];
68         start_server!(
69             HTTPS;
70             ServerNum: server_num,
71             Runtime: runtime,
72             Handles: handles_vec,
73             ServeFnName: $server_fn_name,
74         );
75 
76         let mut shut_downs = vec![];
77         async_client_assert!(
78             HTTPS;
79             RootCA: $ca_file,
80             Runtime: runtime,
81             ServerNum: server_num,
82             Handles: handles_vec,
83             ShutDownHandles: shut_downs,
84             $(Request: {
85                 Method: $method,
86                 Host: $host,
87                 $(
88                     Header: $req_n, $req_v,
89                 )*
90                 Body: $req_body,
91             },
92             Response: {
93                 Status: $status,
94                 Version: $version,
95                 $(
96                     Header: $resp_n, $resp_v,
97                 )*
98                 Body: $resp_body,
99             },)*
100         );
101 
102         for shutdown_handle in shut_downs {
103             runtime.block_on(shutdown_handle).expect("Runtime wait for server shutdown failed");
104         }
105     }};
106     (
107         HTTP;
108         ServeFnName: $server_fn_name: ident,
109         RuntimeThreads: $thread_num: expr,
110         $(ClientNum: $client_num: expr,)?
111         $(Request: {
112             Method: $method: expr,
113             Host: $host: expr,
114             $(
115                 Header: $req_n: expr, $req_v: expr,
116             )*
117             Body: $req_body: expr,
118         },
119         Response: {
120             Status: $status: expr,
121             Version: $version: expr,
122             $(
123                 Header: $resp_n: expr, $resp_v: expr,
124             )*
125             Body: $resp_body: expr,
126         },)*
127     ) => {{
128         define_service_handle!(HTTP;);
129         set_server_fn!(
130             ASYNC;
131             $server_fn_name,
132             $(Request: {
133                 Method: $method,
134                 $(
135                     Header: $req_n, $req_v,
136                 )*
137                 Body: $req_body,
138             },
139             Response: {
140                 Status: $status,
141                 Version: $version,
142                 $(
143                     Header: $resp_n, $resp_v,
144                 )*
145                 Body: $resp_body,
146             },)*
147         );
148 
149         let runtime = init_test_work_runtime($thread_num);
150         // The number of servers may be variable based on the number of servers set by the user.
151         // However, clippy checks that the variable does not need to be variable.
152         #[allow(unused_mut, unused_assignments)]
153         let mut server_num = 1;
154         $(server_num = $client_num;)?
155         let mut handles_vec = vec![];
156 
157         start_server!(
158             HTTP;
159             ServerNum: server_num,
160             Runtime: runtime,
161             Handles: handles_vec,
162             ServeFnName: $server_fn_name,
163         );
164 
165         let mut shut_downs = vec![];
166         async_client_assert!(
167             HTTP;
168             Runtime: runtime,
169             ServerNum: server_num,
170             Handles: handles_vec,
171             ShutDownHandles: shut_downs,
172             $(Request: {
173                 Method: $method,
174                 Host: $host,
175                 $(
176                     Header: $req_n, $req_v,
177                 )*
178                 Body: $req_body,
179             },
180             Response: {
181                 Status: $status,
182                 Version: $version,
183                 $(
184                     Header: $resp_n, $resp_v,
185                 )*
186                 Body: $resp_body,
187             },)*
188         );
189 
190         for shutdown_handle in shut_downs {
191             runtime.block_on(shutdown_handle).expect("Runtime wait for server shutdown failed");
192         }
193     }};
194 
195 }
196 
197 #[macro_export]
198 macro_rules! async_client_assert {
199     (
200         HTTPS;
201         RootCA: $ca_file: expr,
202         Runtime: $runtime: expr,
203         ServerNum: $server_num: expr,
204         Handles: $handle_vec: expr,
205         ShutDownHandles: $shut_downs: expr,
206         $(Request: {
207             Method: $method: expr,
208             Host: $host: expr,
209             $(
210             Header: $req_n: expr, $req_v: expr,
211             )*
212             Body: $req_body: expr,
213         },
214         Response: {
215             Status: $status: expr,
216             Version: $version: expr,
217             $(
218             Header: $resp_n: expr, $resp_v: expr,
219             )*
220             Body: $resp_body: expr,
221         },)*
222     ) => {{
223         let client = ylong_http_client::async_impl::Client::builder()
224         .tls_ca_file($ca_file)
225         .danger_accept_invalid_hostnames(true)
226         .build()
227         .unwrap();
228         let client = std::sync::Arc::new(client);
229         for _i in 0..$server_num {
230             let handle = $handle_vec.pop().expect("No more handles !");
231             let client = std::sync::Arc::clone(&client);
232             let shutdown_handle = $runtime.spawn(async move {
233                 async_client_assertions!(
234                     ServerHandle: handle,
235                     ClientRef: client,
236                     $(Request: {
237                         Method: $method,
238                         Host: $host,
239                         $(
240                             Header: $req_n, $req_v,
241                         )*
242                         Body: $req_body,
243                     },
244                     Response: {
245                         Status: $status,
246                         Version: $version,
247                         $(
248                             Header: $resp_n, $resp_v,
249                         )*
250                         Body: $resp_body,
251                     },)*
252                 );
253             });
254             $shut_downs.push(shutdown_handle);
255         }
256     }};
257     (
258         HTTP;
259         Runtime: $runtime: expr,
260         ServerNum: $server_num: expr,
261         Handles: $handle_vec: expr,
262         ShutDownHandles: $shut_downs: expr,
263         $(Request: {
264             Method: $method: expr,
265             Host: $host: expr,
266             $(
267             Header: $req_n: expr, $req_v: expr,
268             )*
269             Body: $req_body: expr,
270         },
271         Response: {
272             Status: $status: expr,
273             Version: $version: expr,
274             $(
275             Header: $resp_n: expr, $resp_v: expr,
276             )*
277             Body: $resp_body: expr,
278         },)*
279     ) => {{
280         //let client = async_build_http_client();
281         let client = ylong_http_client::async_impl::Client::new();
282         let client = std::sync::Arc::new(client);
283         for _i in 0..$server_num {
284             let mut handle = $handle_vec.pop().expect("No more handles !");
285             let client = std::sync::Arc::clone(&client);
286             let shutdown_handle = $runtime.spawn(async move {
287                 async_client_assertions!(
288                     ServerHandle: handle,
289                     ClientRef: client,
290                     $(Request: {
291                         Method: $method,
292                         Host: $host,
293                         $(
294                             Header: $req_n, $req_v,
295                         )*
296                         Body: $req_body,
297                     },
298                     Response: {
299                         Status: $status,
300                         Version: $version,
301                         $(
302                             Header: $resp_n, $resp_v,
303                         )*
304                         Body: $resp_body,
305                     },)*
306                 );
307                 ensure_server_shutdown!(ServerHandle: handle);
308             });
309             $shut_downs.push(shutdown_handle);
310         }
311     }}
312 }
313 
314 #[macro_export]
315 macro_rules! async_client_assertions {
316     (
317         ServerHandle: $handle:expr,
318         ClientRef: $client:expr,
319         $(Request: {
320             Method: $method: expr,
321             Host: $host: expr,
322             $(
323             Header: $req_n: expr, $req_v: expr,
324             )*
325             Body: $req_body: expr,
326         },
327         Response: {
328             Status: $status: expr,
329             Version: $version: expr,
330             $(
331                 Header: $resp_n: expr, $resp_v: expr,
332             )*
333             Body: $resp_body: expr,
334         },)*
335     ) => {
336         $(
337             let request = ylong_http_client::async_impl::Request::builder()
338                 .method($method)
339                 .url(format!("{}:{}", $host, $handle.port).as_str())
340                 $(.header($req_n, $req_v))*
341                 .body(ylong_http_client::async_impl::Body::slice($req_body))
342                 .expect("Request build failed");
343 
344             let mut response = $client
345                 .request(request)
346                 .await
347                 .expect("Request send failed");
348 
349             assert_eq!(response.status().as_u16(), $status, "Assert response status code failed") ;
350             assert_eq!(response.version().as_str(), $version, "Assert response version failed");
351             $(assert_eq!(
352                 response
353                     .headers()
354                     .get($resp_n)
355                     .expect(format!("Get response header \"{}\" failed", $resp_n).as_str())
356                     .to_string()
357                     .expect(format!("Convert response header \"{}\"into string failed", $resp_n).as_str()),
358                 $resp_v,
359                 "Assert response header \"{}\" failed", $resp_n,
360             );)*
361             let mut buf = [0u8; 4096];
362             let mut size = 0;
363             loop {
364                 let read = response
365                     .data(&mut buf[size..]).await
366                     .expect("Response body read failed");
367                 if read == 0 {
368                     break;
369                 }
370                 size += read;
371             }
372             assert_eq!(&buf[..size], $resp_body.as_bytes(), "Assert response body failed");
373         )*
374     }
375 }
376