diff --git a/moto/s3/responses.py b/moto/s3/responses.py index a1d5757c8..ec1361cb8 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -13,7 +13,7 @@ from moto.core.responses import _TemplateEnvironmentMixin from moto.s3bucket_path.utils import bucket_name_from_url as bucketpath_bucket_name_from_url, parse_key_name as bucketpath_parse_key_name, is_delete_keys as bucketpath_is_delete_keys -from .exceptions import BucketAlreadyExists, S3ClientError, MissingKey, InvalidPartOrder +from .exceptions import BucketAlreadyExists, S3ClientError, MissingBucket, MissingKey, InvalidPartOrder from .models import s3_backend, get_canned_acl, FakeGrantee, FakeGrant, FakeAcl, FakeKey, FakeTagging, FakeTagSet, FakeTag from .utils import bucket_name_from_url, metadata_from_headers from xml.dom import minidom @@ -155,7 +155,14 @@ class ResponseObject(_TemplateEnvironmentMixin): "Method {0} has not been impelemented in the S3 backend yet".format(method)) def _bucket_response_head(self, bucket_name, headers): - self.backend.get_bucket(bucket_name) + try: + self.backend.get_bucket(bucket_name) + except MissingBucket: + # Unless we do this, boto3 does not raise ClientError on + # HEAD (which the real API responds with), and instead + # raises NoSuchBucket, leading to inconsistency in + # error response between real and mocked responses. + return 404, {}, "Not Found" return 200, {}, "" def _bucket_response_get(self, bucket_name, querystring, headers): diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 6e6b999ce..26b25dd9a 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -1250,6 +1250,31 @@ def test_boto3_head_object(): e.exception.response['Error']['Code'].should.equal('404') +@mock_s3 +def test_boto3_bucket_deletion(): + cli = boto3.client('s3', region_name='us-east-1') + cli.create_bucket(Bucket="foobar") + + cli.put_object(Bucket="foobar", Key="the-key", Body="some value") + + # Try to delete a bucket that still has keys + cli.delete_bucket.when.called_with(Bucket="foobar").should.throw( + cli.exceptions.ClientError, + ('An error occurred (BucketNotEmpty) when calling the DeleteBucket operation: ' + 'The bucket you tried to delete is not empty')) + + cli.delete_object(Bucket="foobar", Key="the-key") + cli.delete_bucket(Bucket="foobar") + + # Get non-existing bucket + cli.head_bucket.when.called_with(Bucket="foobar").should.throw( + cli.exceptions.ClientError, + "An error occurred (404) when calling the HeadBucket operation: Not Found") + + # Delete non-existing bucket + cli.delete_bucket.when.called_with(Bucket="foobar").should.throw(cli.exceptions.NoSuchBucket) + + @mock_s3 def test_boto3_get_object(): s3 = boto3.resource('s3', region_name='us-east-1') @@ -1560,4 +1585,3 @@ TEST_XML = """\ """ -