|
| 1 | +import uuid |
| 2 | +from copy import deepcopy |
| 3 | + |
1 | 4 | import boto3
|
2 | 5 | import pytest
|
3 | 6 |
|
|
10 | 13 | INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME,
|
11 | 14 | INTEG_TEST_DEFAULT_TABLE_CONFIGS,
|
12 | 15 | )
|
13 |
| -from ...items import complex_item_dict, simple_item_dict |
| 16 | +from ...items import complex_item_dict, complex_key_dict, simple_item_dict, simple_key_dict |
14 | 17 | from ...requests import (
|
15 | 18 | basic_delete_item_request_dict,
|
16 | 19 | basic_get_item_request_dict,
|
@@ -58,13 +61,20 @@ def table(encrypted):
|
58 | 61 | return plaintext_table()
|
59 | 62 |
|
60 | 63 |
|
| 64 | +@pytest.fixture(scope="module") |
| 65 | +def test_run_suffix(): |
| 66 | + return "-" + str(uuid.uuid4()) |
| 67 | + |
| 68 | + |
61 | 69 | # Creates a matrix of tests for each value in param,
|
62 | 70 | # with a user-friendly string for test output:
|
63 | 71 | # use_complex_item = True -> "complex_item"
|
64 | 72 | # use_complex_item = False -> "simple_item"
|
65 | 73 | @pytest.fixture(params=[simple_item_dict, complex_item_dict], ids=["simple_item", "complex_item"])
|
66 |
| -def test_item(request): |
67 |
| - return request.param |
| 74 | +def test_item(request, test_run_suffix): |
| 75 | + item = deepcopy(request.param) |
| 76 | + item["partition_key"] += test_run_suffix |
| 77 | + return item |
68 | 78 |
|
69 | 79 |
|
70 | 80 | def test_GIVEN_item_WHEN_basic_put_AND_basic_get_AND_basic_delete_THEN_round_trip_passes(table, test_item):
|
@@ -99,51 +109,57 @@ def test_GIVEN_item_WHEN_basic_put_AND_basic_get_AND_basic_delete_THEN_round_tri
|
99 | 109 | assert "Item" not in get_response
|
100 | 110 |
|
101 | 111 |
|
| 112 | +@pytest.fixture |
| 113 | +def multiple_test_items(test_run_suffix): |
| 114 | + """Get two test items in the appropriate format for the client.""" |
| 115 | + items = [deepcopy(simple_item_dict), deepcopy(complex_item_dict)] |
| 116 | + for item in items: |
| 117 | + item["partition_key"] += test_run_suffix |
| 118 | + return items |
| 119 | + |
| 120 | + |
| 121 | +@pytest.fixture |
| 122 | +def multiple_test_keys(test_run_suffix): |
| 123 | + """Get two test keys in the appropriate format for the client.""" |
| 124 | + keys = [deepcopy(simple_key_dict), deepcopy(complex_key_dict)] |
| 125 | + for key in keys: |
| 126 | + key["partition_key"] += test_run_suffix |
| 127 | + return keys |
| 128 | + |
| 129 | + |
102 | 130 | def test_GIVEN_items_WHEN_batch_write_and_get_THEN_round_trip_passes(
|
103 | 131 | table,
|
| 132 | + multiple_test_items, |
| 133 | + multiple_test_keys, |
104 | 134 | ):
|
105 | 135 | # Given: Simple and complex items in appropriate format for client
|
106 | 136 | # When: Batch put items
|
107 | 137 | with table.batch_writer() as batch_writer:
|
108 | 138 | # boto3 documentation for batch_writer.put_item() is incorrect;
|
109 | 139 | # the method accepts the item directly, not the item inside an "Item" key.
|
110 |
| - batch_writer.put_item(simple_item_dict) |
111 |
| - batch_writer.put_item(complex_item_dict) |
| 140 | + for item in multiple_test_items: |
| 141 | + batch_writer.put_item(item) |
112 | 142 |
|
113 | 143 | # When: Get items
|
114 |
| - get_item_request_dict = basic_get_item_request_dict(simple_item_dict) |
115 |
| - get_response = table.get_item(**get_item_request_dict) |
116 |
| - # Then: All items are encrypted and decrypted correctly |
117 |
| - assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
118 |
| - assert get_response["Item"] == simple_item_dict |
119 |
| - |
120 |
| - get_item_request_dict = basic_get_item_request_dict(complex_item_dict) |
121 |
| - get_response = table.get_item(**get_item_request_dict) |
122 |
| - # Then: All items are encrypted and decrypted correctly |
123 |
| - assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
124 |
| - assert get_response["Item"] == complex_item_dict |
| 144 | + for item in multiple_test_items: |
| 145 | + get_item_request_dict = basic_get_item_request_dict(item) |
| 146 | + get_response = table.get_item(**get_item_request_dict) |
| 147 | + # Then: All items are encrypted and decrypted correctly |
| 148 | + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
| 149 | + assert get_response["Item"] == item |
125 | 150 |
|
126 | 151 | # When: Batch delete items
|
127 | 152 | with table.batch_writer() as batch_writer:
|
128 |
| - batch_writer.delete_item( |
129 |
| - {"partition_key": simple_item_dict["partition_key"], "sort_key": simple_item_dict["sort_key"]} |
130 |
| - ) |
131 |
| - batch_writer.delete_item( |
132 |
| - {"partition_key": complex_item_dict["partition_key"], "sort_key": complex_item_dict["sort_key"]} |
133 |
| - ) |
| 153 | + for key in multiple_test_keys: |
| 154 | + batch_writer.delete_item(key) |
134 | 155 |
|
135 | 156 | # When: Get items
|
136 |
| - get_item_request_dict = basic_get_item_request_dict(simple_item_dict) |
137 |
| - get_response = table.get_item(**get_item_request_dict) |
138 |
| - # Then: All items are encrypted and decrypted correctly |
139 |
| - assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
140 |
| - assert "Item" not in get_response |
141 |
| - |
142 |
| - get_item_request_dict = basic_get_item_request_dict(complex_item_dict) |
143 |
| - get_response = table.get_item(**get_item_request_dict) |
144 |
| - # Then: All items are encrypted and decrypted correctly |
145 |
| - assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
146 |
| - assert "Item" not in get_response |
| 157 | + for item in multiple_test_items: |
| 158 | + get_item_request_dict = basic_get_item_request_dict(item) |
| 159 | + get_response = table.get_item(**get_item_request_dict) |
| 160 | + # Then: All items are encrypted and decrypted correctly |
| 161 | + assert get_response["ResponseMetadata"]["HTTPStatusCode"] == 200 |
| 162 | + assert "Item" not in get_response |
147 | 163 |
|
148 | 164 |
|
149 | 165 | def test_GIVEN_items_in_table_WHEN_query_THEN_items_are_decrypted_correctly(table, test_item):
|
@@ -183,7 +199,10 @@ def test_GIVEN_valid_put_and_scan_requests_WHEN_put_and_scan_THEN_round_trip_pas
|
183 | 199 | # When: Scanning items
|
184 | 200 | scan_request_dict = scan_request
|
185 | 201 | scan_response = table.scan(**scan_request_dict)
|
186 |
| - # Then: Scan returns both test items |
| 202 | + # Then: Scan succeeds |
| 203 | + # Can't assert anything about the scan; |
| 204 | + # there are too many items. |
| 205 | + # The critical assertion is that the scan succeeds. |
187 | 206 | assert scan_response["ResponseMetadata"]["HTTPStatusCode"] == 200
|
188 | 207 |
|
189 | 208 |
|
@@ -228,3 +247,14 @@ def test_WHEN_call_passthrough_method_THEN_correct_response_is_returned():
|
228 | 247 | response = encrypted_table().table_name
|
229 | 248 | # Then: Correct response is returned, i.e. EncryptedTable forwards the call to the underlying boto3 table
|
230 | 249 | assert response == INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME
|
| 250 | + |
| 251 | + |
| 252 | +# Delete the items in the table after the module runs |
| 253 | +@pytest.fixture(scope="module", autouse=True) |
| 254 | +def cleanup_after_module(test_run_suffix): |
| 255 | + yield |
| 256 | + table = boto3.resource("dynamodb").Table(INTEG_TEST_DEFAULT_DYNAMODB_TABLE_NAME) |
| 257 | + items = [deepcopy(simple_item_dict), deepcopy(complex_item_dict)] |
| 258 | + for item in items: |
| 259 | + item["partition_key"] = item["partition_key"] + test_run_suffix |
| 260 | + table.delete_item(**basic_delete_item_request_dict(item)) |
0 commit comments