Skip to content

Commit 27c1640

Browse files
committed
add tests to cover #75 and convert TableInfo secondary index storage from set to list to fix #75
1 parent 0ceb1b7 commit 27c1640

File tree

4 files changed

+170
-5
lines changed

4 files changed

+170
-5
lines changed

CHANGELOG.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
Changelog
33
*********
44

5-
1.0.4 -- 2018-05-16
5+
1.0.4 -- 2018-05-xx
66
===================
77

88
Bugfixes
@@ -11,6 +11,8 @@ Bugfixes
1111
`#72 <https://github.com/awslabs/aws-dynamodb-encryption-python/issues/72>`_
1212
* Fix :class:`MostRecentProvider` lock acquisition for Python 2.7.
1313
`#74 <https://github.com/awslabs/aws-dynamodb-encryption-python/issues/74>`_
14+
* Fix :class:`TableInfo` secondary index storage.
15+
`#75 <https://github.com/awslabs/aws-dynamodb-encryption-python/issues/75>`_
1416

1517
1.0.3 -- 2018-05-03
1618
===================

src/dynamodb_encryption_sdk/structures.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ class TableInfo(object):
304304
default=None
305305
)
306306
_secondary_indexes = attr.ib(
307-
validator=attr.validators.optional(iterable_validator(set, TableIndex)),
307+
validator=attr.validators.optional(iterable_validator(list, TableIndex)),
308308
default=None
309309
)
310310

@@ -378,10 +378,10 @@ def refresh_indexed_attributes(self, client):
378378
table = client.describe_table(TableName=self.name)['Table']
379379
self._primary_index = TableIndex.from_key_schema(table['KeySchema'])
380380

381-
self._secondary_indexes = set()
381+
self._secondary_indexes = []
382382
for group in ('LocalSecondaryIndexes', 'GlobalSecondaryIndexes'):
383383
try:
384384
for index in table[group]:
385-
self._secondary_indexes.add(TableIndex.from_key_schema(index['KeySchema']))
385+
self._secondary_indexes.append(TableIndex.from_key_schema(index['KeySchema']))
386386
except KeyError:
387387
pass # Not all tables will have secondary indexes.

test/functional/functional_test_utils.py

+136
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@
4848
'value': Decimal('99.233')
4949
}
5050
}
51+
SECONARY_INDEX = {
52+
'secondary_index_1': {
53+
'type': 'B',
54+
'value': Binary(b'\x00\x01\x02')
55+
},
56+
'secondary_index_1': {
57+
'type': 'S',
58+
'value': 'another_value'
59+
}
60+
}
5161
TEST_KEY = {name: value['value'] for name, value in TEST_INDEX.items()}
5262
TEST_BATCH_INDEXES = [
5363
{
@@ -130,6 +140,132 @@ def example_table():
130140
mock_dynamodb2().stop()
131141

132142

143+
@pytest.fixture
144+
def table_with_local_seconary_indexes():
145+
mock_dynamodb2().start()
146+
ddb = boto3.client('dynamodb', region_name='us-west-2')
147+
ddb.create_table(
148+
TableName=TEST_TABLE_NAME,
149+
KeySchema=[
150+
{
151+
'AttributeName': 'partition_attribute',
152+
'KeyType': 'HASH'
153+
},
154+
{
155+
'AttributeName': 'sort_attribute',
156+
'KeyType': 'RANGE'
157+
}
158+
],
159+
LocalSecondaryIndexes=[
160+
{
161+
'IndexName': 'lsi-1',
162+
'KeySchema': [
163+
{
164+
'AttributeName': 'secondary_index_1',
165+
'KeyType': 'HASH'
166+
}
167+
],
168+
'Projection': {
169+
'ProjectionType': 'ALL'
170+
}
171+
},
172+
{
173+
'IndexName': 'lsi-2',
174+
'KeySchema': [
175+
{
176+
'AttributeName': 'secondary_index_2',
177+
'KeyType': 'HASH'
178+
}
179+
],
180+
'Projection': {
181+
'ProjectionType': 'ALL'
182+
}
183+
}
184+
],
185+
AttributeDefinitions=[
186+
{
187+
'AttributeName': name,
188+
'AttributeType': value['type']
189+
}
190+
for name, value in list(TEST_INDEX.items()) + list(SECONARY_INDEX.items())
191+
],
192+
ProvisionedThroughput={
193+
'ReadCapacityUnits': 100,
194+
'WriteCapacityUnits': 100
195+
}
196+
)
197+
yield
198+
ddb.delete_table(TableName=TEST_TABLE_NAME)
199+
mock_dynamodb2().stop()
200+
201+
202+
@pytest.fixture
203+
def table_with_global_seconary_indexes():
204+
mock_dynamodb2().start()
205+
ddb = boto3.client('dynamodb', region_name='us-west-2')
206+
ddb.create_table(
207+
TableName=TEST_TABLE_NAME,
208+
KeySchema=[
209+
{
210+
'AttributeName': 'partition_attribute',
211+
'KeyType': 'HASH'
212+
},
213+
{
214+
'AttributeName': 'sort_attribute',
215+
'KeyType': 'RANGE'
216+
}
217+
],
218+
GlobalSecondaryIndexes=[
219+
{
220+
'IndexName': 'gsi-1',
221+
'KeySchema': [
222+
{
223+
'AttributeName': 'secondary_index_1',
224+
'KeyType': 'HASH'
225+
}
226+
],
227+
'Projection': {
228+
'ProjectionType': 'ALL'
229+
},
230+
'ProvisionedThroughput': {
231+
'ReadCapacityUnits': 100,
232+
'WriteCapacityUnits': 100
233+
}
234+
},
235+
{
236+
'IndexName': 'gsi-2',
237+
'KeySchema': [
238+
{
239+
'AttributeName': 'secondary_index_2',
240+
'KeyType': 'HASH'
241+
}
242+
],
243+
'Projection': {
244+
'ProjectionType': 'ALL'
245+
},
246+
'ProvisionedThroughput': {
247+
'ReadCapacityUnits': 100,
248+
'WriteCapacityUnits': 100
249+
}
250+
}
251+
],
252+
AttributeDefinitions=[
253+
{
254+
'AttributeName': name,
255+
'AttributeType': value['type']
256+
}
257+
for name, value in list(TEST_INDEX.items()) + list(SECONARY_INDEX.items())
258+
],
259+
ProvisionedThroughput={
260+
'ReadCapacityUnits': 100,
261+
'WriteCapacityUnits': 100
262+
}
263+
)
264+
yield
265+
ddb.delete_table(TableName=TEST_TABLE_NAME)
266+
mock_dynamodb2().stop()
267+
268+
133269
def _get_from_cache(dk_class, algorithm, key_length):
134270
"""Don't generate new keys every time. All we care about is that they are valid keys, not that they are unique."""
135271
try:

test/functional/test_structures.py

+28-1
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,42 @@
1111
# ANY KIND, either express or implied. See the License for the specific
1212
# language governing permissions and limitations under the License.
1313
"""Functional tests for ``dynamodb_encryption_sdk.structures``."""
14+
import boto3
1415
import pytest
1516

1617
from dynamodb_encryption_sdk.exceptions import InvalidArgumentError
1718
from dynamodb_encryption_sdk.identifiers import CryptoAction
18-
from dynamodb_encryption_sdk.structures import AttributeActions, TableIndex
19+
from dynamodb_encryption_sdk.structures import AttributeActions, TableIndex, TableInfo
20+
from .functional_test_utils import (
21+
example_table, table_with_global_seconary_indexes, table_with_local_seconary_indexes, TEST_TABLE_NAME
22+
)
1923

2024
pytestmark = [pytest.mark.functional, pytest.mark.local]
2125

2226

27+
# TODO: There is a way to parameterize fixtures, but the existing docs on that are very unclear.
28+
# This will get us what we need for now, but we should come back to this to clean this up later.
29+
def test_tableinfo_refresh_indexes_no_secondary_indexes(example_table):
30+
client = boto3.client('dynamodb', region_name='us-west-2')
31+
table = TableInfo(name=TEST_TABLE_NAME)
32+
33+
table.refresh_indexed_attributes(client)
34+
35+
36+
def test_tableinfo_refresh_indexes_with_gsis(table_with_global_seconary_indexes):
37+
client = boto3.client('dynamodb', region_name='us-west-2')
38+
table = TableInfo(name=TEST_TABLE_NAME)
39+
40+
table.refresh_indexed_attributes(client)
41+
42+
43+
def test_tableinfo_refresh_indexes_with_lsis(table_with_local_seconary_indexes):
44+
client = boto3.client('dynamodb', region_name='us-west-2')
45+
table = TableInfo(name=TEST_TABLE_NAME)
46+
47+
table.refresh_indexed_attributes(client)
48+
49+
2350
@pytest.mark.parametrize('kwargs, expected_attributes', (
2451
(dict(partition='partition_name'), set(['partition_name'])),
2552
(dict(partition='partition_name', sort='sort_name'), set(['partition_name', 'sort_name']))

0 commit comments

Comments
 (0)