DynamoDB:batch_put_item() now has validatior for empty keys (#5439)

This commit is contained in:
Bert Blommers 2022-08-31 20:09:39 +00:00 committed by GitHub
parent 53efd628c4
commit f23b44e256
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 70 additions and 12 deletions

View File

@ -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:

View File

@ -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": [

View File

@ -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": ""})

View File

@ -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"
)