aws / aws-sdk-go-v2

AWS SDK for the Go programming language.
https://aws.github.io/aws-sdk-go-v2/docs/
Apache License 2.0
2.52k stars 606 forks source link

A clean, middleware-based mocking interface #1481

Closed indrora closed 2 years ago

indrora commented 2 years ago

The current mocking mechanism isn't so much a mocking mechanism as it is "use this language feature to do the work".

Currently, mocking is achieved by

Bringing a codebase that was not designed for this up to this level is tiresome and may not be available in some cases (such as when doing integration testing in a Kubernetes cluster based application).

Describe the solution you'd like

A clean, straightforward mechanism to provide a mocked API: Provide some JSON that represents responses, those become the "read" responses.

Botocore has this with the Stubber API: https://botocore.amazonaws.com/v1/documentation/api/latest/reference/stubber.html

This means that in boto, you can do the following:

import datetime
import botocore.session
from botocore.stub import Stubber

s3 = botocore.session.get_session().create_client('s3')
stubber = Stubber(s3)

response = {
    'IsTruncated': False,
    'Name': 'test-bucket',
    'MaxKeys': 1000, 'Prefix': '',
    'Contents': [{
        'Key': 'test.txt',
        'ETag': '"abc123"',
        'StorageClass': 'STANDARD',
        'LastModified': datetime.datetime(2016, 1, 20, 22, 9),
        'Owner': {'ID': 'abc123', 'DisplayName': 'myname'},
        'Size': 14814
    }],
    'EncodingType': 'url',
    'ResponseMetadata': {
        'RequestId': 'abc123',
        'HTTPStatusCode': 200,
        'HostId': 'abc123'
    },
    'Marker': ''
}

expected_params = {'Bucket': 'test-bucket'}

stubber.add_response('list_objects', response, expected_params)
stubber.activate()

service_response = s3.list_objects(Bucket='test-bucket')
assert service_response == response

Ideally, the Go implementation would look something like this:


// ...

mockMiddleware := mocking.NewMocker()
mockMiddleware.AddResponse("s3", "getBucket", `{"name":"test-bucket"}`, 
   ` {
    'IsTruncated': False,
    'Name': 'test-bucket',
    'MaxKeys': 1000, 'Prefix': '',
    'Contents': [{
        'Key': 'test.txt',
        'ETag': '"abc123"',
        'StorageClass': 'STANDARD',
        'LastModified': '2021-01-02 12:34:56Z',
        'Owner': {'ID': 'abc123', 'DisplayName': 'myname'},
        'Size': 14814
    }],
    'EncodingType': 'url',
    'ResponseMetadata': {
        'RequestId': 'abc123',
        'HTTPStatusCode': 200,
        'HostId': 'abc123'
    },
    'Marker': ''
}`)

cfg := config.WithMocks(mockMiddleware)

This, additionally, allows for some services to be fully mocked, such as Secrets Manager, S3, and others (which are functionally key-value stores with bells and whistles) to have more complex functionality.

Something between the Stubber interface and the HTTP client replacement would be ideal, where I can glue responses to requests.

Boto3 has a community-supported Moto project: https://github.com/spulec/moto -- one that even includes a testing server for network operations. Folks looking for a mocking interface for boto often find Moto through stackoverflow.

Digging through Google and other repo searches, it seems this isn't the first time this issue has come up:

Obviously, this indicates that more straightforward mocking interfaces have been a topic of desire.

Describe alternatives you've considered

indrora commented 2 years ago

Updated the ticket to have more context.

vudh1 commented 2 years ago

I have discussed with the team and we decided that we would not consider implementing this feature. However, we will create a backlog item for alternate solution like another second documentation that show how customer can use the middleware to do mocking.

andreip commented 1 year ago

Thank you! is https://github.com/awsdocs/aws-doc-sdk-examples/blob/main/gov2/testtools/docs.go the outcome of that @vudh1 ? Is using middleware a good approach or would you recommend to use a DIY interface approach to make it easier to migrate to a future SDK V3?