From 4283cca63c334a138c82b56fde9c58e0e5763758 Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Mon, 18 Feb 2013 21:22:03 -0500 Subject: [PATCH] clean up urls. start to clean up responses --- .gitignore | 1 + Makefile | 2 +- moto/core/models.py | 3 +-- moto/ec2/models.py | 1 - moto/ec2/urls.py | 2 +- moto/s3/models.py | 5 +--- moto/s3/responses.py | 52 ++++++++++++++++++++++++++++------------ moto/s3/urls.py | 9 ++++--- moto/s3/utils.py | 8 +++++++ requirements.txt | 1 + tests/test_s3/test_s3.py | 13 ++++++++++ 11 files changed, 70 insertions(+), 27 deletions(-) create mode 100644 moto/s3/utils.py diff --git a/.gitignore b/.gitignore index 0d20b6487..b04e81aaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +.coverage *.pyc diff --git a/Makefile b/Makefile index 94deffdd0..44017f156 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ init: pip install -r requirements.txt test: - nosetests ./tests/ + nosetests --with-coverage ./tests/ --cover-package=moto travis: nosetests ./tests/ diff --git a/moto/core/models.py b/moto/core/models.py index f24974d56..965c35c40 100644 --- a/moto/core/models.py +++ b/moto/core/models.py @@ -5,7 +5,6 @@ from httpretty import HTTPretty class BaseBackend(object): - base_url = None def reset(self): self = self.__class__() @@ -30,7 +29,7 @@ class BaseBackend(object): for key, value in self.urls.iteritems(): HTTPretty.register_uri( method=method, - uri=re.compile(self.base_url + key), + uri=re.compile(key), body=value, ) try: diff --git a/moto/ec2/models.py b/moto/ec2/models.py index f022fdd74..cb74e5c3f 100644 --- a/moto/ec2/models.py +++ b/moto/ec2/models.py @@ -5,7 +5,6 @@ from .utils import random_instance_id, random_reservation_id class EC2Backend(BaseBackend): - base_url = "https://ec2.us-east-1.amazonaws.com" def __init__(self): self.reservations = {} diff --git a/moto/ec2/urls.py b/moto/ec2/urls.py index 0d12059e6..3d981805c 100644 --- a/moto/ec2/urls.py +++ b/moto/ec2/urls.py @@ -1,5 +1,5 @@ from .responses import instances urls = { - '/': instances, + "https://ec2.us-east-1.amazonaws.com/": instances, } diff --git a/moto/s3/models.py b/moto/s3/models.py index 45598a583..8acb65448 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -23,7 +23,6 @@ class FakeBucket(object): class S3Backend(BaseBackend): - base_url = "https://(.*)s3.amazonaws.com" def __init__(self): self.buckets = {} @@ -47,9 +46,7 @@ class S3Backend(BaseBackend): return False else: return self.buckets.pop(bucket_name) - else: - # implement this - import pdb;pdb.set_trace() + return None def set_key(self, bucket_name, key_name, value): diff --git a/moto/s3/responses.py b/moto/s3/responses.py index e877a4d97..49c488145 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -1,19 +1,28 @@ from jinja2 import Template from .models import s3_backend +from .utils import bucket_name_from_hostname + + +def all_buckets(uri, body, method): + # No bucket specified. Listing all buckets + all_buckets = s3_backend.get_all_buckets() + template = Template(S3_ALL_BUCKETS) + return template.render(buckets=all_buckets) + def bucket_response(uri, body, headers): hostname = uri.hostname method = uri.method - s3_base_url = "s3.amazonaws.com" - if hostname == s3_base_url: - # No bucket specified. Listing all buckets - all_buckets = s3_backend.get_all_buckets() - template = Template(S3_ALL_BUCKETS) - return template.render(buckets=all_buckets) + # s3_base_url = "s3.amazonaws.com" + # if hostname == s3_base_url: + # # No bucket specified. Listing all buckets + # all_buckets = s3_backend.get_all_buckets() + # template = Template(S3_ALL_BUCKETS) + # return template.render(buckets=all_buckets) - bucket_name = hostname.replace(".s3.amazonaws.com", "") + bucket_name = bucket_name_from_hostname(hostname) if method == 'GET': bucket = s3_backend.get_bucket(bucket_name) @@ -28,14 +37,18 @@ def bucket_response(uri, body, headers): return template.render(bucket=new_bucket) elif method == 'DELETE': removed_bucket = s3_backend.delete_bucket(bucket_name) - if removed_bucket: + if removed_bucket is None: + # Non-existant bucket + template = Template(S3_DELETE_NON_EXISTING_BUCKET) + return template.render(bucket_name=bucket_name), dict(status=404) + elif removed_bucket: + # Bucket exists 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() @@ -44,15 +57,13 @@ 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 + bucket_name = bucket_name_from_hostname(hostname) + if method == 'GET': key = s3_backend.get_key(bucket_name, key_name) - if key: - return key.value - else: - return "", dict(status=404) + return key.value if method == 'PUT': if body: @@ -65,7 +76,10 @@ def key_response(uri_info, body, headers): return "" elif method == 'HEAD': key = s3_backend.get_key(bucket_name, key_name) - return S3_OBJECT_RESPONSE, dict(etag=key.etag) + if key: + return S3_OBJECT_RESPONSE, dict(etag=key.etag) + else: + return "", dict(status=404) elif method == 'DELETE': removed_key = s3_backend.delete_key(bucket_name, key_name) template = Template(S3_DELETE_OBJECT_SUCCESS) @@ -112,6 +126,14 @@ S3_DELETE_BUCKET_SUCCESS = """ +NoSuchBucket +The specified bucket does not exist +{{ bucket_name }} +asdfasdfsadf +asfasdfsfsafasdf +""" + S3_DELETE_BUCKET_WITH_ITEMS_ERROR = """ BucketNotEmpty The bucket you tried to delete is not empty diff --git a/moto/s3/urls.py b/moto/s3/urls.py index b7b20d82f..4a1632bd5 100644 --- a/moto/s3/urls.py +++ b/moto/s3/urls.py @@ -1,6 +1,9 @@ -from .responses import bucket_response, key_response +from .responses import all_buckets, bucket_response, key_response + +base_url = "https://(.*).s3.amazonaws.com" urls = { - '/$': bucket_response, - '/(.+)': key_response, + 'https://s3.amazonaws.com/$': all_buckets, + '{0}/$'.format(base_url): bucket_response, + '{}/(.+)'.format(base_url): key_response, } diff --git a/moto/s3/utils.py b/moto/s3/utils.py new file mode 100644 index 000000000..4f1325aae --- /dev/null +++ b/moto/s3/utils.py @@ -0,0 +1,8 @@ +import re + +bucket_name_regex = re.compile("(.+).s3.amazonaws.com") + + +def bucket_name_from_hostname(hostname): + bucket_result = bucket_name_regex.search(hostname) + return bucket_result.groups()[0] diff --git a/requirements.txt b/requirements.txt index 5c5d0814c..22c17953d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ boto +coverage #httpretty Jinja2 mock diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 49ffb38fa..cff2899d4 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -32,6 +32,14 @@ def test_my_model_save(): assert conn.get_bucket('mybucket').get_key('steve').get_contents_as_string() == 'is awesome' + +@mock_s3 +def test_missing_key(): + conn = boto.connect_s3('the_key', 'the_secret') + bucket = conn.create_bucket("foobar") + bucket.get_key("the-key").should.equal(None) + + @mock_s3 def test_missing_bucket(): conn = boto.connect_s3('the_key', 'the_secret') @@ -47,13 +55,18 @@ def test_bucket_deletion(): key.key = "the-key" key.set_contents_from_string("some value") + # Try to delete a bucket that still has keys conn.delete_bucket.when.called_with("foobar").should.throw(S3ResponseError) bucket.delete_key("the-key") conn.delete_bucket("foobar") + # Get non-existing bucket conn.get_bucket.when.called_with("foobar").should.throw(S3ResponseError) + # Delete non-existant bucket + conn.delete_bucket.when.called_with("foobar").should.throw(S3ResponseError) + @mock_s3 def test_get_all_buckets():