Skip to content

Commit 61007da

Browse files
authored
Add configuration ability to mock_client macro (#4001)
## Motivation and Context We've seen folks who need to be able to modify configuration of the client, but there's no way to deal with it outside of ejecting from the macro. ## Description - add configure option to the macro - improve some docs ## Testing I ran those doc tests unignored ## Checklist <!--- If a checkbox below is not applicable, then please DELETE it rather than leaving it unchecked --> - [ ] For changes to the smithy-rs codegen or runtime crates, I have created a changelog entry Markdown file in the `.changelog` directory, specifying "client," "server," or both in the `applies_to` key. - [ ] For changes to the AWS SDK, generated SDK code, or SDK runtime crates, I have created a changelog entry Markdown file in the `.changelog` directory, specifying "aws-sdk-rust" in the `applies_to` key. ---- _By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._
1 parent 935c265 commit 61007da

File tree

3 files changed

+72
-7
lines changed

3 files changed

+72
-7
lines changed

rust-runtime/aws-smithy-mocks-experimental/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aws-smithy-mocks-experimental"
3-
version = "0.2.1"
3+
version = "0.2.2"
44
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>"]
55
description = "Experimental testing utilities for smithy-rs generated clients"
66
edition = "2021"

rust-runtime/aws-smithy-mocks-experimental/README.md

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
11
# aws-smithy-mocks
22

3-
Experiment for mocking Smithy Clients using interceptors. See [`tests/get-object-mocks.rs`](tests/get-object-mocks.rs) for example usage.
3+
This package allows testing clients generated by smithy-rs (including all packages of the AWS Rust SDK) by using interceptors to return stub responses. This approach is quite useful for testing both happy-path and simple error scenarios and avoids the need for mocking the entire client or using traits.
4+
5+
As an example, consider this simple usage with S3:
6+
7+
```rust
8+
#[tokio::test]
9+
async fn test_s3() {
10+
let s3_real_object = mock!(Client::get_object).then_output(|| {
11+
GetObjectOutput::builder()
12+
.body(ByteStream::from_static(b"test-test-test"))
13+
.build()
14+
});
15+
let s3 = mock_client!(aws_sdk_s3, [&s3_real_object]);
16+
let data = s3
17+
.get_object()
18+
.bucket("test-bucket")
19+
.key("correct-key")
20+
.send()
21+
.await
22+
.expect("success response")
23+
.body
24+
.collect()
25+
.await
26+
.expect("successful read")
27+
.to_vec();
28+
assert_eq!(data, b"test-test-test");
29+
assert_eq!(s3_real_object.num_calls(), 1);
30+
}
31+
```
32+
33+
You can find more examples in the `tests` folder of this crate.
34+
35+
## Shortcomings of this approach
36+
This approach is not well suited for testing precise error handling, especially when considering retries or interactions with HTTP responses—This approach hijacks the request response flow entirely and is not a faithful model in these cases.
37+
38+
If you need to test behavior around retries or connection management, you should use HTTP-connection based mocking instead.
439

540
<!-- anchor_start:footer -->
641
This crate is part of the [AWS SDK for Rust](https://awslabs.github.io/aws-sdk-rust/) and the [smithy-rs](https://github.com/smithy-lang/smithy-rs) code generator.

rust-runtime/aws-smithy-mocks-experimental/src/lib.rs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6+
//! This crate allows mocking of smithy clients.
7+
68
/* Automatically managed default lints */
79
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
810
/* End of automatically managed default lints */
@@ -94,23 +96,51 @@ macro_rules! mock {
9496
/// .then_error(||GetObjectError::NoSuchKey(NoSuchKey::builder().build()));
9597
/// let client = mock_client!(aws_sdk_s3, RuleMode::Sequential, &[&get_object_error_path, &get_object_happy_path]);
9698
/// ```
99+
///
100+
/// **Create a client but customize a specific setting**:
101+
/// ```rust,ignore
102+
/// use aws_sdk_s3::operation::get_object::GetObjectOutput;
103+
/// use aws_sdk_s3::Client;
104+
/// use aws_smithy_types::byte_stream::ByteStream;
105+
/// use aws_smithy_mocks_experimental::{mock_client, mock, RuleMode};
106+
/// let get_object_happy_path = mock!(Client::get_object)
107+
/// .match_requests(|req|req.bucket() == Some("test-bucket") && req.key() == Some("test-key"))
108+
/// .then_output(||GetObjectOutput::builder().body(ByteStream::from_static(b"12345-abcde")).build());
109+
/// let client = mock_client!(
110+
/// aws_sdk_s3,
111+
/// RuleMode::Sequential,
112+
/// &[&get_object_happy_path],
113+
/// // Perhaps you need to force path style
114+
/// |client_builder|client_builder.force_path_style(true)
115+
/// );
116+
/// ```
117+
///
97118
#[macro_export]
98119
macro_rules! mock_client {
99120
($aws_crate: ident, $rules: expr) => {
100121
mock_client!($aws_crate, $crate::RuleMode::Sequential, $rules)
101122
};
102123
($aws_crate: ident, $rule_mode: expr, $rules: expr) => {{
124+
mock_client!($aws_crate, $rule_mode, $rules, |conf| conf)
125+
}};
126+
($aws_crate: ident, $rule_mode: expr, $rules: expr, $additional_configuration: expr) => {{
103127
let mut mock_response_interceptor =
104128
$crate::MockResponseInterceptor::new().rule_mode($rule_mode);
105129
for rule in $rules {
106130
mock_response_interceptor = mock_response_interceptor.with_rule(rule)
107131
}
132+
// allow callers to avoid explicitly specifying the type
133+
fn coerce<T: Fn($aws_crate::config::Builder) -> $aws_crate::config::Builder>(f: T) -> T {
134+
f
135+
}
108136
$aws_crate::client::Client::from_conf(
109-
$aws_crate::config::Config::builder()
110-
.with_test_defaults()
111-
.region($aws_crate::config::Region::from_static("us-east-1"))
112-
.interceptor(mock_response_interceptor)
113-
.build(),
137+
coerce($additional_configuration)(
138+
$aws_crate::config::Config::builder()
139+
.with_test_defaults()
140+
.region($aws_crate::config::Region::from_static("us-east-1"))
141+
.interceptor(mock_response_interceptor),
142+
)
143+
.build(),
114144
)
115145
}};
116146
}

0 commit comments

Comments
 (0)