Adding sqs queue creation
This commit is contained in:
parent
e261b82f29
commit
89364ed864
@ -4,3 +4,4 @@ logging.getLogger('boto').setLevel(logging.CRITICAL)
|
|||||||
from .dynamodb import mock_dynamodb
|
from .dynamodb import mock_dynamodb
|
||||||
from .ec2 import mock_ec2
|
from .ec2 import mock_ec2
|
||||||
from .s3 import mock_s3
|
from .s3 import mock_s3
|
||||||
|
from .sqs import mock_sqs
|
||||||
|
43
moto/core/utils.py
Normal file
43
moto/core/utils.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import inspect
|
||||||
|
from urlparse import parse_qs
|
||||||
|
|
||||||
|
|
||||||
|
def headers_to_dict(headers):
|
||||||
|
result = {}
|
||||||
|
for index, header in enumerate(headers.split("\r\n")):
|
||||||
|
if not header:
|
||||||
|
continue
|
||||||
|
if index:
|
||||||
|
# Parsing headers
|
||||||
|
key, value = header.split(":", 1)
|
||||||
|
result[key.strip()] = value.strip()
|
||||||
|
else:
|
||||||
|
# Parsing method and path
|
||||||
|
path_and_querystring = header.split(" /")[1]
|
||||||
|
if '?' in path_and_querystring:
|
||||||
|
querystring = path_and_querystring.split("?")[1]
|
||||||
|
else:
|
||||||
|
querystring = path_and_querystring
|
||||||
|
queryset_dict = parse_qs(querystring)
|
||||||
|
result.update(queryset_dict)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def camelcase_to_underscores(argument):
|
||||||
|
''' Converts a camelcase param like theNewAttribute to the equivalent
|
||||||
|
python underscore variable like the_new_attribute'''
|
||||||
|
result = ''
|
||||||
|
prev_char_title = True
|
||||||
|
for char in argument:
|
||||||
|
if char.istitle() and not prev_char_title:
|
||||||
|
# Only add underscore if char is capital, not first letter, and prev
|
||||||
|
# char wasn't capital
|
||||||
|
result += "_"
|
||||||
|
prev_char_title = char.istitle()
|
||||||
|
if not char.isspace(): # Only add non-whitespace
|
||||||
|
result += char.lower()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def method_names_from_class(clazz):
|
||||||
|
return [x[0] for x in inspect.getmembers(clazz, predicate=inspect.ismethod)]
|
@ -1,6 +1,6 @@
|
|||||||
from urlparse import parse_qs
|
from urlparse import parse_qs
|
||||||
|
|
||||||
from moto.ec2.utils import camelcase_to_underscores, method_namess_from_class
|
from moto.core.utils import camelcase_to_underscores, method_names_from_class
|
||||||
|
|
||||||
from .amazon_dev_pay import AmazonDevPay
|
from .amazon_dev_pay import AmazonDevPay
|
||||||
from .amis import AmisResponse
|
from .amis import AmisResponse
|
||||||
@ -76,7 +76,7 @@ class EC2Response(object):
|
|||||||
action = camelcase_to_underscores(action)
|
action = camelcase_to_underscores(action)
|
||||||
|
|
||||||
for sub_response in self.sub_responses:
|
for sub_response in self.sub_responses:
|
||||||
method_names = method_namess_from_class(sub_response)
|
method_names = method_names_from_class(sub_response)
|
||||||
if action in method_names:
|
if action in method_names:
|
||||||
response = sub_response(querystring)
|
response = sub_response(querystring)
|
||||||
method = getattr(response, action)
|
method = getattr(response, action)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
|
|
||||||
|
from moto.core.utils import camelcase_to_underscores
|
||||||
from moto.ec2.models import ec2_backend
|
from moto.ec2.models import ec2_backend
|
||||||
from moto.ec2.utils import instance_ids_from_querystring, camelcase_to_underscores
|
from moto.ec2.utils import instance_ids_from_querystring
|
||||||
|
|
||||||
|
|
||||||
class InstanceResponse(object):
|
class InstanceResponse(object):
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import inspect
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
@ -53,23 +52,3 @@ def resource_ids_from_querystring(querystring_dict):
|
|||||||
response_values[value[0]] = (tag_key, tag_value)
|
response_values[value[0]] = (tag_key, tag_value)
|
||||||
|
|
||||||
return response_values
|
return response_values
|
||||||
|
|
||||||
|
|
||||||
def camelcase_to_underscores(argument):
|
|
||||||
''' Converts a camelcase param like theNewAttribute to the equivalent
|
|
||||||
python underscore variable like the_new_attribute'''
|
|
||||||
result = ''
|
|
||||||
prev_char_title = True
|
|
||||||
for char in argument:
|
|
||||||
if char.istitle() and not prev_char_title:
|
|
||||||
# Only add underscore if char is capital, not first letter, and prev
|
|
||||||
# char wasn't capital
|
|
||||||
result += "_"
|
|
||||||
prev_char_title = char.istitle()
|
|
||||||
if not char.isspace(): # Only add non-whitespace
|
|
||||||
result += char.lower()
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def method_namess_from_class(clazz):
|
|
||||||
return [x[0] for x in inspect.getmembers(clazz, predicate=inspect.ismethod)]
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
|
|
||||||
from .models import s3_backend
|
from .models import s3_backend
|
||||||
from .utils import bucket_name_from_hostname, headers_to_dict
|
from moto.core.utils import headers_to_dict
|
||||||
|
from .utils import bucket_name_from_hostname
|
||||||
|
|
||||||
|
|
||||||
def all_buckets(uri, body, method):
|
def all_buckets(uri, body, method):
|
||||||
|
@ -6,13 +6,3 @@ bucket_name_regex = re.compile("(.+).s3.amazonaws.com")
|
|||||||
def bucket_name_from_hostname(hostname):
|
def bucket_name_from_hostname(hostname):
|
||||||
bucket_result = bucket_name_regex.search(hostname)
|
bucket_result = bucket_name_regex.search(hostname)
|
||||||
return bucket_result.groups()[0]
|
return bucket_result.groups()[0]
|
||||||
|
|
||||||
|
|
||||||
def headers_to_dict(headers):
|
|
||||||
result = {}
|
|
||||||
for header in headers.split("\r\n"):
|
|
||||||
if ':' in header:
|
|
||||||
key, value = header.split(":", 1)
|
|
||||||
result[key.strip()] = value.strip()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
2
moto/sqs/__init__.py
Normal file
2
moto/sqs/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .models import sqs_backend
|
||||||
|
mock_sqs = sqs_backend.decorator
|
42
moto/sqs/models.py
Normal file
42
moto/sqs/models.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
from moto.core import BaseBackend
|
||||||
|
from moto.core.utils import camelcase_to_underscores
|
||||||
|
|
||||||
|
|
||||||
|
class Queue(object):
|
||||||
|
camelcase_attributes = ['VisibilityTimeout']
|
||||||
|
|
||||||
|
def __init__(self, name, visibility_timeout):
|
||||||
|
self.name = name
|
||||||
|
self.visibility_timeout = visibility_timeout
|
||||||
|
|
||||||
|
@property
|
||||||
|
def attributes(self):
|
||||||
|
result = {}
|
||||||
|
for attribute in self.camelcase_attributes:
|
||||||
|
result[attribute] = getattr(self, camelcase_to_underscores(attribute))
|
||||||
|
return result
|
||||||
|
|
||||||
|
class SQSBackend(BaseBackend):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.queues = {}
|
||||||
|
super(SQSBackend, self).__init__()
|
||||||
|
|
||||||
|
def create_queue(self, name, visibility_timeout):
|
||||||
|
queue = Queue(name, visibility_timeout)
|
||||||
|
self.queues[name] = queue
|
||||||
|
return queue
|
||||||
|
|
||||||
|
def list_queues(self):
|
||||||
|
return self.queues.values()
|
||||||
|
|
||||||
|
def get_queue(self, queue_name):
|
||||||
|
return self.queues[queue_name]
|
||||||
|
|
||||||
|
def delete_queue(self, queue_name):
|
||||||
|
if queue_name in self.queues:
|
||||||
|
return self.queues.pop(queue_name)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
sqs_backend = SQSBackend()
|
110
moto/sqs/responses.py
Normal file
110
moto/sqs/responses.py
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
from urlparse import parse_qs
|
||||||
|
|
||||||
|
from jinja2 import Template
|
||||||
|
|
||||||
|
from moto.core.utils import headers_to_dict, camelcase_to_underscores, method_names_from_class
|
||||||
|
from .models import sqs_backend
|
||||||
|
|
||||||
|
|
||||||
|
class BaseResponse(object):
|
||||||
|
def dispatch(self, uri, body, headers):
|
||||||
|
if body:
|
||||||
|
querystring = parse_qs(body)
|
||||||
|
else:
|
||||||
|
querystring = headers_to_dict(headers)
|
||||||
|
|
||||||
|
self.path = uri.path
|
||||||
|
self.querystring = querystring
|
||||||
|
|
||||||
|
action = querystring['Action'][0]
|
||||||
|
action = camelcase_to_underscores(action)
|
||||||
|
|
||||||
|
method_names = method_names_from_class(self.__class__)
|
||||||
|
if action in method_names:
|
||||||
|
method = getattr(self, action)
|
||||||
|
return method()
|
||||||
|
raise NotImplementedError("The {} action has not been implemented".format(action))
|
||||||
|
|
||||||
|
|
||||||
|
class QueuesResponse(BaseResponse):
|
||||||
|
|
||||||
|
def create_queue(self):
|
||||||
|
visibility_timeout = None
|
||||||
|
if 'Attribute.1.Name' in self.querystring and self.querystring.get('Attribute.1.Name')[0] == 'VisibilityTimeout':
|
||||||
|
visibility_timeout = self.querystring.get("Attribute.1.Value")[0]
|
||||||
|
|
||||||
|
queue_name = self.querystring.get("QueueName")[0]
|
||||||
|
queue = sqs_backend.create_queue(queue_name, visibility_timeout=visibility_timeout)
|
||||||
|
template = Template(CREATE_QUEUE_RESPONSE)
|
||||||
|
return template.render(queue=queue)
|
||||||
|
|
||||||
|
def list_queues(self):
|
||||||
|
queues = sqs_backend.list_queues()
|
||||||
|
template = Template(LIST_QUEUES_RESPONSE)
|
||||||
|
return template.render(queues=queues)
|
||||||
|
|
||||||
|
|
||||||
|
class QueueResponse(BaseResponse):
|
||||||
|
def get_queue_attributes(self):
|
||||||
|
queue_name = self.path.split("/")[-1]
|
||||||
|
queue = sqs_backend.get_queue(queue_name)
|
||||||
|
template = Template(GET_QUEUE_ATTRIBUTES_RESPONSE)
|
||||||
|
return template.render(queue=queue)
|
||||||
|
|
||||||
|
def delete_queue(self):
|
||||||
|
queue_name = self.path.split("/")[-1]
|
||||||
|
queue = sqs_backend.delete_queue(queue_name)
|
||||||
|
if not queue:
|
||||||
|
return "A queue with name {} does not exist".format(queue_name), dict(status=404)
|
||||||
|
template = Template(DELETE_QUEUE_RESPONSE)
|
||||||
|
return template.render(queue=queue)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CREATE_QUEUE_RESPONSE = """<CreateQueueResponse>
|
||||||
|
<CreateQueueResult>
|
||||||
|
<QueueUrl>http://sqs.us-east-1.amazonaws.com/123456789012/{{ queue.name }}</QueueUrl>
|
||||||
|
<VisibilityTimeout>{{ queue.visibility_timeout }}</VisibilityTimeout>
|
||||||
|
</CreateQueueResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>
|
||||||
|
7a62c49f-347e-4fc4-9331-6e8e7a96aa73
|
||||||
|
</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</CreateQueueResponse>"""
|
||||||
|
|
||||||
|
LIST_QUEUES_RESPONSE = """<ListQueuesResponse>
|
||||||
|
<ListQueuesResult>
|
||||||
|
{% for queue in queues %}
|
||||||
|
<QueueUrl>http://sqs.us-east-1.amazonaws.com/123456789012/{{ queue.name }}</QueueUrl>
|
||||||
|
<VisibilityTimeout>{{ queue.visibility_timeout }}</VisibilityTimeout>
|
||||||
|
{% endfor %}
|
||||||
|
</ListQueuesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>
|
||||||
|
725275ae-0b9b-4762-b238-436d7c65a1ac
|
||||||
|
</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</ListQueuesResponse>"""
|
||||||
|
|
||||||
|
DELETE_QUEUE_RESPONSE = """<DeleteQueueResponse>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>
|
||||||
|
6fde8d1e-52cd-4581-8cd9-c512f4c64223
|
||||||
|
</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</DeleteQueueResponse>"""
|
||||||
|
|
||||||
|
GET_QUEUE_ATTRIBUTES_RESPONSE = """<GetQueueAttributesResponse>
|
||||||
|
<GetQueueAttributesResult>
|
||||||
|
{% for key, value in queue.attributes.items() %}
|
||||||
|
<Attribute>
|
||||||
|
<Name>{{ key }}</Name>
|
||||||
|
<Value>{{ value }}</Value>
|
||||||
|
</Attribute>
|
||||||
|
{% endfor %}
|
||||||
|
</GetQueueAttributesResult>
|
||||||
|
<ResponseMetadata>
|
||||||
|
<RequestId>1ea71be5-b5a2-4f9d-b85a-945d8d08cd0b</RequestId>
|
||||||
|
</ResponseMetadata>
|
||||||
|
</GetQueueAttributesResponse>"""
|
10
moto/sqs/urls.py
Normal file
10
moto/sqs/urls.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from .responses import QueueResponse, QueuesResponse
|
||||||
|
|
||||||
|
base_url = "https://(.*).amazonaws.com"
|
||||||
|
#base_url2 = "https://sqs.us-east-1.amazonaws.com"
|
||||||
|
|
||||||
|
|
||||||
|
urls = {
|
||||||
|
'{0}/$'.format(base_url): QueuesResponse().dispatch,
|
||||||
|
'{0}/(\d+)/(.*)$'.format(base_url): QueueResponse().dispatch,
|
||||||
|
}
|
30
tests/test_sqs/test_sqs.py
Normal file
30
tests/test_sqs/test_sqs.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import boto
|
||||||
|
from boto.exception import SQSError
|
||||||
|
|
||||||
|
from sure import expect
|
||||||
|
|
||||||
|
from moto import mock_sqs
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_create_queue():
|
||||||
|
conn = boto.connect_sqs('the_key', 'the_secret')
|
||||||
|
conn.create_queue("test-queue", visibility_timeout=60)
|
||||||
|
|
||||||
|
all_queues = conn.get_all_queues()
|
||||||
|
all_queues[0].name.should.equal("test-queue")
|
||||||
|
|
||||||
|
all_queues[0].get_timeout().should.equal(60)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_sqs
|
||||||
|
def test_delete_queue():
|
||||||
|
conn = boto.connect_sqs('the_key', 'the_secret')
|
||||||
|
queue = conn.create_queue("test-queue", visibility_timeout=60)
|
||||||
|
|
||||||
|
conn.get_all_queues().should.have.length_of(1)
|
||||||
|
|
||||||
|
queue.delete()
|
||||||
|
conn.get_all_queues().should.have.length_of(0)
|
||||||
|
|
||||||
|
queue.delete.when.called_with().should.throw(SQSError)
|
Loading…
Reference in New Issue
Block a user