DynamoDB: put_item(): Improve type validation (#5654)
This commit is contained in:
parent
96b2eff1bc
commit
37845792d3
@ -332,3 +332,8 @@ class TransactWriteSingleOpException(MockValidationException):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(self.there_can_be_only_one)
|
||||
|
||||
|
||||
class SerializationException(DynamodbException):
|
||||
def __init__(self, msg):
|
||||
super().__init__(error_type="SerializationException", message=msg)
|
||||
|
@ -33,6 +33,7 @@ from moto.dynamodb.exceptions import (
|
||||
MockValidationException,
|
||||
InvalidConversion,
|
||||
TransactWriteSingleOpException,
|
||||
SerializationException,
|
||||
)
|
||||
from moto.dynamodb.models.utilities import bytesize
|
||||
from moto.dynamodb.models.dynamo_type import DynamoType
|
||||
@ -658,6 +659,17 @@ class Table(CloudFormationModel):
|
||||
self._validate_item_types(value)
|
||||
elif type(value) == int and key == "N":
|
||||
raise InvalidConversion
|
||||
if key == "S":
|
||||
# This scenario is usually caught by boto3, but the user can disable parameter validation
|
||||
# Which is why we need to catch it 'server-side' as well
|
||||
if type(value) == int:
|
||||
raise SerializationException(
|
||||
"NUMBER_VALUE cannot be converted to String"
|
||||
)
|
||||
if type(value) == dict:
|
||||
raise SerializationException(
|
||||
"Start of structure or map found where not expected"
|
||||
)
|
||||
|
||||
def put_item(
|
||||
self,
|
||||
@ -699,9 +711,8 @@ class Table(CloudFormationModel):
|
||||
actual_type=range_value.type,
|
||||
)
|
||||
|
||||
self._validate_key_sizes(item_attrs)
|
||||
|
||||
self._validate_item_types(item_attrs)
|
||||
self._validate_key_sizes(item_attrs)
|
||||
|
||||
if expected is None:
|
||||
expected = {}
|
||||
|
@ -870,3 +870,29 @@ def test_update_primary_key():
|
||||
table.get_item(Key={"pk": "testchangepk"})["Item"].should.equal(
|
||||
{"pk": "testchangepk"}
|
||||
)
|
||||
|
||||
|
||||
@mock_dynamodb
|
||||
def test_put_item__string_as_integer_value():
|
||||
if settings.TEST_SERVER_MODE:
|
||||
raise SkipTest("Unable to mock a session with Config in ServerMode")
|
||||
session = botocore.session.Session()
|
||||
config = botocore.client.Config(parameter_validation=False)
|
||||
client = session.create_client("dynamodb", region_name="us-east-1", config=config)
|
||||
client.create_table(
|
||||
TableName="without_sk",
|
||||
KeySchema=[{"AttributeName": "pk", "KeyType": "HASH"}],
|
||||
AttributeDefinitions=[{"AttributeName": "pk", "AttributeType": "S"}],
|
||||
ProvisionedThroughput={"ReadCapacityUnits": 10, "WriteCapacityUnits": 10},
|
||||
)
|
||||
with pytest.raises(ClientError) as exc:
|
||||
client.put_item(TableName="without_sk", Item={"pk": {"S": 123}})
|
||||
err = exc.value.response["Error"]
|
||||
err["Code"].should.equal("SerializationException")
|
||||
err["Message"].should.equal("NUMBER_VALUE cannot be converted to String")
|
||||
|
||||
with pytest.raises(ClientError) as exc:
|
||||
client.put_item(TableName="without_sk", Item={"pk": {"S": {"S": "asdf"}}})
|
||||
err = exc.value.response["Error"]
|
||||
err["Code"].should.equal("SerializationException")
|
||||
err["Message"].should.equal("Start of structure or map found where not expected")
|
||||
|
Loading…
Reference in New Issue
Block a user