diff --git a/aws_lambda_powertools/utilities/idempotency/idempotency.py b/aws_lambda_powertools/utilities/idempotency/idempotency.py index abd45a86be1..14fd3bfe5af 100644 --- a/aws_lambda_powertools/utilities/idempotency/idempotency.py +++ b/aws_lambda_powertools/utilities/idempotency/idempotency.py @@ -134,14 +134,14 @@ def decorate(*args, **kwargs): if os.getenv(constants.IDEMPOTENCY_DISABLED_ENV): return function(*args, **kwargs) - payload = kwargs.get(data_keyword_argument) - - if not payload: + if data_keyword_argument not in kwargs: raise RuntimeError( f"Unable to extract '{data_keyword_argument}' from keyword arguments." f" Ensure this exists in your function's signature as well as the caller used it as a keyword argument" ) + payload = kwargs.get(data_keyword_argument) + idempotency_handler = IdempotencyHandler( function=function, function_payload=payload, diff --git a/tests/functional/idempotency/test_idempotency.py b/tests/functional/idempotency/test_idempotency.py index e5c5c777971..8f39b832554 100644 --- a/tests/functional/idempotency/test_idempotency.py +++ b/tests/functional/idempotency/test_idempotency.py @@ -72,7 +72,7 @@ def test_idempotent_lambda_already_completed( lambda_context, ): """ - Test idempotent decorator where event with matching event key has already been succesfully processed + Test idempotent decorator where event with matching event key has already been successfully processed """ stubber = stub.Stubber(persistence_store.table.meta.client) @@ -1247,6 +1247,46 @@ def lambda_handler(event, _): assert handler_result == expected_result +@pytest.mark.parametrize("data", [None, 0, False]) +def test_idempotent_function_falsy_values(data): + # Scenario to validate we can use idempotent_function with any function + # receiving a falsy value (`None`, `False`, `0`, etc.) + # shouldn't cause a RuntimeError + mock_event = data + idempotency_key = f"{TESTS_MODULE_PREFIX}.test_idempotent_function_falsy_values..record_handler#{hash_idempotency_key(mock_event)}" # noqa: E501 + + persistence_layer = MockPersistenceLayer(expected_idempotency_key=idempotency_key) + expected_result = {"message": "Foo"} + + @idempotent_function(persistence_store=persistence_layer, data_keyword_argument="record") + def record_handler(record): + return expected_result + + # WHEN calling the function + result = record_handler(record=mock_event) + # THEN we expect the function to execute successfully + assert result == expected_result + + +@pytest.mark.parametrize("data", [None, 0, False]) +def test_idempotent_function_falsy_values_with_raise_on_no_idempotency_key( + data, persistence_store: DynamoDBPersistenceLayer +): + # GIVEN raise_on_no_idempotency_key is True + idempotency_config = IdempotencyConfig(event_key_jmespath="idemKey", raise_on_no_idempotency_key=True) + + @idempotent_function(data_keyword_argument="record", persistence_store=persistence_store, config=idempotency_config) + def record_handler(record): + return ValueError("Should not be raised") + + # WHEN calling the function + with pytest.raises(IdempotencyKeyError) as e: + record_handler(record=data) + + # THEN we expect an idempotency key error message + assert "No data found to create a hashed idempotency_key" == e.value.args[0] + + def test_idempotent_data_sorting(): # Scenario to validate same data in different order hashes to the same idempotency key data_one = {"data": "test message 1", "more_data": "more data 1"}