Skip to content

Commit

Permalink
Add tests for checksum user-agent business metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
landonxjames committed Sep 28, 2024
1 parent 7be1e00 commit bf27b74
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 60 deletions.
6 changes: 3 additions & 3 deletions aws/rust-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion aws/rust-runtime/aws-config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aws-config"
version = "1.5.7"
version = "1.5.8"
authors = [
"AWS Rust SDK Team <aws-sdk-rust@amazon.com>",
"Russell Cohen <rcoh@amazon.com>",
Expand Down
3 changes: 2 additions & 1 deletion aws/rust-runtime/aws-inlineable/src/http_request_checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ where
/// Calculate a checksum and modify the request to include the checksum as a header
/// (for in-memory request bodies) or a trailer (for streaming request bodies).
/// Streaming bodies must be sized or this will return an error.
fn modify_before_signing(
fn modify_before_retry_loop(
&self,
context: &mut BeforeTransmitInterceptorContextMut<'_>,
_runtime_components: &RuntimeComponents,
Expand Down Expand Up @@ -192,6 +192,7 @@ where
cfg.interceptor_state()
.store_append(SmithySdkFeature::FlexibleChecksumsReqCrc32c);
}
#[allow(deprecated)]
ChecksumAlgorithm::Md5 => {
tracing::warn!(more_info = "Unsupported ChecksumAlgorithm MD5 set");
}
Expand Down
34 changes: 19 additions & 15 deletions aws/rust-runtime/aws-inlineable/src/http_response_checksum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,25 @@ where
layer.store_put(ResponseChecksumInterceptorState { validation_enabled });
cfg.push_layer(layer);

let response_checksum_validation = cfg
.load::<ResponseChecksumValidation>()
.unwrap_or(&ResponseChecksumValidation::WhenSupported);

// Set the user-agent feature metric for the response checksum config
match response_checksum_validation {
ResponseChecksumValidation::WhenSupported => {
cfg.interceptor_state()
.store_append(SmithySdkFeature::FlexibleChecksumsResWhenSupported);
}
ResponseChecksumValidation::WhenRequired => {
cfg.interceptor_state()
.store_append(SmithySdkFeature::FlexibleChecksumsResWhenRequired);
}
unsupported => tracing::warn!(
more_info = "Unsupported value of ResponseChecksumValidation when setting user-agent metrics",
unsupported = ?unsupported),
};

Ok(())
}

Expand Down Expand Up @@ -127,21 +146,6 @@ where
}
}

// Set the user-agent feature metric for the response checksum config
match response_checksum_validation {
ResponseChecksumValidation::WhenSupported => {
cfg.interceptor_state()
.store_append(SmithySdkFeature::FlexibleChecksumsResWhenSupported);
}
ResponseChecksumValidation::WhenRequired => {
cfg.interceptor_state()
.store_append(SmithySdkFeature::FlexibleChecksumsResWhenRequired);
}
unsupported => tracing::warn!(
more_info = "Unsupported value of ResponseChecksumValidation when setting user-agent metrics",
unsupported = ?unsupported),
};

Ok(())
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ internal class HttpChecksumTest {
checksumResponseFailTests.map { createResponseChecksumValidationFailureTest(it, context) }.join("\n")
val checksumStreamingRequestTestWritables =
streamingRequestTests.map { createStreamingRequestChecksumCalculationTest(it, context) }.join("\n")
val miscTests = createMiscellaneousTests(context)

// Shared imports for all test types
val testBase =
Expand All @@ -156,18 +157,42 @@ internal class HttpChecksumTest {
use #{SdkBody};
use std::io::Write;
use http_body::Body;
use #{HttpRequest};
""",
*preludeScope,
"Blob" to RuntimeType.smithyTypes(rc).resolve("Blob"),
"Region" to AwsRuntimeType.awsTypes(rc).resolve("region::Region"),
"pretty_assertions" to CargoDependency.PrettyAssertions.toType(),
"SdkBody" to RuntimeType.smithyTypes(rc).resolve("body::SdkBody"),
"HttpRequest" to RuntimeType.smithyRuntimeApi(rc).resolve("client::orchestrator::HttpRequest"),
)
}

val uaExtractor =
writable {
rustTemplate(
"""
fn get_sdk_metric_str(req: &HttpRequest) -> &str {
req.headers()
.get("x-amz-user-agent")
.unwrap()
.split(" ")
.filter_map(|sec| {
if sec.starts_with("m/") {
Some(&sec[2..])
} else {
None
}
})
.collect::<Vec<&str>>()[0]
}
""".trimIndent(),
)
}

// Create one integ test per test type
rustCrate.integrationTest("request_checksums") {
testBase.plus(checksumRequestTestWritables)()
testBase.plus(checksumRequestTestWritables).plus(uaExtractor)()
}

rustCrate.integrationTest("response_checksums_success") {
Expand All @@ -181,6 +206,10 @@ internal class HttpChecksumTest {
rustCrate.integrationTest("streaming_request_checksums") {
testBase.plus(checksumStreamingRequestTestWritables)()
}

rustCrate.integrationTest("misc_tests") {
testBase.plus(uaExtractor).plus(miscTests)()
}
}
}

Expand Down Expand Up @@ -232,6 +261,10 @@ internal class HttpChecksumTest {
.expect("algo header should exist");
assert_eq!(algo_header, "${testDef.algoHeader}");
// Check the user-agent metrics for the selected algo
let sdk_metrics = get_sdk_metric_str(&request);
assert!(sdk_metrics.contains("${testDef.algoFeatureId}"));
}
""",
*preludeScope,
Expand Down Expand Up @@ -427,6 +460,128 @@ internal class HttpChecksumTest {
)
}
}

/**
* Generate miscellaneous tests
*/
private fun createMiscellaneousTests(context: ClientCodegenContext): Writable {
val rc = context.runtimeConfig
val moduleName = context.moduleUseName()
return writable {
rustTemplate(
"""
// The following tests confirm that the user-agent business metrics header is correctly
// set for the request/response checksum config values
##[::tokio::test]
async fn request_config_ua_required() {
let (http_client, rx) = #{capture_request}(None);
let config = $moduleName::Config::builder()
.region(Region::from_static("doesntmatter"))
.with_test_defaults()
.http_client(http_client)
.request_checksum_calculation(
aws_types::sdk_config::RequestChecksumCalculation::WhenRequired,
)
.build();
let client = $moduleName::Client::from_conf(config);
let _ = client
.some_operation()
.body(Blob::new(b"Doesn't matter"))
.send()
.await;
let request = rx.expect_request();
let sdk_metrics = get_sdk_metric_str(&request);
assert!(sdk_metrics.contains("a"));
assert!(!sdk_metrics.contains("Z"));
}
##[::tokio::test]
async fn request_config_ua_supported() {
let (http_client, rx) = #{capture_request}(None);
let config = $moduleName::Config::builder()
.region(Region::from_static("doesntmatter"))
.with_test_defaults()
.http_client(http_client)
.build();
let client = $moduleName::Client::from_conf(config);
let _ = client
.some_operation()
.body(Blob::new(b"Doesn't matter"))
.send()
.await;
let request = rx.expect_request();
let sdk_metrics = get_sdk_metric_str(&request);
assert!(sdk_metrics.contains("Z"));
assert!(!sdk_metrics.contains("a"));
}
##[::tokio::test]
async fn response_config_ua_supported() {
let (http_client, rx) = #{capture_request}(Some(
http::Response::builder()
.header("x-amz-checksum-crc32", "i9aeUg==")
.body(SdkBody::from("Hello world"))
.unwrap(),
));
let config = $moduleName::Config::builder()
.region(Region::from_static("doesntmatter"))
.with_test_defaults()
.http_client(http_client)
.build();
let client = $moduleName::Client::from_conf(config);
let _ = client
.some_operation()
.body(Blob::new(b"Doesn't matter"))
.send()
.await;
let request = rx.expect_request();
let sdk_metrics = get_sdk_metric_str(&request);
assert!(sdk_metrics.contains("b"));
assert!(!sdk_metrics.contains("c"));
}
##[::tokio::test]
async fn response_config_ua_required() {
let (http_client, rx) = #{capture_request}(Some(
http::Response::builder()
.header("x-amz-checksum-crc32", "i9aeUg==")
.body(SdkBody::from("Hello world"))
.unwrap(),
));
let config = $moduleName::Config::builder()
.region(Region::from_static("doesntmatter"))
.with_test_defaults()
.http_client(http_client)
.response_checksum_validation(
aws_types::sdk_config::ResponseChecksumValidation::WhenRequired,
)
.build();
let client = $moduleName::Client::from_conf(config);
let _ = client
.some_operation()
.body(Blob::new(b"Doesn't matter"))
.send()
.await;
let request = rx.expect_request();
let sdk_metrics = get_sdk_metric_str(&request);
assert!(sdk_metrics.contains("c"));
assert!(!sdk_metrics.contains("b"));
}
""",
*preludeScope,
"tokio" to CargoDependency.Tokio.toType(),
"capture_request" to RuntimeType.captureRequest(rc),
)
}
}
}

// Classes and data for test definitions
Expand All @@ -437,6 +592,7 @@ data class RequestChecksumCalculationTest(
val checksumAlgorithm: String,
val algoHeader: String,
val checksumHeader: String,
val algoFeatureId: String,
)

val checksumRequestTests =
Expand All @@ -447,13 +603,15 @@ val checksumRequestTests =
"Crc32",
"CRC32",
"i9aeUg==",
"U",
),
RequestChecksumCalculationTest(
"CRC32C checksum calculation works.",
"Hello world",
"Crc32C",
"CRC32C",
"crUfeA==",
"V",
),
/* We do not yet support Crc64Nvme checksums
RequestChecksumCalculationTest(
Expand All @@ -462,6 +620,7 @@ val checksumRequestTests =
"Crc64Nvme",
"CRC64NVME",
"uc8X9yrZrD4=",
"W",
),
*/
RequestChecksumCalculationTest(
Expand All @@ -470,13 +629,15 @@ val checksumRequestTests =
"Sha1",
"SHA1",
"e1AsOh9IyGCa4hLN+2Od7jlnP14=",
"X",
),
RequestChecksumCalculationTest(
"SHA256 checksum calculation works.",
"Hello world",
"Sha256",
"SHA256",
"ZOyIygCyaOW6GjVnihtTFtIS9PNmskdyMlNKiuyjfzw=",
"Y",
),
)

Expand Down
Loading

0 comments on commit bf27b74

Please sign in to comment.