AWS SDK

AWS SDK

rev. 24cdfca3d678a4fcc7189d43ab93f4131a5691fa

Files changed:

tmp-codegen-diff/aws-sdk/sdk/aws-smithy-runtime/src/client/defaults.rs

@@ -154,154 +213,237 @@
  174    174   
                validate_timeout_config,
  175    175   
            ))
  176    176   
        })
  177    177   
        .with_config(layer("default_timeout_config", |layer| {
  178    178   
            layer.store_put(TimeoutConfig::disabled());
  179    179   
        }))
  180    180   
        .into_shared(),
  181    181   
    )
  182    182   
}
  183    183   
         184  +
/// Runtime plugin that sets the default timeout config (no timeouts).
         185  +
pub fn default_timeout_config_plugin_v2() -> Option<SharedRuntimePlugin> {
         186  +
    Some(
         187  +
        default_plugin("default_timeout_config_plugin", |components| {
         188  +
            components.with_config_validator(SharedConfigValidator::base_client_config_fn(
         189  +
                validate_timeout_config,
         190  +
            ))
         191  +
        })
         192  +
        .with_config(layer("default_timeout_config", |layer| {
         193  +
            let timeout_config = if default_sleep_impl_plugin().is_some() {
         194  +
                TimeoutConfig::builder()
         195  +
                    .connect_timeout(Duration::from_millis(3100))
         196  +
                    .disable_operation_attempt_timeout()
         197  +
                    .disable_operation_timeout()
         198  +
                    .build()
         199  +
            } else {
         200  +
                TimeoutConfig::disabled()
         201  +
            };
         202  +
            layer.store_put(timeout_config);
         203  +
        }))
         204  +
        .into_shared(),
         205  +
    )
         206  +
}
         207  +
  184    208   
fn validate_timeout_config(
  185    209   
    components: &RuntimeComponentsBuilder,
  186    210   
    cfg: &ConfigBag,
  187    211   
) -> Result<(), BoxError> {
  188    212   
    if let Some(timeout_config) = cfg.load::<TimeoutConfig>() {
  189    213   
        if timeout_config.has_timeouts() && components.sleep_impl().is_none() {
  190    214   
            Err("An async sleep implementation is required for timeouts to work. Please provide a `sleep_impl` on \
  191    215   
                 the config, or disable timeouts.".into())
  192    216   
        } else {
  193    217   
            Ok(())
@@ -300,324 +360,384 @@
  320    344   
    [
  321    345   
        default_http_client_plugin_v2(behavior_version),
  322    346   
        default_identity_cache_plugin(),
  323    347   
        default_retry_config_plugin(
  324    348   
            params
  325    349   
                .retry_partition_name
  326    350   
                .expect("retry_partition_name is required"),
  327    351   
        ),
  328    352   
        default_sleep_impl_plugin(),
  329    353   
        default_time_source_plugin(),
  330         -
        default_timeout_config_plugin(),
         354  +
        default_timeout_config_plugin_v2(),
  331    355   
        enforce_content_length_runtime_plugin(),
  332    356   
        default_stalled_stream_protection_config_plugin_v2(behavior_version),
  333    357   
    ]
  334    358   
    .into_iter()
  335    359   
    .flatten()
  336    360   
    .collect::<Vec<SharedRuntimePlugin>>()
  337    361   
}
  338    362   
  339    363   
#[cfg(test)]
  340    364   
mod tests {

tmp-codegen-diff/aws-sdk/sdk/s3/tests/timeouts.rs

@@ -139,139 +207,277 @@
  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   
}