88from aws_dbesdk_dynamodb .smithygenerated .aws_cryptography_dbencryptionsdk_dynamodb_transforms .errors import (
99 DynamoDbEncryptionTransformsException ,
1010)
11+ import uuid
12+ from copy import deepcopy
1113
1214from ...constants import (
1315 INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME ,
@@ -110,45 +112,80 @@ def client(encrypted, expect_standard_dictionaries):
110112def use_complex_item (request ):
111113 return request .param
112114
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 ())
113119
114120@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 ):
116122 """Get a single test item in the appropriate format for the client."""
117123 if expect_standard_dictionaries :
118124 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
125139
126140@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 ):
128142 """Get a single test item in the appropriate format for the client."""
129143 if expect_standard_dictionaries :
130144 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
136159
137160
138161@pytest .fixture
139- def multiple_test_items (expect_standard_dictionaries ):
162+ def multiple_test_items (expect_standard_dictionaries , test_run_suffix ):
140163 """Get two test items in the appropriate format for the client."""
141164 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
144174
145175
146176@pytest .fixture
147- def multiple_test_keys (expect_standard_dictionaries ):
177+ def multiple_test_keys (expect_standard_dictionaries , test_run_suffix ):
148178 """Get two test keys in the appropriate format for the client."""
149179 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
152189
153190
154191@pytest .fixture
@@ -303,10 +340,18 @@ def test_GIVEN_valid_put_and_query_requests_WHEN_put_and_query_THEN_round_trip_p
303340
304341
305342@pytest .fixture
306- def scan_request (expect_standard_dictionaries , test_item ):
343+ def scan_request (expect_standard_dictionaries , test_item , encrypted ):
307344 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
310355
311356
312357def 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
323368 scan_response = client .scan (** scan_request )
324369 # Then: scan succeeds
325370 assert scan_response ["ResponseMetadata" ]["HTTPStatusCode" ] == 200
326- assert len (scan_response ["Items" ]) >= 1
327371 # Can't assert anything about the scan;
328372 # there are too many items.
329373 # The critical assertion is that the scan succeeds.
@@ -590,3 +634,13 @@ def test_WHEN_call_passthrough_method_THEN_correct_response_is_returned():
590634 response = encrypted_client (expect_standard_dictionaries = False ).list_backups ()
591635 # Then: Correct response is returned, i.e. EncryptedClient forwards the call to the underlying boto3 client
592636 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