aws-sdk-rust icon indicating copy to clipboard operation
aws-sdk-rust copied to clipboard

[request]: Ability to mock *::Client

Open NickLarsenNZ opened this issue 4 years ago • 6 comments

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue, please leave a comment

Tell us about your request Some way of being able to mock the Clients

Tell us about the problem you're trying to solve. What are you trying to do, and why is it hard? In a contrived piece of code, I'm trying to list EC2 instances - but I'd like to test this offline by mocking the aws_sdk_ec2::Client.

Are you currently working around this issue? I'm not (just using a real account, and weakening my test assertions).

Additional context I wondered if there should be some traits to make mocking portions of the Clients easier.

NickLarsenNZ avatar Aug 19 '21 12:08 NickLarsenNZ

hello! is it just one request you're making? It's possible to swap out the entire HTTP connection used by the client for one that returns canned responses.

Here's an example where we do this to test the KMS client: https://github.com/awslabs/aws-sdk-rust/blob/main/sdk/kms/tests/integration.rs#L24-L49

Note that assuming you don't care about the request being made, you don't need to fill out the request in test connection, it just gets ignored.

To grab the response body, you can turn on trace logging:

// in your main function:
tracing_subscriber::fmt::init();

then:

RUST_LOG='smithy_http=trace' cargo run

I should also add that you can build your own more complex test connections (eg. to pass requests through except for the request you care about). The key piece is the tower service implementation: https://github.com/awslabs/aws-sdk-rust/blob/main/sdk/smithy-client/src/test_connection.rs#L117-L141

Just make sure that your type implements clone.

rcoh avatar Aug 19 '21 13:08 rcoh

I'll keep this issue open as a place to track work on the general topic of testing code using the SDK

rcoh avatar Aug 19 '21 13:08 rcoh

I'm using something along these lines to successfully mock client calls, it's not the best example but hopefully you get the idea. I call this at the beginning of a test to get a client with the responses I want, then I call the client as usual.

    // S3Config and S3Client are aliases to the AWS SDK since I already
    // had structs called Client and Config
    fn mock_client(data_files: Vec<&str>) -> Client {
        let creds = Credentials::from_keys(
            "ATESTCLIENT",
            "atestsecretkey",
            Some("atestsessiontoken".to_string()),
        );

        let conf = S3Config::builder()
            .credentials_provider(creds)
            .region(aws_sdk_s3::Region::new("eu-west-1"))
            .build();

        // Get a vec of events based on the given data_files
        let events = data_files
            .iter()
            .map(|d| {
                let path = Path::new("test-data").join(d);
                let data = fs::read_to_string(path).unwrap();

                // Events
                (
                    // Request
                    http::Request::builder()
                        .body(SdkBody::from("request body"))
                        .unwrap(),

                    // Response
                    http::Response::builder()
                        .status(200)
                        .body(SdkBody::from(data))
                        .unwrap(),
                )
            })
            .collect();

        let conn = TestConnection::new(events);
        let conn = DynConnector::new(conn);
        let client = S3Client::from_conf_conn(conf, conn);

        // My client is wrapped with other things for various reasons.
        Client { client }
    }

The data files here are XML files with API responses that I want to test against, they live in a test-data directory at the root of the crate.

phyber avatar Aug 24 '21 11:08 phyber

@phyber How do you access DynConnection and what is TestConnection?

Would be curious to see what that code needs for 0.2

Fishrock123 avatar Dec 06 '21 19:12 Fishrock123

TestConnection is in aws-smithy-client gated behind the test-util feature, DynConnector is also in aws-smithy-client

rcoh avatar Dec 06 '21 19:12 rcoh

@phyber How do you access DynConnection and what is TestConnection?

Would be curious to see what that code needs for 0.2

Sorry for not including the use statements with that. As rcoh says, they're in aws_smithy_client.

    use aws_smithy_client::erase::DynConnector;
    use aws_smithy_client::test_connection::TestConnection;

My test code didn't change much after an upgrade to 0.2, just a few minor changes related to Credentials::from_keys (enabling the feature so I could keep the same test code, static keys used only in tests, not in the real code), and the various DateTime stuff so I could convert to/from chrono types.

phyber avatar Dec 06 '21 19:12 phyber

This is now well supported by aws-smithy-mocks-experimental please give it a try!

rcoh avatar Apr 24 '24 15:04 rcoh

Comments on closed issues are hard for our team to see. If you need more assistance, please either tag a team member or open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Apr 24 '24 15:04 github-actions[bot]