Skip to content

Commit ca9686d

Browse files
heitorlessaAdam Tankanow
and
Adam Tankanow
authored
fix(idempotency): revert dict mutation that impacted static_pk_value feature (#1970)
Co-authored-by: Adam Tankanow <[email protected]>
1 parent af7f760 commit ca9686d

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

aws_lambda_powertools/utilities/idempotency/persistence/dynamodb.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,21 @@ def __init__(
104104
super(DynamoDBPersistenceLayer, self).__init__()
105105

106106
def _get_key(self, idempotency_key: str) -> dict:
107+
"""Build primary key attribute simple or composite based on params.
108+
109+
When sort_key_attr is set, we must return a composite key with static_pk_value,
110+
otherwise we use the idempotency key given.
111+
112+
Parameters
113+
----------
114+
idempotency_key : str
115+
idempotency key to use for simple primary key
116+
117+
Returns
118+
-------
119+
dict
120+
simple or composite key for DynamoDB primary key
121+
"""
107122
if self.sort_key_attr:
108123
return {self.key_attr: {"S": self.static_pk_value}, self.sort_key_attr: {"S": idempotency_key}}
109124
return {self.key_attr: {"S": idempotency_key}}
@@ -145,8 +160,8 @@ def _get_record(self, idempotency_key) -> DataRecord:
145160

146161
def _put_record(self, data_record: DataRecord) -> None:
147162
item = {
163+
# get simple or composite primary key
148164
**self._get_key(data_record.idempotency_key),
149-
self.key_attr: {"S": data_record.idempotency_key},
150165
self.expiry_attr: {"N": str(data_record.expiry_timestamp)},
151166
self.status_attr: {"S": data_record.status},
152167
}

tests/functional/idempotency/conftest.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,13 @@ def persistence_store_compound(config):
215215
return DynamoDBPersistenceLayer(table_name=TABLE_NAME, boto_config=config, key_attr="id", sort_key_attr="sk")
216216

217217

218+
@pytest.fixture
219+
def persistence_store_compound_static_pk_value(config, static_pk_value):
220+
return DynamoDBPersistenceLayer(
221+
table_name=TABLE_NAME, boto_config=config, key_attr="id", sort_key_attr="sk", static_pk_value=static_pk_value
222+
)
223+
224+
218225
@pytest.fixture
219226
def idempotency_config(config, request, default_jmespath):
220227
return IdempotencyConfig(
@@ -246,3 +253,37 @@ def _func_echo_decoder(self, value):
246253
@pytest.fixture
247254
def mock_function():
248255
return mock.MagicMock()
256+
257+
258+
@pytest.fixture
259+
def static_pk_value():
260+
return "static-value"
261+
262+
263+
@pytest.fixture
264+
def expected_params_update_item_compound_key_static_pk_value(
265+
expected_params_update_item, hashed_idempotency_key, static_pk_value
266+
):
267+
return {
268+
# same as in any update_item transaction except the `Key` due to composite key value
269+
**expected_params_update_item,
270+
"Key": {"id": {"S": static_pk_value}, "sk": {"S": hashed_idempotency_key}},
271+
}
272+
273+
274+
@pytest.fixture
275+
def expected_params_put_item_compound_key_static_pk_value(
276+
expected_params_put_item, hashed_idempotency_key, static_pk_value
277+
):
278+
return {
279+
# same as in any put_item transaction except the `Item` due to composite key value
280+
**expected_params_put_item,
281+
"Item": {
282+
"expiration": {"N": stub.ANY},
283+
"in_progress_expiration": {"N": stub.ANY},
284+
"id": {"S": static_pk_value},
285+
"sk": {"S": hashed_idempotency_key},
286+
"status": {"S": "INPROGRESS"},
287+
},
288+
"TableName": "TEST_TABLE",
289+
}

tests/functional/idempotency/test_idempotency.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1504,3 +1504,34 @@ def lambda_handler(event, context):
15041504

15051505
stubber.assert_no_pending_responses()
15061506
stubber.deactivate()
1507+
1508+
1509+
@pytest.mark.parametrize("idempotency_config", [{"use_local_cache": False}], indirect=True)
1510+
def test_idempotent_lambda_compound_static_pk_value_has_correct_pk(
1511+
idempotency_config: IdempotencyConfig,
1512+
persistence_store_compound_static_pk_value: DynamoDBPersistenceLayer,
1513+
lambda_apigw_event,
1514+
expected_params_put_item_compound_key_static_pk_value,
1515+
expected_params_update_item_compound_key_static_pk_value,
1516+
lambda_response,
1517+
lambda_context,
1518+
):
1519+
"""
1520+
Test idempotent decorator having a DynamoDBPersistenceLayer with a compound key and a static PK value
1521+
"""
1522+
1523+
stubber = stub.Stubber(persistence_store_compound_static_pk_value._client)
1524+
ddb_response = {}
1525+
1526+
stubber.add_response("put_item", ddb_response, expected_params_put_item_compound_key_static_pk_value)
1527+
stubber.add_response("update_item", ddb_response, expected_params_update_item_compound_key_static_pk_value)
1528+
stubber.activate()
1529+
1530+
@idempotent(config=idempotency_config, persistence_store=persistence_store_compound_static_pk_value)
1531+
def lambda_handler(event, context):
1532+
return lambda_response
1533+
1534+
lambda_handler(lambda_apigw_event, lambda_context)
1535+
1536+
stubber.assert_no_pending_responses()
1537+
stubber.deactivate()

0 commit comments

Comments
 (0)