Skip to content

Commit

Permalink
Add operation metadata to property bag just before sending request th…
Browse files Browse the repository at this point in the history
…rough middleware (#1920)

* update: add operation metadata to property bag during `make_operation`
add: test ensuring metadata is added to property bag
add: CHANGELOG.next.toml entry

* update: use new strategy for op metadata insertion
update: a new strategy requires a new test
update: CHANGELOG.next.toml

* format: run cargo fmt
  • Loading branch information
Velfi authored Oct 28, 2022
1 parent c5c87be commit 4c852b1
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 4 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.next.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,12 @@ message = "Fix bug that can cause panics in paginators"
references = ["smithy-rs#1903", "smithy-rs#1902"]
meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "client"}
author = "rcoh"

[[smithy-rs]]
message = """
Operation metadata is now added to the property bag before sending requests allowing middlewares to behave
differently depending on the operation being sent.
"""
references = ["smithy-rs#1919"]
meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client"}
author = "Velfi"
38 changes: 38 additions & 0 deletions aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use aws_http::retry::AwsResponseRetryClassifier;
use aws_http::user_agent::AwsUserAgent;
use aws_inlineable::middleware::DefaultMiddleware;
use aws_sig_auth::signer::OperationSigningConfig;
use aws_smithy_client::erase::DynConnector;

use aws_smithy_client::test_connection::TestConnection;
use aws_smithy_http::body::SdkBody;
Expand Down Expand Up @@ -112,6 +113,7 @@ fn test_operation() -> Operation<TestOperationParser, AwsResponseRetryClassifier
.unwrap();
Operation::new(req, TestOperationParser)
.with_retry_classifier(AwsResponseRetryClassifier::new())
.with_metadata(operation::Metadata::new("test-op", "test-service"))
}

#[cfg(any(feature = "native-tls", feature = "rustls"))]
Expand Down Expand Up @@ -148,3 +150,39 @@ async fn e2e_test() {

conn.assert_requests_match(&[]);
}

#[tokio::test]
async fn test_operation_metadata_is_available_to_middlewares() {
let conn = TestConnection::new(vec![(
http::Request::builder()
.header(USER_AGENT, "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0")
.header("x-amz-user-agent", "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0")
.header(AUTHORIZATION, "AWS4-HMAC-SHA256 Credential=access_key/20210215/test-region/test-service-signing/aws4_request, SignedHeaders=host;x-amz-date;x-amz-user-agent, Signature=da249491d7fe3da22c2e09cbf910f37aa5b079a3cedceff8403d0b18a7bfab75")
.header("x-amz-date", "20210215T184017Z")
.uri(Uri::from_static("https://test-service.test-region.amazonaws.com/"))
.body(SdkBody::from("request body")).unwrap(),
http::Response::builder()
.status(200)
.body("response body")
.unwrap(),
)]);
let client = aws_smithy_client::Client::builder()
.middleware_fn(|req| {
let metadata = req
.properties()
.get::<operation::Metadata>()
.cloned()
.unwrap();

assert_eq!("test-op", metadata.name());
assert_eq!("test-service", metadata.service());

req
})
.connector(DynConnector::new(conn))
.build();

let resp = client.call(test_operation()).await;
let resp = resp.expect("successful operation");
assert_eq!(resp, "Hello!");
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ open class MakeOperationGenerator(
) {
val operationName = symbolProvider.toSymbol(shape).name
val baseReturnType = buildOperationType(implBlockWriter, shape, customizations)
val returnType = "std::result::Result<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>"
val returnType =
"std::result::Result<$baseReturnType, ${implBlockWriter.format(runtimeConfig.operationBuildError())}>"
val outputSymbol = symbolProvider.toSymbol(shape)

val takesOwnership = bodyGenerator.payloadMetadata(shape).takesOwnership
Expand All @@ -82,8 +83,10 @@ open class MakeOperationGenerator(

implBlockWriter.docs("Consumes the builder and constructs an Operation<#D>", outputSymbol)
Attribute.AllowUnusedMut.render(implBlockWriter) // For codegen simplicity
Attribute.Custom("allow(clippy::let_and_return)").render(implBlockWriter) // For codegen simplicity, allow `let x = ...; x`
Attribute.Custom("allow(clippy::needless_borrow)").render(implBlockWriter) // Allows builders that don’t consume the input borrow
Attribute.Custom("allow(clippy::let_and_return)")
.render(implBlockWriter) // For codegen simplicity, allow `let x = ...; x`
Attribute.Custom("allow(clippy::needless_borrow)")
.render(implBlockWriter) // Allows builders that don’t consume the input borrow
implBlockWriter.rustBlockTemplate(
"$fnType $functionName($self, _config: &#{config}::Config) -> $returnType",
*codegenScope,
Expand Down
3 changes: 2 additions & 1 deletion rust-runtime/aws-smithy-http-tower/src/parse_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ where
}

fn call(&mut self, req: Operation<ResponseHandler, RetryPolicy>) -> Self::Future {
let (req, parts) = req.into_request_response();
let (mut req, parts) = req.into_request_response();
let handler = parts.response_handler;
// send_operation records the full request-response lifecycle.
// NOTE: For operations that stream output, only the setup is captured in this span.
Expand All @@ -103,6 +103,7 @@ where
if let Some(metadata) = parts.metadata {
span.record("operation", &metadata.name());
span.record("service", &metadata.service());
req.properties_mut().insert(metadata);
}
let resp = self.inner.call(req);
let fut = async move {
Expand Down

0 comments on commit 4c852b1

Please sign in to comment.