Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(12)

Unified Diff: third_party/gsutil/third_party/boto/tests/integration/dynamodb2/test_highlevel.py

Issue 1377933002: [catapult] - Copy Telemetry's gsutilz over to third_party. (Closed) Base URL: https://github.com/catapult-project/catapult.git@master
Patch Set: Rename to gsutil. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/gsutil/third_party/boto/tests/integration/dynamodb2/test_highlevel.py
diff --git a/third_party/gsutil/third_party/boto/tests/integration/dynamodb2/test_highlevel.py b/third_party/gsutil/third_party/boto/tests/integration/dynamodb2/test_highlevel.py
new file mode 100644
index 0000000000000000000000000000000000000000..833400783ee98aad066494e6302dc4fa36468b55
--- /dev/null
+++ b/third_party/gsutil/third_party/boto/tests/integration/dynamodb2/test_highlevel.py
@@ -0,0 +1,821 @@
+# Copyright (c) 2013 Amazon.com, Inc. or its affiliates.
+# All rights reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish, dis-
+# tribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to the fol-
+# lowing conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
+# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+
+"""
+Tests for DynamoDB v2 high-level abstractions.
+"""
+import os
+import time
+
+from tests.unit import unittest
+from boto.dynamodb2 import exceptions
+from boto.dynamodb2.fields import (HashKey, RangeKey, KeysOnlyIndex,
+ GlobalKeysOnlyIndex, GlobalIncludeIndex,
+ GlobalAllIndex)
+from boto.dynamodb2.items import Item
+from boto.dynamodb2.table import Table
+from boto.dynamodb2.types import NUMBER, STRING
+
+try:
+ import json
+except ImportError:
+ import simplejson as json
+
+
+class DynamoDBv2Test(unittest.TestCase):
+ dynamodb = True
+
+ def test_integration(self):
+ # Test creating a full table with all options specified.
+ users = Table.create('users', schema=[
+ HashKey('username'),
+ RangeKey('friend_count', data_type=NUMBER)
+ ], throughput={
+ 'read': 5,
+ 'write': 5,
+ }, indexes=[
+ KeysOnlyIndex('LastNameIndex', parts=[
+ HashKey('username'),
+ RangeKey('last_name')
+ ]),
+ ])
+ self.addCleanup(users.delete)
+
+ self.assertEqual(len(users.schema), 2)
+ self.assertEqual(users.throughput['read'], 5)
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Make sure things line up if we're introspecting the table.
+ users_hit_api = Table('users')
+ users_hit_api.describe()
+ self.assertEqual(len(users.schema), len(users_hit_api.schema))
+ self.assertEqual(users.throughput, users_hit_api.throughput)
+ self.assertEqual(len(users.indexes), len(users_hit_api.indexes))
+
+ # Test putting some items individually.
+ users.put_item(data={
+ 'username': 'johndoe',
+ 'first_name': 'John',
+ 'last_name': 'Doe',
+ 'friend_count': 4
+ })
+
+ users.put_item(data={
+ 'username': 'alice',
+ 'first_name': 'Alice',
+ 'last_name': 'Expert',
+ 'friend_count': 2
+ })
+
+ time.sleep(5)
+
+ # Test batch writing.
+ with users.batch_write() as batch:
+ batch.put_item({
+ 'username': 'jane',
+ 'first_name': 'Jane',
+ 'last_name': 'Doe',
+ 'friend_count': 3
+ })
+ batch.delete_item(username='alice', friend_count=2)
+ batch.put_item({
+ 'username': 'bob',
+ 'first_name': 'Bob',
+ 'last_name': 'Smith',
+ 'friend_count': 1
+ })
+
+ time.sleep(5)
+
+ # Does it exist? It should?
+ self.assertTrue(users.has_item(username='jane', friend_count=3))
+ # But this shouldn't be there...
+ self.assertFalse(users.has_item(
+ username='mrcarmichaeljones',
+ friend_count=72948
+ ))
+
+ # Test getting an item & updating it.
+ # This is the "safe" variant (only write if there have been no
+ # changes).
+ jane = users.get_item(username='jane', friend_count=3)
+ self.assertEqual(jane['first_name'], 'Jane')
+ jane['last_name'] = 'Doh'
+ self.assertTrue(jane.save())
+
+ # Test strongly consistent getting of an item.
+ # Additionally, test the overwrite behavior.
+ client_1_jane = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ self.assertEqual(jane['first_name'], 'Jane')
+ client_2_jane = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ self.assertEqual(jane['first_name'], 'Jane')
+
+ # Write & assert the ``first_name`` is gone, then...
+ del client_1_jane['first_name']
+ self.assertTrue(client_1_jane.save())
+ check_name = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ self.assertEqual(check_name['first_name'], None)
+
+ # ...overwrite the data with what's in memory.
+ client_2_jane['first_name'] = 'Joan'
+ # Now a write that fails due to default expectations...
+ self.assertRaises(exceptions.JSONResponseError, client_2_jane.save)
+ # ... so we force an overwrite.
+ self.assertTrue(client_2_jane.save(overwrite=True))
+ check_name_again = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ self.assertEqual(check_name_again['first_name'], 'Joan')
+
+ # Reset it.
+ jane['username'] = 'jane'
+ jane['first_name'] = 'Jane'
+ jane['last_name'] = 'Doe'
+ jane['friend_count'] = 3
+ self.assertTrue(jane.save(overwrite=True))
+
+ # Test the partial update behavior.
+ client_3_jane = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ client_4_jane = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ client_3_jane['favorite_band'] = 'Feed Me'
+ # No ``overwrite`` needed due to new data.
+ self.assertTrue(client_3_jane.save())
+ # Expectations are only checked on the ``first_name``, so what wouldn't
+ # have succeeded by default does succeed here.
+ client_4_jane['first_name'] = 'Jacqueline'
+ self.assertTrue(client_4_jane.partial_save())
+ partial_jane = users.get_item(
+ username='jane',
+ friend_count=3,
+ consistent=True
+ )
+ self.assertEqual(partial_jane['favorite_band'], 'Feed Me')
+ self.assertEqual(partial_jane['first_name'], 'Jacqueline')
+
+ # Reset it.
+ jane['username'] = 'jane'
+ jane['first_name'] = 'Jane'
+ jane['last_name'] = 'Doe'
+ jane['friend_count'] = 3
+ self.assertTrue(jane.save(overwrite=True))
+
+ # Ensure that partial saves of a brand-new object work.
+ sadie = Item(users, data={
+ 'username': 'sadie',
+ 'first_name': 'Sadie',
+ 'favorite_band': 'Zedd',
+ 'friend_count': 7
+ })
+ self.assertTrue(sadie.partial_save())
+ serverside_sadie = users.get_item(
+ username='sadie',
+ friend_count=7,
+ consistent=True
+ )
+ self.assertEqual(serverside_sadie['first_name'], 'Sadie')
+
+ # Test the eventually consistent query.
+ results = users.query_2(
+ username__eq='johndoe',
+ last_name__eq='Doe',
+ index='LastNameIndex',
+ attributes=('username',),
+ reverse=True
+ )
+
+ for res in results:
+ self.assertTrue(res['username'] in ['johndoe',])
+ self.assertEqual(list(res.keys()), ['username'])
+
+ # Ensure that queries with attributes don't return the hash key.
+ results = users.query_2(
+ username__eq='johndoe',
+ friend_count__eq=4,
+ attributes=('first_name',)
+ )
+
+ for res in results:
+ self.assertEqual(res['first_name'], 'John')
+ self.assertEqual(list(res.keys()), ['first_name'])
+
+ # Test the strongly consistent query.
+ c_results = users.query_2(
+ username__eq='johndoe',
+ last_name__eq='Doe',
+ index='LastNameIndex',
+ reverse=True,
+ consistent=True
+ )
+
+ for res in c_results:
+ self.assertEqual(res['username'], 'johndoe')
+
+ # Test a query with query filters
+ results = users.query_2(
+ username__eq='johndoe',
+ query_filter={
+ 'first_name__beginswith': 'J'
+ },
+ attributes=('first_name',)
+ )
+
+ for res in results:
+ self.assertTrue(res['first_name'] in ['John'])
+
+ # Test scans without filters.
+ all_users = users.scan(limit=7)
+ self.assertEqual(next(all_users)['username'], 'bob')
+ self.assertEqual(next(all_users)['username'], 'jane')
+ self.assertEqual(next(all_users)['username'], 'johndoe')
+
+ # Test scans with a filter.
+ filtered_users = users.scan(limit=2, username__beginswith='j')
+ self.assertEqual(next(filtered_users)['username'], 'jane')
+ self.assertEqual(next(filtered_users)['username'], 'johndoe')
+
+ # Test deleting a single item.
+ johndoe = users.get_item(username='johndoe', friend_count=4)
+ johndoe.delete()
+
+ # Set batch get limit to ensure keys with no results are
+ # handled correctly.
+ users.max_batch_get = 2
+
+ # Test the eventually consistent batch get.
+ results = users.batch_get(keys=[
+ {'username': 'noone', 'friend_count': 4},
+ {'username': 'nothere', 'friend_count': 10},
+ {'username': 'bob', 'friend_count': 1},
+ {'username': 'jane', 'friend_count': 3}
+ ])
+ batch_users = []
+
+ for res in results:
+ batch_users.append(res)
+ self.assertIn(res['first_name'], ['Bob', 'Jane'])
+
+ self.assertEqual(len(batch_users), 2)
+
+ # Test the strongly consistent batch get.
+ c_results = users.batch_get(keys=[
+ {'username': 'bob', 'friend_count': 1},
+ {'username': 'jane', 'friend_count': 3}
+ ], consistent=True)
+ c_batch_users = []
+
+ for res in c_results:
+ c_batch_users.append(res)
+ self.assertTrue(res['first_name'] in ['Bob', 'Jane'])
+
+ self.assertEqual(len(c_batch_users), 2)
+
+ # Test count, but in a weak fashion. Because lag time.
+ self.assertTrue(users.count() > -1)
+
+ # Test query count
+ count = users.query_count(
+ username__eq='bob',
+ )
+
+ self.assertEqual(count, 1)
+
+ # Test without LSIs (describe calls shouldn't fail).
+ admins = Table.create('admins', schema=[
+ HashKey('username')
+ ])
+ self.addCleanup(admins.delete)
+ time.sleep(60)
+ admins.describe()
+ self.assertEqual(admins.throughput['read'], 5)
+ self.assertEqual(admins.indexes, [])
+
+ # A single query term should fail on a table with *ONLY* a HashKey.
+ self.assertRaises(
+ exceptions.QueryError,
+ admins.query,
+ username__eq='johndoe'
+ )
+ # But it shouldn't break on more complex tables.
+ res = users.query_2(username__eq='johndoe')
+
+ # Test putting with/without sets.
+ mau5_created = users.put_item(data={
+ 'username': 'mau5',
+ 'first_name': 'dead',
+ 'last_name': 'mau5',
+ 'friend_count': 2,
+ 'friends': set(['skrill', 'penny']),
+ })
+ self.assertTrue(mau5_created)
+
+ penny_created = users.put_item(data={
+ 'username': 'penny',
+ 'first_name': 'Penny',
+ 'friend_count': 0,
+ 'friends': set([]),
+ })
+ self.assertTrue(penny_created)
+
+ # Test attributes.
+ mau5 = users.get_item(
+ username='mau5',
+ friend_count=2,
+ attributes=['username', 'first_name']
+ )
+ self.assertEqual(mau5['username'], 'mau5')
+ self.assertEqual(mau5['first_name'], 'dead')
+ self.assertTrue('last_name' not in mau5)
+
+ def test_unprocessed_batch_writes(self):
+ # Create a very limited table w/ low throughput.
+ users = Table.create('slow_users', schema=[
+ HashKey('user_id'),
+ ], throughput={
+ 'read': 1,
+ 'write': 1,
+ })
+ self.addCleanup(users.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ with users.batch_write() as batch:
+ for i in range(500):
+ batch.put_item(data={
+ 'user_id': str(i),
+ 'name': 'Droid #{0}'.format(i),
+ })
+
+ # Before ``__exit__`` runs, we should have a bunch of unprocessed
+ # items.
+ self.assertTrue(len(batch._unprocessed) > 0)
+
+ # Post-__exit__, they should all be gone.
+ self.assertEqual(len(batch._unprocessed), 0)
+
+ def test_gsi(self):
+ users = Table.create('gsi_users', schema=[
+ HashKey('user_id'),
+ ], throughput={
+ 'read': 5,
+ 'write': 3,
+ },
+ global_indexes=[
+ GlobalKeysOnlyIndex('StuffIndex', parts=[
+ HashKey('user_id')
+ ], throughput={
+ 'read': 2,
+ 'write': 1,
+ }),
+ ])
+ self.addCleanup(users.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ users.update(
+ throughput={
+ 'read': 3,
+ 'write': 4
+ },
+ global_indexes={
+ 'StuffIndex': {
+ 'read': 1,
+ 'write': 2
+ }
+ }
+ )
+
+ # Wait again for the changes to finish propagating.
+ time.sleep(150)
+
+ def test_gsi_with_just_hash_key(self):
+ # GSI allows for querying off of different keys. This is behavior we
+ # previously disallowed (due to standard & LSI queries).
+ # See https://forums.aws.amazon.com/thread.jspa?threadID=146212&tstart=0
+ users = Table.create('gsi_query_users', schema=[
+ HashKey('user_id')
+ ], throughput={
+ 'read': 5,
+ 'write': 3,
+ },
+ global_indexes=[
+ GlobalIncludeIndex('UsernameIndex', parts=[
+ HashKey('username'),
+ ], includes=['user_id', 'username'], throughput={
+ 'read': 3,
+ 'write': 1,
+ })
+ ])
+ self.addCleanup(users.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ users.put_item(data={
+ 'user_id': '7',
+ 'username': 'johndoe',
+ 'first_name': 'John',
+ 'last_name': 'Doe',
+ })
+ users.put_item(data={
+ 'user_id': '24',
+ 'username': 'alice',
+ 'first_name': 'Alice',
+ 'last_name': 'Expert',
+ })
+ users.put_item(data={
+ 'user_id': '35',
+ 'username': 'jane',
+ 'first_name': 'Jane',
+ 'last_name': 'Doe',
+ })
+
+ # Try the main key. Should be fine.
+ rs = users.query_2(
+ user_id__eq='24'
+ )
+ results = sorted([user['username'] for user in rs])
+ self.assertEqual(results, ['alice'])
+
+ # Now try the GSI. Also should work.
+ rs = users.query_2(
+ username__eq='johndoe',
+ index='UsernameIndex'
+ )
+ results = sorted([user['username'] for user in rs])
+ self.assertEqual(results, ['johndoe'])
+
+ def test_query_with_limits(self):
+ # Per the DDB team, it's recommended to do many smaller gets with a
+ # reduced page size.
+ # Clamp down the page size while ensuring that the correct number of
+ # results are still returned.
+ posts = Table.create('posts', schema=[
+ HashKey('thread'),
+ RangeKey('posted_on')
+ ], throughput={
+ 'read': 5,
+ 'write': 5,
+ })
+ self.addCleanup(posts.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Add some data.
+ test_data_path = os.path.join(
+ os.path.dirname(__file__),
+ 'forum_test_data.json'
+ )
+ with open(test_data_path, 'r') as test_data:
+ data = json.load(test_data)
+
+ with posts.batch_write() as batch:
+ for post in data:
+ batch.put_item(post)
+
+ time.sleep(5)
+
+ # Test the reduced page size.
+ results = posts.query_2(
+ thread__eq='Favorite chiptune band?',
+ posted_on__gte='2013-12-24T00:00:00',
+ max_page_size=2
+ )
+
+ all_posts = list(results)
+ self.assertEqual(
+ [post['posted_by'] for post in all_posts],
+ ['joe', 'jane', 'joe', 'joe', 'jane', 'joe']
+ )
+ self.assertTrue(results._fetches >= 3)
+
+ def test_query_with_reverse(self):
+ posts = Table.create('more-posts', schema=[
+ HashKey('thread'),
+ RangeKey('posted_on')
+ ], throughput={
+ 'read': 5,
+ 'write': 5,
+ })
+ self.addCleanup(posts.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Add some data.
+ test_data_path = os.path.join(
+ os.path.dirname(__file__),
+ 'forum_test_data.json'
+ )
+ with open(test_data_path, 'r') as test_data:
+ data = json.load(test_data)
+
+ with posts.batch_write() as batch:
+ for post in data:
+ batch.put_item(post)
+
+ time.sleep(5)
+
+ # Test the default order (ascending).
+ results = posts.query_2(
+ thread__eq='Favorite chiptune band?',
+ posted_on__gte='2013-12-24T00:00:00'
+ )
+ self.assertEqual(
+ [post['posted_on'] for post in results],
+ [
+ '2013-12-24T12:30:54',
+ '2013-12-24T12:35:40',
+ '2013-12-24T13:45:30',
+ '2013-12-24T14:15:14',
+ '2013-12-24T14:25:33',
+ '2013-12-24T15:22:22',
+ ]
+ )
+
+ # Test the explicit ascending order.
+ results = posts.query_2(
+ thread__eq='Favorite chiptune band?',
+ posted_on__gte='2013-12-24T00:00:00',
+ reverse=False
+ )
+ self.assertEqual(
+ [post['posted_on'] for post in results],
+ [
+ '2013-12-24T12:30:54',
+ '2013-12-24T12:35:40',
+ '2013-12-24T13:45:30',
+ '2013-12-24T14:15:14',
+ '2013-12-24T14:25:33',
+ '2013-12-24T15:22:22',
+ ]
+ )
+
+ # Test the explicit descending order.
+ results = posts.query_2(
+ thread__eq='Favorite chiptune band?',
+ posted_on__gte='2013-12-24T00:00:00',
+ reverse=True
+ )
+ self.assertEqual(
+ [post['posted_on'] for post in results],
+ [
+ '2013-12-24T15:22:22',
+ '2013-12-24T14:25:33',
+ '2013-12-24T14:15:14',
+ '2013-12-24T13:45:30',
+ '2013-12-24T12:35:40',
+ '2013-12-24T12:30:54',
+ ]
+ )
+
+ # Test the old, broken style.
+ results = posts.query(
+ thread__eq='Favorite chiptune band?',
+ posted_on__gte='2013-12-24T00:00:00'
+ )
+ self.assertEqual(
+ [post['posted_on'] for post in results],
+ [
+ '2013-12-24T15:22:22',
+ '2013-12-24T14:25:33',
+ '2013-12-24T14:15:14',
+ '2013-12-24T13:45:30',
+ '2013-12-24T12:35:40',
+ '2013-12-24T12:30:54',
+ ]
+ )
+ results = posts.query(
+ thread__eq='Favorite chiptune band?',
+ posted_on__gte='2013-12-24T00:00:00',
+ reverse=True
+ )
+ self.assertEqual(
+ [post['posted_on'] for post in results],
+ [
+ '2013-12-24T12:30:54',
+ '2013-12-24T12:35:40',
+ '2013-12-24T13:45:30',
+ '2013-12-24T14:15:14',
+ '2013-12-24T14:25:33',
+ '2013-12-24T15:22:22',
+ ]
+ )
+
+ def test_query_after_describe_with_gsi(self):
+ # Create a table to using gsi to reproduce the error mentioned on issue
+ # https://github.com/boto/boto/issues/2828
+ users = Table.create('more_gsi_query_users', schema=[
+ HashKey('user_id')
+ ], throughput={
+ 'read': 5,
+ 'write': 5
+ }, global_indexes=[
+ GlobalAllIndex('EmailGSIIndex', parts=[
+ HashKey('email')
+ ], throughput={
+ 'read': 1,
+ 'write': 1
+ })
+ ])
+
+ # Add this function to be called after tearDown()
+ self.addCleanup(users.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ # populate a couple of items in it
+ users.put_item(data={
+ 'user_id': '7',
+ 'username': 'johndoe',
+ 'first_name': 'John',
+ 'last_name': 'Doe',
+ 'email': 'johndoe@johndoe.com',
+ })
+ users.put_item(data={
+ 'user_id': '24',
+ 'username': 'alice',
+ 'first_name': 'Alice',
+ 'last_name': 'Expert',
+ 'email': 'alice@alice.com',
+ })
+ users.put_item(data={
+ 'user_id': '35',
+ 'username': 'jane',
+ 'first_name': 'Jane',
+ 'last_name': 'Doe',
+ 'email': 'jane@jane.com',
+ })
+
+ # Try the GSI. it should work.
+ rs = users.query_2(
+ email__eq='johndoe@johndoe.com',
+ index='EmailGSIIndex'
+ )
+
+ for rs_item in rs:
+ self.assertEqual(rs_item['username'], ['johndoe'])
+
+ # The issue arises when we're introspecting the table and try to
+ # query_2 after call describe method
+ users_hit_api = Table('more_gsi_query_users')
+ users_hit_api.describe()
+
+ # Try the GSI. This is what os going wrong on #2828 issue. It should
+ # work fine now.
+ rs = users_hit_api.query_2(
+ email__eq='johndoe@johndoe.com',
+ index='EmailGSIIndex'
+ )
+
+ for rs_item in rs:
+ self.assertEqual(rs_item['username'], ['johndoe'])
+
+ def test_update_table_online_indexing_support(self):
+ # Create a table using gsi to test the DynamoDB online indexing support
+ # https://github.com/boto/boto/pull/2925
+ users = Table.create('online_indexing_support_users', schema=[
+ HashKey('user_id')
+ ], throughput={
+ 'read': 5,
+ 'write': 5
+ }, global_indexes=[
+ GlobalAllIndex('EmailGSIIndex', parts=[
+ HashKey('email')
+ ], throughput={
+ 'read': 2,
+ 'write': 2
+ })
+ ])
+
+ # Add this function to be called after tearDown()
+ self.addCleanup(users.delete)
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Fetch fresh table desc from DynamoDB
+ users.describe()
+
+ # Assert if everything is fine so far
+ self.assertEqual(len(users.global_indexes), 1)
+ self.assertEqual(users.global_indexes[0].throughput['read'], 2)
+ self.assertEqual(users.global_indexes[0].throughput['write'], 2)
+
+ # Update a GSI throughput. it should work.
+ users.update_global_secondary_index(global_indexes={
+ 'EmailGSIIndex': {
+ 'read': 2,
+ 'write': 1,
+ }
+ })
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Fetch fresh table desc from DynamoDB
+ users.describe()
+
+ # Assert if everything is fine so far
+ self.assertEqual(len(users.global_indexes), 1)
+ self.assertEqual(users.global_indexes[0].throughput['read'], 2)
+ self.assertEqual(users.global_indexes[0].throughput['write'], 1)
+
+ # Update a GSI throughput using the old fashion way for compatibility
+ # purposes. it should work.
+ users.update(global_indexes={
+ 'EmailGSIIndex': {
+ 'read': 3,
+ 'write': 2,
+ }
+ })
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Fetch fresh table desc from DynamoDB
+ users.describe()
+
+ # Assert if everything is fine so far
+ self.assertEqual(len(users.global_indexes), 1)
+ self.assertEqual(users.global_indexes[0].throughput['read'], 3)
+ self.assertEqual(users.global_indexes[0].throughput['write'], 2)
+
+ # Delete a GSI. it should work.
+ users.delete_global_secondary_index('EmailGSIIndex')
+
+ # Wait for it.
+ time.sleep(60)
+
+ # Fetch fresh table desc from DynamoDB
+ users.describe()
+
+ # Assert if everything is fine so far
+ self.assertEqual(len(users.global_indexes), 0)
+
+ # Create a GSI. it should work.
+ users.create_global_secondary_index(
+ global_index=GlobalAllIndex(
+ 'AddressGSIIndex', parts=[
+ HashKey('address', data_type=STRING)
+ ], throughput={
+ 'read': 1,
+ 'write': 1,
+ })
+ )
+ # Wait for it. This operation usually takes much longer than the others
+ time.sleep(60*10)
+
+ # Fetch fresh table desc from DynamoDB
+ users.describe()
+
+ # Assert if everything is fine so far
+ self.assertEqual(len(users.global_indexes), 1)
+ self.assertEqual(users.global_indexes[0].throughput['read'], 1)
+ self.assertEqual(users.global_indexes[0].throughput['write'], 1)

Powered by Google App Engine
This is Rietveld 408576698