diff --git a/moto/s3/models.py b/moto/s3/models.py index c7c394959..65b191620 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -19,7 +19,7 @@ class FakeKey(object): class FakeBucket(object): def __init__(self, name): self.name = name - self.keys = [] + self.keys = {} class S3Backend(BaseBackend): @@ -36,22 +36,33 @@ class S3Backend(BaseBackend): def get_bucket(self, bucket_name): return self.buckets.get(bucket_name) + def delete_bucket(self, bucket_name): + bucket = self.buckets.get(bucket_name) + if bucket: + if bucket.keys: + # Can't delete a bucket with keys + return False + else: + return self.buckets.pop(bucket_name) + else: + # implement this + import pdb;pdb.set_trace() + + def set_key(self, bucket_name, key_name, value): bucket = self.buckets[bucket_name] new_key = FakeKey(name=key_name, value=value) - bucket.keys.append(new_key) + bucket.keys[key_name] = new_key return new_key def get_key(self, bucket_name, key_name): bucket = self.buckets[bucket_name] - found_key = None - for key in bucket.keys: - if key.name == key_name: - found_key = key - break + return bucket.keys.get(key_name) - return found_key + def delete_key(self, bucket_name, key_name): + bucket = self.buckets[bucket_name] + return bucket.keys.pop(key_name) s3_backend = S3Backend() diff --git a/moto/s3/responses.py b/moto/s3/responses.py index 57a44dd08..fff5beb7e 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -5,18 +5,31 @@ from .models import s3_backend def bucket_response(uri, body, headers): hostname = uri.hostname bucket_name = hostname.replace(".s3.amazonaws.com", "") + method = uri.method - if uri.method == 'GET': + if method == 'GET': bucket = s3_backend.get_bucket(bucket_name) if bucket: template = Template(S3_BUCKET_GET_RESPONSE) return template.render(bucket=bucket) else: return "", dict(status=404) - else: + elif method == 'PUT': new_bucket = s3_backend.create_bucket(bucket_name) template = Template(S3_BUCKET_CREATE_RESPONSE) return template.render(bucket=new_bucket) + elif method == 'DELETE': + removed_bucket = s3_backend.delete_bucket(bucket_name) + if removed_bucket: + template = Template(S3_DELETE_BUCKET_SUCCESS) + return template.render(bucket=removed_bucket), dict(status=204) + else: + # Tried to delete a bucket that still has keys + template = Template(S3_DELETE_BUCKET_WITH_ITEMS_ERROR) + return template.render(bucket=removed_bucket), dict(status=409) + + else: + import pdb;pdb.set_trace() def key_response(uri_info, body, headers): @@ -24,15 +37,16 @@ def key_response(uri_info, body, headers): key_name = uri_info.path.lstrip('/') hostname = uri_info.hostname bucket_name = hostname.replace(".s3.amazonaws.com", "") + method = uri_info.method - if uri_info.method == 'GET': + if method == 'GET': key = s3_backend.get_key(bucket_name, key_name) if key: return key.value else: return "", dict(status=404) - if uri_info.method == 'PUT': + if method == 'PUT': if body: new_key = s3_backend.set_key(bucket_name, key_name, body) return S3_OBJECT_RESPONSE, dict(etag=new_key.etag) @@ -41,9 +55,13 @@ def key_response(uri_info, body, headers): return "", dict(etag=key.etag) else: return "" - elif uri_info.method == 'HEAD': + elif method == 'HEAD': key = s3_backend.get_key(bucket_name, key_name) return S3_OBJECT_RESPONSE, dict(etag=key.etag) + elif method == 'DELETE': + removed_key = s3_backend.delete_key(bucket_name, key_name) + template = Template(S3_DELETE_OBJECT_SUCCESS) + return template.render(bucket=removed_key), dict(status=204) else: import pdb;pdb.set_trace() @@ -64,6 +82,28 @@ S3_BUCKET_CREATE_RESPONSE = """ + + 204 + No Content + +""" + +S3_DELETE_BUCKET_WITH_ITEMS_ERROR = """ +BucketNotEmpty +The bucket you tried to delete is not empty +{{ bucket.name }} +asdfasdfsdafds +sdfgdsfgdsfgdfsdsfgdfs +""" + +S3_DELETE_OBJECT_SUCCESS = """ + + 200 + OK + +""" + S3_OBJECT_RESPONSE = """ "asdlfkdalsjfsalfkjsadlfjsdjkk" diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 0f8444766..08439e6f9 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -1,6 +1,9 @@ import boto +from boto.exception import S3ResponseError from boto.s3.key import Key +import sure + from moto import mock_s3 @@ -28,3 +31,25 @@ def test_my_model_save(): model_instance.save() assert conn.get_bucket('mybucket').get_key('steve').get_contents_as_string() == 'is awesome' + +@mock_s3 +def test_missing_bucket(): + conn = boto.connect_s3('the_key', 'the_secret') + conn.get_bucket.when.called_with('mybucket').should.throw(S3ResponseError) + + +@mock_s3 +def test_bucket_deletion(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket("foobar") + + key = Key(bucket) + key.key = "the-key" + key.set_contents_from_string("some value") + + conn.delete_bucket.when.called_with("foobar").should.throw(S3ResponseError) + + bucket.delete_key("the-key") + conn.delete_bucket("foobar") + + conn.get_bucket.when.called_with("foobar").should.throw(S3ResponseError)