mirror of https://github.com/smithy-lang/smithy-rs
parent
d952ccd8f3
commit
c7949be857
|
@ -82,7 +82,7 @@ class IntegrationTestDependencies(
|
|||
|
||||
private fun serviceSpecificCustomizations(): List<LibRsCustomization> = when (moduleName) {
|
||||
"transcribestreaming" -> listOf(TranscribeTestDependencies())
|
||||
"s3" -> listOf(S3TestDependencies())
|
||||
"s3" -> listOf(S3TestDependencies(runtimeConfig))
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
@ -95,19 +95,29 @@ class TranscribeTestDependencies : LibRsCustomization() {
|
|||
}
|
||||
}
|
||||
|
||||
class S3TestDependencies : LibRsCustomization() {
|
||||
class S3TestDependencies(
|
||||
private val runtimeConfig: RuntimeConfig
|
||||
) : LibRsCustomization() {
|
||||
override fun section(section: LibRsSection): Writable = writable {
|
||||
addDependency(AsyncStd)
|
||||
addDependency(BytesUtils)
|
||||
addDependency(Smol)
|
||||
addDependency(TempFile)
|
||||
runtimeConfig.runtimeCrate("async", scope = DependencyScope.Dev)
|
||||
runtimeConfig.runtimeCrate("client", scope = DependencyScope.Dev)
|
||||
runtimeConfig.runtimeCrate("http", scope = DependencyScope.Dev)
|
||||
runtimeConfig.runtimeCrate("types", scope = DependencyScope.Dev)
|
||||
}
|
||||
}
|
||||
|
||||
private val AsyncStd = CargoDependency("async-std", CratesIo("1.12"), scope = DependencyScope.Dev)
|
||||
private val AsyncStream = CargoDependency("async-stream", CratesIo("0.3"), DependencyScope.Dev)
|
||||
private val Criterion = CargoDependency("criterion", CratesIo("0.3"), scope = DependencyScope.Dev)
|
||||
private val FuturesCore = CargoDependency("futures-core", CratesIo("0.3"), DependencyScope.Dev)
|
||||
private val FuturesUtil = CargoDependency("futures-util", CratesIo("0.3"), scope = DependencyScope.Dev)
|
||||
private val Hound = CargoDependency("hound", CratesIo("3.4"), DependencyScope.Dev)
|
||||
private val SerdeJson = CargoDependency("serde_json", CratesIo("1"), features = emptySet(), scope = DependencyScope.Dev)
|
||||
private val Smol = CargoDependency("smol", CratesIo("1.2"), scope = DependencyScope.Dev)
|
||||
private val Tokio = CargoDependency("tokio", CratesIo("1"), features = setOf("macros", "test-util"), scope = DependencyScope.Dev)
|
||||
private val FuturesUtil = CargoDependency("futures-util", CratesIo("0.3"), scope = DependencyScope.Dev)
|
||||
private val Tracing = CargoDependency("tracing", CratesIo("0.1"), scope = DependencyScope.Dev)
|
||||
private val TracingSubscriber = CargoDependency("tracing-subscriber", CratesIo("0.2"), scope = DependencyScope.Dev)
|
||||
|
|
|
@ -8,8 +8,10 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dev-dependencies]
|
||||
async-std = "1.12"
|
||||
aws-config = { path = "../../build/aws-sdk/sdk/aws-config" }
|
||||
aws-http = { path = "../../build/aws-sdk/sdk/aws-http" }
|
||||
aws-types = { path = "../../build/aws-sdk/sdk/aws-types" }
|
||||
aws-sdk-s3 = { path = "../../build/aws-sdk/sdk/s3" }
|
||||
aws-sdk-sts = { path = "../../build/aws-sdk/sdk/sts" }
|
||||
aws-smithy-async = { path = "../../build/aws-sdk/sdk/aws-smithy-async", features = ["rt-tokio"] }
|
||||
|
@ -24,6 +26,7 @@ http-body = "0.4.5"
|
|||
hyper = "0.14"
|
||||
serde_json = "1"
|
||||
tempfile = "3"
|
||||
smol = "1.2"
|
||||
tokio = { version = "1", features = ["full", "test-util"] }
|
||||
tracing-subscriber = { version = "0.3.5", features = ["env-filter"] }
|
||||
tracing = "0.1"
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
use aws_sdk_s3::model::{
|
||||
CompressionType, CsvInput, CsvOutput, ExpressionType, FileHeaderInfo, InputSerialization,
|
||||
OutputSerialization,
|
||||
};
|
||||
use aws_sdk_s3::{Client, Config, Credentials, Region};
|
||||
use aws_smithy_async::assert_elapsed;
|
||||
use aws_smithy_async::rt::sleep::{AsyncSleep, Sleep};
|
||||
use aws_smithy_client::never::NeverConnector;
|
||||
use aws_smithy_http::result::SdkError;
|
||||
use aws_smithy_types::timeout;
|
||||
use aws_smithy_types::tristate::TriState;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SmolSleep;
|
||||
|
||||
impl AsyncSleep for SmolSleep {
|
||||
fn sleep(&self, duration: Duration) -> Sleep {
|
||||
Sleep::new(async move {
|
||||
smol::Timer::after(duration).await;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_smol_runtime_timeouts() {
|
||||
if let Err(err) = smol::block_on(async { timeout_test(Arc::new(SmolSleep)).await }) {
|
||||
println!("{err}");
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_smol_runtime_retry() {
|
||||
if let Err(err) = smol::block_on(async { retry_test(Arc::new(SmolSleep)).await }) {
|
||||
println!("{err}");
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AsyncStdSleep;
|
||||
|
||||
impl AsyncSleep for AsyncStdSleep {
|
||||
fn sleep(&self, duration: Duration) -> Sleep {
|
||||
Sleep::new(async move { async_std::task::sleep(duration).await })
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_async_std_runtime_timeouts() {
|
||||
if let Err(err) =
|
||||
async_std::task::block_on(async { timeout_test(Arc::new(AsyncStdSleep)).await })
|
||||
{
|
||||
println!("{err}");
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_async_std_runtime_retry() {
|
||||
if let Err(err) = async_std::task::block_on(async { retry_test(Arc::new(AsyncStdSleep)).await })
|
||||
{
|
||||
println!("{err}");
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
async fn timeout_test(sleep_impl: Arc<dyn AsyncSleep>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let conn = NeverConnector::new();
|
||||
let region = Region::from_static("us-east-2");
|
||||
let credentials = Credentials::new("test", "test", None, None, "test");
|
||||
let api_timeouts =
|
||||
timeout::Api::new().with_call_timeout(TriState::Set(Duration::from_secs_f32(0.5)));
|
||||
let timeout_config = timeout::Config::new().with_api_timeouts(api_timeouts);
|
||||
let config = Config::builder()
|
||||
.region(region)
|
||||
.credentials_provider(credentials)
|
||||
.timeout_config(timeout_config)
|
||||
.sleep_impl(sleep_impl)
|
||||
.build();
|
||||
let client = Client::from_conf_conn(config, conn.clone());
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
|
||||
let err = client
|
||||
.select_object_content()
|
||||
.bucket("aws-rust-sdk")
|
||||
.key("sample_data.csv")
|
||||
.expression_type(ExpressionType::Sql)
|
||||
.expression("SELECT * FROM s3object s WHERE s.\"Name\" = 'Jane'")
|
||||
.input_serialization(
|
||||
InputSerialization::builder()
|
||||
.csv(
|
||||
CsvInput::builder()
|
||||
.file_header_info(FileHeaderInfo::Use)
|
||||
.build(),
|
||||
)
|
||||
.compression_type(CompressionType::None)
|
||||
.build(),
|
||||
)
|
||||
.output_serialization(
|
||||
OutputSerialization::builder()
|
||||
.csv(CsvOutput::builder().build())
|
||||
.build(),
|
||||
)
|
||||
.send()
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(format!("{:?}", err), "TimeoutError(RequestTimeoutError { kind: \"API call (all attempts including retries)\", duration: 500ms })");
|
||||
assert_elapsed!(now, std::time::Duration::from_secs_f32(0.5));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn retry_test(sleep_impl: Arc<dyn AsyncSleep>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let conn = NeverConnector::new();
|
||||
let credentials = Credentials::new("test", "test", None, None, "test");
|
||||
let conf = aws_types::SdkConfig::builder()
|
||||
.region(Region::new("us-east-2"))
|
||||
.credentials_provider(aws_types::credentials::SharedCredentialsProvider::new(
|
||||
credentials,
|
||||
))
|
||||
.timeout_config(
|
||||
timeout::Config::new().with_api_timeouts(
|
||||
timeout::Api::new()
|
||||
.with_call_attempt_timeout(TriState::Set(Duration::from_secs_f64(0.1))),
|
||||
),
|
||||
)
|
||||
.sleep_impl(sleep_impl)
|
||||
.build();
|
||||
let client = Client::from_conf_conn(Config::new(&conf), conn.clone());
|
||||
let resp = client
|
||||
.list_buckets()
|
||||
.send()
|
||||
.await
|
||||
.expect_err("call should fail");
|
||||
assert_eq!(
|
||||
conn.num_calls(),
|
||||
3,
|
||||
"client level timeouts should be retried"
|
||||
);
|
||||
assert!(
|
||||
matches!(resp, SdkError::TimeoutError { .. }),
|
||||
"expected a timeout error, got: {}",
|
||||
resp
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -19,7 +19,7 @@ use aws_smithy_types::tristate::TriState;
|
|||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
#[tokio::test]
|
||||
#[tokio::test(start_paused = true)]
|
||||
async fn test_timeout_service_ends_request_that_never_completes() {
|
||||
let conn: NeverService<http::Request<SdkBody>, http::Response<SdkBody>, ConnectorError> =
|
||||
NeverService::new();
|
||||
|
@ -38,7 +38,6 @@ async fn test_timeout_service_ends_request_that_never_completes() {
|
|||
let client = Client::from_conf_conn(config, conn.clone());
|
||||
|
||||
let now = tokio::time::Instant::now();
|
||||
tokio::time::pause();
|
||||
|
||||
let err = client
|
||||
.select_object_content()
|
||||
|
|
|
@ -217,7 +217,7 @@ data class CargoDependency(
|
|||
fun SmithyHttp(runtimeConfig: RuntimeConfig) = runtimeConfig.runtimeCrate("http")
|
||||
fun SmithyHttpTower(runtimeConfig: RuntimeConfig) = runtimeConfig.runtimeCrate("http-tower")
|
||||
fun SmithyProtocolTestHelpers(runtimeConfig: RuntimeConfig) =
|
||||
runtimeConfig.runtimeCrate("protocol-test").copy(scope = DependencyScope.Dev)
|
||||
runtimeConfig.runtimeCrate("protocol-test", scope = DependencyScope.Dev)
|
||||
fun smithyJson(runtimeConfig: RuntimeConfig): CargoDependency = runtimeConfig.runtimeCrate("json")
|
||||
fun smithyQuery(runtimeConfig: RuntimeConfig): CargoDependency = runtimeConfig.runtimeCrate("query")
|
||||
fun smithyXml(runtimeConfig: RuntimeConfig): CargoDependency = runtimeConfig.runtimeCrate("xml")
|
||||
|
|
|
@ -12,6 +12,7 @@ import software.amazon.smithy.model.traits.TimestampFormatTrait
|
|||
import software.amazon.smithy.rust.codegen.rustlang.CargoDependency
|
||||
import software.amazon.smithy.rust.codegen.rustlang.CratesIo
|
||||
import software.amazon.smithy.rust.codegen.rustlang.DependencyLocation
|
||||
import software.amazon.smithy.rust.codegen.rustlang.DependencyScope
|
||||
import software.amazon.smithy.rust.codegen.rustlang.InlineDependency
|
||||
import software.amazon.smithy.rust.codegen.rustlang.Local
|
||||
import software.amazon.smithy.rust.codegen.rustlang.RustDependency
|
||||
|
@ -87,8 +88,8 @@ data class RuntimeConfig(
|
|||
|
||||
val crateSrcPrefix: String = cratePrefix.replace("-", "_")
|
||||
|
||||
fun runtimeCrate(runtimeCrateName: String, optional: Boolean = false): CargoDependency =
|
||||
CargoDependency("$cratePrefix-$runtimeCrateName", runtimeCrateLocation.crateLocation(), optional = optional)
|
||||
fun runtimeCrate(runtimeCrateName: String, optional: Boolean = false, scope: DependencyScope = DependencyScope.Compile): CargoDependency =
|
||||
CargoDependency("$cratePrefix-$runtimeCrateName", runtimeCrateLocation.crateLocation(), optional = optional, scope = scope)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@ use std::task::{Context, Poll};
|
|||
use std::time::Duration;
|
||||
|
||||
/// Async trait with a `sleep` function.
|
||||
pub trait AsyncSleep: std::fmt::Debug + Send + Sync {
|
||||
pub trait AsyncSleep: Debug + Send + Sync {
|
||||
/// Returns a future that sleeps for the given `duration` of time.
|
||||
fn sleep(&self, duration: Duration) -> Sleep;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue