8
8
from aws_dbesdk_dynamodb .smithygenerated .aws_cryptography_dbencryptionsdk_dynamodb_transforms .errors import (
9
9
DynamoDbEncryptionTransformsException ,
10
10
)
11
+ import uuid
12
+ from copy import deepcopy
11
13
12
14
from ...constants import (
13
15
INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME ,
@@ -110,45 +112,80 @@ def client(encrypted, expect_standard_dictionaries):
110
112
def use_complex_item (request ):
111
113
return request .param
112
114
115
+ # Append a suffix to the partition key to avoid collisions between test runs.
116
+ @pytest .fixture (scope = "module" )
117
+ def test_run_suffix ():
118
+ return str (uuid .uuid4 ())
113
119
114
120
@pytest .fixture
115
- def test_item (expect_standard_dictionaries , use_complex_item ):
121
+ def test_item (expect_standard_dictionaries , use_complex_item , test_run_suffix ):
116
122
"""Get a single test item in the appropriate format for the client."""
117
123
if expect_standard_dictionaries :
118
124
if use_complex_item :
119
- return complex_item_dict
120
- return simple_item_dict
121
- if use_complex_item :
122
- return complex_item_ddb
123
- return simple_item_ddb
124
-
125
+ item = deepcopy (complex_item_dict )
126
+ else :
127
+ item = deepcopy (simple_item_dict )
128
+ else :
129
+ if use_complex_item :
130
+ item = deepcopy (complex_item_ddb )
131
+ else :
132
+ item = deepcopy (simple_item_ddb )
133
+ # Add a suffix to the partition key to avoid collisions between test runs.
134
+ if isinstance (item ["partition_key" ], dict ):
135
+ item ["partition_key" ]["S" ] += test_run_suffix
136
+ else :
137
+ item ["partition_key" ] += test_run_suffix
138
+ return item
125
139
126
140
@pytest .fixture
127
- def test_key (expect_standard_dictionaries , use_complex_item ):
141
+ def test_key (expect_standard_dictionaries , use_complex_item , test_run_suffix ):
128
142
"""Get a single test item in the appropriate format for the client."""
129
143
if expect_standard_dictionaries :
130
144
if use_complex_item :
131
- return complex_key_dict
132
- return simple_key_dict
133
- if use_complex_item :
134
- return complex_key_ddb
135
- return simple_key_ddb
145
+ key = deepcopy (complex_key_dict )
146
+ else :
147
+ key = deepcopy (simple_key_dict )
148
+ else :
149
+ if use_complex_item :
150
+ key = deepcopy (complex_key_ddb )
151
+ else :
152
+ key = deepcopy (simple_key_ddb )
153
+ # Add a suffix to the partition key to avoid collisions between test runs.
154
+ if isinstance (key ["partition_key" ], dict ):
155
+ key ["partition_key" ]["S" ] += test_run_suffix
156
+ else :
157
+ key ["partition_key" ] += test_run_suffix
158
+ return key
136
159
137
160
138
161
@pytest .fixture
139
- def multiple_test_items (expect_standard_dictionaries ):
162
+ def multiple_test_items (expect_standard_dictionaries , test_run_suffix ):
140
163
"""Get two test items in the appropriate format for the client."""
141
164
if expect_standard_dictionaries :
142
- return [simple_item_dict , complex_item_dict ]
143
- return [simple_item_ddb , complex_item_ddb ]
165
+ items = [deepcopy (simple_item_dict ), deepcopy (complex_item_dict )]
166
+ else :
167
+ items = [deepcopy (simple_item_ddb ), deepcopy (complex_item_ddb )]
168
+ for item in items :
169
+ if isinstance (item ["partition_key" ], dict ):
170
+ item ["partition_key" ]["S" ] += test_run_suffix
171
+ else :
172
+ item ["partition_key" ] += test_run_suffix
173
+ return items
144
174
145
175
146
176
@pytest .fixture
147
- def multiple_test_keys (expect_standard_dictionaries ):
177
+ def multiple_test_keys (expect_standard_dictionaries , test_run_suffix ):
148
178
"""Get two test keys in the appropriate format for the client."""
149
179
if expect_standard_dictionaries :
150
- return [simple_key_dict , complex_key_dict ]
151
- return [simple_key_ddb , complex_key_ddb ]
180
+ keys = [deepcopy (simple_key_dict ), deepcopy (complex_key_dict )]
181
+ else :
182
+ keys = [deepcopy (simple_key_ddb ), deepcopy (complex_key_ddb )]
183
+ for key in keys :
184
+ if isinstance (key ["partition_key" ], dict ):
185
+ key ["partition_key" ]["S" ] += test_run_suffix
186
+ else :
187
+ key ["partition_key" ] += test_run_suffix
188
+ return keys
152
189
153
190
154
191
@pytest .fixture
@@ -303,10 +340,18 @@ def test_GIVEN_valid_put_and_query_requests_WHEN_put_and_query_THEN_round_trip_p
303
340
304
341
305
342
@pytest .fixture
306
- def scan_request (expect_standard_dictionaries , test_item ):
343
+ def scan_request (expect_standard_dictionaries , test_item , encrypted ):
307
344
if expect_standard_dictionaries :
308
- return {** basic_scan_request_dict (test_item ), "TableName" : INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME }
309
- return basic_scan_request_ddb (test_item )
345
+ request = {** basic_scan_request_dict (test_item ), "TableName" : INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME }
346
+ else :
347
+ request = basic_scan_request_ddb (test_item )
348
+ if encrypted :
349
+ # If the encrypted scan encounters a plaintext item, the scan will fail.
350
+ # To avoid this, encrypted scans add a filter expression that matches only encrypted items.
351
+ request ["FilterExpression" ] = request ["FilterExpression" ] + " AND attribute_exists (#sig)"
352
+ request ["ExpressionAttributeNames" ] = {}
353
+ request ["ExpressionAttributeNames" ]["#sig" ] = "amzn-ddb-map-sig"
354
+ return request
310
355
311
356
312
357
def test_GIVEN_valid_put_and_scan_requests_WHEN_put_and_scan_THEN_round_trip_passes (
@@ -323,7 +368,6 @@ def test_GIVEN_valid_put_and_scan_requests_WHEN_put_and_scan_THEN_round_trip_pas
323
368
scan_response = client .scan (** scan_request )
324
369
# Then: scan succeeds
325
370
assert scan_response ["ResponseMetadata" ]["HTTPStatusCode" ] == 200
326
- assert len (scan_response ["Items" ]) >= 1
327
371
# Can't assert anything about the scan;
328
372
# there are too many items.
329
373
# The critical assertion is that the scan succeeds.
@@ -590,3 +634,13 @@ def test_WHEN_call_passthrough_method_THEN_correct_response_is_returned():
590
634
response = encrypted_client (expect_standard_dictionaries = False ).list_backups ()
591
635
# Then: Correct response is returned, i.e. EncryptedClient forwards the call to the underlying boto3 client
592
636
assert response ["ResponseMetadata" ]["HTTPStatusCode" ] == 200
637
+
638
+ # Delete the items in the table after the module runs
639
+ @pytest .fixture (scope = "module" , autouse = True )
640
+ def cleanup_after_module (test_run_suffix ):
641
+ yield
642
+ table = boto3 .client ("dynamodb" )
643
+ items = [deepcopy (simple_item_ddb ), deepcopy (complex_item_ddb )]
644
+ for item in items :
645
+ item ["partition_key" ]["S" ] += test_run_suffix
646
+ table .delete_item (** basic_delete_item_request_ddb (item ))
0 commit comments