Unverified Commit 7b54e540 authored by greenwoodcm's avatar greenwoodcm Committed by GitHub
Browse files

add `RuleBuilder::then_compute_output` (#4299)



this allows the developer to compute a mocked output using content from
the input.

## Motivation and Context
Some richer use cases for stubbing/mocking require computing a stubbed
output using data from the input, for instance stubbing a method that
returns the item that was put.

## Description
Add a new method to `RuleBuilder` that allows for providing a function
that computes the output. That function takes in a reference to the
input as an argument. I'm not sure how this works with the mutable
inputs like streamed bytes, but seems to work for the simple stuff.

## Testing
added a simple unit test

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._

---------

Co-authored-by: default avatarAaron Todd <aajtodd@users.noreply.github.com>
parent 9f495a45
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
---
applies_to: ["client"]
authors: ["greenwoodcm"]
references: ["smithy-rs#4299"]
breaking: false
new_feature: true
bug_fix: false
---
Added a new `then_compute_output` to `aws-smithy-mocks` rule builder that allows using the input type when computing a mocked response, e.g. 
```rs
// Return a computed output based on the input
let compute_rule = mock!(Client::get_object)
    .then_compute_output(|req| {
        let key = req.key().unwrap_or("unknown");
        GetObjectOutput::builder()
            .body(ByteStream::from_static(format!("content for {}", key).as_bytes()))
            .build()
    });
```
+33 −0
Original line number Diff line number Diff line
@@ -89,6 +89,39 @@ async fn test_mock_client() {
    assert_eq!(err.code(), Some("InvalidAccessKey"));
}

#[tokio::test]
async fn test_mock_client_compute() {
    let s3_computed = mock!(aws_sdk_s3::Client::get_object)
        .match_requests(|inp| {
            inp.bucket() == Some("test-bucket") && inp.key() == Some("correct-key")
        })
        .then_compute_output(|input| {
            let content =
                format!("{}.{}", input.bucket().unwrap(), input.key().unwrap()).into_bytes();
            GetObjectOutput::builder()
                .body(ByteStream::from(content))
                .build()
        });

    let s3 = mock_client!(aws_sdk_s3, &[&s3_computed]);

    let data = s3
        .get_object()
        .bucket("test-bucket")
        .key("correct-key")
        .send()
        .await
        .expect("success response")
        .body
        .collect()
        .await
        .expect("successful read")
        .to_vec();

    assert_eq!(data, b"test-bucket.correct-key");
    assert_eq!(s3_computed.num_calls(), 1);
}

#[tokio::test]
async fn test_mock_client_sequence() {
    let rule = mock!(aws_sdk_s3::Client::get_object)
+1 −1
Original line number Diff line number Diff line
@@ -560,7 +560,7 @@ dependencies = [

[[package]]
name = "aws-smithy-mocks"
version = "0.1.1"
version = "0.1.2"
dependencies = [
 "aws-smithy-async",
 "aws-smithy-http-client",
+2 −2
Original line number Diff line number Diff line
[package]
name = "aws-smithy-mocks"
version = "0.1.1"
version = "0.1.2"
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
description = "Testing utilities for smithy-rs generated clients"
edition = "2021"
@@ -9,7 +9,7 @@ repository = "https://github.com/smithy-lang/smithy-rs"

[dependencies]
aws-smithy-types = { path = "../aws-smithy-types" }
aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["client", "http-1x"] }
aws-smithy-runtime-api = { path = "../aws-smithy-runtime-api", features = ["client", "http-1x", "test-util"] }
aws-smithy-http-client = { path = "../aws-smithy-http-client", features = ["test-util"] }
http = "1"

+9 −0
Original line number Diff line number Diff line
@@ -83,6 +83,15 @@ let http_rule = mock!(Client::get_object)
        StatusCode::try_from(503).unwrap(),
        SdkBody::from("service unavailable")
    ));

// Return a computed output based on the input
let compute_rule = mock!(Client::get_object)
    .then_compute_output(|req| {
        let key = req.key().unwrap_or("unknown");
        GetObjectOutput::builder()
            .body(ByteStream::from_static(format!("content for {}", key).as_bytes()))
            .build()
    });
```

### Response Sequences
Loading