2021-10-18 19:44:29 +00:00
from __future__ import print_function
2014-08-26 17:25:50 +00:00
2021-06-10 06:05:07 +00:00
import uuid
2020-05-08 14:57:48 +00:00
from datetime import datetime
2018-06-06 16:50:29 +00:00
from decimal import Decimal
2013-12-05 11:16:56 +00:00
import boto
2017-05-11 01:58:42 +00:00
import boto3
2018-06-06 16:50:29 +00:00
from boto3 . dynamodb . conditions import Attr , Key
2019-01-13 08:38:38 +00:00
import re
2021-10-18 19:44:29 +00:00
import sure # noqa # pylint: disable=unused-import
2017-02-16 03:35:45 +00:00
from moto import mock_dynamodb2 , mock_dynamodb2_deprecated
2019-12-24 18:23:46 +00:00
from moto . dynamodb2 import dynamodb_backend2 , dynamodb_backends2
2013-12-05 11:16:56 +00:00
from boto . exception import JSONResponseError
2021-01-31 12:21:24 +00:00
from botocore . exceptions import ClientError
2014-01-07 08:56:51 +00:00
from tests . helpers import requires_boto_gte
2017-10-07 20:57:14 +00:00
import moto . dynamodb2 . comparisons
import moto . dynamodb2 . models
2021-04-30 12:47:47 +00:00
from moto . dynamodb2 . limits import HASH_KEY_MAX_LENGTH , RANGE_KEY_MAX_LENGTH
2017-10-07 20:57:14 +00:00
2020-10-06 05:54:49 +00:00
import pytest
2019-10-31 15:44:26 +00:00
2014-01-07 10:59:36 +00:00
try :
import boto . dynamodb2
except ImportError :
2014-08-26 17:25:50 +00:00
print ( " This boto version is not supported " )
2013-12-05 11:16:56 +00:00
2017-02-24 02:37:43 +00:00
2014-01-07 08:56:51 +00:00
@requires_boto_gte ( " 2.9 " )
2021-09-22 18:13:28 +00:00
# Has boto3 equivalent
2017-02-16 03:35:45 +00:00
@mock_dynamodb2_deprecated
2013-12-05 11:16:56 +00:00
def test_list_tables ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
2017-10-29 16:25:17 +00:00
# Should make tables properly with boto
2019-10-31 15:44:26 +00:00
dynamodb_backend2 . create_table (
name ,
2021-11-10 21:42:33 +00:00
attr = [
{ " AttributeType " : " S " , " AttributeName " : " forum_name " } ,
{ " AttributeType " : " S " , " AttributeName " : " subject " } ,
] ,
2019-10-31 15:44:26 +00:00
schema = [
{ " KeyType " : " HASH " , " AttributeName " : " forum_name " } ,
{ " KeyType " : " RANGE " , " AttributeName " : " subject " } ,
] ,
)
2017-02-24 02:37:43 +00:00
conn = boto . dynamodb2 . connect_to_region (
2019-10-31 15:44:26 +00:00
" us-east-1 " , aws_access_key_id = " ak " , aws_secret_access_key = " sk "
)
2013-12-05 11:16:56 +00:00
assert conn . list_tables ( ) [ " TableNames " ] == [ name ]
2021-09-22 18:13:28 +00:00
@mock_dynamodb2
@pytest.mark.parametrize (
" names " ,
[ [ ] , [ " TestTable " ] , [ " TestTable1 " , " TestTable2 " ] ] ,
ids = [ " no-table " , " one-table " , " multiple-tables " ] ,
)
def test_list_tables_boto3 ( names ) :
conn = boto3 . client ( " dynamodb " , region_name = " us-west-2 " )
for name in names :
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
conn . list_tables ( ) [ " TableNames " ] . should . equal ( names )
2014-01-07 08:56:51 +00:00
@requires_boto_gte ( " 2.9 " )
2021-09-22 18:13:28 +00:00
# Has boto3 equivalent
2017-02-16 03:35:45 +00:00
@mock_dynamodb2_deprecated
2013-12-05 11:16:56 +00:00
def test_list_tables_layer_1 ( ) :
2017-10-29 16:25:17 +00:00
# Should make tables properly with boto
2019-10-31 15:44:26 +00:00
dynamodb_backend2 . create_table (
2021-11-10 21:42:33 +00:00
" test_1 " ,
attr = [ { " AttributeType " : " S " , " AttributeName " : " name " } , ] ,
schema = [ { " KeyType " : " HASH " , " AttributeName " : " name " } ] ,
2019-10-31 15:44:26 +00:00
)
dynamodb_backend2 . create_table (
2021-11-10 21:42:33 +00:00
" test_2 " ,
attr = [ { " AttributeType " : " S " , " AttributeName " : " name " } ] ,
schema = [ { " KeyType " : " HASH " , " AttributeName " : " name " } ] ,
2019-10-31 15:44:26 +00:00
)
2017-02-24 02:37:43 +00:00
conn = boto . dynamodb2 . connect_to_region (
2019-10-31 15:44:26 +00:00
" us-east-1 " , aws_access_key_id = " ak " , aws_secret_access_key = " sk "
)
2014-08-27 15:17:06 +00:00
2013-12-05 11:16:56 +00:00
res = conn . list_tables ( limit = 1 )
expected = { " TableNames " : [ " test_1 " ] , " LastEvaluatedTableName " : " test_1 " }
res . should . equal ( expected )
res = conn . list_tables ( limit = 1 , exclusive_start_table_name = " test_1 " )
expected = { " TableNames " : [ " test_2 " ] }
res . should . equal ( expected )
2021-09-22 18:13:28 +00:00
@mock_dynamodb2
def test_list_tables_paginated ( ) :
conn = boto3 . client ( " dynamodb " , region_name = " us-west-2 " )
for name in [ " name1 " , " name2 " , " name3 " ] :
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
res = conn . list_tables ( Limit = 2 )
res . should . have . key ( " TableNames " ) . equal ( [ " name1 " , " name2 " ] )
res . should . have . key ( " LastEvaluatedTableName " ) . equal ( " name2 " )
res = conn . list_tables ( Limit = 1 , ExclusiveStartTableName = " name1 " )
res . should . have . key ( " TableNames " ) . equal ( [ " name2 " ] )
res . should . have . key ( " LastEvaluatedTableName " ) . equal ( " name2 " )
res = conn . list_tables ( ExclusiveStartTableName = " name1 " )
res . should . have . key ( " TableNames " ) . equal ( [ " name2 " , " name3 " ] )
res . shouldnt . have . key ( " LastEvaluatedTableName " )
2014-01-07 08:56:51 +00:00
@requires_boto_gte ( " 2.9 " )
2021-09-22 18:13:28 +00:00
# Has boto3 equivalent
2017-02-16 03:35:45 +00:00
@mock_dynamodb2_deprecated
2013-12-05 11:16:56 +00:00
def test_describe_missing_table ( ) :
2017-02-24 02:37:43 +00:00
conn = boto . dynamodb2 . connect_to_region (
2019-10-31 15:44:26 +00:00
" us-west-2 " , aws_access_key_id = " ak " , aws_secret_access_key = " sk "
)
2020-10-06 05:54:49 +00:00
with pytest . raises ( JSONResponseError ) :
2019-10-31 15:44:26 +00:00
conn . describe_table ( " messages " )
2017-05-11 01:58:42 +00:00
2021-09-22 18:13:28 +00:00
@mock_dynamodb2
def test_describe_missing_table_boto3 ( ) :
conn = boto3 . client ( " dynamodb " , region_name = " us-west-2 " )
with pytest . raises ( ClientError ) as ex :
conn . describe_table ( TableName = " messages " )
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ResourceNotFoundException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal ( " Requested resource not found " )
2017-05-11 01:58:42 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_list_table_tags ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2017-05-11 01:58:42 +00:00
table_description = conn . describe_table ( TableName = name )
2019-10-31 15:44:26 +00:00
arn = table_description [ " Table " ] [ " TableArn " ]
2017-10-29 16:06:09 +00:00
# Tag table
2019-10-31 15:44:26 +00:00
tags = [
{ " Key " : " TestTag " , " Value " : " TestValue " } ,
{ " Key " : " TestTag2 " , " Value " : " TestValue2 " } ,
]
2017-10-29 16:06:09 +00:00
conn . tag_resource ( ResourceArn = arn , Tags = tags )
# Check tags
2017-05-11 01:58:42 +00:00
resp = conn . list_tags_of_resource ( ResourceArn = arn )
assert resp [ " Tags " ] == tags
2017-10-29 16:06:09 +00:00
# Remove 1 tag
2019-10-31 15:44:26 +00:00
conn . untag_resource ( ResourceArn = arn , TagKeys = [ " TestTag " ] )
2017-10-29 16:06:09 +00:00
# Check tags
resp = conn . list_tags_of_resource ( ResourceArn = arn )
2019-10-31 15:44:26 +00:00
assert resp [ " Tags " ] == [ { " Key " : " TestTag2 " , " Value " : " TestValue2 " } ]
2017-10-29 16:06:09 +00:00
2017-05-11 01:58:42 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_list_table_tags_empty ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2017-05-11 01:58:42 +00:00
table_description = conn . describe_table ( TableName = name )
2019-10-31 15:44:26 +00:00
arn = table_description [ " Table " ] [ " TableArn " ]
2017-05-11 01:58:42 +00:00
resp = conn . list_tags_of_resource ( ResourceArn = arn )
assert resp [ " Tags " ] == [ ]
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_list_table_tags_paginated ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2017-05-11 01:58:42 +00:00
table_description = conn . describe_table ( TableName = name )
2019-10-31 15:44:26 +00:00
arn = table_description [ " Table " ] [ " TableArn " ]
2017-05-11 01:58:42 +00:00
for i in range ( 11 ) :
2019-10-31 15:44:26 +00:00
tags = [ { " Key " : " TestTag %d " % i , " Value " : " TestValue " } ]
conn . tag_resource ( ResourceArn = arn , Tags = tags )
2017-05-11 01:58:42 +00:00
resp = conn . list_tags_of_resource ( ResourceArn = arn )
assert len ( resp [ " Tags " ] ) == 10
2019-10-31 15:44:26 +00:00
assert " NextToken " in resp . keys ( )
resp2 = conn . list_tags_of_resource ( ResourceArn = arn , NextToken = resp [ " NextToken " ] )
2017-05-11 01:58:42 +00:00
assert len ( resp2 [ " Tags " ] ) == 1
2019-10-31 15:44:26 +00:00
assert " NextToken " not in resp2 . keys ( )
2017-05-11 01:58:42 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_list_not_found_table_tags ( ) :
2019-10-31 15:44:26 +00:00
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
arn = " DymmyArn "
2017-05-11 01:58:42 +00:00
try :
conn . list_tags_of_resource ( ResourceArn = arn )
except ClientError as exception :
2019-10-31 15:44:26 +00:00
assert exception . response [ " Error " ] [ " Code " ] == " ResourceNotFoundException "
2017-09-11 21:28:36 +00:00
@mock_dynamodb2
2021-04-30 12:47:47 +00:00
def test_item_add_empty_string_hash_key_exception ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2017-09-12 00:21:08 +00:00
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2017-09-12 00:21:08 +00:00
conn . put_item (
TableName = name ,
Item = {
2020-11-17 09:12:39 +00:00
" forum_name " : { " S " : " " } ,
2019-10-31 15:44:26 +00:00
" subject " : { " S " : " Check this out! " } ,
" Body " : { " S " : " http://url_to_lolcat.gif " } ,
2020-11-17 09:12:39 +00:00
" SentBy " : { " S " : " someone@somewhere.edu " } ,
2019-10-31 15:44:26 +00:00
" ReceivedTime " : { " S " : " 12/9/2011 11:36:03 PM " } ,
} ,
2017-09-12 00:21:08 +00:00
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" One or more parameter values were invalid: An AttributeValue may not contain an empty string "
2017-09-12 20:28:42 +00:00
)
2017-09-19 20:43:55 +00:00
2018-08-02 03:38:50 +00:00
@mock_dynamodb2
2021-04-30 12:47:47 +00:00
def test_item_add_empty_string_range_key_exception ( ) :
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
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 } ,
)
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 " : " " } ,
} ,
)
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
" One or more parameter values were invalid: An AttributeValue may not contain an empty string "
)
@mock_dynamodb2
def test_item_add_empty_string_attr_no_exception ( ) :
2020-11-17 09:12:39 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
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 " : " LOLCat Forum " } ,
" subject " : { " S " : " Check this out! " } ,
" Body " : { " S " : " http://url_to_lolcat.gif " } ,
" SentBy " : { " S " : " " } ,
" ReceivedTime " : { " S " : " 12/9/2011 11:36:03 PM " } ,
} ,
)
@mock_dynamodb2
2021-04-30 12:47:47 +00:00
def test_update_item_with_empty_string_attr_no_exception ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2018-08-02 03:38:50 +00:00
conn . put_item (
TableName = name ,
Item = {
2019-10-31 15:44:26 +00:00
" forum_name " : { " S " : " LOLCat Forum " } ,
" subject " : { " S " : " Check this out! " } ,
" Body " : { " S " : " http://url_to_lolcat.gif " } ,
" SentBy " : { " S " : " test " } ,
" ReceivedTime " : { " S " : " 12/9/2011 11:36:03 PM " } ,
} ,
2018-08-02 03:38:50 +00:00
)
2021-04-30 12:47:47 +00:00
conn . update_item (
TableName = name ,
Key = { " forum_name " : { " S " : " LOLCat Forum " } } ,
UpdateExpression = " set Body=:Body " ,
ExpressionAttributeValues = { " :Body " : { " S " : " " } } ,
)
@mock_dynamodb2
def test_item_add_long_string_hash_key_exception ( ) :
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
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 " } ,
} ,
)
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2021-04-30 12:47:47 +00:00
conn . put_item (
2018-08-02 03:38:50 +00:00
TableName = name ,
2021-04-30 12:47:47 +00:00
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 " } ,
} ,
2019-10-31 15:44:26 +00:00
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
2021-04-30 12:47:47 +00:00
# deliberately no space between "of" and "2048"
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2021-04-30 12:47:47 +00:00
" One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes "
2018-08-02 03:38:50 +00:00
)
2020-11-17 09:12:39 +00:00
@mock_dynamodb2
2021-04-30 12:47:47 +00:00
def test_item_add_long_string_nonascii_hash_key_exception ( ) :
2020-11-17 09:12:39 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2021-04-30 12:47:47 +00:00
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
2020-11-17 09:12:39 +00:00
conn . put_item (
TableName = name ,
Item = {
2021-04-30 12:47:47 +00:00
" forum_name " : { " S " : short_enough } ,
2020-11-17 09:12:39 +00:00
" subject " : { " S " : " Check this out! " } ,
" Body " : { " S " : " http://url_to_lolcat.gif " } ,
" SentBy " : { " S " : " test " } ,
" ReceivedTime " : { " S " : " 12/9/2011 11:36:03 PM " } ,
} ,
)
2021-04-30 12:47:47 +00:00
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 " } ,
} ,
)
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
# deliberately no space between "of" and "2048"
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
" One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes "
)
@mock_dynamodb2
def test_item_add_long_string_range_key_exception ( ) :
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
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 ) } ,
} ,
)
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
" One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes "
)
@mock_dynamodb2
def test_update_item_with_long_string_hash_key_exception ( ) :
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2020-11-17 09:12:39 +00:00
conn . update_item (
TableName = name ,
2021-04-30 12:47:47 +00:00
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 " } } ,
)
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
# deliberately no space between "of" and "2048"
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
" One or more parameter values were invalid: Size of hashkey has exceeded the maximum size limit of2048 bytes "
)
@mock_dynamodb2
def test_update_item_with_long_string_range_key_exception ( ) :
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
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 " } } ,
)
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
# deliberately no space between "of" and "2048"
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
" One or more parameter values were invalid: Aggregated size of all range keys has exceeded the size limit of 1024 bytes "
2020-11-17 09:12:39 +00:00
)
2017-09-19 20:43:55 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_query_invalid_table ( ) :
2019-10-31 15:44:26 +00:00
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
2017-09-19 20:43:55 +00:00
try :
2019-10-31 15:44:26 +00:00
conn . query (
TableName = " invalid_table " ,
KeyConditionExpression = " index1 = :partitionkeyval " ,
ExpressionAttributeValues = { " :partitionkeyval " : { " S " : " test " } } ,
)
2017-09-19 20:43:55 +00:00
except ClientError as exception :
2019-10-31 15:44:26 +00:00
assert exception . response [ " Error " ] [ " Code " ] == " ResourceNotFoundException "
2017-09-20 01:51:22 +00:00
2018-04-14 15:16:43 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_put_item_with_special_chars ( ) :
2019-10-31 15:44:26 +00:00
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
2018-04-14 15:16:43 +00:00
2019-10-31 15:44:26 +00:00
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2018-04-14 15:16:43 +00:00
conn . put_item (
2019-10-31 15:44:26 +00:00
TableName = name ,
Item = {
" forum_name " : { " S " : " LOLCat Forum " } ,
" subject " : { " S " : " Check this out! " } ,
" Body " : { " S " : " http://url_to_lolcat.gif " } ,
" SentBy " : { " S " : " test " } ,
" ReceivedTime " : { " S " : " 12/9/2011 11:36:03 PM " } ,
' " ' : { " S " : " foo " } ,
} ,
)
2019-12-20 19:30:36 +00:00
2019-12-20 19:16:17 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_put_item_with_streams ( ) :
name = " TestTable "
conn = boto3 . client (
" dynamodb " ,
region_name = " us-west-2 " ,
aws_access_key_id = " ak " ,
aws_secret_access_key = " sk " ,
)
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
2019-12-20 19:30:36 +00:00
StreamSpecification = {
" StreamEnabled " : True ,
" StreamViewType " : " NEW_AND_OLD_IMAGES " ,
} ,
2019-12-20 19:16:17 +00:00
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 " : " test " } ,
2019-12-20 19:30:36 +00:00
" Data " : { " M " : { " Key1 " : { " S " : " Value1 " } , " Key2 " : { " S " : " Value2 " } } } ,
2019-12-20 19:16:17 +00:00
} ,
)
2018-04-14 15:16:43 +00:00
2019-12-24 18:23:46 +00:00
result = conn . get_item ( TableName = name , Key = { " forum_name " : { " S " : " LOLCat Forum " } } )
result [ " Item " ] . should . be . equal (
{
" forum_name " : { " S " : " LOLCat Forum " } ,
" subject " : { " S " : " Check this out! " } ,
" Body " : { " S " : " http://url_to_lolcat.gif " } ,
" SentBy " : { " S " : " test " } ,
" Data " : { " M " : { " Key1 " : { " S " : " Value1 " } , " Key2 " : { " S " : " Value2 " } } } ,
}
)
2019-12-24 19:01:54 +00:00
table = dynamodb_backends2 [ " us-west-2 " ] . get_table ( name )
if not table :
# There is no way to access stream data over the API, so this part can't run in server-tests mode.
return
len ( table . stream_shard . items ) . should . be . equal ( 1 )
stream_record = table . stream_shard . items [ 0 ] . record
2019-12-24 18:23:46 +00:00
stream_record [ " eventName " ] . should . be . equal ( " INSERT " )
stream_record [ " dynamodb " ] [ " SizeBytes " ] . should . be . equal ( 447 )
2018-04-14 15:16:43 +00:00
2017-09-22 01:12:11 +00:00
@mock_dynamodb2
2019-10-08 19:29:09 +00:00
def test_basic_projection_expression_using_get_item ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-10-08 19:29:09 +00:00
# Create the DynamoDB table.
table = dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2019-10-08 19:29:09 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2019-10-08 19:29:09 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2019-10-08 19:29:09 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
2019-10-08 19:29:09 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " users " )
2019-10-08 19:29:09 +00:00
2019-10-31 15:44:26 +00:00
table . put_item (
Item = { " forum_name " : " the-key " , " subject " : " 123 " , " body " : " some test message " }
)
2019-10-08 19:29:09 +00:00
2019-10-31 15:44:26 +00:00
table . put_item (
Item = {
" forum_name " : " not-the-key " ,
" subject " : " 123 " ,
" body " : " some other test message " ,
}
)
2019-10-08 19:29:09 +00:00
result = table . get_item (
2019-10-31 15:44:26 +00:00
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
ProjectionExpression = " body, subject " ,
2019-10-08 19:29:09 +00:00
)
2019-10-31 15:44:26 +00:00
result [ " Item " ] . should . be . equal ( { " subject " : " 123 " , " body " : " some test message " } )
2019-10-08 19:29:09 +00:00
# The projection expression should not remove data from storage
2019-10-31 15:44:26 +00:00
result = table . get_item ( Key = { " forum_name " : " the-key " , " subject " : " 123 " } )
2019-10-08 19:29:09 +00:00
2019-10-31 15:44:26 +00:00
result [ " Item " ] . should . be . equal (
{ " forum_name " : " the-key " , " subject " : " 123 " , " body " : " some test message " }
)
2019-10-08 19:29:09 +00:00
2019-06-26 20:54:48 +00:00
@mock_dynamodb2
def test_basic_projection_expressions_using_scan ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-06-26 20:54:48 +00:00
# Create the DynamoDB table.
2021-08-21 15:33:15 +00:00
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2019-06-26 20:54:48 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2019-06-26 20:54:48 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2019-06-26 20:54:48 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
2019-06-26 20:54:48 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " users " )
2019-06-26 20:54:48 +00:00
2019-10-31 15:44:26 +00:00
table . put_item (
Item = { " forum_name " : " the-key " , " subject " : " 123 " , " body " : " some test message " }
)
2019-06-26 20:54:48 +00:00
2019-10-31 15:44:26 +00:00
table . put_item (
Item = {
" forum_name " : " not-the-key " ,
" subject " : " 123 " ,
" body " : " some other test message " ,
}
)
2019-06-27 18:37:46 +00:00
# Test a scan returning all items
2019-06-26 20:54:48 +00:00
results = table . scan (
2019-10-31 15:44:26 +00:00
FilterExpression = Key ( " forum_name " ) . eq ( " the-key " ) ,
ProjectionExpression = " body, subject " ,
2019-06-26 20:54:48 +00:00
)
2019-10-31 15:44:26 +00:00
assert " body " in results [ " Items " ] [ 0 ]
assert results [ " Items " ] [ 0 ] [ " body " ] == " some test message "
assert " subject " in results [ " Items " ] [ 0 ]
2019-06-26 20:54:48 +00:00
2019-10-31 15:44:26 +00:00
table . put_item (
Item = {
" forum_name " : " the-key " ,
" subject " : " 1234 " ,
" body " : " yet another test message " ,
}
)
2019-06-26 20:54:48 +00:00
results = table . scan (
2019-10-31 15:44:26 +00:00
FilterExpression = Key ( " forum_name " ) . eq ( " the-key " ) , ProjectionExpression = " body "
2019-06-26 20:54:48 +00:00
)
2021-08-21 15:33:15 +00:00
bodies = [ item [ " body " ] for item in results [ " Items " ] ]
bodies . should . contain ( " some test message " )
bodies . should . contain ( " yet another test message " )
2019-10-31 15:44:26 +00:00
assert " subject " not in results [ " Items " ] [ 0 ]
assert " forum_name " not in results [ " Items " ] [ 0 ]
assert " subject " not in results [ " Items " ] [ 1 ]
assert " forum_name " not in results [ " Items " ] [ 1 ]
2019-06-26 20:54:48 +00:00
# The projection expression should not remove data from storage
2019-10-31 15:44:26 +00:00
results = table . query ( KeyConditionExpression = Key ( " forum_name " ) . eq ( " the-key " ) )
assert " subject " in results [ " Items " ] [ 0 ]
assert " body " in results [ " Items " ] [ 1 ]
assert " forum_name " in results [ " Items " ] [ 1 ]
2017-11-11 05:35:01 +00:00
2017-10-07 20:57:14 +00:00
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_nested_projection_expression_using_get_item ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
" foo " : " bar " ,
}
)
table . put_item (
Item = {
" forum_name " : " key2 " ,
" nested " : { " id " : " id2 " , " incode " : " code2 " } ,
" foo " : " bar " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a get_item returning all items
2019-11-03 15:33:27 +00:00
result = table . get_item (
Key = { " forum_name " : " key1 " } ,
ProjectionExpression = " nested.level1.id, nested.level2 " ,
) [ " Item " ]
result . should . equal (
{ " nested " : { " level1 " : { " id " : " id1 " } , " level2 " : { " id " : " id2 " , " include " : " all " } } }
)
2019-11-03 14:02:25 +00:00
# Assert actual data has not been deleted
2019-11-03 15:33:27 +00:00
result = table . get_item ( Key = { " forum_name " : " key1 " } ) [ " Item " ]
result . should . equal (
{
" foo " : " bar " ,
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
}
)
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_basic_projection_expressions_using_query ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
] ,
AttributeDefinitions = [
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = { " forum_name " : " the-key " , " subject " : " 123 " , " body " : " some test message " }
)
table . put_item (
Item = {
" forum_name " : " not-the-key " ,
" subject " : " 123 " ,
" body " : " some other test message " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a query returning all items
2019-11-03 15:33:27 +00:00
result = table . query (
KeyConditionExpression = Key ( " forum_name " ) . eq ( " the-key " ) ,
ProjectionExpression = " body, subject " ,
) [ " Items " ] [ 0 ]
2019-11-03 14:02:25 +00:00
2019-11-03 15:33:27 +00:00
assert " body " in result
assert result [ " body " ] == " some test message "
assert " subject " in result
assert " forum_name " not in result
2019-11-03 14:02:25 +00:00
2019-11-03 15:33:27 +00:00
table . put_item (
Item = {
" forum_name " : " the-key " ,
" subject " : " 1234 " ,
" body " : " yet another test message " ,
}
)
2019-11-03 14:02:25 +00:00
2019-11-03 15:33:27 +00:00
items = table . query (
KeyConditionExpression = Key ( " forum_name " ) . eq ( " the-key " ) ,
ProjectionExpression = " body " ,
) [ " Items " ]
2019-11-03 14:02:25 +00:00
2019-11-03 15:33:27 +00:00
assert " body " in items [ 0 ]
assert " subject " not in items [ 0 ]
assert items [ 0 ] [ " body " ] == " some test message "
assert " body " in items [ 1 ]
assert " subject " not in items [ 1 ]
assert items [ 1 ] [ " body " ] == " yet another test message "
2019-11-03 14:02:25 +00:00
# The projection expression should not remove data from storage
2019-11-03 15:33:27 +00:00
items = table . query ( KeyConditionExpression = Key ( " forum_name " ) . eq ( " the-key " ) ) [ " Items " ]
assert " subject " in items [ 0 ]
assert " body " in items [ 1 ]
assert " forum_name " in items [ 1 ]
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_nested_projection_expression_using_query ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
" foo " : " bar " ,
}
)
table . put_item (
Item = {
" forum_name " : " key2 " ,
" nested " : { " id " : " id2 " , " incode " : " code2 " } ,
" foo " : " bar " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a query returning all items
2019-11-03 15:33:27 +00:00
result = table . query (
KeyConditionExpression = Key ( " forum_name " ) . eq ( " key1 " ) ,
ProjectionExpression = " nested.level1.id, nested.level2 " ,
) [ " Items " ] [ 0 ]
assert " nested " in result
result [ " nested " ] . should . equal (
{ " level1 " : { " id " : " id1 " } , " level2 " : { " id " : " id2 " , " include " : " all " } }
)
assert " foo " not in result
2019-11-03 14:02:25 +00:00
# Assert actual data has not been deleted
2019-11-03 15:33:27 +00:00
result = table . query ( KeyConditionExpression = Key ( " forum_name " ) . eq ( " key1 " ) ) [ " Items " ] [
0
]
result . should . equal (
{
" foo " : " bar " ,
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
}
)
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_nested_projection_expression_using_scan ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
" foo " : " bar " ,
}
)
table . put_item (
Item = {
" forum_name " : " key2 " ,
" nested " : { " id " : " id2 " , " incode " : " code2 " } ,
" foo " : " bar " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a scan
2019-11-03 15:33:27 +00:00
results = table . scan (
FilterExpression = Key ( " forum_name " ) . eq ( " key1 " ) ,
ProjectionExpression = " nested.level1.id, nested.level2 " ,
) [ " Items " ]
results . should . equal (
[
{
" nested " : {
" level1 " : { " id " : " id1 " } ,
" level2 " : { " include " : " all " , " id " : " id2 " } ,
}
}
]
)
2019-11-03 14:02:25 +00:00
# Assert original data is still there
2019-11-03 15:33:27 +00:00
results = table . scan ( FilterExpression = Key ( " forum_name " ) . eq ( " key1 " ) ) [ " Items " ]
results . should . equal (
[
{
" forum_name " : " key1 " ,
" foo " : " bar " ,
" nested " : {
" level1 " : { " att " : " irrelevant " , " id " : " id1 " } ,
" level2 " : { " include " : " all " , " id " : " id2 " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
}
]
)
2019-11-03 14:02:25 +00:00
2017-09-22 03:40:30 +00:00
@mock_dynamodb2
2019-10-08 19:29:09 +00:00
def test_basic_projection_expression_using_get_item_with_attr_expression_names ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-10-08 19:29:09 +00:00
# Create the DynamoDB table.
table = dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2019-10-08 19:29:09 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2019-10-08 19:29:09 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2019-10-08 19:29:09 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " the-key " ,
" subject " : " 123 " ,
" body " : " some test message " ,
" attachment " : " something " ,
}
)
table . put_item (
Item = {
" forum_name " : " not-the-key " ,
" subject " : " 123 " ,
" body " : " some other test message " ,
" attachment " : " something " ,
2019-10-08 19:29:09 +00:00
}
)
result = table . get_item (
2019-10-31 15:44:26 +00:00
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
ProjectionExpression = " #rl, #rt, subject " ,
ExpressionAttributeNames = { " #rl " : " body " , " #rt " : " attachment " } ,
2019-10-08 19:29:09 +00:00
)
2019-10-31 15:44:26 +00:00
result [ " Item " ] . should . be . equal (
{ " subject " : " 123 " , " body " : " some test message " , " attachment " : " something " }
)
2019-10-08 19:29:09 +00:00
@mock_dynamodb2
def test_basic_projection_expressions_using_query_with_attr_expression_names ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-09-22 03:40:30 +00:00
# Create the DynamoDB table.
table = dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2017-09-22 03:40:30 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2017-09-22 03:40:30 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2017-09-22 03:40:30 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " the-key " ,
" subject " : " 123 " ,
" body " : " some test message " ,
" attachment " : " something " ,
}
)
table . put_item (
Item = {
" forum_name " : " not-the-key " ,
" subject " : " 123 " ,
" body " : " some other test message " ,
" attachment " : " something " ,
2017-09-22 03:40:30 +00:00
}
)
# Test a query returning all items
results = table . query (
2019-10-31 15:44:26 +00:00
KeyConditionExpression = Key ( " forum_name " ) . eq ( " the-key " ) ,
ProjectionExpression = " #rl, #rt, subject " ,
ExpressionAttributeNames = { " #rl " : " body " , " #rt " : " attachment " } ,
2017-09-22 03:40:30 +00:00
)
2019-10-31 15:44:26 +00:00
assert " body " in results [ " Items " ] [ 0 ]
assert results [ " Items " ] [ 0 ] [ " body " ] == " some test message "
assert " subject " in results [ " Items " ] [ 0 ]
assert results [ " Items " ] [ 0 ] [ " subject " ] == " 123 "
assert " attachment " in results [ " Items " ] [ 0 ]
assert results [ " Items " ] [ 0 ] [ " attachment " ] == " something "
2017-09-24 22:39:09 +00:00
2019-10-08 19:29:09 +00:00
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_nested_projection_expression_using_get_item_with_attr_expression ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
" foo " : " bar " ,
}
)
table . put_item (
Item = {
" forum_name " : " key2 " ,
" nested " : { " id " : " id2 " , " incode " : " code2 " } ,
" foo " : " bar " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a get_item returning all items
2019-11-03 15:33:27 +00:00
result = table . get_item (
Key = { " forum_name " : " key1 " } ,
ProjectionExpression = " #nst.level1.id, #nst.#lvl2 " ,
ExpressionAttributeNames = { " #nst " : " nested " , " #lvl2 " : " level2 " } ,
) [ " Item " ]
result . should . equal (
{ " nested " : { " level1 " : { " id " : " id1 " } , " level2 " : { " id " : " id2 " , " include " : " all " } } }
)
2019-11-03 14:02:25 +00:00
# Assert actual data has not been deleted
2019-11-03 15:33:27 +00:00
result = table . get_item ( Key = { " forum_name " : " key1 " } ) [ " Item " ]
result . should . equal (
{
" foo " : " bar " ,
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
}
)
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_nested_projection_expression_using_query_with_attr_expression_names ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
" foo " : " bar " ,
}
)
table . put_item (
Item = {
" forum_name " : " key2 " ,
" nested " : { " id " : " id2 " , " incode " : " code2 " } ,
" foo " : " bar " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a query returning all items
2019-11-03 15:33:27 +00:00
result = table . query (
KeyConditionExpression = Key ( " forum_name " ) . eq ( " key1 " ) ,
ProjectionExpression = " #nst.level1.id, #nst.#lvl2 " ,
ExpressionAttributeNames = { " #nst " : " nested " , " #lvl2 " : " level2 " } ,
) [ " Items " ] [ 0 ]
assert " nested " in result
result [ " nested " ] . should . equal (
{ " level1 " : { " id " : " id1 " } , " level2 " : { " id " : " id2 " , " include " : " all " } }
)
assert " foo " not in result
2019-11-03 14:02:25 +00:00
# Assert actual data has not been deleted
2019-11-03 15:33:27 +00:00
result = table . query ( KeyConditionExpression = Key ( " forum_name " ) . eq ( " key1 " ) ) [ " Items " ] [
0
]
result . should . equal (
{
" foo " : " bar " ,
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
}
)
2019-11-03 14:02:25 +00:00
2019-06-27 18:37:46 +00:00
@mock_dynamodb2
def test_basic_projection_expressions_using_scan_with_attr_expression_names ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-06-27 18:37:46 +00:00
# Create the DynamoDB table.
table = dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2019-06-27 18:37:46 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2019-06-27 18:37:46 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2019-06-27 18:37:46 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " the-key " ,
" subject " : " 123 " ,
" body " : " some test message " ,
" attachment " : " something " ,
}
)
table . put_item (
Item = {
" forum_name " : " not-the-key " ,
" subject " : " 123 " ,
" body " : " some other test message " ,
" attachment " : " something " ,
2019-06-27 18:37:46 +00:00
}
)
# Test a scan returning all items
results = table . scan (
2019-10-31 15:44:26 +00:00
FilterExpression = Key ( " forum_name " ) . eq ( " the-key " ) ,
ProjectionExpression = " #rl, #rt, subject " ,
ExpressionAttributeNames = { " #rl " : " body " , " #rt " : " attachment " } ,
2019-06-27 18:37:46 +00:00
)
2019-10-31 15:44:26 +00:00
assert " body " in results [ " Items " ] [ 0 ]
assert " attachment " in results [ " Items " ] [ 0 ]
assert " subject " in results [ " Items " ] [ 0 ]
assert " form_name " not in results [ " Items " ] [ 0 ]
2019-06-27 18:37:46 +00:00
# Test without a FilterExpression
results = table . scan (
2019-10-31 15:44:26 +00:00
ProjectionExpression = " #rl, #rt, subject " ,
ExpressionAttributeNames = { " #rl " : " body " , " #rt " : " attachment " } ,
2019-06-27 18:37:46 +00:00
)
2019-10-31 15:44:26 +00:00
assert " body " in results [ " Items " ] [ 0 ]
assert " attachment " in results [ " Items " ] [ 0 ]
assert " subject " in results [ " Items " ] [ 0 ]
assert " form_name " not in results [ " Items " ] [ 0 ]
2019-06-27 18:37:46 +00:00
2017-10-07 20:57:14 +00:00
2019-11-03 14:02:25 +00:00
@mock_dynamodb2
def test_nested_projection_expression_using_scan_with_attr_expression_names ( ) :
2019-11-03 15:33:27 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-11-03 14:02:25 +00:00
# Create the DynamoDB table.
2019-11-03 15:33:27 +00:00
dynamodb . create_table (
TableName = " users " ,
KeySchema = [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " users " )
table . put_item (
Item = {
" forum_name " : " key1 " ,
" nested " : {
" level1 " : { " id " : " id1 " , " att " : " irrelevant " } ,
" level2 " : { " id " : " id2 " , " include " : " all " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
" foo " : " bar " ,
}
)
table . put_item (
Item = {
" forum_name " : " key2 " ,
" nested " : { " id " : " id2 " , " incode " : " code2 " } ,
" foo " : " bar " ,
}
)
2019-11-03 14:02:25 +00:00
# Test a scan
2019-11-03 15:33:27 +00:00
results = table . scan (
FilterExpression = Key ( " forum_name " ) . eq ( " key1 " ) ,
ProjectionExpression = " nested.level1.id, nested.level2 " ,
ExpressionAttributeNames = { " #nst " : " nested " , " #lvl2 " : " level2 " } ,
) [ " Items " ]
results . should . equal (
[
{
" nested " : {
" level1 " : { " id " : " id1 " } ,
" level2 " : { " include " : " all " , " id " : " id2 " } ,
}
}
]
)
2019-11-03 14:02:25 +00:00
# Assert original data is still there
2019-11-03 15:33:27 +00:00
results = table . scan ( FilterExpression = Key ( " forum_name " ) . eq ( " key1 " ) ) [ " Items " ]
results . should . equal (
[
{
" forum_name " : " key1 " ,
" foo " : " bar " ,
" nested " : {
" level1 " : { " att " : " irrelevant " , " id " : " id1 " } ,
" level2 " : { " include " : " all " , " id " : " id2 " } ,
" level3 " : { " id " : " irrelevant " } ,
} ,
}
]
)
2019-11-03 14:02:25 +00:00
2020-03-28 17:59:42 +00:00
@mock_dynamodb2
def test_put_empty_item ( ) :
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
2020-11-11 15:55:37 +00:00
AttributeDefinitions = [ { " AttributeName " : " structure_id " , " AttributeType " : " S " } , ] ,
2020-03-28 17:59:42 +00:00
TableName = " test " ,
2020-11-11 15:55:37 +00:00
KeySchema = [ { " AttributeName " : " structure_id " , " KeyType " : " HASH " } , ] ,
2020-03-28 17:59:42 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
)
table = dynamodb . Table ( " test " )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-03-28 17:59:42 +00:00
table . put_item ( Item = { } )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-03-28 17:59:42 +00:00
" One or more parameter values were invalid: Missing the key structure_id in the item "
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
2020-03-28 17:59:42 +00:00
2020-03-10 13:25:40 +00:00
@mock_dynamodb2
def test_put_item_nonexisting_hash_key ( ) :
2020-03-10 14:28:12 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2020-03-10 13:25:40 +00:00
dynamodb . create_table (
2020-11-11 15:55:37 +00:00
AttributeDefinitions = [ { " AttributeName " : " structure_id " , " AttributeType " : " S " } , ] ,
2020-03-10 13:25:40 +00:00
TableName = " test " ,
2020-11-11 15:55:37 +00:00
KeySchema = [ { " AttributeName " : " structure_id " , " KeyType " : " HASH " } , ] ,
2020-03-10 13:25:40 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
)
table = dynamodb . Table ( " test " )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-03-10 13:25:40 +00:00
table . put_item ( Item = { " a_terribly_misguided_id_attribute " : " abcdef " } )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-03-10 13:25:40 +00:00
" One or more parameter values were invalid: Missing the key structure_id in the item "
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
2020-03-28 17:59:42 +00:00
@mock_dynamodb2
def test_put_item_nonexisting_range_key ( ) :
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
AttributeDefinitions = [
{ " AttributeName " : " structure_id " , " AttributeType " : " S " } ,
{ " AttributeName " : " added_at " , " AttributeType " : " N " } ,
] ,
TableName = " test " ,
KeySchema = [
{ " AttributeName " : " structure_id " , " KeyType " : " HASH " } ,
{ " AttributeName " : " added_at " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
)
table = dynamodb . Table ( " test " )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-03-28 17:59:42 +00:00
table . put_item ( Item = { " structure_id " : " abcdef " } )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-03-28 17:59:42 +00:00
" One or more parameter values were invalid: Missing the key added_at in the item "
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
2020-03-10 13:25:40 +00:00
2017-10-07 20:57:14 +00:00
def test_filter_expression ( ) :
2019-10-31 15:44:26 +00:00
row1 = moto . dynamodb2 . models . Item (
2021-11-10 21:42:33 +00:00
hash_key = None ,
range_key = None ,
attrs = {
2019-10-31 15:44:26 +00:00
" Id " : { " N " : " 8 " } ,
" Subs " : { " N " : " 5 " } ,
" Desc " : { " S " : " Some description " } ,
" KV " : { " SS " : [ " test1 " , " test2 " ] } ,
} ,
)
row2 = moto . dynamodb2 . models . Item (
2021-11-10 21:42:33 +00:00
hash_key = None ,
range_key = None ,
attrs = {
2019-10-31 15:44:26 +00:00
" Id " : { " N " : " 8 " } ,
" Subs " : { " N " : " 10 " } ,
" Desc " : { " S " : " A description " } ,
" KV " : { " SS " : [ " test3 " , " test4 " ] } ,
} ,
)
2017-10-07 20:57:14 +00:00
2017-10-22 22:20:00 +00:00
# NOT test 1
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" NOT attribute_not_exists(Id) " , { } , { }
)
2017-10-22 22:20:00 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
# NOT test 2
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" NOT (Id = :v0) " , { } , { " :v0 " : { " N " : " 8 " } }
)
2017-10-22 22:20:00 +00:00
filter_expr . expr ( row1 ) . should . be ( False ) # Id = 8 so should be false
2017-10-08 03:18:25 +00:00
# AND test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" Id > :v0 AND Subs < :v1 " , { } , { " :v0 " : { " N " : " 5 " } , " :v1 " : { " N " : " 7 " } }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
filter_expr . expr ( row2 ) . should . be ( False )
2017-10-07 20:57:14 +00:00
2020-03-20 12:29:04 +00:00
# lowercase AND test
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" Id > :v0 and Subs < :v1 " , { } , { " :v0 " : { " N " : " 5 " } , " :v1 " : { " N " : " 7 " } }
)
filter_expr . expr ( row1 ) . should . be ( True )
filter_expr . expr ( row2 ) . should . be ( False )
2017-10-08 03:18:25 +00:00
# OR test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" Id = :v0 OR Id=:v1 " , { } , { " :v0 " : { " N " : " 5 " } , " :v1 " : { " N " : " 8 " } }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
2017-10-07 20:57:14 +00:00
2017-10-08 03:18:25 +00:00
# BETWEEN test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" Id BETWEEN :v0 AND :v1 " , { } , { " :v0 " : { " N " : " 5 " } , " :v1 " : { " N " : " 10 " } }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
2017-10-07 20:57:14 +00:00
2017-10-08 03:18:25 +00:00
# PAREN test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" Id = :v0 AND (Subs = :v0 OR Subs = :v1) " ,
{ } ,
{ " :v0 " : { " N " : " 8 " } , " :v1 " : { " N " : " 5 " } } ,
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
2017-10-07 20:57:14 +00:00
2017-10-08 03:18:25 +00:00
# IN test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" Id IN (:v0, :v1, :v2) " ,
{ } ,
{ " :v0 " : { " N " : " 7 " } , " :v1 " : { " N " : " 8 " } , " :v2 " : { " N " : " 9 " } } ,
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
2017-10-07 20:57:14 +00:00
2018-10-12 07:59:52 +00:00
# attribute function tests (with extra spaces)
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" attribute_exists(Id) AND attribute_not_exists (User) " , { } , { }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" attribute_type(Id, :v0) " , { } , { " :v0 " : { " S " : " N " } }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
# beginswith function test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" begins_with(Desc, :v0) " , { } , { " :v0 " : { " S " : " Some " } }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
filter_expr . expr ( row2 ) . should . be ( False )
# contains function test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" contains(KV, :v0) " , { } , { " :v0 " : { " S " : " test1 " } }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
filter_expr . expr ( row2 ) . should . be ( False )
# size function test
2019-10-31 15:44:26 +00:00
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
" size(Desc) > size(KV) " , { } , { }
)
2017-10-08 03:18:25 +00:00
filter_expr . expr ( row1 ) . should . be ( True )
2017-10-07 20:57:14 +00:00
2017-10-22 22:20:00 +00:00
# Expression from @batkuip
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
2019-10-31 15:44:26 +00:00
" (#n0 < :v0 AND attribute_not_exists(#n1)) " ,
{ " #n0 " : " Subs " , " #n1 " : " fanout_ts " } ,
{ " :v0 " : { " N " : " 7 " } } ,
2017-10-22 22:20:00 +00:00
)
filter_expr . expr ( row1 ) . should . be ( True )
2018-04-09 08:12:50 +00:00
# Expression from to check contains on string value
filter_expr = moto . dynamodb2 . comparisons . get_filter_expression (
2019-10-31 15:44:26 +00:00
" contains(#n0, :v0) " , { " #n0 " : " Desc " } , { " :v0 " : { " S " : " Some " } }
2018-04-09 08:12:50 +00:00
)
filter_expr . expr ( row1 ) . should . be ( True )
filter_expr . expr ( row2 ) . should . be ( False )
2017-10-22 22:20:00 +00:00
2017-10-07 20:57:14 +00:00
2017-11-08 22:53:31 +00:00
@mock_dynamodb2
def test_query_filter ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-11-08 22:53:31 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-11-08 22:53:31 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
2017-11-08 22:53:31 +00:00
Item = {
2019-10-31 15:44:26 +00:00
" client " : { " S " : " client1 " } ,
" app " : { " S " : " app1 " } ,
" nested " : {
" M " : {
" version " : { " S " : " version1 " } ,
" contents " : { " L " : [ { " S " : " value1 " } , { " S " : " value2 " } ] } ,
}
} ,
} ,
2017-11-08 22:53:31 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
2017-11-08 22:53:31 +00:00
Item = {
2019-10-31 15:44:26 +00:00
" client " : { " S " : " client1 " } ,
" app " : { " S " : " app2 " } ,
" nested " : {
" M " : {
" version " : { " S " : " version2 " } ,
" contents " : { " L " : [ { " S " : " value1 " } , { " S " : " value2 " } ] } ,
}
} ,
} ,
2017-11-08 22:53:31 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test1 " )
response = table . query ( KeyConditionExpression = Key ( " client " ) . eq ( " client1 " ) )
assert response [ " Count " ] == 2
2017-11-08 22:53:31 +00:00
response = table . query (
2019-10-31 15:44:26 +00:00
KeyConditionExpression = Key ( " client " ) . eq ( " client1 " ) ,
FilterExpression = Attr ( " app " ) . eq ( " app2 " ) ,
2017-11-08 22:53:31 +00:00
)
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 1
assert response [ " Items " ] [ 0 ] [ " app " ] == " app2 "
2018-04-09 08:12:50 +00:00
response = table . query (
2019-10-31 15:44:26 +00:00
KeyConditionExpression = Key ( " client " ) . eq ( " client1 " ) ,
FilterExpression = Attr ( " app " ) . contains ( " app " ) ,
2018-04-09 08:12:50 +00:00
)
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 2
2017-11-08 22:53:31 +00:00
2019-04-01 19:15:20 +00:00
response = table . query (
2019-10-31 15:44:26 +00:00
KeyConditionExpression = Key ( " client " ) . eq ( " client1 " ) ,
FilterExpression = Attr ( " nested.version " ) . contains ( " version " ) ,
2019-04-01 19:15:20 +00:00
)
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 2
2019-04-01 19:15:20 +00:00
response = table . query (
2019-10-31 15:44:26 +00:00
KeyConditionExpression = Key ( " client " ) . eq ( " client1 " ) ,
FilterExpression = Attr ( " nested.contents[0] " ) . eq ( " value1 " ) ,
2019-04-01 19:15:20 +00:00
)
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 2
2019-04-01 19:15:20 +00:00
2017-11-08 22:53:31 +00:00
2019-09-09 23:08:16 +00:00
@mock_dynamodb2
def test_query_filter_overlapping_expression_prefixes ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-09-09 23:08:16 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2019-09-09 23:08:16 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
2019-09-09 23:08:16 +00:00
Item = {
2019-10-31 15:44:26 +00:00
" client " : { " S " : " client1 " } ,
" app " : { " S " : " app1 " } ,
" nested " : {
" M " : {
" version " : { " S " : " version1 " } ,
" contents " : { " L " : [ { " S " : " value1 " } , { " S " : " value2 " } ] } ,
}
} ,
} ,
)
table = dynamodb . Table ( " test1 " )
2019-09-09 23:08:16 +00:00
response = table . query (
2019-10-31 15:44:26 +00:00
KeyConditionExpression = Key ( " client " ) . eq ( " client1 " ) & Key ( " app " ) . eq ( " app1 " ) ,
ProjectionExpression = " #1, #10, nested " ,
ExpressionAttributeNames = { " #1 " : " client " , " #10 " : " app " } ,
2019-09-09 23:08:16 +00:00
)
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 1
assert response [ " Items " ] [ 0 ] == {
" client " : " client1 " ,
" app " : " app1 " ,
" nested " : { " version " : " version1 " , " contents " : [ " value1 " , " value2 " ] } ,
2019-09-09 23:08:16 +00:00
}
2017-10-07 20:57:14 +00:00
@mock_dynamodb2
def test_scan_filter ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-10-07 20:57:14 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-07 20:57:14 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " , Item = { " client " : { " S " : " client1 " } , " app " : { " S " : " app1 " } }
2017-10-07 20:57:14 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test1 " )
response = table . scan ( FilterExpression = Attr ( " app " ) . eq ( " app2 " ) )
assert response [ " Count " ] == 0
2017-10-07 20:57:14 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " app " ) . eq ( " app1 " ) )
assert response [ " Count " ] == 1
2017-10-08 03:18:25 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " app " ) . ne ( " app2 " ) )
assert response [ " Count " ] == 1
2018-10-23 19:37:28 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " app " ) . ne ( " app1 " ) )
assert response [ " Count " ] == 0
2018-10-23 19:37:28 +00:00
2017-10-08 03:18:25 +00:00
2017-10-16 20:56:03 +00:00
@mock_dynamodb2
def test_scan_filter2 ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2017-10-16 20:56:03 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " N " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-16 20:56:03 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " , Item = { " client " : { " S " : " client1 " } , " app " : { " N " : " 1 " } }
2017-10-16 20:56:03 +00:00
)
response = client . scan (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
Select = " ALL_ATTRIBUTES " ,
FilterExpression = " #tb >= :dt " ,
2017-10-16 20:56:03 +00:00
ExpressionAttributeNames = { " #tb " : " app " } ,
2019-10-31 15:44:26 +00:00
ExpressionAttributeValues = { " :dt " : { " N " : str ( 1 ) } } ,
2017-10-16 20:56:03 +00:00
)
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 1
2017-10-16 20:56:03 +00:00
@mock_dynamodb2
def test_scan_filter3 ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-10-16 20:56:03 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " N " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-16 20:56:03 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
Item = { " client " : { " S " : " client1 " } , " app " : { " N " : " 1 " } , " active " : { " BOOL " : True } } ,
2017-10-16 20:56:03 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test1 " )
response = table . scan ( FilterExpression = Attr ( " active " ) . eq ( True ) )
assert response [ " Count " ] == 1
2017-10-16 20:56:03 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " active " ) . ne ( True ) )
assert response [ " Count " ] == 0
2018-10-23 19:37:28 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " active " ) . ne ( False ) )
assert response [ " Count " ] == 1
2018-10-23 19:37:28 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " app " ) . ne ( 1 ) )
assert response [ " Count " ] == 0
2018-10-23 19:37:28 +00:00
2019-10-31 15:44:26 +00:00
response = table . scan ( FilterExpression = Attr ( " app " ) . ne ( 2 ) )
assert response [ " Count " ] == 1
2018-10-23 19:37:28 +00:00
2017-10-16 20:56:03 +00:00
2017-10-22 22:20:00 +00:00
@mock_dynamodb2
def test_scan_filter4 ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-10-22 22:20:00 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " N " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-22 22:20:00 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test1 " )
2017-10-22 22:20:00 +00:00
response = table . scan (
2019-10-31 15:44:26 +00:00
FilterExpression = Attr ( " epoch_ts " ) . lt ( 7 ) & Attr ( " fanout_ts " ) . not_exists ( )
2017-10-22 22:20:00 +00:00
)
# Just testing
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 0
2017-10-22 22:20:00 +00:00
2020-01-12 12:05:08 +00:00
@mock_dynamodb2
def test_scan_filter_should_not_return_non_existing_attributes ( ) :
table_name = " my-table "
item = { " partitionKey " : " pk-2 " , " my-attr " : 42 }
# Create table
2020-01-12 12:20:55 +00:00
res = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2020-01-12 12:05:08 +00:00
res . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " partitionKey " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " partitionKey " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
table = res . Table ( table_name )
# Insert items
table . put_item ( Item = { " partitionKey " : " pk-1 " } )
table . put_item ( Item = item )
# Verify a few operations
# Assert we only find the item that has this attribute
table . scan ( FilterExpression = Attr ( " my-attr " ) . lt ( 43 ) ) [ " Items " ] . should . equal ( [ item ] )
table . scan ( FilterExpression = Attr ( " my-attr " ) . lte ( 42 ) ) [ " Items " ] . should . equal ( [ item ] )
table . scan ( FilterExpression = Attr ( " my-attr " ) . gte ( 42 ) ) [ " Items " ] . should . equal ( [ item ] )
table . scan ( FilterExpression = Attr ( " my-attr " ) . gt ( 41 ) ) [ " Items " ] . should . equal ( [ item ] )
# Sanity check that we can't find the item if the FE is wrong
table . scan ( FilterExpression = Attr ( " my-attr " ) . gt ( 43 ) ) [ " Items " ] . should . equal ( [ ] )
2017-10-08 03:18:25 +00:00
@mock_dynamodb2
def test_bad_scan_filter ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-10-08 03:18:25 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-08 03:18:25 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test1 " )
2017-10-08 03:18:25 +00:00
# Bad expression
try :
2019-10-31 15:44:26 +00:00
table . scan ( FilterExpression = " client test " )
2017-10-08 03:18:25 +00:00
except ClientError as err :
2019-10-31 15:44:26 +00:00
err . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationError " )
2017-10-08 03:18:25 +00:00
else :
2019-10-31 15:44:26 +00:00
raise RuntimeError ( " Should have raised ResourceInUseException " )
2017-10-08 03:18:25 +00:00
2019-04-30 10:35:21 +00:00
@mock_dynamodb2
def test_create_table_pay_per_request ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-04-30 10:35:21 +00:00
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
BillingMode = " PAY_PER_REQUEST " ,
2019-04-30 10:35:21 +00:00
)
@mock_dynamodb2
def test_create_table_error_pay_per_request_with_provisioned_param ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-04-30 10:35:21 +00:00
try :
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
BillingMode = " PAY_PER_REQUEST " ,
2019-04-30 10:35:21 +00:00
)
except ClientError as err :
2019-10-31 15:44:26 +00:00
err . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
2019-04-30 10:35:21 +00:00
2017-10-08 03:18:25 +00:00
@mock_dynamodb2
def test_duplicate_create ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2017-10-08 03:18:25 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-08 03:18:25 +00:00
)
try :
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-08 03:18:25 +00:00
)
except ClientError as err :
2019-10-31 15:44:26 +00:00
err . response [ " Error " ] [ " Code " ] . should . equal ( " ResourceInUseException " )
2017-10-08 03:18:25 +00:00
else :
2019-10-31 15:44:26 +00:00
raise RuntimeError ( " Should have raised ResourceInUseException " )
2017-10-08 03:18:25 +00:00
@mock_dynamodb2
def test_delete_table ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2017-10-08 03:18:25 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-08 03:18:25 +00:00
)
2019-10-31 15:44:26 +00:00
client . delete_table ( TableName = " test1 " )
2017-10-08 03:18:25 +00:00
resp = client . list_tables ( )
2019-10-31 15:44:26 +00:00
len ( resp [ " TableNames " ] ) . should . equal ( 0 )
2017-10-08 03:18:25 +00:00
try :
2019-10-31 15:44:26 +00:00
client . delete_table ( TableName = " test1 " )
2017-10-08 03:18:25 +00:00
except ClientError as err :
2019-10-31 15:44:26 +00:00
err . response [ " Error " ] [ " Code " ] . should . equal ( " ResourceNotFoundException " )
2017-10-08 03:18:25 +00:00
else :
2019-10-31 15:44:26 +00:00
raise RuntimeError ( " Should have raised ResourceNotFoundException " )
2017-10-08 03:18:25 +00:00
@mock_dynamodb2
def test_delete_item ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-10-08 03:18:25 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-08 03:18:25 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " , Item = { " client " : { " S " : " client1 " } , " app " : { " S " : " app1 " } }
2017-10-08 03:18:25 +00:00
)
client . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test1 " , Item = { " client " : { " S " : " client1 " } , " app " : { " S " : " app2 " } }
2017-10-08 03:18:25 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test1 " )
2017-10-08 03:18:25 +00:00
response = table . scan ( )
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 2
2017-10-08 03:18:25 +00:00
2018-11-09 18:21:38 +00:00
# Test ReturnValues validation
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-31 15:44:26 +00:00
table . delete_item (
Key = { " client " : " client1 " , " app " : " app1 " } , ReturnValues = " ALL_NEW "
)
2021-10-18 19:44:29 +00:00
err = ex . value . response [ " Error " ]
err [ " Code " ] . should . equal ( " ValidationException " )
err [ " Message " ] . should . equal ( " Return values set to invalid value " )
2019-04-01 19:15:20 +00:00
2017-10-08 03:18:25 +00:00
# Test deletion and returning old value
2019-10-31 15:44:26 +00:00
response = table . delete_item (
Key = { " client " : " client1 " , " app " : " app1 " } , ReturnValues = " ALL_OLD "
)
response [ " Attributes " ] . should . contain ( " client " )
response [ " Attributes " ] . should . contain ( " app " )
2017-10-08 03:18:25 +00:00
response = table . scan ( )
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 1
2017-10-08 03:18:25 +00:00
# Test deletion returning nothing
2019-10-31 15:44:26 +00:00
response = table . delete_item ( Key = { " client " : " client1 " , " app " : " app2 " } )
len ( response [ " Attributes " ] ) . should . equal ( 0 )
2017-10-08 03:18:25 +00:00
response = table . scan ( )
2019-10-31 15:44:26 +00:00
assert response [ " Count " ] == 0
2017-10-29 16:06:09 +00:00
@mock_dynamodb2
def test_describe_limits ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " eu-central-1 " )
2017-10-29 16:06:09 +00:00
resp = client . describe_limits ( )
2019-10-31 15:44:26 +00:00
resp [ " AccountMaxReadCapacityUnits " ] . should . equal ( 20000 )
resp [ " AccountMaxWriteCapacityUnits " ] . should . equal ( 20000 )
resp [ " TableMaxWriteCapacityUnits " ] . should . equal ( 10000 )
resp [ " TableMaxReadCapacityUnits " ] . should . equal ( 10000 )
2017-10-29 16:06:09 +00:00
@mock_dynamodb2
def test_set_ttl ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2017-10-29 16:06:09 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
2017-10-29 16:06:09 +00:00
)
client . update_time_to_live (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
TimeToLiveSpecification = { " Enabled " : True , " AttributeName " : " expire " } ,
2017-10-29 16:06:09 +00:00
)
2019-10-31 15:44:26 +00:00
resp = client . describe_time_to_live ( TableName = " test1 " )
resp [ " TimeToLiveDescription " ] [ " TimeToLiveStatus " ] . should . equal ( " ENABLED " )
resp [ " TimeToLiveDescription " ] [ " AttributeName " ] . should . equal ( " expire " )
2017-10-29 16:06:09 +00:00
client . update_time_to_live (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
TimeToLiveSpecification = { " Enabled " : False , " AttributeName " : " expire " } ,
2017-10-29 16:06:09 +00:00
)
2019-10-31 15:44:26 +00:00
resp = client . describe_time_to_live ( TableName = " test1 " )
resp [ " TimeToLiveDescription " ] [ " TimeToLiveStatus " ] . should . equal ( " DISABLED " )
2017-11-10 21:00:21 +00:00
2020-05-08 14:57:48 +00:00
@mock_dynamodb2
def test_describe_continuous_backups ( ) :
# given
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
table_name = client . create_table (
TableName = " test " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
BillingMode = " PAY_PER_REQUEST " ,
) [ " TableDescription " ] [ " TableName " ]
# when
response = client . describe_continuous_backups ( TableName = table_name )
# then
response [ " ContinuousBackupsDescription " ] . should . equal (
{
" ContinuousBackupsStatus " : " ENABLED " ,
" PointInTimeRecoveryDescription " : { " PointInTimeRecoveryStatus " : " DISABLED " } ,
}
)
@mock_dynamodb2
def test_describe_continuous_backups_errors ( ) :
# given
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
# when
2020-10-06 05:54:49 +00:00
with pytest . raises ( Exception ) as e :
2020-05-08 14:57:48 +00:00
client . describe_continuous_backups ( TableName = " not-existing-table " )
# then
2020-10-06 06:04:09 +00:00
ex = e . value
2020-05-08 14:57:48 +00:00
ex . operation_name . should . equal ( " DescribeContinuousBackups " )
ex . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . response [ " Error " ] [ " Code " ] . should . contain ( " TableNotFoundException " )
ex . response [ " Error " ] [ " Message " ] . should . equal ( " Table not found: not-existing-table " )
@mock_dynamodb2
def test_update_continuous_backups ( ) :
# given
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
table_name = client . create_table (
TableName = " test " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
BillingMode = " PAY_PER_REQUEST " ,
) [ " TableDescription " ] [ " TableName " ]
# when
response = client . update_continuous_backups (
TableName = table_name ,
PointInTimeRecoverySpecification = { " PointInTimeRecoveryEnabled " : True } ,
)
# then
response [ " ContinuousBackupsDescription " ] [ " ContinuousBackupsStatus " ] . should . equal (
" ENABLED "
)
point_in_time = response [ " ContinuousBackupsDescription " ] [
" PointInTimeRecoveryDescription "
]
earliest_datetime = point_in_time [ " EarliestRestorableDateTime " ]
earliest_datetime . should . be . a ( datetime )
latest_datetime = point_in_time [ " LatestRestorableDateTime " ]
latest_datetime . should . be . a ( datetime )
point_in_time [ " PointInTimeRecoveryStatus " ] . should . equal ( " ENABLED " )
# when
# a second update should not change anything
response = client . update_continuous_backups (
TableName = table_name ,
PointInTimeRecoverySpecification = { " PointInTimeRecoveryEnabled " : True } ,
)
# then
response [ " ContinuousBackupsDescription " ] [ " ContinuousBackupsStatus " ] . should . equal (
" ENABLED "
)
point_in_time = response [ " ContinuousBackupsDescription " ] [
" PointInTimeRecoveryDescription "
]
point_in_time [ " EarliestRestorableDateTime " ] . should . equal ( earliest_datetime )
point_in_time [ " LatestRestorableDateTime " ] . should . equal ( latest_datetime )
point_in_time [ " PointInTimeRecoveryStatus " ] . should . equal ( " ENABLED " )
# when
response = client . update_continuous_backups (
TableName = table_name ,
PointInTimeRecoverySpecification = { " PointInTimeRecoveryEnabled " : False } ,
)
# then
response [ " ContinuousBackupsDescription " ] . should . equal (
{
" ContinuousBackupsStatus " : " ENABLED " ,
" PointInTimeRecoveryDescription " : { " PointInTimeRecoveryStatus " : " DISABLED " } ,
}
)
@mock_dynamodb2
def test_update_continuous_backups_errors ( ) :
# given
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
# when
2020-10-06 05:54:49 +00:00
with pytest . raises ( Exception ) as e :
2020-05-08 14:57:48 +00:00
client . update_continuous_backups (
TableName = " not-existing-table " ,
PointInTimeRecoverySpecification = { " PointInTimeRecoveryEnabled " : True } ,
)
# then
2020-10-06 06:04:09 +00:00
ex = e . value
2020-05-08 14:57:48 +00:00
ex . operation_name . should . equal ( " UpdateContinuousBackups " )
ex . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . response [ " Error " ] [ " Code " ] . should . contain ( " TableNotFoundException " )
ex . response [ " Error " ] [ " Message " ] . should . equal ( " Table not found: not-existing-table " )
2017-11-10 21:00:21 +00:00
# https://github.com/spulec/moto/issues/1043
@mock_dynamodb2
def test_query_missing_expr_names ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2017-11-10 21:00:21 +00:00
# Create the DynamoDB table.
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test1 " ,
AttributeDefinitions = [
{ " AttributeName " : " client " , " AttributeType " : " S " } ,
{ " AttributeName " : " app " , " AttributeType " : " S " } ,
] ,
KeySchema = [
{ " AttributeName " : " client " , " KeyType " : " HASH " } ,
{ " AttributeName " : " app " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 123 , " WriteCapacityUnits " : 123 } ,
)
client . put_item (
TableName = " test1 " , Item = { " client " : { " S " : " test1 " } , " app " : { " S " : " test1 " } }
)
client . put_item (
TableName = " test1 " , Item = { " client " : { " S " : " test2 " } , " app " : { " S " : " test2 " } }
2017-11-10 21:00:21 +00:00
)
2019-10-31 15:44:26 +00:00
resp = client . query (
TableName = " test1 " ,
KeyConditionExpression = " client=:client " ,
ExpressionAttributeValues = { " :client " : { " S " : " test1 " } } ,
)
2017-11-10 21:00:21 +00:00
2019-10-31 15:44:26 +00:00
resp [ " Count " ] . should . equal ( 1 )
resp [ " Items " ] [ 0 ] [ " client " ] [ " S " ] . should . equal ( " test1 " )
2017-11-10 21:00:21 +00:00
2019-10-31 15:44:26 +00:00
resp = client . query (
TableName = " test1 " ,
KeyConditionExpression = " :name=test2 " ,
ExpressionAttributeNames = { " :name " : " client " } ,
)
2017-11-10 21:00:21 +00:00
2019-10-31 15:44:26 +00:00
resp [ " Count " ] . should . equal ( 1 )
resp [ " Items " ] [ 0 ] [ " client " ] [ " S " ] . should . equal ( " test2 " )
2017-11-17 08:49:59 +00:00
2019-07-21 15:34:20 +00:00
# https://github.com/spulec/moto/issues/2328
@mock_dynamodb2
def test_update_item_with_list ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-07-21 15:34:20 +00:00
# Create the DynamoDB table.
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " Table " ,
KeySchema = [ { " AttributeName " : " key " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " key " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2019-07-21 15:34:20 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " Table " )
2019-07-21 15:34:20 +00:00
table . update_item (
2019-10-31 15:44:26 +00:00
Key = { " key " : " the-key " } ,
AttributeUpdates = { " list " : { " Value " : [ 1 , 2 ] , " Action " : " PUT " } } ,
2019-07-21 15:34:20 +00:00
)
2019-10-31 15:44:26 +00:00
resp = table . get_item ( Key = { " key " : " the-key " } )
resp [ " Item " ] . should . equal ( { " key " : " the-key " , " list " : [ 1 , 2 ] } )
2019-07-21 15:34:20 +00:00
2020-11-14 11:10:38 +00:00
# https://github.com/spulec/moto/issues/2328
@mock_dynamodb2
def test_update_item_with_no_action_passed_with_list ( ) :
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
# Create the DynamoDB table.
dynamodb . create_table (
TableName = " Table " ,
KeySchema = [ { " AttributeName " : " key " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " key " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
table = dynamodb . Table ( " Table " )
table . update_item (
Key = { " key " : " the-key " } ,
# Do not pass 'Action' key, in order to check that the
# parameter's default value will be used.
AttributeUpdates = { " list " : { " Value " : [ 1 , 2 ] } } ,
)
resp = table . get_item ( Key = { " key " : " the-key " } )
resp [ " Item " ] . should . equal ( { " key " : " the-key " , " list " : [ 1 , 2 ] } )
2017-11-17 08:49:59 +00:00
# https://github.com/spulec/moto/issues/1342
@mock_dynamodb2
def test_update_item_on_map ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2017-11-17 08:49:59 +00:00
# Create the DynamoDB table.
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2017-11-17 08:49:59 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2017-11-17 08:49:59 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2017-11-17 08:49:59 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
2017-11-17 08:49:59 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " users " )
2017-11-17 08:49:59 +00:00
2019-10-31 15:44:26 +00:00
table . put_item (
Item = {
" forum_name " : " the-key " ,
" subject " : " 123 " ,
" body " : { " nested " : { " data " : " test " } } ,
}
)
2017-11-17 08:49:59 +00:00
resp = table . scan ( )
2019-10-31 15:44:26 +00:00
resp [ " Items " ] [ 0 ] [ " body " ] . should . equal ( { " nested " : { " data " : " test " } } )
2017-11-17 08:49:59 +00:00
2018-05-04 18:33:56 +00:00
# Nonexistent nested attributes are supported for existing top-level attributes.
2019-10-31 15:44:26 +00:00
table . update_item (
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
2020-04-19 15:50:53 +00:00
UpdateExpression = " SET body.#nested.#data = :tb " ,
2020-11-11 15:55:37 +00:00
ExpressionAttributeNames = { " #nested " : " nested " , " #data " : " data " , } ,
2020-04-19 15:50:53 +00:00
ExpressionAttributeValues = { " :tb " : " new_value " } ,
)
# Running this against AWS DDB gives an exception so make sure it also fails.:
2020-10-06 05:54:49 +00:00
with pytest . raises ( client . exceptions . ClientError ) :
2020-04-19 15:50:53 +00:00
# botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the UpdateItem
# operation: The document path provided in the update expression is invalid for update
table . update_item (
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
UpdateExpression = " SET body.#nested.#nonexistentnested.#data = :tb2 " ,
ExpressionAttributeNames = {
" #nested " : " nested " ,
" #nonexistentnested " : " nonexistentnested " ,
" #data " : " data " ,
} ,
ExpressionAttributeValues = { " :tb2 " : " other_value " } ,
)
table . update_item (
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
UpdateExpression = " SET body.#nested.#nonexistentnested = :tb2 " ,
2017-11-17 08:49:59 +00:00
ExpressionAttributeNames = {
2019-10-31 15:44:26 +00:00
" #nested " : " nested " ,
" #nonexistentnested " : " nonexistentnested " ,
2017-11-17 08:49:59 +00:00
} ,
2020-04-19 15:50:53 +00:00
ExpressionAttributeValues = { " :tb2 " : { " data " : " other_value " } } ,
2019-10-31 15:44:26 +00:00
)
2017-11-17 08:49:59 +00:00
resp = table . scan ( )
2019-10-31 15:44:26 +00:00
resp [ " Items " ] [ 0 ] [ " body " ] . should . equal (
{ " nested " : { " data " : " new_value " , " nonexistentnested " : { " data " : " other_value " } } }
)
2018-05-04 18:33:56 +00:00
2020-04-19 15:50:53 +00:00
# Test nested value for a nonexistent attribute throws a ClientError.
2020-10-06 05:54:49 +00:00
with pytest . raises ( client . exceptions . ClientError ) :
2019-10-31 15:44:26 +00:00
table . update_item (
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
UpdateExpression = " SET nonexistent.#nested = :tb " ,
ExpressionAttributeNames = { " #nested " : " nested " } ,
ExpressionAttributeValues = { " :tb " : " new_value " } ,
)
2017-11-26 22:29:23 +00:00
# https://github.com/spulec/moto/issues/1358
@mock_dynamodb2
def test_update_if_not_exists ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2017-11-26 22:29:23 +00:00
# Create the DynamoDB table.
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
2017-11-26 22:29:23 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " KeyType " : " HASH " } ,
{ " AttributeName " : " subject " , " KeyType " : " RANGE " } ,
2017-11-26 22:29:23 +00:00
] ,
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " forum_name " , " AttributeType " : " S " } ,
{ " AttributeName " : " subject " , " AttributeType " : " S " } ,
2017-11-26 22:29:23 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
2017-11-26 22:29:23 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " users " )
2017-11-26 22:29:23 +00:00
2019-10-31 15:44:26 +00:00
table . put_item ( Item = { " forum_name " : " the-key " , " subject " : " 123 " } )
2017-11-26 22:29:23 +00:00
2019-10-31 15:44:26 +00:00
table . update_item (
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
2018-10-11 09:21:53 +00:00
# if_not_exists without space
2019-10-31 15:44:26 +00:00
UpdateExpression = " SET created_at=if_not_exists(created_at,:created_at) " ,
ExpressionAttributeValues = { " :created_at " : 123 } ,
2017-11-26 22:29:23 +00:00
)
resp = table . scan ( )
2019-10-31 15:44:26 +00:00
assert resp [ " Items " ] [ 0 ] [ " created_at " ] == 123
2017-11-26 22:29:23 +00:00
2019-10-31 15:44:26 +00:00
table . update_item (
Key = { " forum_name " : " the-key " , " subject " : " 123 " } ,
2018-10-11 09:21:53 +00:00
# if_not_exists with space
2019-10-31 15:44:26 +00:00
UpdateExpression = " SET created_at = if_not_exists (created_at, :created_at) " ,
ExpressionAttributeValues = { " :created_at " : 456 } ,
2017-11-26 22:29:23 +00:00
)
resp = table . scan ( )
# Still the original value
2019-10-31 15:44:26 +00:00
assert resp [ " Items " ] [ 0 ] [ " created_at " ] == 123
2018-06-06 16:50:29 +00:00
2018-11-08 21:21:06 +00:00
# https://github.com/spulec/moto/issues/1937
@mock_dynamodb2
def test_update_return_attributes ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2018-11-08 21:21:06 +00:00
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2018-11-08 21:21:06 +00:00
)
def update ( col , to , rv ) :
return dynamodb . update_item (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
Key = { " id " : { " S " : " foo " } } ,
AttributeUpdates = { col : { " Value " : { " S " : to } , " Action " : " PUT " } } ,
ReturnValues = rv ,
2018-11-08 21:21:06 +00:00
)
2019-10-31 15:44:26 +00:00
r = update ( " col1 " , " val1 " , " ALL_NEW " )
assert r [ " Attributes " ] == { " id " : { " S " : " foo " } , " col1 " : { " S " : " val1 " } }
2018-11-08 21:21:06 +00:00
2019-10-31 15:44:26 +00:00
r = update ( " col1 " , " val2 " , " ALL_OLD " )
assert r [ " Attributes " ] == { " id " : { " S " : " foo " } , " col1 " : { " S " : " val1 " } }
2018-11-08 21:21:06 +00:00
2019-10-31 15:44:26 +00:00
r = update ( " col2 " , " val3 " , " UPDATED_NEW " )
assert r [ " Attributes " ] == { " col2 " : { " S " : " val3 " } }
2018-11-08 21:21:06 +00:00
2019-10-31 15:44:26 +00:00
r = update ( " col2 " , " val4 " , " UPDATED_OLD " )
assert r [ " Attributes " ] == { " col2 " : { " S " : " val3 " } }
2018-11-08 21:21:06 +00:00
2019-10-31 15:44:26 +00:00
r = update ( " col1 " , " val5 " , " NONE " )
assert r [ " Attributes " ] == { }
2018-11-08 21:21:06 +00:00
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2021-10-18 19:44:29 +00:00
update ( " col1 " , " val6 " , " WRONG " )
err = ex . value . response [ " Error " ]
err [ " Code " ] . should . equal ( " ValidationException " )
err [ " Message " ] . should . equal ( " Return values set to invalid value " )
2018-11-09 18:21:38 +00:00
2018-11-08 21:21:06 +00:00
2020-11-17 07:41:54 +00:00
# https://github.com/spulec/moto/issues/3448
@mock_dynamodb2
def test_update_return_updated_new_attributes_when_same ( ) :
dynamo_client = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamo_client . create_table (
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " HashKey1 " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " HashKey1 " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
dynamodb_table = dynamo_client . Table ( " moto-test " )
dynamodb_table . put_item (
Item = { " HashKey1 " : " HashKeyValue1 " , " listValuedAttribute1 " : [ " a " , " b " ] }
)
def update ( col , to , rv ) :
return dynamodb_table . update_item (
TableName = " moto-test " ,
Key = { " HashKey1 " : " HashKeyValue1 " } ,
UpdateExpression = " SET listValuedAttribute1=: " + col ,
ExpressionAttributeValues = { " : " + col : to } ,
ReturnValues = rv ,
)
r = update ( " a " , [ " a " , " c " ] , " UPDATED_NEW " )
assert r [ " Attributes " ] == { " listValuedAttribute1 " : [ " a " , " c " ] }
r = update ( " a " , { " a " , " c " } , " UPDATED_NEW " )
assert r [ " Attributes " ] == { " listValuedAttribute1 " : { " a " , " c " } }
r = update ( " a " , { 1 , 2 } , " UPDATED_NEW " )
assert r [ " Attributes " ] == { " listValuedAttribute1 " : { 1 , 2 } }
with pytest . raises ( ClientError ) as ex :
2021-10-18 19:44:29 +00:00
update ( " a " , [ " a " , " c " ] , " WRONG " )
err = ex . value . response [ " Error " ]
err [ " Code " ] . should . equal ( " ValidationException " )
err [ " Message " ] . should . equal ( " Return values set to invalid value " )
2020-11-17 07:41:54 +00:00
2018-11-08 21:21:06 +00:00
@mock_dynamodb2
def test_put_return_attributes ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2018-11-08 21:21:06 +00:00
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2018-11-08 21:21:06 +00:00
)
r = dynamodb . put_item (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
Item = { " id " : { " S " : " foo " } , " col1 " : { " S " : " val1 " } } ,
ReturnValues = " NONE " ,
2018-11-08 21:21:06 +00:00
)
2019-10-31 15:44:26 +00:00
assert " Attributes " not in r
2019-04-01 19:15:20 +00:00
2018-11-08 21:21:06 +00:00
r = dynamodb . put_item (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
Item = { " id " : { " S " : " foo " } , " col1 " : { " S " : " val2 " } } ,
ReturnValues = " ALL_OLD " ,
2018-11-08 21:21:06 +00:00
)
2019-10-31 15:44:26 +00:00
assert r [ " Attributes " ] == { " id " : { " S " : " foo " } , " col1 " : { " S " : " val1 " } }
2018-11-09 18:21:38 +00:00
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2018-11-09 18:21:38 +00:00
dynamodb . put_item (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
Item = { " id " : { " S " : " foo " } , " col1 " : { " S " : " val3 " } } ,
ReturnValues = " ALL_NEW " ,
2018-11-09 18:21:38 +00:00
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" Return values set to invalid value "
)
2019-04-01 19:15:20 +00:00
2018-11-08 21:21:06 +00:00
2018-06-06 16:50:29 +00:00
@mock_dynamodb2
def test_query_global_secondary_index_when_created_via_update_table_resource ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2018-06-06 16:50:29 +00:00
# Create the DynamoDB table.
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
KeySchema = [ { " AttributeName " : " user_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " user_id " , " AttributeType " : " N " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
2018-06-06 16:50:29 +00:00
)
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " users " )
2018-06-06 16:50:29 +00:00
table . update (
2019-10-31 15:44:26 +00:00
AttributeDefinitions = [ { " AttributeName " : " forum_name " , " AttributeType " : " S " } ] ,
2018-06-06 16:50:29 +00:00
GlobalSecondaryIndexUpdates = [
2019-10-31 15:44:26 +00:00
{
" Create " : {
" IndexName " : " forum_name_index " ,
" KeySchema " : [ { " AttributeName " : " forum_name " , " KeyType " : " HASH " } ] ,
" Projection " : { " ProjectionType " : " ALL " } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 5 ,
" WriteCapacityUnits " : 5 ,
2018-06-06 16:50:29 +00:00
} ,
}
}
2019-10-31 15:44:26 +00:00
] ,
2018-06-06 16:50:29 +00:00
)
next_user_id = 1
2019-10-31 15:44:26 +00:00
for my_forum_name in [ " cats " , " dogs " ] :
for my_subject in [
" my pet is the cutest " ,
" wow look at what my pet did " ,
" don ' t you love my pet? " ,
] :
table . put_item (
Item = {
" user_id " : next_user_id ,
" forum_name " : my_forum_name ,
" subject " : my_subject ,
}
)
2018-06-06 16:50:29 +00:00
next_user_id + = 1
# get all the cat users
forum_only_query_response = table . query (
2019-10-31 15:44:26 +00:00
IndexName = " forum_name_index " ,
Select = " ALL_ATTRIBUTES " ,
KeyConditionExpression = Key ( " forum_name " ) . eq ( " cats " ) ,
2018-06-06 16:50:29 +00:00
)
2019-10-31 15:44:26 +00:00
forum_only_items = forum_only_query_response [ " Items " ]
2018-06-06 16:50:29 +00:00
assert len ( forum_only_items ) == 3
for item in forum_only_items :
2019-10-31 15:44:26 +00:00
assert item [ " forum_name " ] == " cats "
2018-06-06 16:50:29 +00:00
# query all cat users with a particular subject
forum_and_subject_query_results = table . query (
2019-10-31 15:44:26 +00:00
IndexName = " forum_name_index " ,
Select = " ALL_ATTRIBUTES " ,
KeyConditionExpression = Key ( " forum_name " ) . eq ( " cats " ) ,
FilterExpression = Attr ( " subject " ) . eq ( " my pet is the cutest " ) ,
2018-06-06 16:50:29 +00:00
)
2019-10-31 15:44:26 +00:00
forum_and_subject_items = forum_and_subject_query_results [ " Items " ]
2018-06-06 16:50:29 +00:00
assert len ( forum_and_subject_items ) == 1
2019-10-31 15:44:26 +00:00
assert forum_and_subject_items [ 0 ] == {
" user_id " : Decimal ( " 1 " ) ,
" forum_name " : " cats " ,
" subject " : " my pet is the cutest " ,
}
2018-11-07 20:03:25 +00:00
@mock_dynamodb2
def test_dynamodb_streams_1 ( ) :
2019-10-31 15:44:26 +00:00
conn = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2018-11-07 20:03:25 +00:00
resp = conn . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test-streams " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2018-11-07 20:03:25 +00:00
StreamSpecification = {
2019-10-31 15:44:26 +00:00
" StreamEnabled " : True ,
" StreamViewType " : " NEW_AND_OLD_IMAGES " ,
} ,
2018-11-07 20:03:25 +00:00
)
2019-04-01 19:15:20 +00:00
2019-10-31 15:44:26 +00:00
assert " StreamSpecification " in resp [ " TableDescription " ]
assert resp [ " TableDescription " ] [ " StreamSpecification " ] == {
" StreamEnabled " : True ,
" StreamViewType " : " NEW_AND_OLD_IMAGES " ,
2018-11-07 20:03:25 +00:00
}
2019-10-31 15:44:26 +00:00
assert " LatestStreamLabel " in resp [ " TableDescription " ]
assert " LatestStreamArn " in resp [ " TableDescription " ]
2019-04-01 19:15:20 +00:00
2019-10-31 15:44:26 +00:00
resp = conn . delete_table ( TableName = " test-streams " )
2018-11-07 20:03:25 +00:00
2019-10-31 15:44:26 +00:00
assert " StreamSpecification " in resp [ " TableDescription " ]
2019-04-01 19:15:20 +00:00
2018-11-07 20:03:25 +00:00
@mock_dynamodb2
def test_dynamodb_streams_2 ( ) :
2019-10-31 15:44:26 +00:00
conn = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2018-11-07 20:03:25 +00:00
resp = conn . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test-stream-update " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2018-11-07 20:03:25 +00:00
)
2019-10-31 15:44:26 +00:00
assert " StreamSpecification " not in resp [ " TableDescription " ]
2018-11-07 20:03:25 +00:00
resp = conn . update_table (
2019-10-31 15:44:26 +00:00
TableName = " test-stream-update " ,
StreamSpecification = { " StreamEnabled " : True , " StreamViewType " : " NEW_IMAGE " } ,
2018-11-07 20:03:25 +00:00
)
2019-10-31 15:44:26 +00:00
assert " StreamSpecification " in resp [ " TableDescription " ]
assert resp [ " TableDescription " ] [ " StreamSpecification " ] == {
" StreamEnabled " : True ,
" StreamViewType " : " NEW_IMAGE " ,
2018-11-07 20:03:25 +00:00
}
2019-10-31 15:44:26 +00:00
assert " LatestStreamLabel " in resp [ " TableDescription " ]
assert " LatestStreamArn " in resp [ " TableDescription " ]
2019-05-21 16:45:30 +00:00
2019-04-01 19:15:20 +00:00
2019-04-18 11:31:46 +00:00
@mock_dynamodb2
def test_query_gsi_with_range_key ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-04-18 11:31:46 +00:00
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2019-04-18 11:31:46 +00:00
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " id " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsi_hash_key " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsi_range_key " , " AttributeType " : " S " } ,
2019-04-18 11:31:46 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2019-04-18 11:31:46 +00:00
GlobalSecondaryIndexes = [
{
2019-10-31 15:44:26 +00:00
" IndexName " : " test_gsi " ,
" KeySchema " : [
{ " AttributeName " : " gsi_hash_key " , " KeyType " : " HASH " } ,
{ " AttributeName " : " gsi_range_key " , " KeyType " : " RANGE " } ,
2019-04-18 11:31:46 +00:00
] ,
2019-10-31 15:44:26 +00:00
" Projection " : { " ProjectionType " : " ALL " } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 1 ,
" WriteCapacityUnits " : 1 ,
2019-04-18 11:31:46 +00:00
} ,
2019-10-31 15:44:26 +00:00
}
] ,
2019-04-18 11:31:46 +00:00
)
dynamodb . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test " ,
2019-04-18 11:31:46 +00:00
Item = {
2019-10-31 15:44:26 +00:00
" id " : { " S " : " test1 " } ,
" gsi_hash_key " : { " S " : " key1 " } ,
" gsi_range_key " : { " S " : " range1 " } ,
} ,
2019-04-18 11:31:46 +00:00
)
dynamodb . put_item (
2019-10-31 15:44:26 +00:00
TableName = " test " , Item = { " id " : { " S " : " test2 " } , " gsi_hash_key " : { " S " : " key1 " } }
2019-04-18 11:31:46 +00:00
)
2019-10-31 15:44:26 +00:00
res = dynamodb . query (
TableName = " test " ,
IndexName = " test_gsi " ,
2020-03-20 12:29:04 +00:00
KeyConditionExpression = " gsi_hash_key = :gsi_hash_key and gsi_range_key = :gsi_range_key " ,
2019-10-31 15:44:26 +00:00
ExpressionAttributeValues = {
" :gsi_hash_key " : { " S " : " key1 " } ,
" :gsi_range_key " : { " S " : " range1 " } ,
} ,
)
2019-04-18 11:31:46 +00:00
res . should . have . key ( " Count " ) . equal ( 1 )
res . should . have . key ( " Items " )
2019-10-31 15:44:26 +00:00
res [ " Items " ] [ 0 ] . should . equal (
{
" id " : { " S " : " test1 " } ,
" gsi_hash_key " : { " S " : " key1 " } ,
" gsi_range_key " : { " S " : " range1 " } ,
}
)
2019-05-21 16:45:30 +00:00
@mock_dynamodb2
def test_scan_by_non_exists_index ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-05-21 16:45:30 +00:00
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2019-05-21 16:45:30 +00:00
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " id " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsi_col " , " AttributeType " : " S " } ,
2019-05-21 16:45:30 +00:00
] ,
2019-10-31 15:44:26 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
2019-05-21 16:45:30 +00:00
GlobalSecondaryIndexes = [
{
2019-10-31 15:44:26 +00:00
" IndexName " : " test_gsi " ,
" KeySchema " : [ { " AttributeName " : " gsi_col " , " KeyType " : " HASH " } ] ,
" Projection " : { " ProjectionType " : " ALL " } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 1 ,
" WriteCapacityUnits " : 1 ,
2019-05-21 16:45:30 +00:00
} ,
2019-10-31 15:44:26 +00:00
}
] ,
2019-05-21 16:45:30 +00:00
)
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-31 15:44:26 +00:00
dynamodb . scan ( TableName = " test " , IndexName = " non_exists_index " )
2019-05-21 16:45:30 +00:00
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" The table does not have the specified index: non_exists_index "
2019-05-21 16:45:30 +00:00
)
2019-08-22 15:12:48 +00:00
2019-12-11 14:08:45 +00:00
@mock_dynamodb2
def test_query_by_non_exists_index ( ) :
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [
{ " AttributeName " : " id " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsi_col " , " AttributeType " : " S " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
GlobalSecondaryIndexes = [
{
" IndexName " : " test_gsi " ,
" KeySchema " : [ { " AttributeName " : " gsi_col " , " KeyType " : " HASH " } ] ,
" Projection " : { " ProjectionType " : " ALL " } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 1 ,
" WriteCapacityUnits " : 1 ,
} ,
}
] ,
)
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-12-11 14:08:45 +00:00
dynamodb . query (
TableName = " test " ,
IndexName = " non_exists_index " ,
KeyConditionExpression = " CarModel=M " ,
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ResourceNotFoundException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-12-11 14:08:45 +00:00
" Invalid index: non_exists_index for table: test. Available indexes are: test_gsi "
)
2019-08-22 15:12:48 +00:00
@mock_dynamodb2
def test_batch_items_returns_all ( ) :
dynamodb = _create_user_table ( )
2019-10-31 15:44:26 +00:00
returned_items = dynamodb . batch_get_item (
RequestItems = {
" users " : {
" Keys " : [
{ " username " : { " S " : " user0 " } } ,
{ " username " : { " S " : " user1 " } } ,
{ " username " : { " S " : " user2 " } } ,
{ " username " : { " S " : " user3 " } } ,
] ,
" ConsistentRead " : True ,
}
2019-08-22 15:12:48 +00:00
}
2019-10-31 15:44:26 +00:00
) [ " Responses " ] [ " users " ]
2019-08-22 15:12:48 +00:00
assert len ( returned_items ) == 3
2019-10-31 15:44:26 +00:00
assert [ item [ " username " ] [ " S " ] for item in returned_items ] == [
" user1 " ,
" user2 " ,
" user3 " ,
]
2019-08-22 15:12:48 +00:00
2020-06-03 14:36:32 +00:00
@mock_dynamodb2
def test_batch_items_throws_exception_when_requesting_100_items_for_single_table ( ) :
dynamodb = _create_user_table ( )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-06-03 14:36:32 +00:00
dynamodb . batch_get_item (
RequestItems = {
" users " : {
2020-06-03 16:14:48 +00:00
" Keys " : [
{ " username " : { " S " : " user " + str ( i ) } } for i in range ( 0 , 104 )
] ,
2020-06-03 14:36:32 +00:00
" ConsistentRead " : True ,
}
}
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
msg = ex . value . response [ " Error " ] [ " Message " ]
2020-06-03 14:36:32 +00:00
msg . should . contain ( " 1 validation error detected: Value " )
msg . should . contain (
" at ' requestItems.users.member.keys ' failed to satisfy constraint: Member must have length less than or equal to 100 "
)
@mock_dynamodb2
def test_batch_items_throws_exception_when_requesting_100_items_across_all_tables ( ) :
dynamodb = _create_user_table ( )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-06-03 14:36:32 +00:00
dynamodb . batch_get_item (
RequestItems = {
" users " : {
" Keys " : [
{ " username " : { " S " : " user " + str ( i ) } } for i in range ( 0 , 75 )
] ,
" ConsistentRead " : True ,
} ,
" users2 " : {
" Keys " : [
{ " username " : { " S " : " user " + str ( i ) } } for i in range ( 0 , 75 )
] ,
" ConsistentRead " : True ,
} ,
}
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-06-03 14:36:32 +00:00
" Too many items requested for the BatchGetItem call "
)
2019-10-08 19:29:09 +00:00
@mock_dynamodb2
def test_batch_items_with_basic_projection_expression ( ) :
dynamodb = _create_user_table ( )
2019-10-31 15:44:26 +00:00
returned_items = dynamodb . batch_get_item (
RequestItems = {
" users " : {
" Keys " : [
{ " username " : { " S " : " user0 " } } ,
{ " username " : { " S " : " user1 " } } ,
{ " username " : { " S " : " user2 " } } ,
{ " username " : { " S " : " user3 " } } ,
] ,
" ConsistentRead " : True ,
" ProjectionExpression " : " username " ,
}
2019-10-08 19:29:09 +00:00
}
2019-10-31 15:44:26 +00:00
) [ " Responses " ] [ " users " ]
2019-10-11 12:30:25 +00:00
returned_items . should . have . length_of ( 3 )
2019-10-31 15:44:26 +00:00
[ item [ " username " ] [ " S " ] for item in returned_items ] . should . be . equal (
[ " user1 " , " user2 " , " user3 " ]
)
[ item . get ( " foo " ) for item in returned_items ] . should . be . equal ( [ None , None , None ] )
2019-10-08 19:29:09 +00:00
# The projection expression should not remove data from storage
2019-10-31 15:44:26 +00:00
returned_items = dynamodb . batch_get_item (
RequestItems = {
" users " : {
" Keys " : [
{ " username " : { " S " : " user0 " } } ,
{ " username " : { " S " : " user1 " } } ,
{ " username " : { " S " : " user2 " } } ,
{ " username " : { " S " : " user3 " } } ,
] ,
" ConsistentRead " : True ,
}
2019-10-08 19:29:09 +00:00
}
2019-10-31 15:44:26 +00:00
) [ " Responses " ] [ " users " ]
2019-10-11 12:30:25 +00:00
2019-10-31 15:44:26 +00:00
[ item [ " username " ] [ " S " ] for item in returned_items ] . should . be . equal (
[ " user1 " , " user2 " , " user3 " ]
)
[ item [ " foo " ] [ " S " ] for item in returned_items ] . should . be . equal ( [ " bar " , " bar " , " bar " ] )
2019-10-08 19:29:09 +00:00
@mock_dynamodb2
def test_batch_items_with_basic_projection_expression_and_attr_expression_names ( ) :
dynamodb = _create_user_table ( )
2019-10-31 15:44:26 +00:00
returned_items = dynamodb . batch_get_item (
RequestItems = {
" users " : {
" Keys " : [
{ " username " : { " S " : " user0 " } } ,
{ " username " : { " S " : " user1 " } } ,
{ " username " : { " S " : " user2 " } } ,
{ " username " : { " S " : " user3 " } } ,
] ,
" ConsistentRead " : True ,
" ProjectionExpression " : " #rl " ,
" ExpressionAttributeNames " : { " #rl " : " username " } ,
}
2019-10-08 19:29:09 +00:00
}
2019-10-31 15:44:26 +00:00
) [ " Responses " ] [ " users " ]
2019-10-11 12:30:25 +00:00
returned_items . should . have . length_of ( 3 )
2019-10-31 15:44:26 +00:00
[ item [ " username " ] [ " S " ] for item in returned_items ] . should . be . equal (
[ " user1 " , " user2 " , " user3 " ]
)
[ item . get ( " foo " ) for item in returned_items ] . should . be . equal ( [ None , None , None ] )
2019-10-08 19:29:09 +00:00
2019-08-22 15:12:48 +00:00
@mock_dynamodb2
def test_batch_items_should_throw_exception_for_duplicate_request ( ) :
client = _create_user_table ( )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-31 15:44:26 +00:00
client . batch_get_item (
RequestItems = {
" users " : {
" Keys " : [
{ " username " : { " S " : " user0 " } } ,
{ " username " : { " S " : " user0 " } } ,
] ,
" ConsistentRead " : True ,
}
}
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" Provided list of item keys contains duplicates "
)
2019-08-22 15:12:48 +00:00
2019-10-03 09:54:10 +00:00
@mock_dynamodb2
def test_index_with_unknown_attributes_should_fail ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-10-03 09:54:10 +00:00
2019-10-31 15:44:26 +00:00
expected_exception = (
" Some index key attributes are not defined in AttributeDefinitions. "
)
2019-10-03 09:54:10 +00:00
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-03 09:54:10 +00:00
dynamodb . create_table (
AttributeDefinitions = [
2019-10-31 15:44:26 +00:00
{ " AttributeName " : " customer_nr " , " AttributeType " : " S " } ,
{ " AttributeName " : " last_name " , " AttributeType " : " S " } ,
] ,
TableName = " table_with_missing_attribute_definitions " ,
2019-10-03 09:54:10 +00:00
KeySchema = [
2019-10-31 15:44:26 +00:00
{ " 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 " ,
)
2019-10-03 09:54:10 +00:00
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . contain ( expected_exception )
2019-10-03 09:54:10 +00:00
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_update_list_index__set_existing_index ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo " } ,
" itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] } ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo " } } ,
UpdateExpression = " set itemlist[1]=:Item " ,
ExpressionAttributeValues = { " :Item " : { " S " : " bar2_update " } } ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo " } } ) [ " Item " ]
result [ " id " ] . should . equal ( { " S " : " foo " } )
result [ " itemlist " ] . should . equal (
{ " L " : [ { " S " : " bar1 " } , { " S " : " bar2_update " } , { " S " : " bar3 " } ] }
)
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_update_list_index__set_existing_nested_index ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo2 " } ,
" itemmap " : {
" M " : { " itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] } }
} ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo2 " } } ,
UpdateExpression = " set itemmap.itemlist[1]=:Item " ,
ExpressionAttributeValues = { " :Item " : { " S " : " bar2_update " } } ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo2 " } } ) [ " Item " ]
result [ " id " ] . should . equal ( { " S " : " foo2 " } )
result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] . should . equal (
[ { " S " : " bar1 " } , { " S " : " bar2_update " } , { " S " : " bar3 " } ]
)
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_update_list_index__set_index_out_of_range ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo " } ,
" itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] } ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo " } } ,
UpdateExpression = " set itemlist[10]=:Item " ,
ExpressionAttributeValues = { " :Item " : { " S " : " bar10 " } } ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo " } } ) [ " Item " ]
assert result [ " id " ] == { " S " : " foo " }
assert result [ " itemlist " ] == {
" L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } , { " S " : " bar10 " } ]
}
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_update_list_index__set_nested_index_out_of_range ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo2 " } ,
" itemmap " : {
" M " : { " itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] } }
} ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo2 " } } ,
UpdateExpression = " set itemmap.itemlist[10]=:Item " ,
ExpressionAttributeValues = { " :Item " : { " S " : " bar10 " } } ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo2 " } } ) [ " Item " ]
assert result [ " id " ] == { " S " : " foo2 " }
assert result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] == [
{ " S " : " bar1 " } ,
{ " S " : " bar2 " } ,
{ " S " : " bar3 " } ,
{ " S " : " bar10 " } ,
]
2019-10-09 16:25:50 +00:00
2019-10-22 19:40:41 +00:00
@mock_dynamodb2
def test_update_list_index__set_double_nested_index ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-22 19:40:41 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo2 " } ,
" itemmap " : {
" M " : {
" itemlist " : {
" L " : [
{ " M " : { " foo " : { " S " : " bar11 " } , " foos " : { " S " : " bar12 " } } } ,
{ " M " : { " foo " : { " S " : " bar21 " } , " foos " : { " S " : " bar21 " } } } ,
]
}
}
} ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo2 " } } ,
UpdateExpression = " set itemmap.itemlist[1].foos=:Item " ,
ExpressionAttributeValues = { " :Item " : { " S " : " bar22 " } } ,
)
2019-10-22 19:40:41 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo2 " } } ) [ " Item " ]
assert result [ " id " ] == { " S " : " foo2 " }
len ( result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] ) . should . equal ( 2 )
result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] [ 0 ] . should . equal (
{ " M " : { " foo " : { " S " : " bar11 " } , " foos " : { " S " : " bar12 " } } }
) # unchanged
result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] [ 1 ] . should . equal (
{ " M " : { " foo " : { " S " : " bar21 " } , " foos " : { " S " : " bar22 " } } }
) # updated
2019-10-22 19:40:41 +00:00
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_update_list_index__set_index_of_a_string ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name , Item = { " id " : { " S " : " foo2 " } , " itemstr " : { " S " : " somestring " } }
)
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-31 15:44:26 +00:00
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo2 " } } ,
UpdateExpression = " set itemstr[1]=:Item " ,
ExpressionAttributeValues = { " :Item " : { " S " : " string_update " } } ,
)
2021-10-18 19:44:29 +00:00
client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo2 " } } ) [ " Item " ]
2019-10-09 16:25:50 +00:00
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" The document path provided in the update expression is invalid for update "
)
2019-10-09 16:25:50 +00:00
2019-10-22 19:40:41 +00:00
@mock_dynamodb2
def test_remove_top_level_attribute ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_remove "
2019-10-22 19:40:41 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name , Item = { " id " : { " S " : " foo " } , " item " : { " S " : " bar " } }
)
client . update_item (
2020-04-19 15:50:53 +00:00
TableName = table_name ,
Key = { " id " : { " S " : " foo " } } ,
UpdateExpression = " REMOVE #i " ,
ExpressionAttributeNames = { " #i " : " item " } ,
2019-10-31 15:44:26 +00:00
)
2019-10-22 19:40:41 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo " } } ) [ " Item " ]
result . should . equal ( { " id " : { " S " : " foo " } } )
2019-10-22 19:40:41 +00:00
2020-04-26 14:12:33 +00:00
@mock_dynamodb2
def test_remove_top_level_attribute_non_existent ( ) :
"""
Remove statements do not require attribute to exist they silently pass
"""
table_name = " test_remove "
client = create_table_with_list ( table_name )
ddb_item = { " id " : { " S " : " foo " } , " item " : { " S " : " bar " } }
client . put_item ( TableName = table_name , Item = ddb_item )
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo " } } ,
UpdateExpression = " REMOVE non_existent_attribute " ,
ExpressionAttributeNames = { " #i " : " item " } ,
)
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo " } } ) [ " Item " ]
result . should . equal ( ddb_item )
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_remove_list_index__remove_existing_index ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo " } ,
" itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] } ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo " } } ,
UpdateExpression = " REMOVE itemlist[1] " ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo " } } ) [ " Item " ]
result [ " id " ] . should . equal ( { " S " : " foo " } )
result [ " itemlist " ] . should . equal ( { " L " : [ { " S " : " bar1 " } , { " S " : " bar3 " } ] } )
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_remove_list_index__remove_existing_nested_index ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo2 " } ,
" itemmap " : { " M " : { " itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } } } ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo2 " } } ,
UpdateExpression = " REMOVE itemmap.itemlist[1] " ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo2 " } } ) [ " Item " ]
result [ " id " ] . should . equal ( { " S " : " foo2 " } )
result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] . should . equal ( [ { " S " : " bar1 " } ] )
2019-10-09 16:25:50 +00:00
2019-10-14 08:59:52 +00:00
@mock_dynamodb2
def test_remove_list_index__remove_existing_double_nested_index ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-14 08:59:52 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo2 " } ,
" itemmap " : {
" M " : {
" itemlist " : {
" L " : [
{ " M " : { " foo00 " : { " S " : " bar1 " } , " foo01 " : { " S " : " bar2 " } } } ,
{ " M " : { " foo10 " : { " S " : " bar1 " } , " foo11 " : { " S " : " bar2 " } } } ,
]
}
}
} ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo2 " } } ,
UpdateExpression = " REMOVE itemmap.itemlist[1].foo10 " ,
)
2019-10-14 08:59:52 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo2 " } } ) [ " Item " ]
assert result [ " id " ] == { " S " : " foo2 " }
assert result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] [ 0 ] [ " M " ] . should . equal (
{ " foo00 " : { " S " : " bar1 " } , " foo01 " : { " S " : " bar2 " } }
) # untouched
assert result [ " itemmap " ] [ " M " ] [ " itemlist " ] [ " L " ] [ 1 ] [ " M " ] . should . equal (
{ " foo11 " : { " S " : " bar2 " } }
) # changed
2019-10-14 08:59:52 +00:00
2019-10-09 16:25:50 +00:00
@mock_dynamodb2
def test_remove_list_index__remove_index_out_of_range ( ) :
2019-10-31 15:44:26 +00:00
table_name = " test_list_index_access "
2019-10-09 16:25:50 +00:00
client = create_table_with_list ( table_name )
2019-10-31 15:44:26 +00:00
client . put_item (
TableName = table_name ,
Item = {
" id " : { " S " : " foo " } ,
" itemlist " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] } ,
} ,
)
client . update_item (
TableName = table_name ,
Key = { " id " : { " S " : " foo " } } ,
UpdateExpression = " REMOVE itemlist[10] " ,
)
2019-10-09 16:25:50 +00:00
#
2019-10-31 15:44:26 +00:00
result = client . get_item ( TableName = table_name , Key = { " id " : { " S " : " foo " } } ) [ " Item " ]
assert result [ " id " ] == { " S " : " foo " }
assert result [ " itemlist " ] == { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } , { " S " : " bar3 " } ] }
2019-10-09 16:25:50 +00:00
def create_table_with_list ( table_name ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
2019-10-09 16:25:50 +00:00
return client
2019-10-10 08:33:11 +00:00
@mock_dynamodb2
def test_sorted_query_with_numerical_sort_key ( ) :
2019-10-31 15:44:26 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " CarCollection " ,
KeySchema = [
{ " AttributeName " : " CarModel " , " KeyType " : " HASH " } ,
{ " AttributeName " : " CarPrice " , " KeyType " : " RANGE " } ,
] ,
AttributeDefinitions = [
{ " AttributeName " : " CarModel " , " AttributeType " : " S " } ,
{ " AttributeName " : " CarPrice " , " AttributeType " : " N " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
2019-10-10 08:33:11 +00:00
def create_item ( price ) :
return { " CarModel " : " M " , " CarPrice " : price }
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " CarCollection " )
2019-10-10 08:33:11 +00:00
items = list ( map ( create_item , [ 2 , 1 , 10 , 3 ] ) )
for item in items :
table . put_item ( Item = item )
2019-10-31 15:44:26 +00:00
response = table . query ( KeyConditionExpression = Key ( " CarModel " ) . eq ( " M " ) )
2019-10-10 08:33:11 +00:00
2019-10-31 15:44:26 +00:00
response_items = response [ " Items " ]
2019-10-10 08:33:11 +00:00
assert len ( items ) == len ( response_items )
assert all ( isinstance ( item [ " CarPrice " ] , Decimal ) for item in response_items )
response_prices = [ item [ " CarPrice " ] for item in response_items ]
expected_prices = [ Decimal ( item [ " CarPrice " ] ) for item in items ]
expected_prices . sort ( )
2019-10-31 15:44:26 +00:00
assert (
expected_prices == response_prices
) , " result items are not sorted by numerical value "
2019-10-10 08:33:11 +00:00
2019-10-05 14:20:43 +00:00
# https://github.com/spulec/moto/issues/1874
@mock_dynamodb2
def test_item_size_is_under_400KB ( ) :
2019-11-18 07:16:15 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-10-05 14:20:43 +00:00
dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
table = dynamodb . Table ( " moto-test " )
large_item = " x " * 410 * 1000
assert_failure_due_to_item_size (
func = client . put_item ,
TableName = " moto-test " ,
2020-04-19 15:50:53 +00:00
Item = { " id " : { " S " : " foo " } , " cont " : { " S " : large_item } } ,
2019-10-31 15:44:26 +00:00
)
assert_failure_due_to_item_size (
2020-04-19 15:50:53 +00:00
func = table . put_item , Item = { " id " : " bar " , " cont " : large_item }
2019-10-31 15:44:26 +00:00
)
2020-04-19 15:50:53 +00:00
assert_failure_due_to_item_size_to_update (
2019-10-31 15:44:26 +00:00
func = client . update_item ,
TableName = " moto-test " ,
Key = { " id " : { " S " : " foo2 " } } ,
2020-04-19 15:50:53 +00:00
UpdateExpression = " set cont=:Item " ,
2019-10-31 15:44:26 +00:00
ExpressionAttributeValues = { " :Item " : { " S " : large_item } } ,
)
2019-10-08 14:51:46 +00:00
# Assert op fails when updating a nested item
2019-10-31 15:44:26 +00:00
assert_failure_due_to_item_size (
2020-04-19 15:50:53 +00:00
func = table . put_item , Item = { " id " : " bar " , " itemlist " : [ { " cont " : large_item } ] }
2019-10-31 15:44:26 +00:00
)
assert_failure_due_to_item_size (
func = client . put_item ,
TableName = " moto-test " ,
Item = {
" id " : { " S " : " foo " } ,
" itemlist " : { " L " : [ { " M " : { " item1 " : { " S " : large_item } } } ] } ,
} ,
)
2019-10-08 14:51:46 +00:00
2019-10-23 08:12:03 +00:00
def assert_failure_due_to_item_size ( func , * * kwargs ) :
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-23 08:12:03 +00:00
func ( * * kwargs )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" Item size has exceeded the maximum allowed size "
)
2019-10-23 08:12:03 +00:00
2020-04-19 15:50:53 +00:00
def assert_failure_due_to_item_size_to_update ( func , * * kwargs ) :
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-04-19 15:50:53 +00:00
func ( * * kwargs )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-04-19 15:50:53 +00:00
" Item size to update has exceeded the maximum allowed size "
)
2019-10-18 08:58:09 +00:00
@mock_dynamodb2
# https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#DDB-Query-request-KeyConditionExpression
def test_hash_key_cannot_use_begins_with_operations ( ) :
2019-11-18 07:16:15 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-10-18 08:58:09 +00:00
table = dynamodb . create_table (
2019-10-31 15:44:26 +00:00
TableName = " test-table " ,
KeySchema = [ { " AttributeName " : " key " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " key " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
2019-10-18 08:58:09 +00:00
2019-10-31 15:44:26 +00:00
items = [
{ " key " : " prefix-$LATEST " , " value " : " $LATEST " } ,
{ " key " : " prefix-DEV " , " value " : " DEV " } ,
{ " key " : " prefix-PROD " , " value " : " PROD " } ,
]
2019-10-18 08:58:09 +00:00
with table . batch_writer ( ) as batch :
for item in items :
batch . put_item ( Item = item )
2019-10-31 15:44:26 +00:00
table = dynamodb . Table ( " test-table " )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2019-10-31 15:44:26 +00:00
table . query ( KeyConditionExpression = Key ( " key " ) . begins_with ( " prefix- " ) )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2019-10-31 15:44:26 +00:00
" Query key condition not supported "
)
2019-10-18 08:58:09 +00:00
2019-10-23 08:12:03 +00:00
@mock_dynamodb2
def test_update_supports_complex_expression_attribute_values ( ) :
2019-11-18 07:16:15 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-10-23 08:12:03 +00:00
2019-10-31 15:44:26 +00:00
client . create_table (
AttributeDefinitions = [ { " AttributeName " : " SHA256 " , " AttributeType " : " S " } ] ,
TableName = " TestTable " ,
KeySchema = [ { " AttributeName " : " SHA256 " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
2019-10-23 08:12:03 +00:00
2019-10-31 15:44:26 +00:00
client . update_item (
TableName = " TestTable " ,
Key = { " SHA256 " : { " S " : " sha-of-file " } } ,
UpdateExpression = (
" SET MD5 = :md5, " " MyStringSet = :string_set, " " MyMap = :map "
) ,
ExpressionAttributeValues = {
" :md5 " : { " S " : " md5-of-file " } ,
" :string_set " : { " SS " : [ " string1 " , " string2 " ] } ,
" :map " : { " M " : { " EntryKey " : { " SS " : [ " thing1 " , " thing2 " ] } } } ,
} ,
)
result = client . get_item (
TableName = " TestTable " , Key = { " SHA256 " : { " S " : " sha-of-file " } }
) [ " Item " ]
result . should . equal (
{
" MyStringSet " : { " SS " : [ " string1 " , " string2 " ] } ,
" MyMap " : { " M " : { " EntryKey " : { " SS " : [ " thing1 " , " thing2 " ] } } } ,
" SHA256 " : { " S " : " sha-of-file " } ,
" MD5 " : { " S " : " md5-of-file " } ,
}
)
2019-10-23 08:12:03 +00:00
@mock_dynamodb2
def test_update_supports_list_append ( ) :
2019-11-25 14:55:43 +00:00
# Verify whether the list_append operation works as expected
2019-11-18 07:16:15 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-10-23 08:12:03 +00:00
2019-10-31 15:44:26 +00:00
client . create_table (
AttributeDefinitions = [ { " AttributeName " : " SHA256 " , " AttributeType " : " S " } ] ,
TableName = " TestTable " ,
KeySchema = [ { " AttributeName " : " SHA256 " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . put_item (
TableName = " TestTable " ,
Item = { " SHA256 " : { " S " : " sha-of-file " } , " crontab " : { " L " : [ { " S " : " bar1 " } ] } } ,
)
2019-10-23 08:12:03 +00:00
# Update item using list_append expression
2020-02-05 08:31:03 +00:00
updated_item = client . update_item (
2019-10-31 15:44:26 +00:00
TableName = " TestTable " ,
Key = { " SHA256 " : { " S " : " sha-of-file " } } ,
UpdateExpression = " SET crontab = list_append(crontab, :i) " ,
ExpressionAttributeValues = { " :i " : { " L " : [ { " S " : " bar2 " } ] } } ,
2020-02-05 08:31:03 +00:00
ReturnValues = " UPDATED_NEW " ,
2019-10-31 15:44:26 +00:00
)
2019-10-23 08:12:03 +00:00
2020-02-05 08:31:03 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " crontab " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } }
)
2019-10-23 08:12:03 +00:00
# Verify item is appended to the existing list
2019-10-31 15:44:26 +00:00
result = client . get_item (
TableName = " TestTable " , Key = { " SHA256 " : { " S " : " sha-of-file " } }
) [ " Item " ]
result . should . equal (
{
" SHA256 " : { " S " : " sha-of-file " } ,
" crontab " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } ,
}
)
2019-10-23 08:12:03 +00:00
2019-11-25 14:55:43 +00:00
@mock_dynamodb2
def test_update_supports_nested_list_append ( ) :
# Verify whether we can append a list that's inside a map
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
client . create_table (
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
TableName = " TestTable " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . put_item (
TableName = " TestTable " ,
Item = {
" id " : { " S " : " nested_list_append " } ,
" a " : { " M " : { " b " : { " L " : [ { " S " : " bar1 " } ] } } } ,
} ,
)
# Update item using list_append expression
2020-02-05 08:31:03 +00:00
updated_item = client . update_item (
2019-11-25 14:55:43 +00:00
TableName = " TestTable " ,
Key = { " id " : { " S " : " nested_list_append " } } ,
UpdateExpression = " SET a.#b = list_append(a.#b, :i) " ,
ExpressionAttributeValues = { " :i " : { " L " : [ { " S " : " bar2 " } ] } } ,
ExpressionAttributeNames = { " #b " : " b " } ,
2020-02-05 08:31:03 +00:00
ReturnValues = " UPDATED_NEW " ,
2019-11-25 14:55:43 +00:00
)
2020-02-05 08:31:03 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " a " : { " M " : { " b " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } } } }
)
2019-11-25 14:55:43 +00:00
result = client . get_item (
TableName = " TestTable " , Key = { " id " : { " S " : " nested_list_append " } }
) [ " Item " ]
result . should . equal (
{
" id " : { " S " : " nested_list_append " } ,
" a " : { " M " : { " b " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } } } ,
}
)
@mock_dynamodb2
def test_update_supports_multiple_levels_nested_list_append ( ) :
# Verify whether we can append a list that's inside a map that's inside a map (Inception!)
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
client . create_table (
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
TableName = " TestTable " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . put_item (
TableName = " TestTable " ,
Item = {
" id " : { " S " : " nested_list_append " } ,
" a " : { " M " : { " b " : { " M " : { " c " : { " L " : [ { " S " : " bar1 " } ] } } } } } ,
} ,
)
# Update item using list_append expression
2020-02-05 08:31:03 +00:00
updated_item = client . update_item (
2019-11-25 14:55:43 +00:00
TableName = " TestTable " ,
Key = { " id " : { " S " : " nested_list_append " } } ,
UpdateExpression = " SET a.#b.c = list_append(a.#b.#c, :i) " ,
ExpressionAttributeValues = { " :i " : { " L " : [ { " S " : " bar2 " } ] } } ,
ExpressionAttributeNames = { " #b " : " b " , " #c " : " c " } ,
2020-02-05 08:31:03 +00:00
ReturnValues = " UPDATED_NEW " ,
2019-11-25 14:55:43 +00:00
)
2020-02-05 08:31:03 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " a " : { " M " : { " b " : { " M " : { " c " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } } } } } }
)
2019-11-25 14:55:43 +00:00
# Verify item is appended to the existing list
result = client . get_item (
TableName = " TestTable " , Key = { " id " : { " S " : " nested_list_append " } }
) [ " Item " ]
result . should . equal (
{
" id " : { " S " : " nested_list_append " } ,
" a " : { " M " : { " b " : { " M " : { " c " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } } } } } ,
}
)
@mock_dynamodb2
def test_update_supports_nested_list_append_onto_another_list ( ) :
# Verify whether we can take the contents of one list, and use that to fill another list
# Note that the contents of the other list is completely overwritten
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
client . create_table (
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
TableName = " TestTable " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . put_item (
TableName = " TestTable " ,
Item = {
" id " : { " S " : " list_append_another " } ,
" a " : { " M " : { " b " : { " L " : [ { " S " : " bar1 " } ] } , " c " : { " L " : [ { " S " : " car1 " } ] } } } ,
} ,
)
# Update item using list_append expression
2020-02-05 08:31:03 +00:00
updated_item = client . update_item (
2019-11-25 14:55:43 +00:00
TableName = " TestTable " ,
Key = { " id " : { " S " : " list_append_another " } } ,
UpdateExpression = " SET a.#c = list_append(a.#b, :i) " ,
ExpressionAttributeValues = { " :i " : { " L " : [ { " S " : " bar2 " } ] } } ,
ExpressionAttributeNames = { " #b " : " b " , " #c " : " c " } ,
2020-02-05 08:31:03 +00:00
ReturnValues = " UPDATED_NEW " ,
2019-11-25 14:55:43 +00:00
)
2020-02-05 08:31:03 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " a " : { " M " : { " c " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } } } }
)
2019-11-25 14:55:43 +00:00
# Verify item is appended to the existing list
result = client . get_item (
TableName = " TestTable " , Key = { " id " : { " S " : " list_append_another " } }
) [ " Item " ]
result . should . equal (
{
" id " : { " S " : " list_append_another " } ,
" a " : {
" M " : {
" b " : { " L " : [ { " S " : " bar1 " } ] } ,
" c " : { " L " : [ { " S " : " bar1 " } , { " S " : " bar2 " } ] } ,
}
} ,
}
)
2020-01-06 08:16:09 +00:00
@mock_dynamodb2
def test_update_supports_list_append_maps ( ) :
client = boto3 . client ( " dynamodb " , region_name = " us-west-1 " )
client . create_table (
AttributeDefinitions = [
{ " AttributeName " : " id " , " AttributeType " : " S " } ,
{ " AttributeName " : " rid " , " AttributeType " : " S " } ,
] ,
TableName = " TestTable " ,
KeySchema = [
{ " AttributeName " : " id " , " KeyType " : " HASH " } ,
{ " AttributeName " : " rid " , " KeyType " : " RANGE " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . put_item (
TableName = " TestTable " ,
Item = {
" id " : { " S " : " nested_list_append " } ,
" rid " : { " S " : " range_key " } ,
" a " : { " L " : [ { " M " : { " b " : { " S " : " bar1 " } } } ] } ,
} ,
)
# Update item using list_append expression
2020-02-05 08:31:03 +00:00
updated_item = client . update_item (
2020-01-06 08:16:09 +00:00
TableName = " TestTable " ,
Key = { " id " : { " S " : " nested_list_append " } , " rid " : { " S " : " range_key " } } ,
UpdateExpression = " SET a = list_append(a, :i) " ,
ExpressionAttributeValues = { " :i " : { " L " : [ { " M " : { " b " : { " S " : " bar2 " } } } ] } } ,
2020-02-05 08:31:03 +00:00
ReturnValues = " UPDATED_NEW " ,
2020-01-06 08:16:09 +00:00
)
2020-02-05 08:31:03 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " a " : { " L " : [ { " M " : { " b " : { " S " : " bar1 " } } } , { " M " : { " b " : { " S " : " bar2 " } } } ] } }
)
2020-01-06 08:16:09 +00:00
# Verify item is appended to the existing list
result = client . query (
TableName = " TestTable " ,
KeyConditionExpression = " id = :i AND begins_with(rid, :r) " ,
ExpressionAttributeValues = {
" :i " : { " S " : " nested_list_append " } ,
" :r " : { " S " : " range_key " } ,
} ,
) [ " Items " ]
result . should . equal (
[
{
" a " : { " L " : [ { " M " : { " b " : { " S " : " bar1 " } } } , { " M " : { " b " : { " S " : " bar2 " } } } ] } ,
" rid " : { " S " : " range_key " } ,
" id " : { " S " : " nested_list_append " } ,
}
]
)
2020-10-05 12:40:33 +00:00
@requires_boto_gte ( " 2.9 " )
@mock_dynamodb2
def test_update_supports_nested_update_if_nested_value_not_exists ( ) :
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
name = " TestTable "
dynamodb . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " user_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " user_id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( name )
table . put_item (
2020-11-11 15:55:37 +00:00
Item = { " user_id " : " 1234 " , " friends " : { " 5678 " : { " name " : " friend_5678 " } } , } ,
2020-10-05 12:40:33 +00:00
)
table . update_item (
Key = { " user_id " : " 1234 " } ,
2020-11-11 15:55:37 +00:00
ExpressionAttributeNames = { " #friends " : " friends " , " #friendid " : " 0000 " , } ,
ExpressionAttributeValues = { " :friend " : { " name " : " friend_0000 " } , } ,
2020-10-05 12:40:33 +00:00
UpdateExpression = " SET #friends.#friendid = :friend " ,
ReturnValues = " UPDATED_NEW " ,
)
item = table . get_item ( Key = { " user_id " : " 1234 " } ) [ " Item " ]
assert item == {
" user_id " : " 1234 " ,
2020-11-11 15:55:37 +00:00
" friends " : { " 5678 " : { " name " : " friend_5678 " } , " 0000 " : { " name " : " friend_0000 " } , } ,
2020-10-05 12:40:33 +00:00
}
2020-02-09 11:47:02 +00:00
@mock_dynamodb2
def test_update_supports_list_append_with_nested_if_not_exists_operation ( ) :
2020-02-09 11:58:41 +00:00
dynamo = boto3 . resource ( " dynamodb " , region_name = " us-west-1 " )
2020-02-09 11:47:02 +00:00
table_name = " test "
dynamo . create_table (
TableName = table_name ,
AttributeDefinitions = [ { " AttributeName " : " Id " , " AttributeType " : " S " } ] ,
KeySchema = [ { " AttributeName " : " Id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 20 , " WriteCapacityUnits " : 20 } ,
)
table = dynamo . Table ( table_name )
table . put_item ( Item = { " Id " : " item-id " , " nest1 " : { " nest2 " : { } } } )
2020-03-12 16:56:11 +00:00
updated_item = table . update_item (
2020-02-09 11:47:02 +00:00
Key = { " Id " : " item-id " } ,
UpdateExpression = " SET nest1.nest2.event_history = list_append(if_not_exists(nest1.nest2.event_history, :empty_list), :new_value) " ,
ExpressionAttributeValues = { " :empty_list " : [ ] , " :new_value " : [ " some_value " ] } ,
2020-03-12 16:56:11 +00:00
ReturnValues = " UPDATED_NEW " ,
2020-02-09 11:47:02 +00:00
)
2020-03-12 16:56:11 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " nest1 " : { " nest2 " : { " event_history " : [ " some_value " ] } } }
2020-02-09 11:47:02 +00:00
)
2020-03-12 16:56:11 +00:00
2020-02-09 11:47:02 +00:00
table . get_item ( Key = { " Id " : " item-id " } ) [ " Item " ] . should . equal (
{ " Id " : " item-id " , " nest1 " : { " nest2 " : { " event_history " : [ " some_value " ] } } }
)
2020-03-05 20:05:00 +00:00
@mock_dynamodb2
def test_update_supports_list_append_with_nested_if_not_exists_operation_and_property_already_exists ( ) :
dynamo = boto3 . resource ( " dynamodb " , region_name = " us-west-1 " )
table_name = " test "
dynamo . create_table (
TableName = table_name ,
AttributeDefinitions = [ { " AttributeName " : " Id " , " AttributeType " : " S " } ] ,
KeySchema = [ { " AttributeName " : " Id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 20 , " WriteCapacityUnits " : 20 } ,
)
table = dynamo . Table ( table_name )
2020-03-05 21:39:20 +00:00
table . put_item ( Item = { " Id " : " item-id " , " event_history " : [ " other_value " ] } )
2020-03-12 16:56:11 +00:00
updated_item = table . update_item (
2020-03-05 20:05:00 +00:00
Key = { " Id " : " item-id " } ,
UpdateExpression = " SET event_history = list_append(if_not_exists(event_history, :empty_list), :new_value) " ,
ExpressionAttributeValues = { " :empty_list " : [ ] , " :new_value " : [ " some_value " ] } ,
2020-03-12 16:56:11 +00:00
ReturnValues = " UPDATED_NEW " ,
2020-03-05 20:05:00 +00:00
)
2020-03-12 16:56:11 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal (
{ " event_history " : [ " other_value " , " some_value " ] }
2020-03-05 20:05:00 +00:00
)
2020-03-12 16:56:11 +00:00
2020-03-05 20:05:00 +00:00
table . get_item ( Key = { " Id " : " item-id " } ) [ " Item " ] . should . equal (
{ " Id " : " item-id " , " event_history " : [ " other_value " , " some_value " ] }
)
2019-08-22 15:12:48 +00:00
def _create_user_table ( ) :
2019-10-31 15:44:26 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-08-22 15:12:48 +00:00
client . create_table (
2019-10-31 15:44:26 +00:00
TableName = " users " ,
KeySchema = [ { " AttributeName " : " username " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " username " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . put_item (
TableName = " users " , Item = { " username " : { " S " : " user1 " } , " foo " : { " S " : " bar " } }
)
client . put_item (
TableName = " users " , Item = { " username " : { " S " : " user2 " } , " foo " : { " S " : " bar " } }
)
client . put_item (
TableName = " users " , Item = { " username " : { " S " : " user3 " } , " foo " : { " S " : " bar " } }
)
2019-08-22 15:12:48 +00:00
return client
2019-11-15 15:47:18 +00:00
@mock_dynamodb2
def test_update_item_if_original_value_is_none ( ) :
dynamo = boto3 . resource ( " dynamodb " , region_name = " eu-central-1 " )
dynamo . create_table (
AttributeDefinitions = [ { " AttributeName " : " job_id " , " AttributeType " : " S " } ] ,
TableName = " origin-rbu-dev " ,
KeySchema = [ { " AttributeName " : " job_id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
table = dynamo . Table ( " origin-rbu-dev " )
table . put_item ( Item = { " job_id " : " a " , " job_name " : None } )
table . update_item (
Key = { " job_id " : " a " } ,
UpdateExpression = " SET job_name = :output " ,
2019-11-21 22:53:58 +00:00
ExpressionAttributeValues = { " :output " : " updated " } ,
2019-11-15 15:47:18 +00:00
)
table . scan ( ) [ " Items " ] [ 0 ] [ " job_name " ] . should . equal ( " updated " )
@mock_dynamodb2
def test_update_nested_item_if_original_value_is_none ( ) :
dynamo = boto3 . resource ( " dynamodb " , region_name = " eu-central-1 " )
dynamo . create_table (
AttributeDefinitions = [ { " AttributeName " : " job_id " , " AttributeType " : " S " } ] ,
TableName = " origin-rbu-dev " ,
KeySchema = [ { " AttributeName " : " job_id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
table = dynamo . Table ( " origin-rbu-dev " )
table . put_item ( Item = { " job_id " : " a " , " job_details " : { " job_name " : None } } )
2020-03-12 16:56:11 +00:00
updated_item = table . update_item (
2019-11-15 15:47:18 +00:00
Key = { " job_id " : " a " } ,
UpdateExpression = " SET job_details.job_name = :output " ,
2019-11-21 22:53:58 +00:00
ExpressionAttributeValues = { " :output " : " updated " } ,
2020-03-12 16:56:11 +00:00
ReturnValues = " UPDATED_NEW " ,
2019-11-15 15:47:18 +00:00
)
2020-03-12 16:56:11 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal ( { " job_details " : { " job_name " : " updated " } } )
2019-11-15 15:47:18 +00:00
table . scan ( ) [ " Items " ] [ 0 ] [ " job_details " ] [ " job_name " ] . should . equal ( " updated " )
@mock_dynamodb2
def test_allow_update_to_item_with_different_type ( ) :
dynamo = boto3 . resource ( " dynamodb " , region_name = " eu-central-1 " )
dynamo . create_table (
AttributeDefinitions = [ { " AttributeName " : " job_id " , " AttributeType " : " S " } ] ,
TableName = " origin-rbu-dev " ,
KeySchema = [ { " AttributeName " : " job_id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
table = dynamo . Table ( " origin-rbu-dev " )
table . put_item ( Item = { " job_id " : " a " , " job_details " : { " job_name " : { " nested " : " yes " } } } )
table . put_item ( Item = { " job_id " : " b " , " job_details " : { " job_name " : { " nested " : " yes " } } } )
2020-03-12 16:56:11 +00:00
updated_item = table . update_item (
2019-11-15 15:47:18 +00:00
Key = { " job_id " : " a " } ,
UpdateExpression = " SET job_details.job_name = :output " ,
ExpressionAttributeValues = { " :output " : " updated " } ,
2020-03-12 16:56:11 +00:00
ReturnValues = " UPDATED_NEW " ,
2019-11-15 15:47:18 +00:00
)
2020-03-12 16:56:11 +00:00
# Verify updated item is correct
updated_item [ " Attributes " ] . should . equal ( { " job_details " : { " job_name " : " updated " } } )
2019-11-15 15:47:18 +00:00
table . get_item ( Key = { " job_id " : " a " } ) [ " Item " ] [ " job_details " ] [
" job_name "
] . should . be . equal ( " updated " )
table . get_item ( Key = { " job_id " : " b " } ) [ " Item " ] [ " job_details " ] [
" job_name "
] . should . be . equal ( { " nested " : " yes " } )
2020-02-01 21:00:15 +00:00
@mock_dynamodb2
def test_query_catches_when_no_filters ( ) :
dynamo = boto3 . resource ( " dynamodb " , region_name = " eu-central-1 " )
dynamo . create_table (
AttributeDefinitions = [ { " AttributeName " : " job_id " , " AttributeType " : " S " } ] ,
TableName = " origin-rbu-dev " ,
KeySchema = [ { " AttributeName " : " job_id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
table = dynamo . Table ( " origin-rbu-dev " )
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-02-01 21:00:15 +00:00
table . query ( TableName = " original-rbu-dev " )
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-02-01 21:00:15 +00:00
" Either KeyConditions or QueryFilter should be present "
)
2019-01-13 08:38:38 +00:00
@mock_dynamodb2
def test_invalid_transact_get_items ( ) :
2020-03-12 14:26:23 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-01-13 08:38:38 +00:00
dynamodb . create_table (
2020-03-12 14:26:23 +00:00
TableName = " test1 " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = dynamodb . Table ( " test1 " )
table . put_item (
2020-11-11 15:55:37 +00:00
Item = { " id " : " 1 " , " val " : " 1 " , }
2019-01-13 08:38:38 +00:00
)
2020-03-12 14:26:23 +00:00
table . put_item (
2020-11-11 15:55:37 +00:00
Item = { " id " : " 1 " , " val " : " 2 " , }
2020-03-12 14:26:23 +00:00
)
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
2019-01-13 08:38:38 +00:00
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-03-12 14:26:23 +00:00
client . transact_get_items (
TransactItems = [
{ " Get " : { " Key " : { " id " : { " S " : " 1 " } } , " TableName " : " test1 " } }
for i in range ( 26 )
]
)
2019-01-13 08:38:38 +00:00
2020-10-06 06:04:09 +00:00
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . match (
2020-03-12 14:26:23 +00:00
r " failed to satisfy constraint: Member must have length less than or equal to 25 " ,
re . I ,
2019-01-13 08:38:38 +00:00
)
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-03-12 14:26:23 +00:00
client . transact_get_items (
TransactItems = [
2020-11-11 15:55:37 +00:00
{ " Get " : { " Key " : { " id " : { " S " : " 1 " } , } , " TableName " : " test1 " , } } ,
{ " Get " : { " Key " : { " id " : { " S " : " 1 " } , } , " TableName " : " non_exists_table " , } } ,
2020-03-12 14:26:23 +00:00
]
)
2019-01-13 08:38:38 +00:00
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ResourceNotFoundException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
2020-10-06 06:46:05 +00:00
ex . value . response [ " Error " ] [ " Message " ] . should . equal ( " Requested resource not found " )
2019-01-13 08:38:38 +00:00
@mock_dynamodb2
def test_valid_transact_get_items ( ) :
2020-03-12 14:26:23 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2019-01-13 08:38:38 +00:00
dynamodb . create_table (
2020-03-12 14:26:23 +00:00
TableName = " test1 " ,
2019-01-13 08:38:38 +00:00
KeySchema = [
2020-03-12 14:26:23 +00:00
{ " AttributeName " : " id " , " KeyType " : " HASH " } ,
{ " AttributeName " : " sort_key " , " KeyType " : " RANGE " } ,
2019-01-13 08:38:38 +00:00
] ,
AttributeDefinitions = [
2020-03-12 14:26:23 +00:00
{ " AttributeName " : " id " , " AttributeType " : " S " } ,
{ " AttributeName " : " sort_key " , " AttributeType " : " S " } ,
2019-01-13 08:38:38 +00:00
] ,
2020-03-12 14:26:23 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table1 = dynamodb . Table ( " test1 " )
table1 . put_item (
2020-11-11 15:55:37 +00:00
Item = { " id " : " 1 " , " sort_key " : " 1 " , }
2019-01-13 08:38:38 +00:00
)
2020-03-12 14:26:23 +00:00
table1 . put_item (
2020-11-11 15:55:37 +00:00
Item = { " id " : " 1 " , " sort_key " : " 2 " , }
2020-03-12 14:26:23 +00:00
)
2019-01-13 08:38:38 +00:00
dynamodb . create_table (
2020-03-12 14:26:23 +00:00
TableName = " test2 " ,
2019-01-13 08:38:38 +00:00
KeySchema = [
2020-03-12 14:26:23 +00:00
{ " AttributeName " : " id " , " KeyType " : " HASH " } ,
{ " AttributeName " : " sort_key " , " KeyType " : " RANGE " } ,
2019-01-13 08:38:38 +00:00
] ,
AttributeDefinitions = [
2020-03-12 14:26:23 +00:00
{ " AttributeName " : " id " , " AttributeType " : " S " } ,
{ " AttributeName " : " sort_key " , " AttributeType " : " S " } ,
2019-01-13 08:38:38 +00:00
] ,
2020-03-12 14:26:23 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table2 = dynamodb . Table ( " test2 " )
table2 . put_item (
2020-11-11 15:55:37 +00:00
Item = { " id " : " 1 " , " sort_key " : " 1 " , }
2019-01-13 08:38:38 +00:00
)
2020-03-12 14:26:23 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
res = client . transact_get_items (
TransactItems = [
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " non_exists_key " } , " sort_key " : { " S " : " 2 " } } ,
" TableName " : " test1 " ,
}
} ,
]
)
res [ " Responses " ] [ 0 ] [ " Item " ] . should . equal ( { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } )
2020-10-29 11:50:45 +00:00
len ( res [ " Responses " ] ) . should . equal ( 2 )
res [ " Responses " ] [ 1 ] . should . equal ( { } )
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res = client . transact_get_items (
TransactItems = [
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 2 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test2 " ,
}
} ,
]
)
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res [ " Responses " ] [ 0 ] [ " Item " ] . should . equal ( { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } )
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res [ " Responses " ] [ 1 ] [ " Item " ] . should . equal ( { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 2 " } } )
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res [ " Responses " ] [ 2 ] [ " Item " ] . should . equal ( { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } )
res = client . transact_get_items (
TransactItems = [
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 2 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test2 " ,
}
} ,
] ,
ReturnConsumedCapacity = " TOTAL " ,
)
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res [ " ConsumedCapacity " ] [ 0 ] . should . equal (
{ " TableName " : " test1 " , " CapacityUnits " : 4.0 , " ReadCapacityUnits " : 4.0 }
)
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res [ " ConsumedCapacity " ] [ 1 ] . should . equal (
{ " TableName " : " test2 " , " CapacityUnits " : 2.0 , " ReadCapacityUnits " : 2.0 }
)
2019-01-13 08:38:38 +00:00
2020-03-12 14:26:23 +00:00
res = client . transact_get_items (
TransactItems = [
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 2 " } } ,
" TableName " : " test1 " ,
}
} ,
{
" Get " : {
" Key " : { " id " : { " S " : " 1 " } , " sort_key " : { " S " : " 1 " } } ,
" TableName " : " test2 " ,
}
} ,
] ,
ReturnConsumedCapacity = " INDEXES " ,
)
res [ " ConsumedCapacity " ] [ 0 ] . should . equal (
2019-01-13 08:38:38 +00:00
{
2020-03-12 14:26:23 +00:00
" TableName " : " test1 " ,
" CapacityUnits " : 4.0 ,
" ReadCapacityUnits " : 4.0 ,
2020-11-11 15:55:37 +00:00
" Table " : { " CapacityUnits " : 4.0 , " ReadCapacityUnits " : 4.0 , } ,
2019-01-13 08:38:38 +00:00
}
2020-03-12 14:26:23 +00:00
)
res [ " ConsumedCapacity " ] [ 1 ] . should . equal (
{
" TableName " : " test2 " ,
" CapacityUnits " : 2.0 ,
" ReadCapacityUnits " : 2.0 ,
2020-11-11 15:55:37 +00:00
" Table " : { " CapacityUnits " : 2.0 , " ReadCapacityUnits " : 2.0 , } ,
2019-01-13 08:38:38 +00:00
}
2020-03-12 14:26:23 +00:00
)
2020-03-17 16:28:49 +00:00
@mock_dynamodb2
def test_gsi_verify_negative_number_order ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " partitionKey " , " KeyType " : " HASH " } ] ,
" GlobalSecondaryIndexes " : [
{
" IndexName " : " GSI-K1 " ,
" KeySchema " : [
{ " AttributeName " : " gsiK1PartitionKey " , " KeyType " : " HASH " } ,
{ " AttributeName " : " gsiK1SortKey " , " KeyType " : " RANGE " } ,
] ,
2020-11-11 15:55:37 +00:00
" Projection " : { " ProjectionType " : " KEYS_ONLY " , } ,
2020-03-17 16:28:49 +00:00
}
] ,
" AttributeDefinitions " : [
{ " AttributeName " : " partitionKey " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsiK1PartitionKey " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsiK1SortKey " , " AttributeType " : " N " } ,
] ,
}
item1 = {
" partitionKey " : " pk-1 " ,
" gsiK1PartitionKey " : " gsi-k1 " ,
" gsiK1SortKey " : Decimal ( " -0.6 " ) ,
}
item2 = {
" partitionKey " : " pk-2 " ,
" gsiK1PartitionKey " : " gsi-k1 " ,
" gsiK1SortKey " : Decimal ( " -0.7 " ) ,
}
item3 = {
" partitionKey " : " pk-3 " ,
" gsiK1PartitionKey " : " gsi-k1 " ,
" gsiK1SortKey " : Decimal ( " 0.7 " ) ,
}
2020-03-17 17:11:35 +00:00
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
2020-03-17 16:28:49 +00:00
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
table = dynamodb . Table ( " test-table " )
table . put_item ( Item = item3 )
table . put_item ( Item = item1 )
table . put_item ( Item = item2 )
resp = table . query (
KeyConditionExpression = Key ( " gsiK1PartitionKey " ) . eq ( " gsi-k1 " ) ,
IndexName = " GSI-K1 " ,
)
# Items should be ordered with the lowest number first
[ float ( item [ " gsiK1SortKey " ] ) for item in resp [ " Items " ] ] . should . equal (
[ - 0.7 , - 0.6 , 0.7 ]
)
2020-04-08 09:49:58 +00:00
@mock_dynamodb2
def test_transact_write_items_put ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Put multiple items
dynamodb . transact_write_items (
TransactItems = [
{
" Put " : {
2020-11-11 15:55:37 +00:00
" Item " : { " id " : { " S " : " foo {} " . format ( str ( i ) ) } , " foo " : { " S " : " bar " } , } ,
2020-04-08 09:49:58 +00:00
" TableName " : " test-table " ,
}
}
for i in range ( 0 , 5 )
]
)
# Assert all are present
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 5 )
@mock_dynamodb2
def test_transact_write_items_put_conditional_expressions ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
dynamodb . put_item (
2020-11-11 15:55:37 +00:00
TableName = " test-table " , Item = { " id " : { " S " : " foo2 " } , } ,
2020-04-08 09:49:58 +00:00
)
# Put multiple items
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-04-08 09:49:58 +00:00
dynamodb . transact_write_items (
TransactItems = [
{
" Put " : {
" Item " : {
" id " : { " S " : " foo {} " . format ( str ( i ) ) } ,
" foo " : { " S " : " bar " } ,
} ,
" TableName " : " test-table " ,
" ConditionExpression " : " #i <> :i " ,
" ExpressionAttributeNames " : { " #i " : " id " } ,
" ExpressionAttributeValues " : {
" :i " : {
" S " : " foo2 "
} # This item already exist, so the ConditionExpression should fail
} ,
}
}
for i in range ( 0 , 5 )
]
)
# Assert the exception is correct
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " TransactionCanceledException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
2020-04-08 09:49:58 +00:00
# Assert all are present
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal ( { " id " : { " S " : " foo2 " } } )
@mock_dynamodb2
def test_transact_write_items_conditioncheck_passes ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item without email address
dynamodb . put_item (
2020-11-11 15:55:37 +00:00
TableName = " test-table " , Item = { " id " : { " S " : " foo " } , } ,
2020-04-08 09:49:58 +00:00
)
# Put an email address, after verifying it doesn't exist yet
dynamodb . transact_write_items (
TransactItems = [
{
" ConditionCheck " : {
" Key " : { " id " : { " S " : " foo " } } ,
" TableName " : " test-table " ,
" ConditionExpression " : " attribute_not_exists(#e) " ,
" ExpressionAttributeNames " : { " #e " : " email_address " } ,
}
} ,
{
" Put " : {
" Item " : {
" id " : { " S " : " foo " } ,
" email_address " : { " S " : " test@moto.com " } ,
} ,
" TableName " : " test-table " ,
}
} ,
]
)
# Assert all are present
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal ( { " email_address " : { " S " : " test@moto.com " } , " id " : { " S " : " foo " } } )
@mock_dynamodb2
def test_transact_write_items_conditioncheck_fails ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item with email address
dynamodb . put_item (
TableName = " test-table " ,
Item = { " id " : { " S " : " foo " } , " email_address " : { " S " : " test@moto.com " } } ,
)
# Try to put an email address, but verify whether it exists
# ConditionCheck should fail
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-04-08 09:49:58 +00:00
dynamodb . transact_write_items (
TransactItems = [
{
" ConditionCheck " : {
" Key " : { " id " : { " S " : " foo " } } ,
" TableName " : " test-table " ,
" ConditionExpression " : " attribute_not_exists(#e) " ,
" ExpressionAttributeNames " : { " #e " : " email_address " } ,
}
} ,
{
" Put " : {
" Item " : {
" id " : { " S " : " foo " } ,
" email_address " : { " S " : " update@moto.com " } ,
} ,
" TableName " : " test-table " ,
}
} ,
]
)
# Assert the exception is correct
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " TransactionCanceledException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
2020-04-08 09:49:58 +00:00
# Assert the original email address is still present
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal ( { " email_address " : { " S " : " test@moto.com " } , " id " : { " S " : " foo " } } )
@mock_dynamodb2
def test_transact_write_items_delete ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item
dynamodb . put_item (
2020-11-11 15:55:37 +00:00
TableName = " test-table " , Item = { " id " : { " S " : " foo " } , } ,
2020-04-08 09:49:58 +00:00
)
# Delete the item
dynamodb . transact_write_items (
TransactItems = [
2020-11-11 15:55:37 +00:00
{ " Delete " : { " Key " : { " id " : { " S " : " foo " } } , " TableName " : " test-table " , } }
2020-04-08 09:49:58 +00:00
]
)
# Assert the item is deleted
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 0 )
@mock_dynamodb2
def test_transact_write_items_delete_with_successful_condition_expression ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item without email address
dynamodb . put_item (
2020-11-11 15:55:37 +00:00
TableName = " test-table " , Item = { " id " : { " S " : " foo " } , } ,
2020-04-08 09:49:58 +00:00
)
# ConditionExpression will pass - no email address has been specified yet
dynamodb . transact_write_items (
TransactItems = [
{
" Delete " : {
2020-11-11 15:55:37 +00:00
" Key " : { " id " : { " S " : " foo " } , } ,
2020-04-08 09:49:58 +00:00
" TableName " : " test-table " ,
" ConditionExpression " : " attribute_not_exists(#e) " ,
" ExpressionAttributeNames " : { " #e " : " email_address " } ,
}
}
]
)
# Assert the item is deleted
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 0 )
@mock_dynamodb2
def test_transact_write_items_delete_with_failed_condition_expression ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item with email address
dynamodb . put_item (
TableName = " test-table " ,
Item = { " id " : { " S " : " foo " } , " email_address " : { " S " : " test@moto.com " } } ,
)
# Try to delete an item that does not have an email address
# ConditionCheck should fail
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-04-08 09:49:58 +00:00
dynamodb . transact_write_items (
TransactItems = [
{
" Delete " : {
2020-11-11 15:55:37 +00:00
" Key " : { " id " : { " S " : " foo " } , } ,
2020-04-08 09:49:58 +00:00
" TableName " : " test-table " ,
" ConditionExpression " : " attribute_not_exists(#e) " ,
" ExpressionAttributeNames " : { " #e " : " email_address " } ,
}
}
]
)
# Assert the exception is correct
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " TransactionCanceledException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
2020-04-08 09:49:58 +00:00
# Assert the original item is still present
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal ( { " email_address " : { " S " : " test@moto.com " } , " id " : { " S " : " foo " } } )
@mock_dynamodb2
def test_transact_write_items_update ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item
dynamodb . put_item ( TableName = " test-table " , Item = { " id " : { " S " : " foo " } } )
# Update the item
dynamodb . transact_write_items (
TransactItems = [
{
" Update " : {
" Key " : { " id " : { " S " : " foo " } } ,
" TableName " : " test-table " ,
" UpdateExpression " : " SET #e = :v " ,
" ExpressionAttributeNames " : { " #e " : " email_address " } ,
" ExpressionAttributeValues " : { " :v " : { " S " : " test@moto.com " } } ,
}
}
]
)
# Assert the item is updated
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal ( { " id " : { " S " : " foo " } , " email_address " : { " S " : " test@moto.com " } } )
@mock_dynamodb2
def test_transact_write_items_update_with_failed_condition_expression ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-08 09:49:58 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert an item with email address
dynamodb . put_item (
TableName = " test-table " ,
Item = { " id " : { " S " : " foo " } , " email_address " : { " S " : " test@moto.com " } } ,
)
# Try to update an item that does not have an email address
# ConditionCheck should fail
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-04-08 09:49:58 +00:00
dynamodb . transact_write_items (
TransactItems = [
{
" Update " : {
" Key " : { " id " : { " S " : " foo " } } ,
" TableName " : " test-table " ,
" UpdateExpression " : " SET #e = :v " ,
" ConditionExpression " : " attribute_not_exists(#e) " ,
" ExpressionAttributeNames " : { " #e " : " email_address " } ,
" ExpressionAttributeValues " : { " :v " : { " S " : " update@moto.com " } } ,
}
}
]
)
# Assert the exception is correct
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " TransactionCanceledException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
2020-04-08 09:49:58 +00:00
# Assert the original item is still present
items = dynamodb . scan ( TableName = " test-table " ) [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal ( { " email_address " : { " S " : " test@moto.com " } , " id " : { " S " : " foo " } } )
2020-04-26 09:24:27 +00:00
2020-03-21 12:20:09 +00:00
@mock_dynamodb2
def test_dynamodb_max_1mb_limit ( ) :
ddb = boto3 . resource ( " dynamodb " , region_name = " eu-west-1 " )
table_name = " populated-mock-table "
table = ddb . create_table (
TableName = table_name ,
KeySchema = [
{ " AttributeName " : " partition_key " , " KeyType " : " HASH " } ,
2020-04-14 06:53:15 +00:00
{ " AttributeName " : " sort_key " , " KeyType " : " RANGE " } ,
2020-03-21 12:20:09 +00:00
] ,
AttributeDefinitions = [
{ " AttributeName " : " partition_key " , " AttributeType " : " S " } ,
{ " AttributeName " : " sort_key " , " AttributeType " : " S " } ,
] ,
2020-04-14 06:53:15 +00:00
BillingMode = " PAY_PER_REQUEST " ,
2020-03-21 12:20:09 +00:00
)
# Populate the table
items = [
{
" partition_key " : " partition_key_val " , # size=30
" sort_key " : " sort_key_value____ " + str ( i ) , # size=30
}
for i in range ( 10000 , 29999 )
]
with table . batch_writer ( ) as batch :
for item in items :
batch . put_item ( Item = item )
response = table . query (
KeyConditionExpression = Key ( " partition_key " ) . eq ( " partition_key_val " )
)
# We shouldn't get everything back - the total result set is well over 1MB
2020-04-16 06:09:50 +00:00
len ( items ) . should . be . greater_than ( response [ " Count " ] )
2020-03-21 12:20:09 +00:00
response [ " LastEvaluatedKey " ] . shouldnt . be ( None )
2020-04-25 23:38:08 +00:00
2020-04-11 20:17:16 +00:00
def assert_raise_syntax_error ( client_error , token , near ) :
"""
Assert whether a client_error is as expected Syntax error . Syntax error looks like : ` syntax_error_template `
Args :
client_error ( ClientError ) : The ClientError exception that was raised
token ( str ) : The token that ws unexpected
near ( str ) : The part in the expression that shows where the error occurs it generally has the preceding token the
optional separation and the problematic token .
"""
syntax_error_template = (
' Invalid UpdateExpression: Syntax error; token: " {token} " , near: " {near} " '
)
expected_syntax_error = syntax_error_template . format ( token = token , near = near )
assert client_error . response [ " Error " ] [ " Code " ] == " ValidationException "
assert expected_syntax_error == client_error . response [ " Error " ] [ " Message " ]
@mock_dynamodb2
def test_update_expression_with_numeric_literal_instead_of_value ( ) :
"""
DynamoDB requires literals to be passed in as values . If they are put literally in the expression a token error will
be raised
"""
dynamodb = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
dynamodb . create_table (
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
)
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = myNum + 1 " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_raise_syntax_error ( e , " 1 " , " + 1 " )
@mock_dynamodb2
def test_update_expression_with_multiple_set_clauses_must_be_comma_separated ( ) :
"""
An UpdateExpression can have multiple set clauses but if they are passed in without the separating comma .
"""
dynamodb = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
dynamodb . create_table (
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
)
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = myNum Mystr2 myNum2 " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_raise_syntax_error ( e , " Mystr2 " , " myNum Mystr2 myNum2 " )
2020-04-22 17:08:05 +00:00
2020-04-20 17:23:37 +00:00
@mock_dynamodb2
def test_list_tables_exclusive_start_table_name_empty ( ) :
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
resp = client . list_tables ( Limit = 1 , ExclusiveStartTableName = " whatever " )
len ( resp [ " TableNames " ] ) . should . equal ( 0 )
2020-04-26 14:12:33 +00:00
def assert_correct_client_error (
client_error , code , message_template , message_values = None , braces = None
) :
"""
Assert whether a client_error is as expected . Allow for a list of values to be passed into the message
Args :
client_error ( ClientError ) : The ClientError exception that was raised
code ( str ) : The code for the error ( e . g . ValidationException )
message_template ( str ) : Error message template . if message_values is not None then this template has a { values }
as placeholder . For example :
' Value provided in ExpressionAttributeValues unused in expressions: keys: {values} '
message_values ( list of str | None ) : The values that are passed in the error message
braces ( list of str | None ) : List of length 2 with opening and closing brace for the values . By default it will be
surrounded by curly brackets
"""
braces = braces or [ " { " , " } " ]
assert client_error . response [ " Error " ] [ " Code " ] == code
if message_values is not None :
values_string = " {open_brace} (?P<values>.*) {close_brace} " . format (
open_brace = braces [ 0 ] , close_brace = braces [ 1 ]
)
re_msg = re . compile ( message_template . format ( values = values_string ) )
match_result = re_msg . match ( client_error . response [ " Error " ] [ " Message " ] )
assert match_result is not None
values_string = match_result . groupdict ( ) [ " values " ]
values = [ key for key in values_string . split ( " , " ) ]
assert len ( message_values ) == len ( values )
for value in message_values :
assert value in values
else :
assert client_error . response [ " Error " ] [ " Message " ] == message_template
def create_simple_table_and_return_client ( ) :
dynamodb = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
dynamodb . create_table (
TableName = " moto-test " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-04-26 14:12:33 +00:00
ProvisionedThroughput = { " ReadCapacityUnits " : 1 , " WriteCapacityUnits " : 1 } ,
)
dynamodb . put_item (
TableName = " moto-test " ,
2020-11-11 15:55:37 +00:00
Item = { " id " : { " S " : " 1 " } , " myNum " : { " N " : " 1 " } , " MyStr " : { " S " : " 1 " } , } ,
2020-04-26 14:12:33 +00:00
)
return dynamodb
# https://github.com/spulec/moto/issues/2806
# https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html
# #DDB-UpdateItem-request-UpdateExpression
@mock_dynamodb2
def test_update_item_with_attribute_in_right_hand_side_and_operation ( ) :
dynamodb = create_simple_table_and_return_client ( )
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET myNum = myNum+:val " ,
ExpressionAttributeValues = { " :val " : { " N " : " 3 " } } ,
)
result = dynamodb . get_item ( TableName = " moto-test " , Key = { " id " : { " S " : " 1 " } } )
assert result [ " Item " ] [ " myNum " ] [ " N " ] == " 4 "
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET myNum = myNum - :val " ,
ExpressionAttributeValues = { " :val " : { " N " : " 1 " } } ,
)
result = dynamodb . get_item ( TableName = " moto-test " , Key = { " id " : { " S " : " 1 " } } )
assert result [ " Item " ] [ " myNum " ] [ " N " ] == " 3 "
@mock_dynamodb2
def test_non_existing_attribute_should_raise_exception ( ) :
"""
Does error message get correctly raised if attribute is referenced but it does not exist for the item .
"""
dynamodb = create_simple_table_and_return_client ( )
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = no_attr + MyStr " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_correct_client_error (
e ,
" ValidationException " ,
" The provided expression refers to an attribute that does not exist in the item " ,
)
@mock_dynamodb2
def test_update_expression_with_plus_in_attribute_name ( ) :
"""
Does error message get correctly raised if attribute contains a plus and is passed in without an AttributeName . And
lhs & rhs are not attribute IDs by themselve .
"""
dynamodb = create_simple_table_and_return_client ( )
dynamodb . put_item (
TableName = " moto-test " ,
2020-11-11 15:55:37 +00:00
Item = { " id " : { " S " : " 1 " } , " my+Num " : { " S " : " 1 " } , " MyStr " : { " S " : " aaa " } , } ,
2020-04-26 14:12:33 +00:00
)
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = my+Num " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_correct_client_error (
e ,
" ValidationException " ,
" The provided expression refers to an attribute that does not exist in the item " ,
)
@mock_dynamodb2
def test_update_expression_with_minus_in_attribute_name ( ) :
"""
Does error message get correctly raised if attribute contains a minus and is passed in without an AttributeName . And
lhs & rhs are not attribute IDs by themselve .
"""
dynamodb = create_simple_table_and_return_client ( )
dynamodb . put_item (
TableName = " moto-test " ,
2020-11-11 15:55:37 +00:00
Item = { " id " : { " S " : " 1 " } , " my-Num " : { " S " : " 1 " } , " MyStr " : { " S " : " aaa " } , } ,
2020-04-26 14:12:33 +00:00
)
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = my-Num " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_correct_client_error (
e ,
" ValidationException " ,
" The provided expression refers to an attribute that does not exist in the item " ,
)
@mock_dynamodb2
def test_update_expression_with_space_in_attribute_name ( ) :
"""
Does error message get correctly raised if attribute contains a space and is passed in without an AttributeName . And
lhs & rhs are not attribute IDs by themselves .
"""
dynamodb = create_simple_table_and_return_client ( )
dynamodb . put_item (
TableName = " moto-test " ,
2020-11-11 15:55:37 +00:00
Item = { " id " : { " S " : " 1 " } , " my Num " : { " S " : " 1 " } , " MyStr " : { " S " : " aaa " } , } ,
2020-04-26 14:12:33 +00:00
)
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = my Num " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_raise_syntax_error ( e , " Num " , " my Num " )
@mock_dynamodb2
def test_summing_up_2_strings_raises_exception ( ) :
"""
Update set supports different DynamoDB types but some operations are not supported . For example summing up 2 strings
raises an exception . It results in ClientError with code ValidationException :
Saying An operand in the update expression has an incorrect data type
"""
dynamodb = create_simple_table_and_return_client ( )
try :
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET MyStr = MyStr + MyStr " ,
)
assert False , " Validation exception not thrown "
except dynamodb . exceptions . ClientError as e :
assert_correct_client_error (
e ,
" ValidationException " ,
" An operand in the update expression has an incorrect data type " ,
)
# https://github.com/spulec/moto/issues/2806
@mock_dynamodb2
def test_update_item_with_attribute_in_right_hand_side ( ) :
"""
After tokenization and building expression make sure referenced attributes are replaced with their current value
"""
dynamodb = create_simple_table_and_return_client ( )
# Make sure there are 2 values
dynamodb . put_item (
TableName = " moto-test " ,
Item = { " id " : { " S " : " 1 " } , " myVal1 " : { " S " : " Value1 " } , " myVal2 " : { " S " : " Value2 " } } ,
)
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET myVal1 = myVal2 " ,
)
result = dynamodb . get_item ( TableName = " moto-test " , Key = { " id " : { " S " : " 1 " } } )
assert result [ " Item " ] [ " myVal1 " ] [ " S " ] == result [ " Item " ] [ " myVal2 " ] [ " S " ] == " Value2 "
@mock_dynamodb2
def test_multiple_updates ( ) :
dynamodb = create_simple_table_and_return_client ( )
dynamodb . put_item (
TableName = " moto-test " ,
Item = { " id " : { " S " : " 1 " } , " myNum " : { " N " : " 1 " } , " path " : { " N " : " 6 " } } ,
)
dynamodb . update_item (
TableName = " moto-test " ,
Key = { " id " : { " S " : " 1 " } } ,
UpdateExpression = " SET myNum = #p + :val, newAttr = myNum " ,
ExpressionAttributeValues = { " :val " : { " N " : " 1 " } } ,
ExpressionAttributeNames = { " #p " : " path " } ,
)
result = dynamodb . get_item ( TableName = " moto-test " , Key = { " id " : { " S " : " 1 " } } ) [ " Item " ]
expected_result = {
" myNum " : { " N " : " 7 " } ,
" newAttr " : { " N " : " 1 " } ,
" path " : { " N " : " 6 " } ,
" id " : { " S " : " 1 " } ,
}
assert result == expected_result
2020-05-01 13:19:20 +00:00
@mock_dynamodb2
def test_update_item_atomic_counter ( ) :
table = " table_t "
ddb_mock = boto3 . client ( " dynamodb " , region_name = " eu-west-3 " )
ddb_mock . create_table (
TableName = table ,
KeySchema = [ { " AttributeName " : " t_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " t_id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
key = { " t_id " : { " S " : " item1 " } }
ddb_mock . put_item (
TableName = table ,
Item = { " t_id " : { " S " : " item1 " } , " n_i " : { " N " : " 5 " } , " n_f " : { " N " : " 5.3 " } } ,
)
ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " set n_i = n_i + :inc1, n_f = n_f + :inc2 " ,
ExpressionAttributeValues = { " :inc1 " : { " N " : " 1.2 " } , " :inc2 " : { " N " : " 0.05 " } } ,
)
updated_item = ddb_mock . get_item ( TableName = table , Key = key ) [ " Item " ]
updated_item [ " n_i " ] [ " N " ] . should . equal ( " 6.2 " )
updated_item [ " n_f " ] [ " N " ] . should . equal ( " 5.35 " )
@mock_dynamodb2
def test_update_item_atomic_counter_return_values ( ) :
table = " table_t "
ddb_mock = boto3 . client ( " dynamodb " , region_name = " eu-west-3 " )
ddb_mock . create_table (
TableName = table ,
KeySchema = [ { " AttributeName " : " t_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " t_id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
key = { " t_id " : { " S " : " item1 " } }
ddb_mock . put_item ( TableName = table , Item = { " t_id " : { " S " : " item1 " } , " v " : { " N " : " 5 " } } )
response = ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " set v = v + :inc " ,
ExpressionAttributeValues = { " :inc " : { " N " : " 1 " } } ,
ReturnValues = " UPDATED_OLD " ,
)
assert (
" v " in response [ " Attributes " ]
) , " v has been updated, and should be returned here "
response [ " Attributes " ] [ " v " ] [ " N " ] . should . equal ( " 5 " )
# second update
response = ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " set v = v + :inc " ,
ExpressionAttributeValues = { " :inc " : { " N " : " 1 " } } ,
ReturnValues = " UPDATED_OLD " ,
)
assert (
" v " in response [ " Attributes " ]
) , " v has been updated, and should be returned here "
response [ " Attributes " ] [ " v " ] [ " N " ] . should . equal ( " 6 " )
# third update
response = ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " set v = v + :inc " ,
ExpressionAttributeValues = { " :inc " : { " N " : " 1 " } } ,
ReturnValues = " UPDATED_NEW " ,
)
assert (
" v " in response [ " Attributes " ]
) , " v has been updated, and should be returned here "
response [ " Attributes " ] [ " v " ] [ " N " ] . should . equal ( " 8 " )
2020-05-07 20:29:20 +00:00
@mock_dynamodb2
def test_update_item_atomic_counter_from_zero ( ) :
table = " table_t "
ddb_mock = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
ddb_mock . create_table (
TableName = table ,
KeySchema = [ { " AttributeName " : " t_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " t_id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
key = { " t_id " : { " S " : " item1 " } }
ddb_mock . put_item (
2020-11-11 15:55:37 +00:00
TableName = table , Item = key ,
2020-05-07 20:29:20 +00:00
)
ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " add n_i :inc1, n_f :inc2 " ,
ExpressionAttributeValues = { " :inc1 " : { " N " : " 1.2 " } , " :inc2 " : { " N " : " -0.5 " } } ,
)
updated_item = ddb_mock . get_item ( TableName = table , Key = key ) [ " Item " ]
assert updated_item [ " n_i " ] [ " N " ] == " 1.2 "
assert updated_item [ " n_f " ] [ " N " ] == " -0.5 "
@mock_dynamodb2
def test_update_item_add_to_non_existent_set ( ) :
table = " table_t "
ddb_mock = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
ddb_mock . create_table (
TableName = table ,
KeySchema = [ { " AttributeName " : " t_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " t_id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
key = { " t_id " : { " S " : " item1 " } }
ddb_mock . put_item (
2020-11-11 15:55:37 +00:00
TableName = table , Item = key ,
2020-05-07 20:29:20 +00:00
)
ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " add s_i :s1 " ,
ExpressionAttributeValues = { " :s1 " : { " SS " : [ " hello " ] } } ,
)
updated_item = ddb_mock . get_item ( TableName = table , Key = key ) [ " Item " ]
assert updated_item [ " s_i " ] [ " SS " ] == [ " hello " ]
@mock_dynamodb2
def test_update_item_add_to_non_existent_number_set ( ) :
table = " table_t "
ddb_mock = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
ddb_mock . create_table (
TableName = table ,
KeySchema = [ { " AttributeName " : " t_id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " t_id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
key = { " t_id " : { " S " : " item1 " } }
ddb_mock . put_item (
2020-11-11 15:55:37 +00:00
TableName = table , Item = key ,
2020-05-07 20:29:20 +00:00
)
ddb_mock . update_item (
TableName = table ,
Key = key ,
UpdateExpression = " add s_i :s1 " ,
ExpressionAttributeValues = { " :s1 " : { " NS " : [ " 3 " ] } } ,
)
updated_item = ddb_mock . get_item ( TableName = table , Key = key ) [ " Item " ]
assert updated_item [ " s_i " ] [ " NS " ] == [ " 3 " ]
2020-05-11 14:29:21 +00:00
@mock_dynamodb2
def test_transact_write_items_fails_with_transaction_canceled_exception ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
2020-11-11 15:55:37 +00:00
" AttributeDefinitions " : [ { " AttributeName " : " id " , " AttributeType " : " S " } , ] ,
2020-05-11 14:29:21 +00:00
}
dynamodb = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
# Insert one item
dynamodb . put_item ( TableName = " test-table " , Item = { " id " : { " S " : " foo " } } )
# Update two items, the one that exists and another that doesn't
2020-10-06 05:54:49 +00:00
with pytest . raises ( ClientError ) as ex :
2020-05-11 14:29:21 +00:00
dynamodb . transact_write_items (
TransactItems = [
{
" Update " : {
" Key " : { " id " : { " S " : " foo " } } ,
" TableName " : " test-table " ,
" UpdateExpression " : " SET #k = :v " ,
" ConditionExpression " : " attribute_exists(id) " ,
" ExpressionAttributeNames " : { " #k " : " key " } ,
" ExpressionAttributeValues " : { " :v " : { " S " : " value " } } ,
}
} ,
{
" Update " : {
" Key " : { " id " : { " S " : " doesnotexist " } } ,
" TableName " : " test-table " ,
" UpdateExpression " : " SET #e = :v " ,
" ConditionExpression " : " attribute_exists(id) " ,
" ExpressionAttributeNames " : { " #e " : " key " } ,
" ExpressionAttributeValues " : { " :v " : { " S " : " value " } } ,
}
} ,
]
)
2020-10-06 06:04:09 +00:00
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " TransactionCanceledException " )
ex . value . response [ " ResponseMetadata " ] [ " HTTPStatusCode " ] . should . equal ( 400 )
ex . value . response [ " Error " ] [ " Message " ] . should . equal (
2020-05-11 14:29:21 +00:00
" Transaction cancelled, please refer cancellation reasons for specific reasons [None, ConditionalCheckFailed] "
)
2020-06-27 10:07:15 +00:00
@mock_dynamodb2
def test_gsi_projection_type_keys_only ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " partitionKey " , " KeyType " : " HASH " } ] ,
" GlobalSecondaryIndexes " : [
{
" IndexName " : " GSI-K1 " ,
" KeySchema " : [
{ " AttributeName " : " gsiK1PartitionKey " , " KeyType " : " HASH " } ,
{ " AttributeName " : " gsiK1SortKey " , " KeyType " : " RANGE " } ,
] ,
2020-11-11 15:55:37 +00:00
" Projection " : { " ProjectionType " : " KEYS_ONLY " , } ,
2020-06-27 10:07:15 +00:00
}
] ,
" AttributeDefinitions " : [
{ " AttributeName " : " partitionKey " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsiK1PartitionKey " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsiK1SortKey " , " AttributeType " : " S " } ,
] ,
}
item = {
" partitionKey " : " pk-1 " ,
" gsiK1PartitionKey " : " gsi-pk " ,
" gsiK1SortKey " : " gsi-sk " ,
" someAttribute " : " lore ipsum " ,
}
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
table = dynamodb . Table ( " test-table " )
table . put_item ( Item = item )
items = table . query (
KeyConditionExpression = Key ( " gsiK1PartitionKey " ) . eq ( " gsi-pk " ) ,
IndexName = " GSI-K1 " ,
) [ " Items " ]
items . should . have . length_of ( 1 )
2020-07-14 12:42:13 +00:00
# Item should only include GSI Keys and Table Keys, as per the ProjectionType
items [ 0 ] . should . equal (
{
" gsiK1PartitionKey " : " gsi-pk " ,
" gsiK1SortKey " : " gsi-sk " ,
" partitionKey " : " pk-1 " ,
}
)
2020-07-03 13:20:04 +00:00
2020-11-25 20:28:05 +00:00
@mock_dynamodb2
def test_gsi_projection_type_include ( ) :
table_schema = {
" KeySchema " : [ { " AttributeName " : " partitionKey " , " KeyType " : " HASH " } ] ,
" GlobalSecondaryIndexes " : [
{
" IndexName " : " GSI-INC " ,
" KeySchema " : [
{ " AttributeName " : " gsiK1PartitionKey " , " KeyType " : " HASH " } ,
{ " AttributeName " : " gsiK1SortKey " , " KeyType " : " RANGE " } ,
] ,
" Projection " : {
" ProjectionType " : " INCLUDE " ,
" NonKeyAttributes " : [ " projectedAttribute " ] ,
} ,
}
] ,
" AttributeDefinitions " : [
{ " AttributeName " : " partitionKey " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsiK1PartitionKey " , " AttributeType " : " S " } ,
{ " AttributeName " : " gsiK1SortKey " , " AttributeType " : " S " } ,
] ,
}
item = {
" partitionKey " : " pk-1 " ,
" gsiK1PartitionKey " : " gsi-pk " ,
" gsiK1SortKey " : " gsi-sk " ,
" projectedAttribute " : " lore ipsum " ,
" nonProjectedAttribute " : " dolor sit amet " ,
}
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
table = dynamodb . Table ( " test-table " )
table . put_item ( Item = item )
items = table . query (
KeyConditionExpression = Key ( " gsiK1PartitionKey " ) . eq ( " gsi-pk " ) ,
IndexName = " GSI-INC " ,
) [ " Items " ]
items . should . have . length_of ( 1 )
# Item should only include keys and additionally projected attributes only
items [ 0 ] . should . equal (
{
" gsiK1PartitionKey " : " gsi-pk " ,
" gsiK1SortKey " : " gsi-sk " ,
" partitionKey " : " pk-1 " ,
" projectedAttribute " : " lore ipsum " ,
}
)
2020-07-03 13:20:04 +00:00
@mock_dynamodb2
def test_lsi_projection_type_keys_only ( ) :
table_schema = {
2020-07-14 12:42:13 +00:00
" KeySchema " : [
{ " AttributeName " : " partitionKey " , " KeyType " : " HASH " } ,
{ " AttributeName " : " sortKey " , " KeyType " : " RANGE " } ,
] ,
2020-07-03 13:20:04 +00:00
" LocalSecondaryIndexes " : [
{
" IndexName " : " LSI " ,
" KeySchema " : [
{ " AttributeName " : " partitionKey " , " KeyType " : " HASH " } ,
{ " AttributeName " : " lsiK1SortKey " , " KeyType " : " RANGE " } ,
] ,
2020-11-11 15:55:37 +00:00
" Projection " : { " ProjectionType " : " KEYS_ONLY " , } ,
2020-07-03 13:20:04 +00:00
}
] ,
" AttributeDefinitions " : [
{ " AttributeName " : " partitionKey " , " AttributeType " : " S " } ,
2020-07-14 12:42:13 +00:00
{ " AttributeName " : " sortKey " , " AttributeType " : " S " } ,
2020-07-03 13:20:04 +00:00
{ " AttributeName " : " lsiK1SortKey " , " AttributeType " : " S " } ,
] ,
}
item = {
" partitionKey " : " pk-1 " ,
2020-07-14 12:42:13 +00:00
" sortKey " : " sk-1 " ,
2020-07-03 13:20:04 +00:00
" lsiK1SortKey " : " lsi-sk " ,
" someAttribute " : " lore ipsum " ,
}
dynamodb = boto3 . resource ( " dynamodb " , region_name = " us-east-1 " )
dynamodb . create_table (
TableName = " test-table " , BillingMode = " PAY_PER_REQUEST " , * * table_schema
)
table = dynamodb . Table ( " test-table " )
table . put_item ( Item = item )
items = table . query (
2020-11-11 15:55:37 +00:00
KeyConditionExpression = Key ( " partitionKey " ) . eq ( " pk-1 " ) , IndexName = " LSI " ,
2020-07-03 13:20:04 +00:00
) [ " Items " ]
items . should . have . length_of ( 1 )
2020-07-14 12:42:13 +00:00
# Item should only include GSI Keys and Table Keys, as per the ProjectionType
items [ 0 ] . should . equal (
{ " partitionKey " : " pk-1 " , " sortKey " : " sk-1 " , " lsiK1SortKey " : " lsi-sk " }
)
2020-10-14 15:32:42 +00:00
@mock_dynamodb2
2021-02-19 07:47:51 +00:00
@pytest.mark.parametrize (
" attr_name " ,
[ " orders " , " #placeholder " ] ,
ids = [ " use attribute name " , " use expression attribute name " ] ,
)
def test_set_attribute_is_dropped_if_empty_after_update_expression ( attr_name ) :
2020-10-14 15:32:42 +00:00
table_name , item_key , set_item = " test-table " , " test-id " , " test-data "
2021-02-19 07:47:51 +00:00
expression_attribute_names = { " #placeholder " : " orders " }
2020-10-14 15:32:42 +00:00
client = boto3 . client ( " dynamodb " , region_name = " us-east-1 " )
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " customer " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " customer " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
client . update_item (
TableName = table_name ,
Key = { " customer " : { " S " : item_key } } ,
2021-02-19 07:47:51 +00:00
UpdateExpression = " ADD {} :order " . format ( attr_name ) ,
ExpressionAttributeNames = expression_attribute_names ,
2020-10-14 15:32:42 +00:00
ExpressionAttributeValues = { " :order " : { " SS " : [ set_item ] } } ,
)
resp = client . scan ( TableName = table_name , ProjectionExpression = " customer, orders " )
item = resp [ " Items " ] [ 0 ]
item . should . have . key ( " customer " )
item . should . have . key ( " orders " )
client . update_item (
TableName = table_name ,
Key = { " customer " : { " S " : item_key } } ,
2021-02-19 07:47:51 +00:00
UpdateExpression = " DELETE {} :order " . format ( attr_name ) ,
ExpressionAttributeNames = expression_attribute_names ,
2020-10-14 15:32:42 +00:00
ExpressionAttributeValues = { " :order " : { " SS " : [ set_item ] } } ,
)
resp = client . scan ( TableName = table_name , ProjectionExpression = " customer, orders " )
item = resp [ " Items " ] [ 0 ]
item . should . have . key ( " customer " )
item . should_not . have . key ( " orders " )
2020-10-29 11:50:45 +00:00
@mock_dynamodb2
def test_transact_get_items_should_return_empty_map_for_non_existent_item ( ) :
client = boto3 . client ( " dynamodb " , region_name = " us-west-2 " )
table_name = " test-table "
key_schema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ]
attribute_definitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ]
client . create_table (
TableName = table_name ,
KeySchema = key_schema ,
AttributeDefinitions = attribute_definitions ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
item = { " id " : { " S " : " 1 " } }
client . put_item ( TableName = table_name , Item = item )
items = client . transact_get_items (
TransactItems = [
{ " Get " : { " Key " : { " id " : { " S " : " 1 " } } , " TableName " : table_name } } ,
{ " Get " : { " Key " : { " id " : { " S " : " 2 " } } , " TableName " : table_name } } ,
]
) . get ( " Responses " , [ ] )
items . should . have . length_of ( 2 )
items [ 0 ] . should . equal ( { " Item " : item } )
items [ 1 ] . should . equal ( { } )
2020-12-07 09:31:53 +00:00
@mock_dynamodb2
def test_dynamodb_update_item_fails_on_string_sets ( ) :
dynamodb = boto3 . resource ( " dynamodb " , region_name = " eu-west-1 " )
client = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
table = dynamodb . create_table (
TableName = " test " ,
KeySchema = [ { " AttributeName " : " record_id " , " KeyType " : " HASH " } , ] ,
AttributeDefinitions = [ { " AttributeName " : " record_id " , " AttributeType " : " S " } , ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
table . meta . client . get_waiter ( " table_exists " ) . wait ( TableName = " test " )
2021-07-26 14:21:17 +00:00
attribute = { " test_field " : { " Value " : { " SS " : [ " test1 " , " test2 " ] , } , " Action " : " PUT " , } }
2020-12-07 09:31:53 +00:00
client . update_item (
TableName = " test " ,
Key = { " record_id " : { " S " : " testrecord " } } ,
AttributeUpdates = attribute ,
)
2021-01-10 14:20:41 +00:00
2021-06-23 16:41:47 +00:00
@mock_dynamodb2
2021-01-10 14:20:41 +00:00
def test_update_item_add_to_list_using_legacy_attribute_updates ( ) :
resource = boto3 . resource ( " dynamodb " , region_name = " us-west-2 " )
resource . create_table (
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
TableName = " TestTable " ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = resource . Table ( " TestTable " )
table . wait_until_exists ( )
table . put_item ( Item = { " id " : " list_add " , " attr " : [ " a " , " b " , " c " ] } , )
table . update_item (
TableName = " TestTable " ,
Key = { " id " : " list_add " } ,
AttributeUpdates = { " attr " : { " Action " : " ADD " , " Value " : [ " d " , " e " ] } } ,
)
resp = table . get_item ( Key = { " id " : " list_add " } )
resp [ " Item " ] [ " attr " ] . should . equal ( [ " a " , " b " , " c " , " d " , " e " ] )
2021-02-17 11:22:00 +00:00
@mock_dynamodb2
def test_get_item_for_non_existent_table_raises_error ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
with pytest . raises ( ClientError ) as ex :
client . get_item ( TableName = " non-existent " , Key = { " site-id " : { " S " : " foo " } } )
ex . value . response [ " Error " ] [ " Code " ] . should . equal ( " ResourceNotFoundException " )
ex . value . response [ " Error " ] [ " Message " ] . should . equal ( " Requested resource not found " )
2021-06-10 06:05:07 +00:00
2021-08-28 06:41:04 +00:00
@mock_dynamodb2
def test_error_when_providing_expression_and_nonexpression_params ( ) :
client = boto3 . client ( " dynamodb " , " eu-central-1 " )
table_name = " testtable "
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " pkey " , " KeyType " : " HASH " } , ] ,
AttributeDefinitions = [ { " AttributeName " : " pkey " , " AttributeType " : " S " } , ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
with pytest . raises ( ClientError ) as ex :
client . update_item (
TableName = table_name ,
Key = { " pkey " : { " S " : " testrecord " } } ,
AttributeUpdates = {
" test_field " : { " Value " : { " SS " : [ " test1 " , " test2 " ] , } , " Action " : " PUT " }
} ,
UpdateExpression = " DELETE orders :order " ,
ExpressionAttributeValues = { " :order " : { " SS " : [ " item " ] } } ,
)
err = ex . value . response [ " Error " ]
err [ " Code " ] . should . equal ( " ValidationException " )
err [ " Message " ] . should . equal (
" Can not use both expression and non-expression parameters in the same request: Non-expression parameters: {AttributeUpdates} Expression parameters: {UpdateExpression} "
)
2021-06-23 16:41:47 +00:00
@mock_dynamodb2
def test_attribute_item_delete ( ) :
name = " TestTable "
conn = boto3 . client ( " dynamodb " , region_name = " eu-west-1 " )
conn . create_table (
TableName = name ,
AttributeDefinitions = [ { " AttributeName " : " name " , " AttributeType " : " S " } ] ,
KeySchema = [ { " AttributeName " : " name " , " KeyType " : " HASH " } ] ,
)
item_name = " foo "
conn . put_item (
TableName = name , Item = { " name " : { " S " : item_name } , " extra " : { " S " : " bar " } }
)
conn . update_item (
TableName = name ,
Key = { " name " : { " S " : item_name } } ,
AttributeUpdates = { " extra " : { " Action " : " DELETE " } } ,
)
items = conn . scan ( TableName = name ) [ " Items " ]
items . should . equal ( [ { " name " : { " S " : " foo " } } ] )
2021-06-17 13:07:24 +00:00
@mock_dynamodb2
def test_gsi_key_can_be_updated ( ) :
name = " TestTable "
conn = boto3 . client ( " dynamodb " , region_name = " eu-west-2 " )
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " main_key " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [
{ " AttributeName " : " main_key " , " AttributeType " : " S " } ,
{ " AttributeName " : " index_key " , " AttributeType " : " S " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
GlobalSecondaryIndexes = [
{
" IndexName " : " test_index " ,
" KeySchema " : [ { " AttributeName " : " index_key " , " KeyType " : " HASH " } ] ,
" Projection " : { " ProjectionType " : " ALL " , } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 1 ,
" WriteCapacityUnits " : 1 ,
} ,
}
] ,
)
conn . put_item (
TableName = name ,
Item = {
" main_key " : { " S " : " testkey1 " } ,
" extra_data " : { " S " : " testdata " } ,
" index_key " : { " S " : " indexkey1 " } ,
} ,
)
conn . update_item (
TableName = name ,
Key = { " main_key " : { " S " : " testkey1 " } } ,
UpdateExpression = " set index_key=:new_index_key " ,
ExpressionAttributeValues = { " :new_index_key " : { " S " : " new_value " } } ,
)
item = conn . scan ( TableName = name ) [ " Items " ] [ 0 ]
item [ " index_key " ] . should . equal ( { " S " : " new_value " } )
item [ " main_key " ] . should . equal ( { " S " : " testkey1 " } )
2021-10-09 21:02:53 +00:00
@mock_dynamodb2
def test_gsi_key_cannot_be_empty ( ) :
name = " TestTable "
conn = boto3 . client ( " dynamodb " , region_name = " eu-west-2 " )
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " main_key " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [
{ " AttributeName " : " main_key " , " AttributeType " : " S " } ,
{ " AttributeName " : " index_key " , " AttributeType " : " S " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
GlobalSecondaryIndexes = [
{
" IndexName " : " test_index " ,
" KeySchema " : [ { " AttributeName " : " index_key " , " KeyType " : " HASH " } ] ,
" Projection " : { " ProjectionType " : " ALL " , } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 1 ,
" WriteCapacityUnits " : 1 ,
} ,
}
] ,
)
conn . put_item (
TableName = name ,
Item = {
" main_key " : { " S " : " testkey1 " } ,
" extra_data " : { " S " : " testdata " } ,
" index_key " : { " S " : " indexkey1 " } ,
} ,
)
with pytest . raises ( ClientError ) as ex :
conn . update_item (
TableName = name ,
Key = { " main_key " : { " S " : " testkey1 " } } ,
UpdateExpression = " set index_key=:new_index_key " ,
ExpressionAttributeValues = { " :new_index_key " : { " S " : " " } } ,
)
err = ex . value . response [ " Error " ]
err [ " Code " ] . should . equal ( " ValidationException " )
err [ " Message " ] . should . equal (
" One or more parameter values are not valid. The update expression attempted to update a secondary index key to a value that is not supported. The AttributeValue for a key attribute cannot contain an empty string value. "
)
2021-06-10 06:05:07 +00:00
@mock_dynamodb2
def test_create_backup_for_non_existent_table_raises_error ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
with pytest . raises ( ClientError ) as ex :
client . create_backup ( TableName = " non-existent " , BackupName = " backup " )
error = ex . value . response [ " Error " ]
error [ " Code " ] . should . equal ( " TableNotFoundException " )
error [ " Message " ] . should . equal ( " Table not found: non-existent " )
@mock_dynamodb2
def test_create_backup ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_name = " test-table "
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
backup_name = " backup-test-table "
resp = client . create_backup ( TableName = table_name , BackupName = backup_name )
details = resp . get ( " BackupDetails " )
details . should . have . key ( " BackupArn " ) . should . contain ( table_name )
details . should . have . key ( " BackupName " ) . should . equal ( backup_name )
details . should . have . key ( " BackupSizeBytes " ) . should . be . a ( int )
details . should . have . key ( " BackupStatus " )
details . should . have . key ( " BackupType " ) . should . equal ( " USER " )
details . should . have . key ( " BackupCreationDateTime " ) . should . be . a ( datetime )
@mock_dynamodb2
def test_create_multiple_backups_with_same_name ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_name = " test-table "
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
backup_name = " backup-test-table "
backup_arns = [ ]
2021-10-18 19:44:29 +00:00
for _ in range ( 4 ) :
2021-06-10 06:05:07 +00:00
backup = client . create_backup ( TableName = table_name , BackupName = backup_name ) . get (
" BackupDetails "
)
backup [ " BackupName " ] . should . equal ( backup_name )
backup_arns . should_not . contain ( backup [ " BackupArn " ] )
backup_arns . append ( backup [ " BackupArn " ] )
@mock_dynamodb2
def test_describe_backup_for_non_existent_backup_raises_error ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
non_existent_arn = " arn:aws:dynamodb:us-east-1:123456789012:table/table-name/backup/01623095754481-2cfcd6f9 "
with pytest . raises ( ClientError ) as ex :
client . describe_backup ( BackupArn = non_existent_arn )
error = ex . value . response [ " Error " ]
error [ " Code " ] . should . equal ( " BackupNotFoundException " )
error [ " Message " ] . should . equal ( " Backup not found: {} " . format ( non_existent_arn ) )
@mock_dynamodb2
def test_describe_backup ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_name = " test-table "
table = client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
) . get ( " TableDescription " )
backup_name = " backup-test-table "
backup_arn = (
client . create_backup ( TableName = table_name , BackupName = backup_name )
. get ( " BackupDetails " )
. get ( " BackupArn " )
)
resp = client . describe_backup ( BackupArn = backup_arn )
description = resp . get ( " BackupDescription " )
details = description . get ( " BackupDetails " )
details . should . have . key ( " BackupArn " ) . should . contain ( table_name )
details . should . have . key ( " BackupName " ) . should . equal ( backup_name )
details . should . have . key ( " BackupSizeBytes " ) . should . be . a ( int )
details . should . have . key ( " BackupStatus " )
details . should . have . key ( " BackupType " ) . should . equal ( " USER " )
details . should . have . key ( " BackupCreationDateTime " ) . should . be . a ( datetime )
source = description . get ( " SourceTableDetails " )
source . should . have . key ( " TableName " ) . should . equal ( table_name )
source . should . have . key ( " TableArn " ) . should . equal ( table [ " TableArn " ] )
source . should . have . key ( " TableSizeBytes " ) . should . be . a ( int )
source . should . have . key ( " KeySchema " ) . should . equal ( table [ " KeySchema " ] )
source . should . have . key ( " TableCreationDateTime " ) . should . equal (
table [ " CreationDateTime " ]
)
source . should . have . key ( " ProvisionedThroughput " ) . should . be . a ( dict )
source . should . have . key ( " ItemCount " ) . should . equal ( table [ " ItemCount " ] )
@mock_dynamodb2
def test_list_backups_for_non_existent_table ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
resp = client . list_backups ( TableName = " non-existent " )
resp [ " BackupSummaries " ] . should . have . length_of ( 0 )
@mock_dynamodb2
def test_list_backups ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_names = [ " test-table-1 " , " test-table-2 " ]
backup_names = [ " backup-1 " , " backup-2 " ]
for table_name in table_names :
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
for backup_name in backup_names :
client . create_backup ( TableName = table_name , BackupName = backup_name )
resp = client . list_backups ( BackupType = " USER " )
resp [ " BackupSummaries " ] . should . have . length_of ( 4 )
for table_name in table_names :
resp = client . list_backups ( TableName = table_name )
resp [ " BackupSummaries " ] . should . have . length_of ( 2 )
for summary in resp [ " BackupSummaries " ] :
summary . should . have . key ( " TableName " ) . should . equal ( table_name )
summary . should . have . key ( " TableArn " ) . should . contain ( table_name )
summary . should . have . key ( " BackupName " ) . should . be . within ( backup_names )
summary . should . have . key ( " BackupArn " )
summary . should . have . key ( " BackupCreationDateTime " ) . should . be . a ( datetime )
summary . should . have . key ( " BackupStatus " )
summary . should . have . key ( " BackupType " ) . should . be . within ( [ " USER " , " SYSTEM " ] )
summary . should . have . key ( " BackupSizeBytes " ) . should . be . a ( int )
@mock_dynamodb2
def test_restore_table_from_non_existent_backup_raises_error ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
non_existent_arn = " arn:aws:dynamodb:us-east-1:123456789012:table/table-name/backup/01623095754481-2cfcd6f9 "
with pytest . raises ( ClientError ) as ex :
client . restore_table_from_backup (
TargetTableName = " from-backup " , BackupArn = non_existent_arn
)
error = ex . value . response [ " Error " ]
error [ " Code " ] . should . equal ( " BackupNotFoundException " )
error [ " Message " ] . should . equal ( " Backup not found: {} " . format ( non_existent_arn ) )
@mock_dynamodb2
def test_restore_table_from_backup_raises_error_when_table_already_exists ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_name = " test-table "
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
resp = client . create_backup ( TableName = table_name , BackupName = " backup " )
backup = resp . get ( " BackupDetails " )
with pytest . raises ( ClientError ) as ex :
client . restore_table_from_backup (
TargetTableName = table_name , BackupArn = backup [ " BackupArn " ]
)
error = ex . value . response [ " Error " ]
error [ " Code " ] . should . equal ( " TableAlreadyExistsException " )
error [ " Message " ] . should . equal ( " Table already exists: {} " . format ( table_name ) )
@mock_dynamodb2
def test_restore_table_from_backup ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_name = " test-table "
resp = client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
table = resp . get ( " TableDescription " )
for i in range ( 5 ) :
client . put_item ( TableName = table_name , Item = { " id " : { " S " : " item %d " % i } } )
backup_arn = (
client . create_backup ( TableName = table_name , BackupName = " backup " )
. get ( " BackupDetails " )
. get ( " BackupArn " )
)
restored_table_name = " restored-from-backup "
restored = client . restore_table_from_backup (
TargetTableName = restored_table_name , BackupArn = backup_arn
) . get ( " TableDescription " )
restored . should . have . key ( " AttributeDefinitions " ) . should . equal (
table [ " AttributeDefinitions " ]
)
restored . should . have . key ( " TableName " ) . should . equal ( restored_table_name )
restored . should . have . key ( " KeySchema " ) . should . equal ( table [ " KeySchema " ] )
restored . should . have . key ( " TableStatus " )
restored . should . have . key ( " ItemCount " ) . should . equal ( 5 )
restored . should . have . key ( " TableArn " ) . should . contain ( restored_table_name )
restored . should . have . key ( " RestoreSummary " ) . should . be . a ( dict )
summary = restored . get ( " RestoreSummary " )
summary . should . have . key ( " SourceBackupArn " ) . should . equal ( backup_arn )
summary . should . have . key ( " SourceTableArn " ) . should . equal ( table [ " TableArn " ] )
summary . should . have . key ( " RestoreDateTime " ) . should . be . a ( datetime )
summary . should . have . key ( " RestoreInProgress " ) . should . equal ( False )
@mock_dynamodb2
def test_delete_non_existent_backup_raises_error ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
non_existent_arn = " arn:aws:dynamodb:us-east-1:123456789012:table/table-name/backup/01623095754481-2cfcd6f9 "
with pytest . raises ( ClientError ) as ex :
client . delete_backup ( BackupArn = non_existent_arn )
error = ex . value . response [ " Error " ]
error [ " Code " ] . should . equal ( " BackupNotFoundException " )
error [ " Message " ] . should . equal ( " Backup not found: {} " . format ( non_existent_arn ) )
@mock_dynamodb2
def test_delete_backup ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
table_name = " test-table-1 "
backup_names = [ " backup-1 " , " backup-2 " ]
client . create_table (
TableName = table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
for backup_name in backup_names :
client . create_backup ( TableName = table_name , BackupName = backup_name )
resp = client . list_backups ( TableName = table_name , BackupType = " USER " )
resp [ " BackupSummaries " ] . should . have . length_of ( 2 )
backup_to_delete = resp [ " BackupSummaries " ] [ 0 ] [ " BackupArn " ]
backup_deleted = client . delete_backup ( BackupArn = backup_to_delete ) . get (
" BackupDescription "
)
backup_deleted . should . have . key ( " SourceTableDetails " )
backup_deleted . should . have . key ( " BackupDetails " )
details = backup_deleted [ " BackupDetails " ]
details . should . have . key ( " BackupArn " ) . should . equal ( backup_to_delete )
details . should . have . key ( " BackupName " ) . should . be . within ( backup_names )
details . should . have . key ( " BackupStatus " ) . should . equal ( " DELETED " )
resp = client . list_backups ( TableName = table_name , BackupType = " USER " )
resp [ " BackupSummaries " ] . should . have . length_of ( 1 )
@mock_dynamodb2
def test_source_and_restored_table_items_are_not_linked ( ) :
client = boto3 . client ( " dynamodb " , " us-east-1 " )
def add_guids_to_table ( table , num_items ) :
guids = [ ]
2021-10-18 19:44:29 +00:00
for _ in range ( num_items ) :
2021-06-10 06:05:07 +00:00
guid = str ( uuid . uuid4 ( ) )
client . put_item ( TableName = table , Item = { " id " : { " S " : guid } } )
guids . append ( guid )
return guids
source_table_name = " source-table "
client . create_table (
TableName = source_table_name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
guids_original = add_guids_to_table ( source_table_name , 5 )
backup_arn = (
client . create_backup ( TableName = source_table_name , BackupName = " backup " )
. get ( " BackupDetails " )
. get ( " BackupArn " )
)
guids_added_after_backup = add_guids_to_table ( source_table_name , 5 )
restored_table_name = " restored-from-backup "
client . restore_table_from_backup (
TargetTableName = restored_table_name , BackupArn = backup_arn
)
guids_added_after_restore = add_guids_to_table ( restored_table_name , 5 )
source_table_items = client . scan ( TableName = source_table_name )
source_table_items . should . have . key ( " Count " ) . should . equal ( 10 )
source_table_guids = [ x [ " id " ] [ " S " ] for x in source_table_items [ " Items " ] ]
set ( source_table_guids ) . should . equal (
set ( guids_original ) | set ( guids_added_after_backup )
)
restored_table_items = client . scan ( TableName = restored_table_name )
restored_table_items . should . have . key ( " Count " ) . should . equal ( 10 )
restored_table_guids = [ x [ " id " ] [ " S " ] for x in restored_table_items [ " Items " ] ]
set ( restored_table_guids ) . should . equal (
set ( guids_original ) | set ( guids_added_after_restore )
)
2021-08-28 06:25:06 +00:00
@mock_dynamodb2
@pytest.mark.parametrize ( " region " , [ " eu-central-1 " , " ap-south-1 " ] )
def test_describe_endpoints ( region ) :
client = boto3 . client ( " dynamodb " , region )
res = client . describe_endpoints ( ) [ " Endpoints " ]
res . should . equal (
[
{
" Address " : " dynamodb. {} .amazonaws.com " . format ( region ) ,
" CachePeriodInMinutes " : 1440 ,
} ,
]
)
2021-08-28 08:38:12 +00:00
@mock_dynamodb2
def test_update_non_existing_item_raises_error_and_does_not_contain_item_afterwards ( ) :
"""
https : / / github . com / spulec / moto / issues / 3729
Exception is raised , but item was persisted anyway
Happened because we would create a placeholder , before validating / executing the UpdateExpression
: return :
"""
name = " TestTable "
conn = boto3 . client ( " dynamodb " , region_name = " us-west-2 " )
hkey = " primary_partition_key "
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : hkey , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : hkey , " AttributeType " : " S " } ] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
)
update_expression = {
" Key " : { hkey : " some_identification_string " } ,
" UpdateExpression " : " set #AA.#AB = :aa " ,
" ExpressionAttributeValues " : { " :aa " : " abc " } ,
" ExpressionAttributeNames " : { " #AA " : " some_dict " , " #AB " : " key1 " } ,
" ConditionExpression " : " attribute_not_exists(#AA.#AB) " ,
}
table = boto3 . resource ( " dynamodb " , region_name = " us-west-2 " ) . Table ( name )
with pytest . raises ( ClientError ) as err :
table . update_item ( * * update_expression )
err . value . response [ " Error " ] [ " Code " ] . should . equal ( " ValidationException " )
conn . scan ( TableName = name ) [ " Items " ] . should . have . length_of ( 0 )
2021-10-13 09:52:29 +00:00
@mock_dynamodb2
def test_batch_write_item ( ) :
conn = boto3 . resource ( " dynamodb " , region_name = " us-west-2 " )
tables = [ f " table- { i } " for i in range ( 3 ) ]
for name in tables :
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " id " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [ { " AttributeName " : " id " , " AttributeType " : " S " } ] ,
BillingMode = " PAY_PER_REQUEST " ,
)
conn . batch_write_item (
RequestItems = {
tables [ 0 ] : [ { " PutRequest " : { " Item " : { " id " : " 0 " } } } ] ,
tables [ 1 ] : [ { " PutRequest " : { " Item " : { " id " : " 1 " } } } ] ,
tables [ 2 ] : [ { " PutRequest " : { " Item " : { " id " : " 2 " } } } ] ,
}
)
for idx , name in enumerate ( tables ) :
table = conn . Table ( f " table- { idx } " )
res = table . get_item ( Key = { " id " : str ( idx ) } )
assert res [ " Item " ] . should . equal ( { " id " : str ( idx ) } )
scan = table . scan ( )
assert scan [ " Count " ] . should . equal ( 1 )
conn . batch_write_item (
RequestItems = {
tables [ 0 ] : [ { " DeleteRequest " : { " Key " : { " id " : " 0 " } } } ] ,
tables [ 1 ] : [ { " DeleteRequest " : { " Key " : { " id " : " 1 " } } } ] ,
tables [ 2 ] : [ { " DeleteRequest " : { " Key " : { " id " : " 2 " } } } ] ,
}
)
for idx , name in enumerate ( tables ) :
table = conn . Table ( f " table- { idx } " )
scan = table . scan ( )
assert scan [ " Count " ] . should . equal ( 0 )
2021-10-28 10:10:11 +00:00
@mock_dynamodb2
def test_gsi_lastevaluatedkey ( ) :
# github.com/spulec/moto/issues/3968
conn = boto3 . resource ( " dynamodb " , region_name = " us-west-2 " )
name = " test-table "
table = conn . Table ( name )
conn . create_table (
TableName = name ,
KeySchema = [ { " AttributeName " : " main_key " , " KeyType " : " HASH " } ] ,
AttributeDefinitions = [
{ " AttributeName " : " main_key " , " AttributeType " : " S " } ,
{ " AttributeName " : " index_key " , " AttributeType " : " S " } ,
] ,
ProvisionedThroughput = { " ReadCapacityUnits " : 5 , " WriteCapacityUnits " : 5 } ,
GlobalSecondaryIndexes = [
{
" IndexName " : " test_index " ,
" KeySchema " : [ { " AttributeName " : " index_key " , " KeyType " : " HASH " } ] ,
" Projection " : { " ProjectionType " : " ALL " , } ,
" ProvisionedThroughput " : {
" ReadCapacityUnits " : 1 ,
" WriteCapacityUnits " : 1 ,
} ,
}
] ,
)
table . put_item (
Item = {
" main_key " : " testkey1 " ,
" extra_data " : " testdata " ,
" index_key " : " indexkey " ,
} ,
)
table . put_item (
Item = {
" main_key " : " testkey2 " ,
" extra_data " : " testdata " ,
" index_key " : " indexkey " ,
} ,
)
response = table . query (
Limit = 1 ,
KeyConditionExpression = Key ( " index_key " ) . eq ( " indexkey " ) ,
IndexName = " test_index " ,
)
items = response [ " Items " ]
items . should . have . length_of ( 1 )
items [ 0 ] . should . equal (
{ " main_key " : " testkey1 " , " extra_data " : " testdata " , " index_key " : " indexkey " }
)
last_evaluated_key = response [ " LastEvaluatedKey " ]
last_evaluated_key . should . have . length_of ( 2 )
last_evaluated_key . should . equal ( { " main_key " : " testkey1 " , " index_key " : " indexkey " } )