4

I have my_module something like this:

import boto3

S3_RESOURCE = boto3.resource('s3')

def some_func():
    local_file='local_file.txt'
    S3_RESOURCE.Object(bucket, key).download_file(Filename=local_file)

i am trying to test this method with moto as follows:

from moto import mock_s3
import unittest
import os

@mock_s3
class TestingS3(unittest.TestCase):

    def setUp(self):
        os.environ["AWS_DEFAULT_REGION"] = "us-east-1"
        os.environ["AWS_ACCESS_KEY_ID"] = "foobar_key"
        os.environ["AWS_SECRET_ACCESS_KEY"] = "foobar_secret"
        os.environ["AWS_SECURITY_TOKEN"] = 'testing'
        os.environ['AWS_SESSION_TOKEN'] = 'testing'
        self.setup_s3()
 
    def setup_s3(self):
        conn = boto3.client('s3')
        conn.create_bucket('my-bucket')
        conn.put_object(Bucket='my-bucket', Key='my-key', Body='data')

    def test_some_func(self):
        import my_module
        local_file = some_func('my-bucket','my-key')
        expected_file_path = 'local_file.txt'
        assert expected_file_path == local_file
        assert os.path.isfile(expected_file_path)

I am trying to use moto on a global s3 boto resource, however when running the tests, it looks like mock_s3 is either not set up or the running tests are not able to mask the global s3 resource. I get the following error

conn.create_bucket('my-bucket')
 if http.status_code >= 300:
             error_code = parsed_response.get("Error", {}).get("Code")
             error_class = self.exceptions.from_code(error_code)
 >           raise error_class(parsed_response, operation_name)
 E           botocore.exceptions.ClientError: An error occurred (ExpiredToken) when calling the CreateBucket operation: The provided token has expired.

However, if I initialize the S3_RESOURCE locally within some_func() it works fine. I understand that in order to use moto, we have to ensure moto mocks are initialized be fore the actual bot3 resource is declared. How can we ensure the global resource is mocked with moto?

Pratik Roy
  • 724
  • 1
  • 5
  • 21

2 Answers2

1

The solution provided did not work for me, what i eventually did is to replace those resources on the fixture part

@pytest.fixture(autouse=True)
@mock_s3
def setup_module():
    my_module.S3_RESOURCE = boto3.resource("s3")
ArielB
  • 1,184
  • 2
  • 11
  • 36
0

I would make a fixture and remove the set_up s3 method

@pytest.yield_fixture
def s3():
    with mock_s3():
        s3 = boto3.client("s3")
        yield s3

Then in the test

@mock_s3
def test_some_func(self, s3):
    import my_module
    CLIENT = s3
    bucket_name = "my-bucket"
    CLIENT.create_bucket(
    Bucket=bucket_name, CreateBucketConfiguration=bucket_config)
    CLIENT.put_object(Bucket='my-bucket', Key='my-key', Body='data')
    local_file = some_func('my-bucket','my-key')
    expected_file_path = 'local_file.txt'
    assert expected_file_path == local_file
    assert os.path.isfile(expected_file_path)
Maxwell Chandler
  • 626
  • 8
  • 18