diff --git a/moto/dynamodb2/responses.py b/moto/dynamodb2/responses.py index 15c1130f8..d07beefd6 100644 --- a/moto/dynamodb2/responses.py +++ b/moto/dynamodb2/responses.py @@ -1,4 +1,5 @@ from __future__ import unicode_literals +import itertools import json import six import re @@ -113,6 +114,21 @@ class DynamoHandler(BaseResponse): # getting the indexes global_indexes = body.get("GlobalSecondaryIndexes", []) local_secondary_indexes = body.get("LocalSecondaryIndexes", []) + # Verify AttributeDefinitions list all + expected_attrs = [] + expected_attrs.extend([key['AttributeName'] for key in key_schema]) + expected_attrs.extend(schema['AttributeName'] for schema in itertools.chain(*list(idx['KeySchema'] for idx in local_secondary_indexes))) + expected_attrs.extend(schema['AttributeName'] for schema in itertools.chain(*list(idx['KeySchema'] for idx in global_indexes))) + expected_attrs = list(set(expected_attrs)) + expected_attrs.sort() + actual_attrs = [item['AttributeName'] for item in attr] + actual_attrs.sort() + if actual_attrs != expected_attrs: + er = 'com.amazonaws.dynamodb.v20111205#ValidationException' + return self.error(er, + 'One or more parameter values were invalid: ' + 'Some index key attributes are not defined in AttributeDefinitions. ' + 'Keys: ' + str(expected_attrs) + ', AttributeDefinitions: ' + str(actual_attrs)) # get the stream specification streams = body.get("StreamSpecification") diff --git a/tests/test_dynamodb2/test_dynamodb.py b/tests/test_dynamodb2/test_dynamodb.py index 4e7b2dfeb..b0952f101 100644 --- a/tests/test_dynamodb2/test_dynamodb.py +++ b/tests/test_dynamodb2/test_dynamodb.py @@ -1676,15 +1676,7 @@ def test_query_global_secondary_index_when_created_via_update_table_resource(): { 'AttributeName': 'user_id', 'AttributeType': 'N', - }, - { - 'AttributeName': 'forum_name', - 'AttributeType': 'S' - }, - { - 'AttributeName': 'subject', - 'AttributeType': 'S' - }, + } ], ProvisionedThroughput={ 'ReadCapacityUnits': 5, @@ -2258,6 +2250,34 @@ def test_batch_items_should_throw_exception_for_duplicate_request(): ex.exception.response['Error']['Message'].should.equal('Provided list of item keys contains duplicates') +@mock_dynamodb2 +def test_index_with_unknown_attributes_should_fail(): + dynamodb = boto3.client('dynamodb', region_name='us-east-1') + + expected_exception = 'Some index key attributes are not defined in AttributeDefinitions.' + + with assert_raises(ClientError) as ex: + dynamodb.create_table( + AttributeDefinitions=[ + {'AttributeName': 'customer_nr', 'AttributeType': 'S'}, + {'AttributeName': 'last_name', 'AttributeType': 'S'}], + TableName='table_with_missing_attribute_definitions', + KeySchema=[ + {'AttributeName': 'customer_nr', 'KeyType': 'HASH'}, + {'AttributeName': 'last_name', 'KeyType': 'RANGE'}], + LocalSecondaryIndexes=[{ + 'IndexName': 'indexthataddsanadditionalattribute', + 'KeySchema': [ + {'AttributeName': 'customer_nr', 'KeyType': 'HASH'}, + {'AttributeName': 'postcode', 'KeyType': 'RANGE'}], + 'Projection': { 'ProjectionType': 'ALL' } + }], + BillingMode='PAY_PER_REQUEST') + + ex.exception.response['Error']['Code'].should.equal('ValidationException') + ex.exception.response['Error']['Message'].should.contain(expected_exception) + + def _create_user_table(): client = boto3.client('dynamodb', region_name='us-east-1') client.create_table( diff --git a/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py b/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py index e64d7d196..7d1975eda 100644 --- a/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py +++ b/tests/test_dynamodb2/test_dynamodb_table_with_range_key.py @@ -1765,6 +1765,14 @@ def test_boto3_update_table_gsi_throughput(): 'AttributeName': 'subject', 'AttributeType': 'S' }, + { + 'AttributeName': 'username', + 'AttributeType': 'S' + }, + { + 'AttributeName': 'created', + 'AttributeType': 'S' + } ], ProvisionedThroughput={ 'ReadCapacityUnits': 5, @@ -1939,6 +1947,14 @@ def test_update_table_gsi_throughput(): 'AttributeName': 'subject', 'AttributeType': 'S' }, + { + 'AttributeName': 'username', + 'AttributeType': 'S' + }, + { + 'AttributeName': 'created', + 'AttributeType': 'S' + } ], ProvisionedThroughput={ 'ReadCapacityUnits': 5,