From 9f912e7a1f38c1c956e9bedec8c18fc837226c58 Mon Sep 17 00:00:00 2001 From: Gabe Rives-Corbett Date: Tue, 6 May 2014 17:21:33 -0400 Subject: [PATCH] Implemeted bucket.delete_keys closes #124 --- moto/s3/responses.py | 34 ++++++++++++++++++++++++++++++++++ tests/test_s3/test_s3.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index d3bbce390..f180a97ab 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -114,6 +114,9 @@ class ResponseObject(object): return 409, headers, template.render(bucket=removed_bucket) def _bucket_response_post(self, request, bucket_name, headers): + if request.path == u'/?delete': + return self._bucket_response_delete_keys(request, bucket_name, headers) + #POST to bucket-url should create file from form if hasattr(request, 'form'): #Not HTTPretty @@ -144,6 +147,23 @@ class ResponseObject(object): new_key.set_metadata(meta_key, metadata) return 200, headers, "" + def _bucket_response_delete_keys(self, request, bucket_name, headers): + template = Template(S3_DELETE_KEYS_RESPONSE) + + keys = minidom.parseString(request.body).getElementsByTagName('Key') + deleted_names = [] + error_names = [] + + for k in keys: + try: + key_name = k.firstChild.nodeValue + self.backend.delete_key(bucket_name, key_name) + deleted_names.append(key_name) + except KeyError as e: + error_names.append(key_name) + + return 200, headers, template.render(deleted=deleted_names,delete_errors=error_names) + def key_response(self, request, full_url, headers): response = self._key_response(request, full_url, headers) if isinstance(response, basestring): @@ -391,6 +411,20 @@ S3_DELETE_BUCKET_WITH_ITEMS_ERROR = """ sdfgdsfgdsfgdfsdsfgdfs """ +S3_DELETE_KEYS_RESPONSE = """ + +{% for k in deleted %} + +{{k}} + +{% endfor %} +{% for k in delete_errors %} + +{{k}} + +{% endfor %} +""" + S3_DELETE_OBJECT_SUCCESS = """ 200 diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index e4775dfa8..72066bcf4 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -335,6 +335,41 @@ def test_post_with_metadata_to_bucket(): bucket.get_key('the-key').get_metadata('test').should.equal('metadata') +@mock_s3 +def test_delete_keys(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket('foobar') + + Key(bucket=bucket, name='file1').set_contents_from_string('abc') + Key(bucket=bucket, name='file2').set_contents_from_string('abc') + Key(bucket=bucket, name='file3').set_contents_from_string('abc') + Key(bucket=bucket, name='file4').set_contents_from_string('abc') + + result = bucket.delete_keys(['file2', 'file3']) + + result.deleted.should.have.length_of(2) + result.errors.should.have.length_of(0) + keys = bucket.get_all_keys() + keys.should.have.length_of(2) + keys[0].name.should.equal('file1') + +@mock_s3 +def test_delete_keys_with_invalid(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket('foobar') + + Key(bucket=bucket, name='file1').set_contents_from_string('abc') + Key(bucket=bucket, name='file2').set_contents_from_string('abc') + Key(bucket=bucket, name='file3').set_contents_from_string('abc') + Key(bucket=bucket, name='file4').set_contents_from_string('abc') + + result = bucket.delete_keys(['abc', 'file3']) + + result.deleted.should.have.length_of(1) + result.errors.should.have.length_of(1) + keys = bucket.get_all_keys() + keys.should.have.length_of(3) + keys[0].name.should.equal('file1') @mock_s3 def test_bucket_method_not_implemented():