159 159 | }
|
160 160 | }
|
161 161 | } else {
|
162 162 | panic!("the client didn't timeout");
|
163 163 | }
|
164 164 |
|
165 165 | server_shutdown.send(()).unwrap();
|
166 166 | server_handle.await.unwrap();
|
167 167 | }
|
168 168 |
|
169 - | #[tokio::test]
|
170 - | async fn test_connect_timeout() {
|
171 - | let config = Config::builder()
|
169 + | async fn run_connect_timeout_test(timeout_config: Option<TimeoutConfig>, expected_timeout_ms: u64) {
|
170 + | let mut config_builder = Config::builder()
|
172 171 | .with_test_defaults()
|
173 172 | .region(Region::new("us-east-1"))
|
174 - | .timeout_config(
|
173 + | .endpoint_url("http://172.255.255.0:18104");
|
174 + |
|
175 + | if let Some(tc) = timeout_config {
|
176 + | config_builder = config_builder.timeout_config(tc);
|
177 + | }
|
178 + |
|
179 + | let client = Client::from_conf(config_builder.build());
|
180 + |
|
181 + | if let Ok(result) = timeout(
|
182 + | Duration::from_millis(expected_timeout_ms + 1000),
|
183 + | client.get_object().bucket("test").key("test").send(),
|
184 + | )
|
185 + | .await
|
186 + | {
|
187 + | match result {
|
188 + | Ok(_) => panic!("should not have succeeded"),
|
189 + | Err(err) => {
|
190 + | let message = format!("{}", DisplayErrorContext(&err));
|
191 + | let expected =
|
192 + | "timeout: client error (Connect): HTTP connect timeout occurred after";
|
193 + | assert!(
|
194 + | message.contains(expected),
|
195 + | "expected '{message}' to contain '{expected}'"
|
196 + | );
|
197 + | }
|
198 + | }
|
199 + | } else {
|
200 + | panic!("the client didn't timeout");
|
201 + | }
|
202 + | }
|
203 + |
|
204 + | #[tokio::test]
|
205 + | async fn test_connect_timeout_explicit() {
|
206 + | run_connect_timeout_test(
|
207 + | Some(
|
175 208 | TimeoutConfig::builder()
|
176 209 | .connect_timeout(Duration::from_millis(300))
|
177 210 | .build(),
|
178 - | )
|
179 - | .endpoint_url(
|
180 - | // Emulate a connect timeout error by hitting an unroutable IP
|
181 - | "http://172.255.255.0:18104",
|
182 - | )
|
211 + | ),
|
212 + | 300,
|
213 + | )
|
214 + | .await;
|
215 + | }
|
216 + |
|
217 + | #[tokio::test]
|
218 + | async fn test_connect_timeout_default() {
|
219 + | run_connect_timeout_test(None, 3100).await;
|
220 + | }
|
221 + |
|
222 + | #[tokio::test]
|
223 + | async fn test_connect_timeout_disabled() {
|
224 + | let config = Config::builder()
|
225 + | .with_test_defaults()
|
226 + | .region(Region::new("us-east-1"))
|
227 + | .timeout_config(TimeoutConfig::disabled())
|
228 + | .endpoint_url("http://172.255.255.0:18104")
|
183 229 | .build();
|
184 230 | let client = Client::from_conf(config);
|
185 231 |
|
232 + | if let Err(_) = timeout(
|
233 + | Duration::from_secs(5),
|
234 + | client.get_object().bucket("test").key("test").send(),
|
235 + | )
|
236 + | .await
|
237 + | {
|
238 + | // Expected: the operation should not complete within 5 seconds when timeout is disabled
|
239 + | } else {
|
240 + | panic!("operation completed unexpectedly when timeout was disabled");
|
241 + | }
|
242 + | }
|
243 + |
|
244 + | // this behavior is surprising—I would have expected this to fail, but it seems like the default
|
245 + | // runtime plugin always is providing a sleep impl. In any case, this pattern does not seem to exist
|
246 + | // in real life
|
247 + | #[tokio::test]
|
248 + | async fn test_connect_timeout_with_sleep_impl_none() {
|
249 + | let mut builder = Config::builder()
|
250 + | .with_test_defaults()
|
251 + | .region(Region::new("us-east-1"))
|
252 + | .endpoint_url("http://172.255.255.0:18104");
|
253 + | builder.set_sleep_impl(None);
|
254 + | let client = Client::from_conf(builder.build());
|
255 + |
|
186 256 | if let Ok(result) = timeout(
|
187 - | Duration::from_millis(1000),
|
257 + | Duration::from_millis(4100),
|
188 258 | client.get_object().bucket("test").key("test").send(),
|
189 259 | )
|
190 260 | .await
|
191 261 | {
|
192 262 | match result {
|
193 263 | Ok(_) => panic!("should not have succeeded"),
|
194 264 | Err(err) => {
|
195 265 | let message = format!("{}", DisplayErrorContext(&err));
|
196 266 | let expected =
|
197 - | "timeout: client error (Connect): HTTP connect timeout occurred after 300ms";
|
267 + | "timeout: client error (Connect): HTTP connect timeout occurred after";
|
198 268 | assert!(
|
199 269 | message.contains(expected),
|
200 270 | "expected '{message}' to contain '{expected}'"
|
201 271 | );
|
202 272 | }
|
203 273 | }
|
204 274 | } else {
|
205 275 | panic!("the client didn't timeout");
|
206 276 | }
|
207 277 | }
|