Merge pull request #6 from Mirantis/master

Merge with upstream
This commit is contained in:
yyekovenko
2014-01-24 08:04:05 -08:00
12 changed files with 139 additions and 42 deletions

View File

@@ -117,8 +117,9 @@ class CreateTableDynamoDBAction(DynamoDBAction):
parser.Props.TABLE_SIZE_BYTES: 0
}
}
except exception.TableAlreadyExistsException:
raise exception.ResourceInUseException()
except exception.AWSErrorResponseException as e:
raise e
except Exception:
raise exception.AWSErrorResponseException()

View File

@@ -70,4 +70,3 @@ class DeleteTableDynamoDBAction(DynamoDBAction):
raise e
except Exception:
raise exception.AWSErrorResponseException()

View File

@@ -20,6 +20,7 @@ from magnetodb.api.amz.dynamodb import parser
from magnetodb.common import exception
class ListTablesDynamoDBAction(DynamoDBAction):
schema = {
"type": "object",
@@ -51,7 +52,7 @@ class ListTablesDynamoDBAction(DynamoDBAction):
res = {parser.Props.TABLE_NAMES: table_names}
if table_names and limit == len(table_names):
res[parser.Props.LAST_EVALUATED_TABLE_NAME] = table_names[-1]
res[parser.Props.LAST_EVALUATED_TABLE_NAME] = table_names[-1]
return res
except exception.AWSErrorResponseException as e:

View File

@@ -179,8 +179,8 @@ class QueryDynamoDBAction(DynamoDBAction):
if limit == len(result.items):
response[parser.Props.LAST_EVALUATED_KEY] = (
parser.Parser.format_item_attributes(result.last_evaluated_key)
parser.Parser.format_item_attributes(
result.last_evaluated_key)
)
return response
except exception.AWSErrorResponseException as e:

View File

@@ -116,7 +116,9 @@ class ScanDynamoDBAction(DynamoDBAction):
)
segment = self.action_params.get(parser.Props.SEGMENT, 0)
total_segments = self.action_params.get(parser.Props.TOTAL_SEGMENTS, 1)
total_segments = self.action_params.get(
parser.Props.TOTAL_SEGMENTS, 1
)
assert segment < total_segments
except Exception:
@@ -148,8 +150,9 @@ class ScanDynamoDBAction(DynamoDBAction):
if result.last_evaluated_key:
response[parser.Props.LAST_EVALUATED_KEY] = (
parser.Parser.format_item_attributes(result.last_evaluated_key)
parser.Parser.format_item_attributes(
result.last_evaluated_key
)
)
return response

View File

@@ -159,7 +159,9 @@ class UpdateItemDynamoDBAction(DynamoDBAction):
if return_values != parser.Values.RETURN_VALUES_NONE:
response[parser.Props.ATTRIBUTES] = (
parser.Parser.format_item_attributes(select_result.items[0]))
parser.Parser.format_item_attributes(
select_result.items[0])
)
if (return_item_collection_metrics !=
parser.Values.RETURN_ITEM_COLLECTION_METRICS_NONE):
@@ -185,4 +187,4 @@ class UpdateItemDynamoDBAction(DynamoDBAction):
except exception.AWSErrorResponseException as e:
raise e
except Exception:
raise exception.AWSErrorResponseException()
raise exception.AWSErrorResponseException()

View File

@@ -56,6 +56,10 @@ class TableNotExistsException(BackendInteractionException):
pass
class TableAlreadyExistsException(BackendInteractionException):
pass
class ServiceUnavailableException(FrontendInteractionException):
pass
@@ -66,9 +70,13 @@ class ConditionalCheckFailedException(FrontendInteractionException):
class AWSErrorResponseException(HTTPException, Response):
""" Base Exception for rendering to AWS DynamoDB error
JSON http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ErrorHandling.html
JSON http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/
ErrorHandling.html
"""
response_message = 'The server encountered an internal error trying to fulfill the request.'
response_message = (
"The server encountered an internal error"
" trying to fulfill the request."
)
error_code = 'InternalServerError'
status = '500'
@@ -77,9 +85,12 @@ class AWSErrorResponseException(HTTPException, Response):
Exception.__init__(self, message)
def __call__(self, environ, start_response):
response_headers = [('Content-type','application/x-amz-json-1.0')]
start_response(self.status,response_headers)
return '{"__type":"com.amazonaws.dynamodb.v20111205#'+self.error_code+'","message":"'+ self.response_message +'"}'
response_headers = [('Content-type', 'application/x-amz-json-1.0')]
start_response(self.status, response_headers)
return (
'{{"__type":"com.amazonaws.dynamodb.v20111205#{}","message":"{}"}}'
.format(self.error_code, self.response_message)
)
class BadRequestException(AWSErrorResponseException):
@@ -95,3 +106,10 @@ class ResourceNotFoundException(BadRequestException):
class ValidationException(BadRequestException):
response_message = 'One or more required parameter values were missing.'
error_code = 'ValidationException'
class ResourceInUseException(BadRequestException):
response_message = (
'The resource which you are attempting to change is in use.'
)
error_code = 'ResourceInUseException'

View File

@@ -19,10 +19,12 @@ import binascii
import time
from cassandra import decoder
from cassandra import AlreadyExists
from magnetodb.common.cassandra import cluster
from magnetodb.common.exception import BackendInteractionException
from magnetodb.common.exception import TableNotExistsException
from magnetodb.common.exception import TableAlreadyExistsException
from magnetodb.openstack.common import importutils
from magnetodb.openstack.common import log as logging
from magnetodb.storage import models
@@ -148,6 +150,10 @@ class CassandraStorageImpl():
LOG.debug("Executing query {}".format(query))
return self.session.execute(query)
except AlreadyExists as e:
msg = "Error executing query {}:{}".format(query, e.message)
LOG.error(msg)
raise TableAlreadyExistsException(msg)
except Exception as e:
msg = "Error executing query {}:{}".format(query, e.message)
LOG.error(msg)

View File

@@ -15,12 +15,10 @@
import httplib
import json
import os
import unittest
from magnetodb import storage
from magnetodb.common.exception import TableNotExistsException
from magnetodb.tests import PROJECT_ROOT_DIR
from magnetodb.tests.fake import magnetodb_api_fake
from mox import Mox, IgnoreArg
@@ -32,16 +30,6 @@ class APITest(unittest.TestCase):
The test for low level API calls
"""
PASTE_CONFIG_FILE = os.path.join(PROJECT_ROOT_DIR, 'etc/api-paste.ini')
@classmethod
def setUpClass(cls):
magnetodb_api_fake.run_fake_magnetodb_api(cls.PASTE_CONFIG_FILE)
@classmethod
def tearDownClass(cls):
magnetodb_api_fake.stop_fake_magnetodb_api()
def setUp(self):
self.storage_mocker = Mox()
@@ -51,7 +39,9 @@ class APITest(unittest.TestCase):
def test_describe_unexisting_table(self):
self.storage_mocker.StubOutWithMock(storage, 'describe_table')
storage.describe_table(IgnoreArg(), 'test_table1').AndRaise(TableNotExistsException)
storage.describe_table(IgnoreArg(), 'test_table1').AndRaise(
TableNotExistsException
)
self.storage_mocker.ReplayAll()
@@ -60,15 +50,23 @@ class APITest(unittest.TestCase):
'X-Amz-Target': 'DynamoDB_20120810.DescribeTable'}
conn = httplib.HTTPConnection('localhost:8080')
conn.request("POST", "/", body='{"TableName": "test_table1"}', headers=headers)
conn.request("POST", "/", body='{"TableName": "test_table1"}',
headers=headers)
response = conn.getresponse()
json_response = response.read()
response_model = json.loads(json_response)
self.assertEqual(response_model['__type'], 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException')
self.assertEqual(response_model['message'], 'The resource which is being requested does not exist.')
self.assertEqual(
response_model['__type'],
'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException')
self.assertEqual(
response_model['message'],
'The resource which is being requested does not exist.')
self.assertEqual(400, response.status)
self.assertEqual(response.getheader('Content-Type'), 'application/x-amz-json-1.0')
self.assertEqual(
response.getheader('Content-Type'), 'application/x-amz-json-1.0')

View File

@@ -31,6 +31,8 @@ from magnetodb.storage import models
from magnetodb import storage
from mox import Mox, IgnoreArg
DynamoDBConnection.NumberRetries = 0
CONF = magnetodb_api_fake.CONF
@@ -74,9 +76,9 @@ class BotoIntegrationTest(unittest.TestCase):
def test_list_table(self):
self.storage_mocker.StubOutWithMock(storage, "list_tables")
storage.list_tables(IgnoreArg(),
exclusive_start_table_name=None, limit=None) \
.AndReturn(['table1', 'table2'])
storage.list_tables(
IgnoreArg(), exclusive_start_table_name=None, limit=None
).AndReturn(['table1', 'table2'])
self.storage_mocker.ReplayAll()
self.assertEqual({'TableNames': ['table1', 'table2']},
@@ -134,17 +136,24 @@ class BotoIntegrationTest(unittest.TestCase):
self.storage_mocker.StubOutWithMock(storage, 'describe_table')
storage.describe_table(IgnoreArg(), 'test_table1').AndRaise(TableNotExistsException)
storage.describe_table(
IgnoreArg(), 'test_table1'
).AndRaise(TableNotExistsException)
self.storage_mocker.ReplayAll()
table = Table('test_table1', connection=self.DYNAMODB_CON)
try:
table_description = table.describe()
table.describe()
except JSONResponseError as e:
self.assertEqual(e.body['__type'],'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException')
self.assertEqual(e.body['message'],'The resource which is being requested does not exist.')
self.assertEqual(
e.body['__type'],
'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException')
self.assertEqual(
e.body['message'],
'The resource which is being requested does not exist.')
def test_delete_table(self):
self.storage_mocker.StubOutWithMock(storage, 'delete_table')
@@ -204,6 +213,67 @@ class BotoIntegrationTest(unittest.TestCase):
self.storage_mocker.VerifyAll()
def test_create_table_duplicate(self):
self.storage_mocker.StubOutWithMock(storage, 'create_table')
self.storage_mocker.StubOutWithMock(storage, 'list_tables')
storage.list_tables(IgnoreArg()).AndReturn([])
storage.create_table(IgnoreArg(), IgnoreArg())
storage.list_tables(IgnoreArg()).AndReturn(['test'])
self.storage_mocker.ReplayAll()
Table.create(
"test",
schema=[
fields.HashKey('hash', data_type=schema_types.NUMBER),
fields.RangeKey('range', data_type=schema_types.STRING)
],
throughput={
'read': 20,
'write': 10,
},
indexes=[
fields.KeysOnlyIndex(
'index_name',
parts=[
fields.RangeKey('indexed_field',
data_type=schema_types.STRING)
]
)
],
connection=self.DYNAMODB_CON
)
try:
Table.create(
"test",
schema=[
fields.HashKey('hash', data_type=schema_types.NUMBER),
fields.RangeKey('range', data_type=schema_types.STRING)
],
throughput={
'read': 20,
'write': 10,
},
indexes=[
fields.KeysOnlyIndex(
'index_name',
parts=[
fields.RangeKey('indexed_field',
data_type=schema_types.STRING)
]
)
],
connection=self.DYNAMODB_CON
)
self.fail()
except JSONResponseError as e:
self.assertEqual('ResourceInUseException', e.error_code)
self.storage_mocker.VerifyAll()
except Exception as e:
self.fail()
def test_put_item(self):
self.storage_mocker.StubOutWithMock(storage, 'put_item')
storage.put_item(
@@ -308,7 +378,8 @@ class BotoIntegrationTest(unittest.TestCase):
storage.select_item(
IgnoreArg(), IgnoreArg(), IgnoreArg(),
select_type=IgnoreArg(), index_name=IgnoreArg(), limit=IgnoreArg(),
order_type=IgnoreArg(), consistent=IgnoreArg()
exclusive_start_key=IgnoreArg(), consistent=IgnoreArg(),
order_type=IgnoreArg(),
).AndReturn(
models.SelectResult(
items=[

View File

@@ -306,7 +306,6 @@ class BotoTestCase(tempest.test.BaseTestCase):
dynamodb_error_code.server = ServerError()
dynamodb_error_code.client = ClientError()
@classmethod
def get_lfunction_gone(cls, obj):
"""If the object is instance of a well know type returns back with

View File

@@ -129,4 +129,3 @@ class MagnetoDBTablesTest(MagnetoDBTestCase):
new_tables = [n for n in self.client.list_tables()['TableNames']
if n == tname]
self.assertEqual(1, len(new_tables))