Merge `sra-test` into the SDK integration tests and fix its tests (#2883)

This PR merges the benchmark and integration tests from `aws/sra-test`
into the SDK integration tests, and updates the tests so that they
compile and pass.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._
This commit is contained in:
John DiSanti 2023-07-28 10:09:18 -07:00 committed by GitHub
parent 55a1536ece
commit cf8df40f18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 2975 additions and 847 deletions

View File

@ -4,6 +4,7 @@
*/
use crate::service_clock_skew::ServiceClockSkew;
use aws_smithy_async::time::TimeSource;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::interceptors::context::BeforeTransmitInterceptorContextMut;
use aws_smithy_runtime_api::client::interceptors::Interceptor;
@ -16,7 +17,7 @@ use aws_smithy_types::timeout::TimeoutConfig;
use aws_smithy_types::DateTime;
use http::{HeaderName, HeaderValue};
use std::borrow::Cow;
use std::time::{Duration, SystemTime};
use std::time::Duration;
#[allow(clippy::declare_interior_mutable_const)] // we will never mutate this
const AMZ_SDK_REQUEST: HeaderName = HeaderName::from_static("amz-sdk-request");
@ -63,11 +64,15 @@ impl RequestInfoInterceptor {
}
}
fn build_ttl_pair(&self, cfg: &ConfigBag) -> Option<(Cow<'static, str>, Cow<'static, str>)> {
fn build_ttl_pair(
&self,
cfg: &ConfigBag,
timesource: impl TimeSource,
) -> Option<(Cow<'static, str>, Cow<'static, str>)> {
let timeout_config = cfg.load::<TimeoutConfig>()?;
let socket_read = timeout_config.read_timeout()?;
let estimated_skew: Duration = cfg.load::<ServiceClockSkew>().cloned()?.into();
let current_time = SystemTime::now();
let current_time = timesource.now();
let ttl = current_time.checked_add(socket_read + estimated_skew)?;
let mut timestamp = DateTime::from(ttl);
// Set subsec_nanos to 0 so that the formatted `DateTime` won't have fractional seconds.
@ -94,11 +99,16 @@ impl Interceptor for RequestInfoInterceptor {
fn modify_before_transmit(
&self,
context: &mut BeforeTransmitInterceptorContextMut<'_>,
_runtime_components: &RuntimeComponents,
runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let mut pairs = RequestPairs::new();
if let Some(pair) = self.build_ttl_pair(cfg) {
if let Some(pair) = self.build_ttl_pair(
cfg,
runtime_components
.time_source()
.ok_or("A timesource must be provided")?,
) {
pairs = pairs.with_pair(pair);
}
if let Some(pair) = self.build_attempts_pair(cfg) {

View File

@ -35,6 +35,7 @@ import software.amazon.smithy.rust.codegen.core.rustlang.writable
import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsCustomization
import software.amazon.smithy.rust.codegen.core.smithy.generators.LibRsSection
import software.amazon.smithy.rust.codegen.core.testutil.testDependenciesOnly
import software.amazon.smithy.rustsdk.AwsCargoDependency.awsRuntime
import java.nio.file.Files
import java.nio.file.Paths
import kotlin.io.path.absolute
@ -99,6 +100,7 @@ class IntegrationTestDependencies(
if (codegenContext.smithyRuntimeMode.generateOrchestrator) {
addDependency(smithyRuntime(runtimeConfig).copy(features = setOf("test-util"), scope = DependencyScope.Dev))
addDependency(smithyRuntimeApi(runtimeConfig).copy(features = setOf("test-util"), scope = DependencyScope.Dev))
addDependency(awsRuntime(runtimeConfig).toDevDependency().withFeature("test-util"))
}
}
if (hasBenches) {
@ -148,12 +150,5 @@ class S3TestDependencies(private val codegenContext: ClientCodegenContext) : Lib
addDependency(TempFile)
addDependency(TracingAppender)
addDependency(TracingTest)
// TODO(enableNewSmithyRuntimeCleanup): These additional dependencies may not be needed anymore when removing this flag
// depending on if the sra-test is kept around or not.
if (codegenContext.smithyRuntimeMode.generateOrchestrator) {
addDependency(smithyRuntime(codegenContext.runtimeConfig).toDevDependency())
addDependency(smithyRuntimeApi(codegenContext.runtimeConfig).toDevDependency())
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
[package]
name = "orchestrator-vs-middleware"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aws-config = { path = "../../build/aws-sdk/sdk/aws-config" }
aws-credential-types = { path = "../../build/aws-sdk/sdk/aws-credential-types", features = ["test-util"] }
aws-sdk-s3 = { path = "../../build/aws-sdk/sdk/s3" }
aws-smithy-client = { path = "../../build/aws-sdk/sdk/aws-smithy-client", features = ["test-util", "wiremock"] }
criterion = { version = "0.4", features = ["async_tokio"] }
http = "0.2.3"
middleware-s3 = { version = "0.28", package = "aws-sdk-s3", features = ["test-util"] }
middleware-smithy-client = { version = "0.55.3", package = "aws-smithy-client", features = ["test-util", "rustls"] }
tokio = { version = "1.23.1", features = ["macros", "test-util", "rt-multi-thread"] }
[profile.release]
debug = 1
[[bench]]
name = "middleware_vs_orchestrator"
harness = false

View File

@ -0,0 +1,6 @@
### Middleware vs. Orchestrator Benchmark
To run the benchmark:
```bash
./gradlew :aws:sdk:assemble && (cd aws/sdk/integration-tests/s3 && cargo bench)
```

View File

@ -9,12 +9,6 @@ use aws_sdk_s3 as s3;
use criterion::{BenchmarkId, Criterion};
macro_rules! test_connection {
(head) => {
test_connection!(aws_smithy_client)
};
(last_release) => {
test_connection!(last_release_smithy_client)
};
($package:ident) => {
$package::test_connection::infallible_connection_fn(|req| {
assert_eq!(
@ -46,44 +40,6 @@ macro_rules! test_connection {
};
}
macro_rules! create_client {
(head) => {
create_client!(head, aws_sdk_s3)
};
(last_release) => {
create_client!(last_release, last_release_s3)
};
($original:ident, $package:ident) => {{
let conn = test_connection!($original);
let config = $package::Config::builder()
.credentials_provider($package::config::Credentials::for_tests())
.region($package::config::Region::new("us-east-1"))
.http_connector(conn.clone())
.build();
$package::Client::from_conf(config)
}};
}
macro_rules! middleware_bench_fn {
($fn_name:ident, head) => {
middleware_bench_fn!($fn_name, aws_sdk_s3)
};
($fn_name:ident, last_release) => {
middleware_bench_fn!($fn_name, last_release_s3)
};
($fn_name:ident, $package:ident) => {
async fn $fn_name(client: &$package::Client) {
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.send()
.await
.expect("successful execution");
}
};
}
async fn orchestrator(client: &s3::Client) {
let _output = client
.list_objects_v2()
@ -94,34 +50,49 @@ async fn orchestrator(client: &s3::Client) {
.expect("successful execution");
}
fn bench(c: &mut Criterion) {
let head_client = create_client!(head);
middleware_bench_fn!(middleware_head, head);
async fn middleware(client: &middleware_s3::Client) {
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.send()
.await
.expect("successful execution");
}
let last_release_client = create_client!(last_release);
middleware_bench_fn!(middleware_last_release, last_release);
fn bench(c: &mut Criterion) {
let orchestrator_client = {
let conn = test_connection!(aws_smithy_client);
let config = aws_sdk_s3::Config::builder()
.credentials_provider(aws_sdk_s3::config::Credentials::for_tests())
.region(aws_sdk_s3::config::Region::new("us-east-1"))
.http_connector(conn.clone())
.build();
aws_sdk_s3::Client::from_conf(config)
};
let middleware_client = {
let conn = test_connection!(middleware_smithy_client);
let config = middleware_s3::Config::builder()
.credentials_provider(middleware_s3::config::Credentials::for_tests())
.region(middleware_s3::config::Region::new("us-east-1"))
.http_connector(conn.clone())
.build();
middleware_s3::Client::from_conf(config)
};
let mut group = c.benchmark_group("compare");
let param = "S3 ListObjectsV2";
group.bench_with_input(
BenchmarkId::new("middleware (HEAD)", param),
param,
|b, _| {
b.to_async(tokio::runtime::Runtime::new().unwrap())
.iter(|| async { middleware_head(&head_client).await })
},
);
group.bench_with_input(
BenchmarkId::new("middleware (last_release)", param),
param,
|b, _| {
b.to_async(tokio::runtime::Runtime::new().unwrap())
.iter(|| async { middleware_last_release(&last_release_client).await })
.iter(|| async { middleware(&middleware_client).await })
},
);
group.bench_with_input(BenchmarkId::new("orchestrator", param), param, |b, _| {
b.to_async(tokio::runtime::Runtime::new().unwrap())
.iter(|| async { orchestrator(&head_client).await })
.iter(|| async { orchestrator(&orchestrator_client).await })
});
group.finish();
}

View File

@ -15,6 +15,7 @@ async-std = "1.12.0"
aws-config = { path = "../../build/aws-sdk/sdk/aws-config" }
aws-credential-types = { path = "../../build/aws-sdk/sdk/aws-credential-types", features = ["test-util"] }
aws-http = { path = "../../build/aws-sdk/sdk/aws-http" }
aws-runtime = { path = "../../build/aws-sdk/sdk/aws-runtime", features = ["test-util"] }
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 = ["test-util", "rt-tokio"] }
@ -22,6 +23,7 @@ aws-smithy-client = { path = "../../build/aws-sdk/sdk/aws-smithy-client", featur
aws-smithy-http = { path = "../../build/aws-sdk/sdk/aws-smithy-http" }
aws-smithy-protocol-test = { path = "../../build/aws-sdk/sdk/aws-smithy-protocol-test" }
aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["test-util"] }
aws-smithy-runtime-api = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["test-util"] }
aws-smithy-types = { path = "../../build/aws-sdk/sdk/aws-smithy-types" }
aws-types = { path = "../../build/aws-sdk/sdk/aws-types" }
bytes = "1"

View File

@ -11,7 +11,7 @@
"notarealsessiontoken"
],
"authorization": [
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20210618/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=e7eccf4e792113f5f17a50bfd8f1719479e89ba0b476894e6f3dba030dc87f82"
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20190601/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=43970cfd0324cb28a86459789b7a1c7684cf54b0b3c9842a84f3b24343fa038a"
],
"x-amz-user-agent": [
"aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
@ -55,9 +55,6 @@
"status": 500,
"version": "HTTP/1.1",
"headers": {
"server": [
"AmazonS3"
],
"x-amz-request-id": [
"foo-id"
],
@ -103,7 +100,7 @@
}
},
{
"connection_id": 0,
"connection_id": 1,
"action": {
"Request": {
"request": {
@ -113,7 +110,7 @@
"notarealsessiontoken"
],
"authorization": [
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20210618/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=e7eccf4e792113f5f17a50bfd8f1719479e89ba0b476894e6f3dba030dc87f82"
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20190601/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=6d0f0da831a7d3ad1bde4e98580177bc0ef0acc21064dd26394006006392cb14"
],
"x-amz-user-agent": [
"aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
@ -140,7 +137,7 @@
}
},
{
"connection_id": 0,
"connection_id": 1,
"action": {
"Eof": {
"ok": true,
@ -149,7 +146,7 @@
}
},
{
"connection_id": 0,
"connection_id": 1,
"action": {
"Response": {
"response": {
@ -157,9 +154,6 @@
"status": 500,
"version": "HTTP/1.1",
"headers": {
"server": [
"AmazonS3"
],
"x-amz-request-id": [
"foo-id"
],
@ -185,7 +179,7 @@
}
},
{
"connection_id": 0,
"connection_id": 1,
"action": {
"Data": {
"data": {
@ -196,7 +190,7 @@
}
},
{
"connection_id": 0,
"connection_id": 1,
"action": {
"Eof": {
"ok": true,
@ -205,7 +199,7 @@
}
},
{
"connection_id": 0,
"connection_id": 2,
"action": {
"Request": {
"request": {
@ -215,7 +209,7 @@
"notarealsessiontoken"
],
"authorization": [
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20210618/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=e7eccf4e792113f5f17a50bfd8f1719479e89ba0b476894e6f3dba030dc87f82"
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20190601/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=8160b1d1200c10cde681ac6f4490c98023af9c4b3b8fd8a82e7560f87c126a53"
],
"x-amz-user-agent": [
"aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
@ -242,7 +236,7 @@
}
},
{
"connection_id": 0,
"connection_id": 2,
"action": {
"Eof": {
"ok": true,
@ -251,7 +245,7 @@
}
},
{
"connection_id": 0,
"connection_id": 2,
"action": {
"Response": {
"response": {
@ -287,7 +281,7 @@
}
},
{
"connection_id": 0,
"connection_id": 2,
"action": {
"Data": {
"data": {
@ -298,7 +292,7 @@
}
},
{
"connection_id": 0,
"connection_id": 2,
"action": {
"Eof": {
"ok": true,

View File

@ -0,0 +1,125 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#[cfg(not(aws_sdk_middleware_mode))]
mod tests {
use aws_sdk_s3::config::interceptors::BeforeTransmitInterceptorContextMut;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::Client;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_client::test_connection::capture_request;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::interceptors::Interceptor;
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
use aws_smithy_types::config_bag::{ConfigBag, Layer, Storable, StoreReplace};
use http::header::USER_AGENT;
use http::HeaderValue;
#[tokio::test]
async fn interceptor_priority() {
#[derive(Debug, Eq, PartialEq)]
struct TestValue(&'static str);
impl Storable for TestValue {
type Storer = StoreReplace<Self>;
}
#[derive(Debug)]
struct TestInterceptor(&'static str);
impl Interceptor for TestInterceptor {
fn name(&self) -> &'static str {
"TestInterceptor"
}
fn modify_before_signing(
&self,
_context: &mut BeforeTransmitInterceptorContextMut<'_>,
_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let mut layer = Layer::new("test");
layer.store_put(TestValue(self.0));
cfg.push_layer(layer);
Ok(())
}
fn modify_before_transmit(
&self,
context: &mut BeforeTransmitInterceptorContextMut<'_>,
_runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let value = cfg.load::<TestValue>().unwrap();
context
.request_mut()
.headers_mut()
.insert("test-header", HeaderValue::from_static(value.0));
Ok(())
}
}
let (conn, rx) = capture_request(None);
// The first `TestInterceptor` will put `value1` into config
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn))
.interceptor(TestInterceptor("value1"))
.build();
let client = Client::from_conf(config);
// The second `TestInterceptor` will replace `value1` with `value2` in config
dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.customize()
.await
.unwrap()
.interceptor(TestInterceptor("value2"))
.send()
.await
)
.expect_err("no fake response set");
let request = rx.expect_request();
assert_eq!("value2", request.headers()["test-header"]);
}
#[tokio::test]
async fn set_test_user_agent_through_request_mutation() {
let (conn, rx) = capture_request(None);
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn.clone()))
.build();
let client = Client::from_conf(config);
dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.customize()
.await
.unwrap()
.mutate_request(|request| {
let headers = request.headers_mut();
headers.insert(USER_AGENT, HeaderValue::try_from("test").unwrap());
headers.insert("x-amz-user-agent", HeaderValue::try_from("test").unwrap());
})
.send()
.await
)
.expect_err("no fake response set");
let request = rx.expect_request();
assert_eq!("test", request.headers()[USER_AGENT]);
assert_eq!("test", request.headers()["x-amz-user-agent"]);
}
}

View File

@ -0,0 +1,285 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
#[cfg(not(aws_sdk_middleware_mode))]
mod tests {
use aws_http::user_agent::AwsUserAgent;
use aws_runtime::invocation_id::{InvocationId, PredefinedInvocationIdGenerator};
use aws_sdk_s3::config::interceptors::BeforeSerializationInterceptorContextMut;
use aws_sdk_s3::config::interceptors::FinalizerInterceptorContextRef;
use aws_sdk_s3::config::retry::RetryConfig;
use aws_sdk_s3::config::timeout::TimeoutConfig;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::config::{Interceptor, SharedAsyncSleep};
use aws_sdk_s3::Client;
use aws_smithy_async::test_util::InstantSleep;
use aws_smithy_async::test_util::ManualTimeSource;
use aws_smithy_async::time::SharedTimeSource;
use aws_smithy_client::dvr;
use aws_smithy_client::dvr::MediaType;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
use aws_smithy_types::config_bag::{ConfigBag, Layer};
use std::time::{Duration, UNIX_EPOCH};
// # One SDK operation invocation.
// # Client retries 3 times, successful response on 3rd attempt.
// # Fast network, latency + server time is less than one second.
// # No clock skew
// # Client waits 1 second between retry attempts.
#[tokio::test]
async fn three_retries_and_then_success() {
let _logs = capture_test_logs();
#[derive(Debug)]
struct TimeInterceptor {
time_source: ManualTimeSource,
}
impl Interceptor for TimeInterceptor {
fn name(&self) -> &'static str {
"TimeInterceptor"
}
fn modify_before_serialization(
&self,
_context: &mut BeforeSerializationInterceptorContextMut<'_>,
_runtime_components: &RuntimeComponents,
cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
let mut layer = Layer::new("test");
layer.store_put(AwsUserAgent::for_tests());
cfg.push_layer(layer);
Ok(())
}
fn read_after_attempt(
&self,
_context: &FinalizerInterceptorContextRef<'_>,
_runtime_components: &RuntimeComponents,
_cfg: &mut ConfigBag,
) -> Result<(), BoxError> {
self.time_source.advance(Duration::from_secs(1));
tracing::info!(
"################ ADVANCED TIME BY 1 SECOND, {:?}",
&self.time_source
);
Ok(())
}
}
let time_source = ManualTimeSource::new(UNIX_EPOCH + Duration::from_secs(1559347200));
let path = "tests/data/request-information-headers/three-retries_and-then-success.json";
let conn = dvr::ReplayingConnection::from_file(path).unwrap();
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn.clone()))
.time_source(SharedTimeSource::new(time_source.clone()))
.sleep_impl(SharedAsyncSleep::new(InstantSleep::new(Default::default())))
.retry_config(RetryConfig::standard())
.timeout_config(
TimeoutConfig::builder()
.connect_timeout(Duration::from_secs(10))
.read_timeout(Duration::from_secs(10))
.build(),
)
.invocation_id_generator(PredefinedInvocationIdGenerator::new(vec![
InvocationId::new_from_str("00000000-0000-4000-8000-000000000000"),
]))
.interceptor(TimeInterceptor { time_source })
.build();
let client = Client::from_conf(config);
let resp = dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.send()
.await
);
let resp = resp.expect("valid e2e test");
assert_eq!(resp.name(), Some("test-bucket"));
conn.full_validate(MediaType::Xml).await.expect("failed")
}
//
// // # Client makes 3 separate SDK operation invocations
// // # All succeed on first attempt.
// // # Fast network, latency + server time is less than one second.
// // - request:
// // time: 2019-06-01T00:00:00Z
// // headers:
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: attempt=1; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:00Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:00:00 GMT
// // - request:
// // time: 2019-06-01T00:01:01Z
// // headers:
// // # Note the different invocation id because it's a new SDK
// // # invocation operation.
// // amz-sdk-invocation-id: 70370531-7b83-4b90-8b93-46975687ecf6
// // amz-sdk-request: ttl=20190601T000011Z; attempt=1; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:01Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:00:01 GMT
// // - request:
// // time: 2019-06-01T00:00:02Z
// // headers:
// // amz-sdk-invocation-id: 910bf450-6c90-43de-a508-3fa126a06b71
// // amz-sdk-request: ttl=20190601T000012Z; attempt=1; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:02Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:00:02 GMT
// const THREE_SUCCESSFUL_ATTEMPTS_PATH: &str = "test-data/request-information-headers/three-successful-attempts.json";
// #[tokio::test]
// async fn three_successful_attempts() {
// tracing_subscriber::fmt::init();
//
// impl RuntimePlugin for FixupPlugin {
// fn configure(
// &self,
// cfg: &mut ConfigBag,
// ) -> Result<(), aws_smithy_runtime_api::client::runtime_plugin::BoxError> {
// let params_builder = Params::builder()
// .set_region(self.client.conf().region().map(|c| c.as_ref().to_string()))
// .bucket("test-bucket");
//
// cfg.put(params_builder);
// cfg.set_request_time(RequestTime::new(self.timestamp.clone()));
// cfg.put(AwsUserAgent::for_tests());
// cfg.put(InvocationId::for_tests());
// Ok(())
// }
// }
//
// let conn = dvr::ReplayingConnection::from_file(THREE_SUCCESSFUL_ATTEMPTS_PATH).unwrap();
// let config = aws_sdk_s3::Config::builder()
// .credentials_provider(Credentials::for_tests())
// .region(Region::new("us-east-1"))
// .http_connector(DynConnector::new(conn.clone()))
// .build();
// let client = Client::from_conf(config);
// let fixup = FixupPlugin {
// client: client.clone(),
// timestamp: UNIX_EPOCH + Duration::from_secs(1624036048),
// };
//
// let resp = dbg!(
// client
// .list_objects_v2()
// .bucket("test-bucket")
// .prefix("prefix~")
// .send_v2_with_plugin(Some(fixup))
// .await
// );
//
// let resp = resp.expect("valid e2e test");
// assert_eq!(resp.name(), Some("test-bucket"));
// conn.full_validate(MediaType::Xml).await.expect("failed")
// }
//
// // # One SDK operation invocation.
// // # Client retries 3 times, successful response on 3rd attempt.
// // # Slow network, one way latency is 2 seconds.
// // # Server takes 1 second to generate response.
// // # Client clock is 10 minutes behind server clock.
// // # One second delay between retries.
// // - request:
// // time: 2019-06-01T00:00:00Z
// // headers:
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: attempt=1; max=3
// // response:
// // status: 500
// // time_received: 2019-06-01T00:00:05Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:10:03 GMT
// // - request:
// // time: 2019-06-01T00:00:06Z
// // # The ttl is 00:00:16 with the client clock,
// // # but accounting for skew we have
// // # 00:10:03 - 00:00:05 = 00:09:58
// // # ttl = 00:00:16 + 00:09:58 = 00:10:14
// // headers:
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: ttl=20190601T001014Z; attempt=2; max=3
// // response:
// // status: 500
// // time_received: 2019-06-01T00:00:11Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:10:09 GMT
// // - request:
// // time: 2019-06-01T00:00:12Z
// // headers:
// // # ttl = 00:00:12 + 20 = 00:00:22
// // # skew is:
// // # 00:10:09 - 00:00:11
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: ttl=20190601T001020Z; attempt=3; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:17Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:10:15 GMT
// const SLOW_NETWORK_AND_LATE_CLIENT_CLOCK_PATH: &str = "test-data/request-information-headers/slow-network-and-late-client-clock.json";
// #[tokio::test]
// async fn slow_network_and_late_client_clock() {
// tracing_subscriber::fmt::init();
//
// impl RuntimePlugin for FixupPlugin {
// fn configure(
// &self,
// cfg: &mut ConfigBag,
// ) -> Result<(), aws_smithy_runtime_api::client::runtime_plugin::BoxError> {
// let params_builder = Params::builder()
// .set_region(self.client.conf().region().map(|c| c.as_ref().to_string()))
// .bucket("test-bucket");
//
// cfg.put(params_builder);
// cfg.set_request_time(RequestTime::new(self.timestamp.clone()));
// cfg.put(AwsUserAgent::for_tests());
// cfg.put(InvocationId::for_tests());
// Ok(())
// }
// }
//
// let conn = dvr::ReplayingConnection::from_file(SLOW_NETWORK_AND_LATE_CLIENT_CLOCK_PATH).unwrap();
// let config = aws_sdk_s3::Config::builder()
// .credentials_provider(Credentials::for_tests())
// .region(Region::new("us-east-1"))
// .http_connector(DynConnector::new(conn.clone()))
// .build();
// let client = Client::from_conf(config);
// let fixup = FixupPlugin {
// client: client.clone(),
// timestamp: UNIX_EPOCH + Duration::from_secs(1624036048),
// };
//
// let resp = dbg!(
// client
// .list_objects_v2()
// .bucket("test-bucket")
// .prefix("prefix~")
// .send_v2_with_plugin(Some(fixup))
// .await
// );
//
// let resp = resp.expect("valid e2e test");
// assert_eq!(resp.name(), Some("test-bucket"));
// conn.full_validate(MediaType::Xml).await.expect("failed")
// }
}

View File

@ -1 +0,0 @@
/smithy-build.json

View File

@ -1,126 +0,0 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
extra["displayName"] = "Smithy :: Rust :: AWS-SDK :: SRA Test"
extra["moduleName"] = "software.amazon.smithy.rust.awssdk.sra.test"
tasks["jar"].enabled = false
plugins {
id("software.amazon.smithy")
}
val smithyVersion: String by project
val defaultRustDocFlags: String by project
val properties = PropertyRetriever(rootProject, project)
val pluginName = "rust-client-codegen"
val workingDirUnderBuildDir = "smithyprojections/sdk-sra-test/"
val publisherToolPath = rootProject.projectDir.resolve("tools/ci-build/publisher")
val outputDir = buildDir.resolve("sdk")
configure<software.amazon.smithy.gradle.SmithyExtension> {
outputDirectory = file("$buildDir/$workingDirUnderBuildDir")
}
buildscript {
val smithyVersion: String by project
dependencies {
classpath("software.amazon.smithy:smithy-cli:$smithyVersion")
}
}
dependencies {
implementation(project(":aws:sdk-codegen"))
implementation("software.amazon.smithy:smithy-protocol-test-traits:$smithyVersion")
implementation("software.amazon.smithy:smithy-aws-traits:$smithyVersion")
}
data class Service(
val serviceId: String,
val moduleName: String,
val imports: List<String>,
)
val servicesToGenerate = listOf(
Service(
"com.amazonaws.dynamodb#DynamoDB_20120810",
"aws-sdk-dynamodb",
listOf("../sdk/aws-models/dynamodb.json"),
),
Service(
"com.amazonaws.s3#AmazonS3",
"aws-sdk-s3",
listOf("../sdk/aws-models/s3.json", "../sdk/aws-models/s3-tests.smithy"),
),
)
val allCodegenTests = servicesToGenerate.map {
CodegenTest(
it.serviceId,
it.moduleName,
imports = it.imports,
extraConfig = """
,
"codegen": {
"includeFluentClient": false,
"enableNewSmithyRuntime": "orchestrator",
"includeEndpointUrlConfig": false
},
"customizationConfig": {
"awsSdk": {
"generateReadme": false
}
}
""",
)
}
project.registerGenerateSmithyBuildTask(rootProject, pluginName, allCodegenTests)
project.registerGenerateCargoWorkspaceTask(rootProject, pluginName, allCodegenTests, workingDirUnderBuildDir)
project.registerGenerateCargoConfigTomlTask(buildDir.resolve(workingDirUnderBuildDir))
tasks["smithyBuildJar"].dependsOn("generateSmithyBuild")
tasks["assemble"].finalizedBy("generateCargoWorkspace")
project.registerModifyMtimeTask()
project.registerCargoCommandsTasks(buildDir.resolve(workingDirUnderBuildDir), defaultRustDocFlags)
tasks["test"].finalizedBy(cargoCommands(properties).map { it.toString })
tasks["clean"].doFirst { delete("smithy-build.json") }
/**
* The aws/rust-runtime crates depend on local versions of the Smithy core runtime enabling local compilation. However,
* those paths need to be replaced in the final build. We should probably fix this with some symlinking.
*/
fun rewritePathDependency(line: String): String {
// some runtime crates are actually dependent on the generated bindings:
return line.replace("../sdk/build/aws-sdk/sdk/", "")
// others use relative dependencies::
.replace("../../rust-runtime/", "")
}
tasks.register("relocateServices") {
description = "relocate AWS services to their final destination"
doLast {
servicesToGenerate.forEach { service ->
logger.info("Relocating ${service.moduleName}...")
copy {
from("$buildDir/smithyprojections/sdk-sra-test/${service.moduleName}/rust-client-codegen")
into(outputDir.resolve(service.moduleName))
}
copy {
from(projectDir.resolve("integration-tests/${service.moduleName}/tests"))
into(outputDir.resolve(service.moduleName).resolve("tests"))
}
}
}
dependsOn("smithyBuildJar")
inputs.dir("$buildDir/smithyprojections/sdk-sra-test/")
outputs.dir(outputDir)
}
tasks["assemble"].apply {
dependsOn("relocateServices")
}

View File

@ -1 +0,0 @@
/Cargo.lock

View File

@ -1,32 +0,0 @@
[package]
name = "aws-smithy-runtime-test"
version = "0.1.0"
edition = "2021"
publish = false
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
aws-http = { path = "../../../rust-runtime/aws-http" }
aws-runtime = { path = "../../../rust-runtime/aws-runtime" }
aws-sdk-s3 = { path = "../../build/sdk/aws-sdk-s3", features = ["test-util"] }
aws-smithy-async = { path = "../../../../rust-runtime/aws-smithy-async", features = ["test-util"]}
aws-smithy-client = { path = "../../../../rust-runtime/aws-smithy-client", features = ["test-util", "rustls"] }
aws-smithy-runtime = { path = "../../../../rust-runtime/aws-smithy-runtime" }
aws-smithy-runtime-api = { path = "../../../../rust-runtime/aws-smithy-runtime-api" }
aws-smithy-types = { path = "../../../../rust-runtime/aws-smithy-types" }
aws-types = { path = "../../../rust-runtime/aws-types" }
criterion = { version = "0.4", features = ["async_tokio"] }
http = "0.2.3"
http-body = "0.4.5"
last-release-smithy-client = { version = "0.55.3", package = "aws-smithy-client", features = ["test-util", "rustls"] }
last-release-s3 = { version = "0.28", package = "aws-sdk-s3", features = ["test-util"] }
tokio = { version = "1.23.1", features = ["macros", "test-util", "rt-multi-thread"] }
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.15", features = ["env-filter", "json"] }
[profile.release]
debug = 1
[[bench]]
name = "middleware_vs_orchestrator"
harness = false

View File

@ -1,6 +0,0 @@
### Middleware vs. Orchestrator Benchmark
To run the benchmark:
```bash
./gradlew :aws:sra-test:assemble && (cd aws/sra-test/integration-tests/aws-sdk-s3 && cargo bench)
```

View File

@ -1,105 +0,0 @@
{
"events": [
{
"connection_id": 0,
"action": {
"Request": {
"request": {
"uri": "https://test-bucket.s3.us-east-1.amazonaws.com/?list-type=2&prefix=prefix~",
"headers": {
"x-amz-security-token": [
"notarealsessiontoken"
],
"authorization": [
"AWS4-HMAC-SHA256 Credential=ANOTREAL/20210618/us-east-1/s3/aws4_request, SignedHeaders=amz-sdk-invocation-id;host;x-amz-content-sha256;x-amz-date;x-amz-security-token;x-amz-user-agent, Signature=e7eccf4e792113f5f17a50bfd8f1719479e89ba0b476894e6f3dba030dc87f82"
],
"x-amz-user-agent": [
"aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
],
"x-amz-date": [
"20210618T170728Z"
],
"x-amz-content-sha256": [
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
],
"amz-sdk-invocation-id": [
"00000000-0000-4000-8000-000000000000"
],
"user-agent": [
"aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
]
},
"method": "GET"
}
}
}
},
{
"connection_id": 0,
"action": {
"Eof": {
"ok": true,
"direction": "Request"
}
}
},
{
"connection_id": 0,
"action": {
"Response": {
"response": {
"Ok": {
"status": 200,
"version": "HTTP/1.1",
"headers": {
"x-amz-request-id": [
"9X5E7C9EAB6AQEP2"
],
"x-amz-id-2": [
"gZsrBxajPyo1Q0DE2plGf7T6kAnxd4Xx7/S+8lq18GegL6kFbnVXLLh1LnBzpEpFiHN9XoNHkeA="
],
"content-type": [
"application/xml"
],
"transfer-encoding": [
"chunked"
],
"server": [
"AmazonS3"
],
"date": [
"Wed, 26 Apr 2023 14:00:24 GMT"
],
"x-amz-bucket-region": [
"us-east-1"
]
}
}
}
}
}
},
{
"connection_id": 0,
"action": {
"Data": {
"data": {
"Utf8": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ListBucketResult>\n <Name>test-bucket</Name>\n <Prefix>prefix~</Prefix>\n <KeyCount>1</KeyCount>\n <MaxKeys>1000</MaxKeys>\n <IsTruncated>false</IsTruncated>\n <Contents>\n <Key>some-file.file</Key>\n <LastModified>2009-10-12T17:50:30.000Z</LastModified>\n <Size>434234</Size>\n <StorageClass>STANDARD</StorageClass>\n </Contents>\n</ListBucketResult>"
},
"direction": "Response"
}
}
},
{
"connection_id": 0,
"action": {
"Eof": {
"ok": true,
"direction": "Response"
}
}
}
],
"docs": "Test sending an S3 ListObjectsV2 operation with a successful response.",
"version": "V0"
}

View File

@ -1,170 +0,0 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
mod util;
use aws_http::user_agent::AwsUserAgent;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::Client;
use aws_smithy_async::test_util::StaticTimeSource;
use aws_smithy_client::dvr;
use aws_smithy_client::dvr::MediaType;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_runtime_api::client::interceptors::{
BeforeTransmitInterceptorContextMut, Interceptor,
};
use aws_smithy_runtime_api::client::orchestrator::ConfigBagAccessors;
use aws_smithy_types::config_bag::ConfigBag;
use http::header::USER_AGENT;
use http::HeaderValue;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const LIST_BUCKETS_PATH: &str = "test-data/list-objects-v2.json";
#[tokio::test]
async fn operation_interceptor_test() {
tracing_subscriber::fmt::init();
let conn = dvr::ReplayingConnection::from_file(LIST_BUCKETS_PATH).unwrap();
// Not setting `TestUserAgentInterceptor` here, expecting it to be set later by the
// operation-level config.
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn.clone()))
.build();
let client = Client::from_conf(config);
let fixup = util::FixupPlugin {
timestamp: UNIX_EPOCH + Duration::from_secs(1624036048),
};
let resp = dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.customize()
.await
.unwrap()
.interceptor(util::TestUserAgentInterceptor)
.send_orchestrator_with_plugin(Some(fixup))
.await
);
let resp = resp.expect("valid e2e test");
assert_eq!(resp.name(), Some("test-bucket"));
conn.full_validate(MediaType::Xml).await.expect("success")
}
#[derive(Debug)]
struct RequestTimeResetInterceptor;
impl Interceptor for RequestTimeResetInterceptor {
fn modify_before_signing(
&self,
_context: &mut BeforeTransmitInterceptorContextMut<'_>,
cfg: &mut ConfigBag,
) -> Result<(), aws_smithy_runtime_api::client::interceptors::BoxError> {
cfg.set_request_time(StaticTimeSource::new(UNIX_EPOCH));
Ok(())
}
}
#[derive(Debug)]
struct RequestTimeAdvanceInterceptor(Duration);
impl Interceptor for RequestTimeAdvanceInterceptor {
fn modify_before_signing(
&self,
_context: &mut BeforeTransmitInterceptorContextMut<'_>,
cfg: &mut ConfigBag,
) -> Result<(), aws_smithy_runtime_api::client::interceptors::BoxError> {
let request_time = cfg.request_time().unwrap();
let request_time = StaticTimeSource::new(request_time.now() + self.0);
cfg.set_request_time(request_time);
Ok(())
}
}
#[tokio::test]
async fn interceptor_priority() {
let conn = dvr::ReplayingConnection::from_file(LIST_BUCKETS_PATH).unwrap();
// `RequestTimeResetInterceptor` will reset a `RequestTime` to `UNIX_EPOCH`, whose previous
// value should be `SystemTime::now()` set by `FixupPlugin`.
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn.clone()))
.interceptor(util::TestUserAgentInterceptor)
.interceptor(RequestTimeResetInterceptor)
.build();
let client = Client::from_conf(config);
let fixup = util::FixupPlugin {
timestamp: SystemTime::now(),
};
// `RequestTimeAdvanceInterceptor` configured at the operation level should run after,
// expecting the `RequestTime` to move forward by the specified amount since `UNIX_EPOCH`.
let resp = dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.customize()
.await
.unwrap()
.interceptor(RequestTimeAdvanceInterceptor(Duration::from_secs(
1624036048
)))
.send_orchestrator_with_plugin(Some(fixup))
.await
);
let resp = resp.expect("valid e2e test");
assert_eq!(resp.name(), Some("test-bucket"));
conn.full_validate(MediaType::Xml).await.expect("success")
}
#[tokio::test]
async fn set_test_user_agent_through_request_mutation() {
let conn = dvr::ReplayingConnection::from_file(LIST_BUCKETS_PATH).unwrap();
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn.clone()))
.build();
let client = Client::from_conf(config);
let fixup = util::FixupPlugin {
timestamp: UNIX_EPOCH + Duration::from_secs(1624036048),
};
let resp = dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.customize()
.await
.unwrap()
.mutate_request(|request| {
let headers = request.headers_mut();
let user_agent = AwsUserAgent::for_tests();
headers.insert(
USER_AGENT,
HeaderValue::try_from(user_agent.ua_header()).unwrap(),
);
headers.insert(
util::X_AMZ_USER_AGENT,
HeaderValue::try_from(user_agent.aws_ua_header()).unwrap(),
);
})
.send_orchestrator_with_plugin(Some(fixup))
.await
);
let resp = resp.expect("valid e2e test");
assert_eq!(resp.name(), Some("test-bucket"));
conn.full_validate(MediaType::Xml).await.expect("success")
}

View File

@ -1,257 +0,0 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
use aws_http::user_agent::AwsUserAgent;
use aws_runtime::invocation_id::InvocationId;
use aws_sdk_s3::config::{Credentials, Region};
use aws_sdk_s3::endpoint::Params;
use aws_sdk_s3::Client;
use aws_smithy_client::dvr;
use aws_smithy_client::dvr::MediaType;
use aws_smithy_client::erase::DynConnector;
use aws_smithy_runtime::client::retries::strategy::FixedDelayRetryStrategy;
use aws_smithy_runtime_api::client::interceptors::InterceptorRegistrar;
use aws_smithy_runtime_api::client::orchestrator::ConfigBagAccessors;
use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugin;
use aws_smithy_types::client::orchestrator::ConfigBagAccessors;
use aws_smithy_types::config_bag::ConfigBag;
use std::time::{Duration, UNIX_EPOCH};
#[derive(Debug)]
struct FixupPlugin {
client: Client,
}
// # One SDK operation invocation.
// # Client retries 3 times, successful response on 3rd attempt.
// # Fast network, latency + server time is less than one second.
// # No clock skew
// # Client waits 1 second between retry attempts.
#[tokio::test]
async fn three_retries_and_then_success() {
tracing_subscriber::fmt::init();
impl RuntimePlugin for FixupPlugin {
fn configure(
&self,
cfg: &mut ConfigBag,
_interceptors: &mut InterceptorRegistrar,
) -> Result<(), aws_smithy_runtime_api::client::runtime_plugin::BoxError> {
let params_builder = Params::builder()
.set_region(self.client.conf().region().map(|c| c.as_ref().to_string()))
.bucket("test-bucket");
cfg.put(params_builder);
cfg.put(AwsUserAgent::for_tests());
cfg.put(InvocationId::for_tests());
cfg.set_retry_strategy(FixedDelayRetryStrategy::one_second_delay());
Ok(())
}
}
let path = "test-data/request-information-headers/three-retries_and-then-success.json";
let conn = dvr::ReplayingConnection::from_file(path).unwrap();
let config = aws_sdk_s3::Config::builder()
.credentials_provider(Credentials::for_tests())
.region(Region::new("us-east-1"))
.http_connector(DynConnector::new(conn.clone()))
.time_source(UNIX_EPOCH + Duration::from_secs(1624036048))
.build();
let client = Client::from_conf(config);
let fixup = FixupPlugin {
client: client.clone(),
};
let resp = dbg!(
client
.list_objects_v2()
.bucket("test-bucket")
.prefix("prefix~")
.customize()
.await
.unwrap()
.config_override(aws_sdk_s3::Config::builder().force_path_style(false))
.send_orchestrator_with_plugin(Some(fixup))
.await
);
let resp = resp.expect("valid e2e test");
assert_eq!(resp.name(), Some("test-bucket"));
conn.full_validate(MediaType::Xml).await.expect("failed")
}
//
// // # Client makes 3 separate SDK operation invocations
// // # All succeed on first attempt.
// // # Fast network, latency + server time is less than one second.
// // - request:
// // time: 2019-06-01T00:00:00Z
// // headers:
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: attempt=1; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:00Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:00:00 GMT
// // - request:
// // time: 2019-06-01T00:01:01Z
// // headers:
// // # Note the different invocation id because it's a new SDK
// // # invocation operation.
// // amz-sdk-invocation-id: 70370531-7b83-4b90-8b93-46975687ecf6
// // amz-sdk-request: ttl=20190601T000011Z; attempt=1; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:01Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:00:01 GMT
// // - request:
// // time: 2019-06-01T00:00:02Z
// // headers:
// // amz-sdk-invocation-id: 910bf450-6c90-43de-a508-3fa126a06b71
// // amz-sdk-request: ttl=20190601T000012Z; attempt=1; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:02Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:00:02 GMT
// const THREE_SUCCESSFUL_ATTEMPTS_PATH: &str = "test-data/request-information-headers/three-successful-attempts.json";
// #[tokio::test]
// async fn three_successful_attempts() {
// tracing_subscriber::fmt::init();
//
// impl RuntimePlugin for FixupPlugin {
// fn configure(
// &self,
// cfg: &mut ConfigBag,
// ) -> Result<(), aws_smithy_runtime_api::client::runtime_plugin::BoxError> {
// let params_builder = Params::builder()
// .set_region(self.client.conf().region().map(|c| c.as_ref().to_string()))
// .bucket("test-bucket");
//
// cfg.put(params_builder);
// cfg.set_request_time(RequestTime::new(self.timestamp.clone()));
// cfg.put(AwsUserAgent::for_tests());
// cfg.put(InvocationId::for_tests());
// Ok(())
// }
// }
//
// let conn = dvr::ReplayingConnection::from_file(THREE_SUCCESSFUL_ATTEMPTS_PATH).unwrap();
// let config = aws_sdk_s3::Config::builder()
// .credentials_provider(Credentials::for_tests())
// .region(Region::new("us-east-1"))
// .http_connector(DynConnector::new(conn.clone()))
// .build();
// let client = Client::from_conf(config);
// let fixup = FixupPlugin {
// client: client.clone(),
// timestamp: UNIX_EPOCH + Duration::from_secs(1624036048),
// };
//
// let resp = dbg!(
// client
// .list_objects_v2()
// .bucket("test-bucket")
// .prefix("prefix~")
// .send_v2_with_plugin(Some(fixup))
// .await
// );
//
// let resp = resp.expect("valid e2e test");
// assert_eq!(resp.name(), Some("test-bucket"));
// conn.full_validate(MediaType::Xml).await.expect("failed")
// }
//
// // # One SDK operation invocation.
// // # Client retries 3 times, successful response on 3rd attempt.
// // # Slow network, one way latency is 2 seconds.
// // # Server takes 1 second to generate response.
// // # Client clock is 10 minutes behind server clock.
// // # One second delay between retries.
// // - request:
// // time: 2019-06-01T00:00:00Z
// // headers:
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: attempt=1; max=3
// // response:
// // status: 500
// // time_received: 2019-06-01T00:00:05Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:10:03 GMT
// // - request:
// // time: 2019-06-01T00:00:06Z
// // # The ttl is 00:00:16 with the client clock,
// // # but accounting for skew we have
// // # 00:10:03 - 00:00:05 = 00:09:58
// // # ttl = 00:00:16 + 00:09:58 = 00:10:14
// // headers:
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: ttl=20190601T001014Z; attempt=2; max=3
// // response:
// // status: 500
// // time_received: 2019-06-01T00:00:11Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:10:09 GMT
// // - request:
// // time: 2019-06-01T00:00:12Z
// // headers:
// // # ttl = 00:00:12 + 20 = 00:00:22
// // # skew is:
// // # 00:10:09 - 00:00:11
// // amz-sdk-invocation-id: 3dfe4f26-c090-4887-8c14-7bac778bca07
// // amz-sdk-request: ttl=20190601T001020Z; attempt=3; max=3
// // response:
// // status: 200
// // time_received: 2019-06-01T00:00:17Z
// // headers:
// // Date: Sat, 01 Jun 2019 00:10:15 GMT
// const SLOW_NETWORK_AND_LATE_CLIENT_CLOCK_PATH: &str = "test-data/request-information-headers/slow-network-and-late-client-clock.json";
// #[tokio::test]
// async fn slow_network_and_late_client_clock() {
// tracing_subscriber::fmt::init();
//
// impl RuntimePlugin for FixupPlugin {
// fn configure(
// &self,
// cfg: &mut ConfigBag,
// ) -> Result<(), aws_smithy_runtime_api::client::runtime_plugin::BoxError> {
// let params_builder = Params::builder()
// .set_region(self.client.conf().region().map(|c| c.as_ref().to_string()))
// .bucket("test-bucket");
//
// cfg.put(params_builder);
// cfg.set_request_time(RequestTime::new(self.timestamp.clone()));
// cfg.put(AwsUserAgent::for_tests());
// cfg.put(InvocationId::for_tests());
// Ok(())
// }
// }
//
// let conn = dvr::ReplayingConnection::from_file(SLOW_NETWORK_AND_LATE_CLIENT_CLOCK_PATH).unwrap();
// let config = aws_sdk_s3::Config::builder()
// .credentials_provider(Credentials::for_tests())
// .region(Region::new("us-east-1"))
// .http_connector(DynConnector::new(conn.clone()))
// .build();
// let client = Client::from_conf(config);
// let fixup = FixupPlugin {
// client: client.clone(),
// timestamp: UNIX_EPOCH + Duration::from_secs(1624036048),
// };
//
// let resp = dbg!(
// client
// .list_objects_v2()
// .bucket("test-bucket")
// .prefix("prefix~")
// .send_v2_with_plugin(Some(fixup))
// .await
// );
//
// let resp = resp.expect("valid e2e test");
// assert_eq!(resp.name(), Some("test-bucket"));
// conn.full_validate(MediaType::Xml).await.expect("failed")
// }

View File

@ -1,53 +0,0 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
use aws_http::user_agent::AwsUserAgent;
use aws_runtime::invocation_id::InvocationId;
use aws_smithy_async::test_util::StaticTimeSource;
use aws_smithy_runtime_api::client::interceptors::{
BeforeTransmitInterceptorContextMut, Interceptor, InterceptorRegistrar,
};
use aws_smithy_runtime_api::client::orchestrator::ConfigBagAccessors;
use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugin;
use aws_smithy_types::config_bag::ConfigBag;
use http::header::USER_AGENT;
use http::{HeaderName, HeaderValue};
use std::time::SystemTime;
pub const X_AMZ_USER_AGENT: HeaderName = HeaderName::from_static("x-amz-user-agent");
#[derive(Debug)]
pub struct FixupPlugin;
impl RuntimePlugin for FixupPlugin {
fn configure(
&self,
cfg: &mut ConfigBag,
_interceptors: &mut InterceptorRegistrar,
) -> Result<(), aws_smithy_runtime_api::client::runtime_plugin::BoxError> {
cfg.put(InvocationId::for_tests());
Ok(())
}
}
#[derive(Debug)]
pub struct TestUserAgentInterceptor;
impl Interceptor for TestUserAgentInterceptor {
fn modify_before_signing(
&self,
context: &mut BeforeTransmitInterceptorContextMut<'_>,
_cfg: &mut ConfigBag,
) -> Result<(), aws_smithy_runtime_api::client::interceptors::BoxError> {
let headers = context.request_mut().headers_mut();
let user_agent = AwsUserAgent::for_tests();
// Overwrite user agent header values provided by `UserAgentInterceptor`
headers.insert(USER_AGENT, HeaderValue::try_from(user_agent.ua_header())?);
headers.insert(
X_AMZ_USER_AGENT,
HeaderValue::try_from(user_agent.aws_ua_header())?,
);
Ok(())
}
}

View File

@ -370,8 +370,16 @@ class ResiliencyConfigCustomization(private val codegenContext: ClientCodegenCon
if (runtimeMode.generateOrchestrator) {
rustTemplate(
"""
let retry_partition = layer.load::<#{RetryPartition}>().cloned().unwrap_or_else(|| #{RetryPartition}::new("${codegenContext.serviceShape.sdkId()}"));
let retry_config = layer.load::<#{RetryConfig}>().cloned().unwrap_or_else(#{RetryConfig}::disabled);
if layer.load::<#{RetryConfig}>().is_none() {
layer.store_put(#{RetryConfig}::disabled());
}
let retry_config = layer.load::<#{RetryConfig}>().expect("set to default above").clone();
if layer.load::<#{RetryPartition}>().is_none() {
layer.store_put(#{RetryPartition}::new("${codegenContext.serviceShape.sdkId()}"));
}
let retry_partition = layer.load::<#{RetryPartition}>().expect("set to default above").clone();
if retry_config.has_retry() {
#{debug}!("using retry strategy with partition '{}'", retry_partition);
}

View File

@ -116,7 +116,7 @@ class TimeSourceCustomization(codegenContext: ClientCodegenContext) : ConfigCust
rustTemplate(
"""
if self.runtime_components.time_source().is_none() {
self.runtime_components.set_time_source(#{Default}::default());
self.runtime_components.set_time_source(#{Some}(#{Default}::default()));
}
""",
*codegenScope,

View File

@ -19,6 +19,7 @@ use tokio::task::JoinHandle;
use aws_smithy_http::body::SdkBody;
use aws_smithy_http::result::ConnectorError;
use aws_smithy_protocol_test::MediaType;
use aws_smithy_types::error::display::DisplayErrorContext;
use crate::dvr::{Action, ConnectionId, Direction, Event, NetworkTraffic};
@ -137,7 +138,14 @@ impl ReplayingConnection {
))
})
.collect::<Vec<_>>();
aws_smithy_protocol_test::validate_headers(actual.headers(), expected_headers)?;
aws_smithy_protocol_test::validate_headers(actual.headers(), expected_headers)
.map_err(|err| {
format!(
"event {} validation failed with: {}",
conn_id.0,
DisplayErrorContext(&err)
)
})?;
}
Ok(())
}
@ -272,6 +280,7 @@ impl tower::Service<http::Request<SdkBody>> for ReplayingConnection {
fn call(&mut self, mut req: Request<SdkBody>) -> Self::Future {
let event_id = self.next_id();
tracing::debug!("received event {}: {req:?}", event_id.0);
let mut events = match self.live_events.lock().unwrap().remove(&event_id) {
Some(traffic) => traffic,
None => {

View File

@ -82,7 +82,7 @@ impl CaptureSmithyConnection {
match self.loader.lock().unwrap().as_ref() {
Some(loader) => loader(),
None => {
println!("no loader was set :-/");
tracing::debug!("no loader was set on the CaptureSmithyConnection");
None
}
}

View File

@ -19,7 +19,6 @@ include(":aws:rust-runtime")
include(":aws:sdk")
include(":aws:sdk-adhoc-test")
include(":aws:sdk-codegen")
include(":aws:sra-test")
pluginManagement {
val smithyGradlePluginVersion: String by settings