DynamoDB:batch_put_item() now has validatior for empty keys (#5439)
This commit is contained in:
parent
53efd628c4
commit
f23b44e256
@ -1381,9 +1381,7 @@ class DynamoDBBackend(BaseBackend):
|
||||
for key in keys:
|
||||
if key in table.hash_key_names:
|
||||
return key, None
|
||||
# for potential_hash, potential_range in zip(table.hash_key_names, table.range_key_names):
|
||||
# if set([potential_hash, potential_range]) == set(keys):
|
||||
# return potential_hash, potential_range
|
||||
|
||||
potential_hash, potential_range = None, None
|
||||
for key in set(keys):
|
||||
if key in table.hash_key_names:
|
||||
|
@ -68,7 +68,10 @@ def include_consumed_capacity(val=1.0):
|
||||
return _inner
|
||||
|
||||
|
||||
def put_has_empty_keys(field_updates, table):
|
||||
def get_empty_keys_on_put(field_updates, table):
|
||||
"""
|
||||
Return the first key-name that has an empty value. None if all keys are filled
|
||||
"""
|
||||
if table:
|
||||
key_names = table.attribute_keys
|
||||
|
||||
@ -78,7 +81,9 @@ def put_has_empty_keys(field_updates, table):
|
||||
for (key, val) in field_updates.items()
|
||||
if next(iter(val.keys())) in ["S", "B"] and next(iter(val.values())) == ""
|
||||
]
|
||||
return any([keyname in empty_str_fields for keyname in key_names])
|
||||
return next(
|
||||
(keyname for keyname in key_names if keyname in empty_str_fields), None
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
@ -371,9 +376,10 @@ class DynamoHandler(BaseResponse):
|
||||
if return_values not in ("ALL_OLD", "NONE"):
|
||||
raise MockValidationException("Return values set to invalid value")
|
||||
|
||||
if put_has_empty_keys(item, self.dynamodb_backend.get_table(name)):
|
||||
empty_key = get_empty_keys_on_put(item, self.dynamodb_backend.get_table(name))
|
||||
if empty_key:
|
||||
raise MockValidationException(
|
||||
"One or more parameter values were invalid: An AttributeValue may not contain an empty string"
|
||||
f"One or more parameter values were invalid: An AttributeValue may not contain an empty string. Key: {empty_key}"
|
||||
)
|
||||
if put_has_empty_attrs(item, self.dynamodb_backend.get_table(name)):
|
||||
raise MockValidationException(
|
||||
@ -421,17 +427,29 @@ class DynamoHandler(BaseResponse):
|
||||
|
||||
def batch_write_item(self):
|
||||
table_batches = self.body["RequestItems"]
|
||||
|
||||
put_requests = []
|
||||
delete_requests = []
|
||||
for table_name, table_requests in table_batches.items():
|
||||
table = self.dynamodb_backend.get_table(table_name)
|
||||
for table_request in table_requests:
|
||||
request_type = list(table_request.keys())[0]
|
||||
request = list(table_request.values())[0]
|
||||
if request_type == "PutRequest":
|
||||
item = request["Item"]
|
||||
self.dynamodb_backend.put_item(table_name, item)
|
||||
empty_key = get_empty_keys_on_put(item, table)
|
||||
if empty_key:
|
||||
raise MockValidationException(
|
||||
f"One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: {empty_key}"
|
||||
)
|
||||
put_requests.append((table_name, item))
|
||||
elif request_type == "DeleteRequest":
|
||||
keys = request["Key"]
|
||||
self.dynamodb_backend.delete_item(table_name, keys)
|
||||
delete_requests.append((table_name, keys))
|
||||
|
||||
for (table_name, item) in put_requests:
|
||||
self.dynamodb_backend.put_item(table_name, item)
|
||||
for (table_name, keys) in delete_requests:
|
||||
self.dynamodb_backend.delete_item(table_name, keys)
|
||||
|
||||
response = {
|
||||
"ConsumedCapacity": [
|
||||
|
@ -625,3 +625,45 @@ def test_update_expression_with_trailing_comma():
|
||||
err["Message"].should.equal(
|
||||
'Invalid UpdateExpression: Syntax error; token: "<EOF>", near: ","'
|
||||
)
|
||||
|
||||
|
||||
@mock_dynamodb
|
||||
def test_batch_put_item_with_empty_value():
|
||||
ddb = boto3.resource("dynamodb", region_name="us-east-1")
|
||||
ddb.create_table(
|
||||
AttributeDefinitions=[
|
||||
{"AttributeName": "pk", "AttributeType": "S"},
|
||||
{"AttributeName": "sk", "AttributeType": "S"},
|
||||
],
|
||||
TableName="test-table",
|
||||
KeySchema=[
|
||||
{"AttributeName": "pk", "KeyType": "HASH"},
|
||||
{"AttributeName": "sk", "KeyType": "SORT"},
|
||||
],
|
||||
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
||||
)
|
||||
table = ddb.Table("test-table")
|
||||
|
||||
# Empty Partition Key throws an error
|
||||
with pytest.raises(botocore.exceptions.ClientError) as exc:
|
||||
with table.batch_writer() as batch:
|
||||
batch.put_item(Item={"pk": "", "sk": "sth"})
|
||||
err = exc.value.response["Error"]
|
||||
err["Message"].should.equal(
|
||||
"One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: pk"
|
||||
)
|
||||
err["Code"].should.equal("ValidationException")
|
||||
|
||||
# Empty SortKey throws an error
|
||||
with pytest.raises(botocore.exceptions.ClientError) as exc:
|
||||
with table.batch_writer() as batch:
|
||||
batch.put_item(Item={"pk": "sth", "sk": ""})
|
||||
err = exc.value.response["Error"]
|
||||
err["Message"].should.equal(
|
||||
"One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: sk"
|
||||
)
|
||||
err["Code"].should.equal("ValidationException")
|
||||
|
||||
# Empty regular parameter workst just fine though
|
||||
with table.batch_writer() as batch:
|
||||
batch.put_item(Item={"pk": "sth", "sk": "else", "par": ""})
|
||||
|
@ -200,7 +200,7 @@ def test_item_add_empty_string_hash_key_exception():
|
||||
|
||||
ex.value.response["Error"]["Code"].should.equal("ValidationException")
|
||||
ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.value.response["Error"]["Message"].should.equal(
|
||||
ex.value.response["Error"]["Message"].should.match(
|
||||
"One or more parameter values were invalid: An AttributeValue may not contain an empty string"
|
||||
)
|
||||
|
||||
@ -241,7 +241,7 @@ def test_item_add_empty_string_range_key_exception():
|
||||
|
||||
ex.value.response["Error"]["Code"].should.equal("ValidationException")
|
||||
ex.value.response["ResponseMetadata"]["HTTPStatusCode"].should.equal(400)
|
||||
ex.value.response["Error"]["Message"].should.equal(
|
||||
ex.value.response["Error"]["Message"].should.match(
|
||||
"One or more parameter values were invalid: An AttributeValue may not contain an empty string"
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user