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