From 549cb23b7f952a2fefc0cb00690ce63f9db1bfe4 Mon Sep 17 00:00:00 2001 From: Steve Pulec Date: Thu, 16 May 2013 22:24:26 -0400 Subject: [PATCH] Better error messaging for dynamodb table gets for range key tables without range keys used. cc #28 --- moto/dynamodb/models.py | 12 ++++++-- moto/dynamodb/responses.py | 7 ++++- .../test_dynamodb_table_with_range_key.py | 28 +++++++++++++++++-- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/moto/dynamodb/models.py b/moto/dynamodb/models.py index 84330e279..66612caa8 100644 --- a/moto/dynamodb/models.py +++ b/moto/dynamodb/models.py @@ -101,6 +101,10 @@ class Table(object): self.created_at = datetime.datetime.now() self.items = defaultdict(dict) + @property + def has_range_key(self): + return self.range_key_attr is not None + @property def describe(self): results = { @@ -122,7 +126,7 @@ class Table(object): "TableSizeBytes": 0, } } - if self.range_key_attr: + if self.has_range_key: results["Table"]["KeySchema"]["RangeKeyElement"] = { "AttributeName": self.range_key_attr, "AttributeType": self.range_key_type @@ -132,7 +136,7 @@ class Table(object): def __len__(self): count = 0 for key, value in self.items.iteritems(): - if self.range_key_attr: + if self.has_range_key: count += len(value) else: count += 1 @@ -143,7 +147,7 @@ class Table(object): def put_item(self, item_attrs): hash_value = DynamoType(item_attrs.get(self.hash_key_attr)) - if self.range_key_attr: + if self.has_range_key: range_value = DynamoType(item_attrs.get(self.range_key_attr)) else: range_value = None @@ -157,6 +161,8 @@ class Table(object): return item def get_item(self, hash_key, range_key): + if self.has_range_key and not range_key: + raise ValueError("Table has a range key, but no range key was passed into get_item") try: if range_key: return self.items[hash_key][range_key] diff --git a/moto/dynamodb/responses.py b/moto/dynamodb/responses.py index 8f3172112..b2cc29e8c 100644 --- a/moto/dynamodb/responses.py +++ b/moto/dynamodb/responses.py @@ -188,12 +188,17 @@ class DynamoHandler(BaseResponse): hash_key = key['HashKeyElement'] range_key = key.get('RangeKeyElement') attrs_to_get = self.body.get('AttributesToGet') - item = dynamodb_backend.get_item(name, hash_key, range_key) + try: + item = dynamodb_backend.get_item(name, hash_key, range_key) + except ValueError: + er = 'com.amazon.coral.validate#ValidationException' + return self.error(er, status=400) if item: item_dict = item.describe_attrs(attrs_to_get) item_dict['ConsumedCapacityUnits'] = 0.5 return dynamo_json_dump(item_dict) else: + # Item not found er = 'com.amazonaws.dynamodb.v20111205#ResourceNotFoundException' return self.error(er, status=404) diff --git a/tests/test_dynamodb/test_dynamodb_table_with_range_key.py b/tests/test_dynamodb/test_dynamodb_table_with_range_key.py index e357c5928..83cc81c10 100644 --- a/tests/test_dynamodb/test_dynamodb_table_with_range_key.py +++ b/tests/test_dynamodb/test_dynamodb_table_with_range_key.py @@ -6,7 +6,7 @@ from moto import mock_dynamodb from moto.dynamodb import dynamodb_backend from boto.dynamodb import condition -from boto.dynamodb.exceptions import DynamoDBKeyNotFoundError +from boto.dynamodb.exceptions import DynamoDBKeyNotFoundError, DynamoDBValidationError from boto.exception import DynamoDBResponseError @@ -154,7 +154,7 @@ def test_get_missing_item(): hash_key='tester', range_key='other', ).should.throw(DynamoDBKeyNotFoundError) - table.has_item("foobar").should.equal(False) + table.has_item("foobar", "more").should.equal(False) @mock_dynamodb @@ -170,6 +170,30 @@ def test_get_item_with_undeclared_table(): ).should.throw(DynamoDBKeyNotFoundError) +@mock_dynamodb +def test_get_item_without_range_key(): + conn = boto.connect_dynamodb() + message_table_schema = conn.create_schema( + hash_key_name="test_hash", + hash_key_proto_value=int, + range_key_name="test_range", + range_key_proto_value=int, + ) + table = conn.create_table( + name='messages', + schema=message_table_schema, + read_units=10, + write_units=10 + ) + + hash_key = 3241526475 + range_key = 1234567890987 + new_item = table.new_item(hash_key=hash_key, range_key=range_key) + new_item.put() + + table.get_item.when.called_with(hash_key=hash_key).should.throw(DynamoDBValidationError) + + @mock_dynamodb def test_delete_item(): conn = boto.connect_dynamodb()