diff --git a/moto/s3/models.py b/moto/s3/models.py index 3b4623d6..9e58fdb4 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -859,6 +859,9 @@ class S3Backend(BaseBackend): if str(key.version_id) != str(version_id) ] ) + + if not bucket.keys.getlist(key_name): + bucket.keys.pop(key_name) return True except KeyError: return False diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 02a9ac40..5e7cf0fe 100755 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -706,8 +706,11 @@ class ResponseObject(_TemplateEnvironmentMixin): if 'x-amz-copy-source' in request.headers: # Copy key - src_key_parsed = urlparse(unquote(request.headers.get("x-amz-copy-source"))) - src_bucket, src_key = src_key_parsed.path.lstrip("/").split("/", 1) + # you can have a quoted ?version=abc with a version Id, so work on + # we need to parse the unquoted string first + src_key_parsed = urlparse(request.headers.get("x-amz-copy-source")) + src_bucket, src_key = unquote(src_key_parsed.path).\ + lstrip("/").split("/", 1) src_version_id = parse_qs(src_key_parsed.query).get( 'versionId', [None])[0] self.backend.copy_key(src_bucket, src_key, bucket_name, key_name, diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 36942675..9f37791c 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -1405,6 +1405,19 @@ def test_boto3_deleted_versionings_list(): assert len(listed['Contents']) == 1 +@mock_s3 +def test_boto3_delete_versioned_bucket(): + client = boto3.client('s3', region_name='us-east-1') + + client.create_bucket(Bucket='blah') + client.put_bucket_versioning(Bucket='blah', VersioningConfiguration={'Status': 'Enabled'}) + + resp = client.put_object(Bucket='blah', Key='test1', Body=b'test1') + client.delete_object(Bucket='blah', Key='test1', VersionId=resp["VersionId"]) + + client.delete_bucket(Bucket='blah') + + @mock_s3 def test_boto3_head_object_if_modified_since(): s3 = boto3.client('s3', region_name='us-east-1')