diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 6ba7a52c6..0815f3ee9 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -566,6 +566,8 @@ class ResponseObject(_TemplateEnvironmentMixin): keys = minidom.parseString(body).getElementsByTagName('Key') deleted_names = [] error_names = [] + if len(keys) == 0: + raise MalformedXML() for k in keys: key_name = k.firstChild.nodeValue diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index e2bcb109d..cd57fc92b 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -639,7 +639,7 @@ def test_delete_keys(): @mock_s3_deprecated -def test_delete_keys_with_invalid(): +def test_delete_keys_invalid(): conn = boto.connect_s3('the_key', 'the_secret') bucket = conn.create_bucket('foobar') @@ -648,6 +648,7 @@ def test_delete_keys_with_invalid(): Key(bucket=bucket, name='file3').set_contents_from_string('abc') Key(bucket=bucket, name='file4').set_contents_from_string('abc') + # non-existing key case result = bucket.delete_keys(['abc', 'file3']) result.deleted.should.have.length_of(1) @@ -656,6 +657,18 @@ def test_delete_keys_with_invalid(): keys.should.have.length_of(3) keys[0].name.should.equal('file1') + # empty keys + result = bucket.delete_keys([]) + + result.deleted.should.have.length_of(0) + result.errors.should.have.length_of(0) + +@mock_s3 +def test_boto3_delete_empty_keys_list(): + with assert_raises(ClientError) as err: + boto3.client('s3').delete_objects(Bucket='foobar', Delete={'Objects': []}) + assert err.exception.response["Error"]["Code"] == "MalformedXML" + @mock_s3_deprecated def test_bucket_name_with_dot():