@@ -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()
|
||||
|
||||
|
||||
@@ -70,4 +70,3 @@ class DeleteTableDynamoDBAction(DynamoDBAction):
|
||||
raise e
|
||||
except Exception:
|
||||
raise exception.AWSErrorResponseException()
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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=[
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user