botocore icon indicating copy to clipboard operation
botocore copied to clipboard

Stubbing custom commands

Open icyc9 opened this issue 8 years ago • 9 comments

When calling stubber.add_response with certain boto3 s3 client methods I have encountered "botocore.model.OperationNotFoundError".

import unittest

import boto3
from botocore.stub import Stubber

def setup_s3_client():
    return boto3.client('s3')

MOCK_BUCKET_NAME = 'test-bucket'

create_bucket_response = {
    'Location': '/' + MOCK_BUCKET_NAME,
    'ResponseMetadata': {
        'HTTPStatusCode': 200,
        'HostId': 'myHostId',
        'RequestId': '80678CD98525D782'
    }
}

upload_file_response = {
    'ServerSideEncryption': 'AES256',
    'ETag': 'string',
    'SSECustomerAlgorithm': 'string',
    'SSECustomerKeyMD5': 'string',
    'SSEKMSKeyId': 'string',
    'RequestCharged': 'requester'
}

class TestS3Bucket(unittest.TestCase):

    def setUp(self):
        self.client = setup_s3_client()
        self.stubber = Stubber(self.client)
        self.stubber.activate()

    def test_create_bucket(self):
        self.stubber.add_response(
            method='create_bucket',
            service_response=create_bucket_response,
            expected_params={'Bucket': MOCK_BUCKET_NAME})

        self.client.create_bucket(Bucket=MOCK_BUCKET_NAME)


    def test_upload(self):
        self.stubber.add_response(
            method='upload_file',
            service_response=upload_file_response,
            expected_params={'Bucket': MOCK_BUCKET_NAME, 'Filename': 'fake_source_uri', 'Key': 'test_key'})

        self.client.upload_file(Filename='fake_filename',
                                Bucket=MOCK_BUCKET_NAME,
                                Key='fake_key')

The test results are shown as follows.

       @instance_cache
    def operation_model(self, operation_name):
        try:
            model = self._service_description['operations'][operation_name]
        except KeyError:
>           raise OperationNotFoundError(operation_name)
E           botocore.model.OperationNotFoundError

env_name/lib/python3.5/site-packages/botocore/model.py:249: OperationNotFoundError
=========================================================================== 1 failed, 1 passed in 0.29 seconds ============================================================================

The add_response method does not seem to allow the 'upload_file' client method to be stubbed. I have also found this to be true with the 'download_file' client method.

icyc9 avatar Jun 30 '16 22:06 icyc9

That's because download_file and upload_file are customizations which live in boto3. They call out to one or many requests under the hood. Right now there's not a great story for supporting customizations other than recording underlying commands they use and adding them to the stubber. There's an external library that can handle that for you, though we don't support it ourselves.

JordonPhillips avatar Jul 01 '16 00:07 JordonPhillips

Just hit this too. It'd be really great if stubber could handle download_file and upload_file

jnoring avatar Jul 07 '16 20:07 jnoring

@JordonPhillips Thanks for your reply. What's the external library that mocks the upload_file()?

montaro avatar Nov 01 '16 09:11 montaro

placebo, though it runs in a different way than the stubber does: it records and replays.

JordonPhillips avatar Nov 04 '16 15:11 JordonPhillips

I just found out that 'get_paginator' seem to be the same story. It is a little confusing for me at this point as it seemed the stubber was for boto3, the relationship between botocore and boto3 is a bit unclear to me. I'll check out placebo.

luck02 avatar Jan 13 '17 17:01 luck02

Anyone found a workaround for this yet?

crizzy9 avatar Aug 23 '20 09:08 crizzy9

In case anyone else comes across, this I found that for get_paginator, rather than adding a response with get_paginator as the service method, instead you should add a response for the service method that get_paginator would access. For example

Instead of:

cfn_stubber = Stubber(cloudformation_client)
cfn_stubber.add_response('get_paginator', expected_response, 'describe_stacks')

Do:

cfn_stubber = Stubber(cloudformation_client)
cfn_stubber.add_response('describe_stacks', expected_response)

The stubber does seem able to return a paginator object that includes the data passed from the expected_response.

bosatsu avatar Nov 06 '20 21:11 bosatsu

Any update on how to mock upload_file using stubber?

mhihasan avatar Aug 02 '21 08:08 mhihasan

Any update on how to mock upload_file using stubber?

Use put_object instead of upload_file

robertsonwang avatar Oct 06 '22 14:10 robertsonwang