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! sync_client_test_on_tcp {
16     (
17         HTTP;
18         $(ClientNum: $client_num: expr,)?
19         $(Request: {
20             Method: $method: expr,
21             Path: $path: expr,
22             $(
23                 Header: $req_n: expr, $req_v: expr,
24             )*
25             Body: $req_body: expr,
26         },
27         Response: {
28             Status: $status: expr,
29             Version: $version: expr,
30             $(
31                 Header: $resp_n: expr, $resp_v: expr,
32             )*
33             Body: $resp_body: expr,
34         },)*
35     ) => {{
36 
37         // The number of servers may be variable based on the number of servers set by the user.
38         // However, cliipy checks that the variable does not need to be variable.
39         #[allow(unused_mut, unused_assignments)]
40         let mut server_num = 1;
41         $(server_num = $client_num;)?
42         let mut handles_vec = vec![];
43 
44         start_tcp_server!(
45             SYNC;
46             ServerNum: server_num,
47             Handles: handles_vec,
48             $(Request: {
49                 Method: $method,
50                 Path: $path,
51                 $(
52                     Header: $req_n, $req_v,
53                 )*
54                 Body: $req_body,
55             },
56             Response: {
57                 Status: $status,
58                 Version: $version,
59                 $(
60                     Header: $resp_n, $resp_v,
61                 )*
62                 Body: $resp_body,
63             },)*
64         );
65 
66         let mut shut_downs = vec![];
67         sync_client_assert_on_tcp!(
68             HTTP;
69             ServerNum: server_num,
70             Handles: handles_vec,
71             ShutDownHandles: shut_downs,
72             $(Request: {
73                 Method: $method,
74                 Path: $path,
75                 $(
76                     Header: $req_n, $req_v,
77                 )*
78                 Body: $req_body,
79             },
80             Response: {
81                 Status: $status,
82                 Version: $version,
83                 $(
84                     Header: $resp_n, $resp_v,
85                 )*
86                 Body: $resp_body,
87             },)*
88         );
89 
90         for shutdown_handle in shut_downs {
91             shutdown_handle.join().expect("join to wait client thread finish failed !");
92         }
93     }};
94 
95 }
96 
97 #[macro_export]
98 macro_rules! sync_client_assert_on_tcp {
99     (
100         HTTP;
101         ServerNum: $server_num: expr,
102         Handles: $handle_vec: expr,
103         ShutDownHandles: $shut_downs: expr,
104         $(Request: {
105             Method: $method: expr,
106             Path: $path: expr,
107             $(
108             Header: $req_n: expr, $req_v: expr,
109             )*
110             Body: $req_body: expr,
111         },
112         Response: {
113             Status: $status: expr,
114             Version: $version: expr,
115             $(
116             Header: $resp_n: expr, $resp_v: expr,
117             )*
118             Body: $resp_body: expr,
119         },)*
120     ) => {{
121         let client = ylong_http_client::sync_impl::Client::new();
122         let client = std::sync::Arc::new(client);
123         for _i in 0..$server_num {
124             let handle = $handle_vec.pop().expect("No more handles !");
125             let client = std::sync::Arc::clone(&client);
126             let shutdown_handle = std::thread::spawn(move || {
127                 sync_client_assertions_on_tcp!(
128                     ServerHandle: handle,
129                     ClientRef: client,
130                     $(Request: {
131                         Method: $method,
132                         Path: $path,
133                         $(
134                             Header: $req_n, $req_v,
135                         )*
136                         Body: $req_body,
137                     },
138                     Response: {
139                         Status: $status,
140                         Version: $version,
141                         $(
142                             Header: $resp_n, $resp_v,
143                         )*
144                         Body: $resp_body,
145                     },)*
146                 );
147                 handle.server_shutdown.recv().expect("server send order failed !");
148             });
149             $shut_downs.push(shutdown_handle);
150         };
151     }}
152 }
153 
154 #[macro_export]
155 macro_rules! sync_client_assertions_on_tcp {
156     (
157         ServerHandle: $handle:expr,
158         ClientRef: $client:expr,
159         $(Request: {
160             Method: $method: expr,
161             Path: $path: expr,
162             $(
163             Header: $req_n: expr, $req_v: expr,
164             )*
165             Body: $req_body: expr,
166         },
167         Response: {
168             Status: $status: expr,
169             Version: $version: expr,
170             $(
171             Header: $resp_n: expr, $resp_v: expr,
172             )*
173             Body: $resp_body: expr,
174         },)*
175     ) => {
176         $(
177             {
178                 let request = build_client_request!(
179                     Request: {
180                         Method: $method,
181                         Path: $path,
182                         Addr: $handle.addr.as_str(),
183                         $(
184                             Header: $req_n, $req_v,
185                         )*
186                         Body: $req_body,
187                     },
188                 );
189                 let mut response = $client
190                     .request(request)
191                     .expect("Request send failed");
192 
193                 assert_eq!(response.status().as_u16(), $status, "Assert response status code failed") ;
194                 assert_eq!(response.version().as_str(), $version, "Assert response version failed");
195                 $(assert_eq!(
196                     response
197                         .headers()
198                         .get($resp_n)
199                         .expect(format!("Get response header \"{}\" failed", $resp_n).as_str())
200                         .to_string()
201                         .expect(format!("Convert response header \"{}\"into string failed", $resp_n).as_str()),
202                     $resp_v,
203                     "Assert response header \"{}\" failed", $resp_n,
204                 );)*
205                 let mut buf = [0u8; 4096];
206                 let mut size = 0;
207                 loop {
208                     let read = response
209                         .body_mut()
210                         .data(&mut buf[size..])
211                         .expect("Response body read failed");
212                     if read == 0 {
213                         break;
214                     }
215                     size += read;
216                 }
217                 assert_eq!(&buf[..size], $resp_body.as_bytes(), "Assert response body failed");
218             }
219         )*
220     }
221 }
222