python-boto3/tests/integration/test_dynamodb.py
2021-11-03 10:27:47 -07:00

223 lines
8.3 KiB
Python

# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"). You
# may not use this file except in compliance with the License. A copy of
# the License is located at
#
# https://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
from decimal import Decimal
import boto3.session
from boto3.compat import collections_abc
from boto3.dynamodb.types import Binary
from boto3.dynamodb.conditions import Attr, Key
from tests import unittest, unique_id
class BaseDynamoDBTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.session = boto3.session.Session(region_name='us-west-2')
cls.dynamodb = cls.session.resource('dynamodb')
cls.table_name = unique_id('boto3db')
cls.item_data = {
'MyHashKey': 'mykey',
'MyNull': None,
'MyBool': True,
'MyString': 'mystring',
'MyNumber': Decimal('1.25'),
'MyBinary': Binary(b'\x01'),
'MyStringSet': set(['foo']),
'MyNumberSet': set([Decimal('1.25')]),
'MyBinarySet': set([Binary(b'\x01')]),
'MyList': ['foo'],
'MyMap': {'foo': 'bar'}
}
cls.table = cls.dynamodb.create_table(
TableName=cls.table_name,
ProvisionedThroughput={"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5},
KeySchema=[{"AttributeName": "MyHashKey", "KeyType": "HASH"}],
AttributeDefinitions=[{"AttributeName": "MyHashKey",
"AttributeType": "S"}])
waiter = cls.dynamodb.meta.client.get_waiter('table_exists')
waiter.wait(TableName=cls.table_name)
@classmethod
def tearDownClass(cls):
cls.table.delete()
class TestDynamoDBTypes(BaseDynamoDBTest):
def test_put_get_item(self):
self.table.put_item(Item=self.item_data)
self.addCleanup(self.table.delete_item, Key={'MyHashKey': 'mykey'})
response = self.table.get_item(Key={'MyHashKey': 'mykey'},
ConsistentRead=True)
self.assertEqual(response['Item'], self.item_data)
class TestDynamoDBConditions(BaseDynamoDBTest):
@classmethod
def setUpClass(cls):
super(TestDynamoDBConditions, cls).setUpClass()
cls.table.put_item(Item=cls.item_data)
@classmethod
def tearDownClass(cls):
cls.table.delete_item(Key={'MyHashKey': 'mykey'})
super(TestDynamoDBConditions, cls).tearDownClass()
def scan(self, filter_expression):
return self.table.scan(FilterExpression=filter_expression,
ConsistentRead=True)
def query(self, key_condition_expression, filter_expression=None):
kwargs = {
'KeyConditionExpression': key_condition_expression,
'ConsistentRead': True
}
if filter_expression is not None:
kwargs['FilterExpression'] = filter_expression
return self.table.query(**kwargs)
def test_filter_expression(self):
r = self.scan(
filter_expression=Attr('MyHashKey').eq('mykey'))
self.assertEqual(r['Items'][0]['MyHashKey'], 'mykey')
def test_key_condition_expression(self):
r = self.query(
key_condition_expression=Key('MyHashKey').eq('mykey'))
self.assertEqual(r['Items'][0]['MyHashKey'], 'mykey')
def test_key_condition_with_filter_condition_expression(self):
r = self.query(
key_condition_expression=Key('MyHashKey').eq('mykey'),
filter_expression=Attr('MyString').eq('mystring'))
self.assertEqual(r['Items'][0]['MyString'], 'mystring')
def test_condition_less_than(self):
r = self.scan(
filter_expression=Attr('MyNumber').lt(Decimal('1.26')))
self.assertTrue(r['Items'][0]['MyNumber'] < Decimal('1.26'))
def test_condition_less_than_equal(self):
r = self.scan(
filter_expression=Attr('MyNumber').lte(Decimal('1.26')))
self.assertTrue(r['Items'][0]['MyNumber'] <= Decimal('1.26'))
def test_condition_greater_than(self):
r = self.scan(
filter_expression=Attr('MyNumber').gt(Decimal('1.24')))
self.assertTrue(r['Items'][0]['MyNumber'] > Decimal('1.24'))
def test_condition_greater_than_equal(self):
r = self.scan(
filter_expression=Attr('MyNumber').gte(Decimal('1.24')))
self.assertTrue(r['Items'][0]['MyNumber'] >= Decimal('1.24'))
def test_condition_begins_with(self):
r = self.scan(
filter_expression=Attr('MyString').begins_with('my'))
self.assertTrue(r['Items'][0]['MyString'].startswith('my'))
def test_condition_between(self):
r = self.scan(
filter_expression=Attr('MyNumber').between(
Decimal('1.24'), Decimal('1.26')))
self.assertTrue(r['Items'][0]['MyNumber'] > Decimal('1.24'))
self.assertTrue(r['Items'][0]['MyNumber'] < Decimal('1.26'))
def test_condition_not_equal(self):
r = self.scan(
filter_expression=Attr('MyHashKey').ne('notmykey'))
self.assertNotEqual(r['Items'][0]['MyHashKey'], 'notmykey')
def test_condition_in(self):
r = self.scan(
filter_expression=Attr('MyHashKey').is_in(['notmykey', 'mykey']))
self.assertIn(r['Items'][0]['MyHashKey'], ['notmykey', 'mykey'])
def test_condition_exists(self):
r = self.scan(
filter_expression=Attr('MyString').exists())
self.assertIn('MyString', r['Items'][0])
def test_condition_not_exists(self):
r = self.scan(
filter_expression=Attr('MyFakeKey').not_exists())
self.assertNotIn('MyFakeKey', r['Items'][0])
def test_condition_contains(self):
r = self.scan(
filter_expression=Attr('MyString').contains('my'))
self.assertIn('my', r['Items'][0]['MyString'])
def test_condition_size(self):
r = self.scan(
filter_expression=Attr('MyString').size().eq(len('mystring')))
self.assertEqual(len(r['Items'][0]['MyString']), len('mystring'))
def test_condition_attribute_type(self):
r = self.scan(
filter_expression=Attr('MyMap').attribute_type('M'))
self.assertIsInstance(r['Items'][0]['MyMap'], collections_abc.Mapping)
def test_condition_and(self):
r = self.scan(
filter_expression=(
Attr('MyHashKey').eq('mykey') & Attr('MyString').eq('mystring')
)
)
item = r['Items'][0]
self.assertTrue(
item['MyHashKey'] == 'mykey' and item['MyString'] == 'mystring')
def test_condition_or(self):
r = self.scan(
filter_expression=(
Attr('MyHashKey').eq('mykey2') | Attr('MyString').eq('mystring')
)
)
item = r['Items'][0]
self.assertTrue(
item['MyHashKey'] == 'mykey2' or item['MyString'] == 'mystring')
def test_condition_not(self):
r = self.scan(
filter_expression=(~Attr('MyHashKey').eq('mykey2')))
item = r['Items'][0]
self.assertTrue(item['MyHashKey'] != 'mykey2')
def test_condition_in_map(self):
r = self.scan(
filter_expression=Attr('MyMap.foo').eq('bar'))
self.assertEqual(r['Items'][0]['MyMap']['foo'], 'bar')
def test_condition_in_list(self):
r = self.scan(
filter_expression=Attr('MyList[0]').eq('foo'))
self.assertEqual(r['Items'][0]['MyList'][0], 'foo')
class TestDynamodbBatchWrite(BaseDynamoDBTest):
def test_batch_write_items(self):
num_elements = 1000
items = []
for i in range(num_elements):
items.append({'MyHashKey': 'foo%s' % i,
'OtherKey': 'bar%s' % i})
with self.table.batch_writer() as batch:
for item in items:
batch.put_item(Item=item)
# Verify all the items were added to dynamodb.
for obj in self.table.scan(ConsistentRead=True)['Items']:
self.assertIn(obj, items)