From 956592d6154d101bbf0d4090bafbfbd7f6540e4f Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Thu, 22 Aug 2019 16:12:48 +0100 Subject: [PATCH] 2380 - Validate parameter-list for duplicates in dynamodb.batch_get_item --- moto/dynamodb2/responses.py | 12 +++++++ tests/test_dynamodb2/test_dynamodb.py | 52 +++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/moto/dynamodb2/responses.py b/moto/dynamodb2/responses.py index 86ca9a362..3e9fbb553 100644 --- a/moto/dynamodb2/responses.py +++ b/moto/dynamodb2/responses.py @@ -318,6 +318,9 @@ class DynamoHandler(BaseResponse): for table_name, table_request in table_batches.items(): keys = table_request['Keys'] + if self._contains_duplicates(keys): + er = 'com.amazon.coral.validate#ValidationException' + return self.error(er, 'Provided list of item keys contains duplicates') attributes_to_get = table_request.get('AttributesToGet') results["Responses"][table_name] = [] for key in keys: @@ -333,6 +336,15 @@ class DynamoHandler(BaseResponse): }) return dynamo_json_dump(results) + def _contains_duplicates(self, keys): + unique_keys = [] + for k in keys: + if k in unique_keys: + return True + else: + unique_keys.append(k) + return False + def query(self): name = self.body['TableName'] # {u'KeyConditionExpression': u'#n0 = :v0', u'ExpressionAttributeValues': {u':v0': {u'S': u'johndoe'}}, u'ExpressionAttributeNames': {u'#n0': u'username'}} diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py index a8f73bee6..fb6c0e17d 100644 --- a/tests/test_dynamodb2/test_dynamodb.py +++ b/tests/test_dynamodb2/test_dynamodb.py @@ -2141,3 +2141,55 @@ def test_scan_by_non_exists_index(): ex.exception.response['Error']['Message'].should.equal( 'The table does not have the specified index: non_exists_index' ) + + +@mock_dynamodb2 +def test_batch_items_returns_all(): + dynamodb = _create_user_table() + returned_items = dynamodb.batch_get_item(RequestItems={ + 'users': { + 'Keys': [{ + 'username': {'S': 'user0'} + }, { + 'username': {'S': 'user1'} + }, { + 'username': {'S': 'user2'} + }, { + 'username': {'S': 'user3'} + }], + 'ConsistentRead': True + } + })['Responses']['users'] + assert len(returned_items) == 3 + assert [item['username']['S'] for item in returned_items] == ['user1', 'user2', 'user3'] + + +@mock_dynamodb2 +def test_batch_items_should_throw_exception_for_duplicate_request(): + client = _create_user_table() + with assert_raises(ClientError) as ex: + client.batch_get_item(RequestItems={ + 'users': { + 'Keys': [{ + 'username': {'S': 'user0'} + }, { + 'username': {'S': 'user0'} + }], + 'ConsistentRead': True + }}) + ex.exception.response['Error']['Code'].should.equal('ValidationException') + ex.exception.response['Error']['Message'].should.equal('Provided list of item keys contains duplicates') + + +def _create_user_table(): + client = boto3.client('dynamodb', region_name='us-east-1') + client.create_table( + TableName='users', + KeySchema=[{'AttributeName': 'username', 'KeyType': 'HASH'}], + AttributeDefinitions=[{'AttributeName': 'username', 'AttributeType': 'S'}], + ProvisionedThroughput={'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5} + ) + client.put_item(TableName='users', Item={'username': {'S': 'user1'}, 'foo': {'S': 'bar'}}) + client.put_item(TableName='users', Item={'username': {'S': 'user2'}, 'foo': {'S': 'bar'}}) + client.put_item(TableName='users', Item={'username': {'S': 'user3'}, 'foo': {'S': 'bar'}}) + return client