364 lines
13 KiB
Python
364 lines
13 KiB
Python
import boto3
|
|
import pytest
|
|
from boto3.dynamodb.conditions import Key
|
|
from botocore.exceptions import ClientError
|
|
|
|
from moto import mock_dynamodb
|
|
from moto.dynamodb.limits import HASH_KEY_MAX_LENGTH, RANGE_KEY_MAX_LENGTH
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_item_add_long_string_hash_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}],
|
|
AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
"forum_name": {"S": "x" * HASH_KEY_MAX_LENGTH},
|
|
"subject": {"S": "Check this out!"},
|
|
"Body": {"S": "http://url_to_lolcat.gif"},
|
|
"SentBy": {"S": "test"},
|
|
"ReceivedTime": {"S": "12/9/2011 11:36:03 PM"},
|
|
},
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
"forum_name": {"S": "x" * (HASH_KEY_MAX_LENGTH + 1)},
|
|
"subject": {"S": "Check this out!"},
|
|
"Body": {"S": "http://url_to_lolcat.gif"},
|
|
"SentBy": {"S": "test"},
|
|
"ReceivedTime": {"S": "12/9/2011 11:36:03 PM"},
|
|
},
|
|
)
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
# deliberately no space between "of" and "2048"
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_item_add_long_string_nonascii_hash_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}],
|
|
AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
|
|
emoji_b = b"\xf0\x9f\x98\x83" # smile emoji
|
|
emoji = emoji_b.decode("utf-8") # 1 character, but 4 bytes
|
|
short_enough = emoji * int(HASH_KEY_MAX_LENGTH / len(emoji.encode("utf-8")))
|
|
too_long = "x" + short_enough
|
|
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
"forum_name": {"S": short_enough},
|
|
"subject": {"S": "Check this out!"},
|
|
"Body": {"S": "http://url_to_lolcat.gif"},
|
|
"SentBy": {"S": "test"},
|
|
"ReceivedTime": {"S": "12/9/2011 11:36:03 PM"},
|
|
},
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
"forum_name": {"S": too_long},
|
|
"subject": {"S": "Check this out!"},
|
|
"Body": {"S": "http://url_to_lolcat.gif"},
|
|
"SentBy": {"S": "test"},
|
|
"ReceivedTime": {"S": "12/9/2011 11:36:03 PM"},
|
|
},
|
|
)
|
|
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
# deliberately no space between "of" and "2048"
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_item_add_long_string_range_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[
|
|
{"AttributeName": "forum_name", "KeyType": "HASH"},
|
|
{"AttributeName": "ReceivedTime", "KeyType": "RANGE"},
|
|
],
|
|
AttributeDefinitions=[
|
|
{"AttributeName": "forum_name", "AttributeType": "S"},
|
|
{"AttributeName": "ReceivedTime", "AttributeType": "S"},
|
|
],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
"forum_name": {"S": "LOLCat Forum"},
|
|
"subject": {"S": "Check this out!"},
|
|
"Body": {"S": "http://url_to_lolcat.gif"},
|
|
"SentBy": {"S": "someone@somewhere.edu"},
|
|
"ReceivedTime": {"S": "x" * RANGE_KEY_MAX_LENGTH},
|
|
},
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
"forum_name": {"S": "LOLCat Forum"},
|
|
"subject": {"S": "Check this out!"},
|
|
"Body": {"S": "http://url_to_lolcat.gif"},
|
|
"SentBy": {"S": "someone@somewhere.edu"},
|
|
"ReceivedTime": {"S": "x" * (RANGE_KEY_MAX_LENGTH + 1)},
|
|
},
|
|
)
|
|
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_put_long_string_gsi_range_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[
|
|
{"AttributeName": "partition_key", "KeyType": "HASH"},
|
|
{"AttributeName": "sort_key", "KeyType": "RANGE"},
|
|
],
|
|
AttributeDefinitions=[
|
|
{"AttributeName": "partition_key", "AttributeType": "S"},
|
|
{"AttributeName": "sort_key", "AttributeType": "S"},
|
|
],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
# partition_key is only used as the HASH key
|
|
# so we can set it to range key length
|
|
"partition_key": {"S": "x" * (RANGE_KEY_MAX_LENGTH + 1)},
|
|
"sort_key": {"S": "sk"},
|
|
},
|
|
)
|
|
|
|
conn.update_table(
|
|
TableName=name,
|
|
AttributeDefinitions=[
|
|
{"AttributeName": "partition_key", "AttributeType": "S"},
|
|
{"AttributeName": "sort_key", "AttributeType": "S"},
|
|
],
|
|
GlobalSecondaryIndexUpdates=[
|
|
{
|
|
"Create": {
|
|
"IndexName": "random-table-index",
|
|
"KeySchema": [
|
|
{"AttributeName": "sort_key", "KeyType": "HASH"},
|
|
{"AttributeName": "partition_key", "KeyType": "RANGE"},
|
|
],
|
|
"Projection": {"ProjectionType": "KEYS_ONLY"},
|
|
"ProvisionedThroughput": {
|
|
"ReadCapacityUnits": 20,
|
|
"WriteCapacityUnits": 20,
|
|
},
|
|
}
|
|
},
|
|
],
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.put_item(
|
|
TableName=name,
|
|
Item={
|
|
# partition_key is used as a range key in the GSI
|
|
# so updating this should still fail
|
|
"partition_key": {"S": "y" * (RANGE_KEY_MAX_LENGTH + 1)},
|
|
"sort_key": {"S": "sk2"},
|
|
},
|
|
)
|
|
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_update_item_with_long_string_hash_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}],
|
|
AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
|
|
conn.update_item(
|
|
TableName=name,
|
|
Key={
|
|
"forum_name": {"S": "x" * HASH_KEY_MAX_LENGTH},
|
|
"ReceivedTime": {"S": "12/9/2011 11:36:03 PM"},
|
|
},
|
|
UpdateExpression="set body=:New",
|
|
ExpressionAttributeValues={":New": {"S": "hello"}},
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.update_item(
|
|
TableName=name,
|
|
Key={
|
|
"forum_name": {"S": "x" * (HASH_KEY_MAX_LENGTH + 1)},
|
|
"ReceivedTime": {"S": "12/9/2011 11:36:03 PM"},
|
|
},
|
|
UpdateExpression="set body=:New",
|
|
ExpressionAttributeValues={":New": {"S": "hello"}},
|
|
)
|
|
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
# deliberately no space between "of" and "2048"
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_update_item_with_long_string_range_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[
|
|
{"AttributeName": "forum_name", "KeyType": "HASH"},
|
|
{"AttributeName": "ReceivedTime", "KeyType": "RANGE"},
|
|
],
|
|
AttributeDefinitions=[
|
|
{"AttributeName": "forum_name", "AttributeType": "S"},
|
|
{"AttributeName": "ReceivedTime", "AttributeType": "S"},
|
|
],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
conn.update_item(
|
|
TableName=name,
|
|
Key={
|
|
"forum_name": {"S": "Lolcat Forum"},
|
|
"ReceivedTime": {"S": "x" * RANGE_KEY_MAX_LENGTH},
|
|
},
|
|
UpdateExpression="set body=:New",
|
|
ExpressionAttributeValues={":New": {"S": "hello"}},
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.update_item(
|
|
TableName=name,
|
|
Key={
|
|
"forum_name": {"S": "Lolcat Forum"},
|
|
"ReceivedTime": {"S": "x" * (RANGE_KEY_MAX_LENGTH + 1)},
|
|
},
|
|
UpdateExpression="set body=:New",
|
|
ExpressionAttributeValues={":New": {"S": "hello"}},
|
|
)
|
|
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
# deliberately no space between "of" and "2048"
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_item_add_empty_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[{"AttributeName": "forum_name", "KeyType": "HASH"}],
|
|
AttributeDefinitions=[{"AttributeName": "forum_name", "AttributeType": "S"}],
|
|
BillingMode="PAY_PER_REQUEST",
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
conn.get_item(
|
|
TableName=name,
|
|
Key={"forum_name": {"S": ""}},
|
|
)
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: forum_name"
|
|
)
|
|
|
|
|
|
@mock_dynamodb
|
|
def test_query_empty_key_exception():
|
|
name = "TestTable"
|
|
conn = boto3.client("dynamodb", region_name="us-west-2")
|
|
conn.create_table(
|
|
TableName=name,
|
|
KeySchema=[
|
|
{"AttributeName": "hk", "KeyType": "HASH"},
|
|
{"AttributeName": "rk", "KeyType": "RANGE"},
|
|
],
|
|
AttributeDefinitions=[
|
|
{"AttributeName": "hk", "AttributeType": "S"},
|
|
{"AttributeName": "rk", "AttributeType": "S"},
|
|
],
|
|
ProvisionedThroughput={"ReadCapacityUnits": 5, "WriteCapacityUnits": 5},
|
|
)
|
|
table = boto3.resource("dynamodb", "us-west-2").Table(name)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
table.query(KeyConditionExpression=Key("hk").eq(""))
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: hk"
|
|
)
|
|
|
|
with pytest.raises(ClientError) as ex:
|
|
table.query(KeyConditionExpression=Key("hk").eq("sth") & Key("rk").eq(""))
|
|
assert ex.value.response["Error"]["Code"] == "ValidationException"
|
|
assert ex.value.response["ResponseMetadata"]["HTTPStatusCode"] == 400
|
|
assert (
|
|
ex.value.response["Error"]["Message"]
|
|
== "One or more parameter values are not valid. The AttributeValue for a key attribute cannot contain an empty string value. Key: rk"
|
|
)
|