@@ -735,15 +735,16 @@ def test_default_no_raise_on_missing_idempotency_key(
735
735
idempotency_config : IdempotencyConfig , persistence_store : DynamoDBPersistenceLayer , lambda_context
736
736
):
737
737
# GIVEN a persistence_store with use_local_cache = False and event_key_jmespath = "body"
738
- persistence_store .configure (idempotency_config )
738
+ function_name = "foo"
739
+ persistence_store .configure (idempotency_config , function_name )
739
740
assert persistence_store .use_local_cache is False
740
741
assert "body" in persistence_store .event_key_jmespath
741
742
742
743
# WHEN getting the hashed idempotency key for an event with no `body` key
743
744
hashed_key = persistence_store ._get_hashed_idempotency_key ({})
744
745
745
746
# THEN return the hash of None
746
- expected_value = "test-func#" + md5 (serialize (None ).encode ()).hexdigest ()
747
+ expected_value = f "test-func. { function_name } #" + md5 (serialize (None ).encode ()).hexdigest ()
747
748
assert expected_value == hashed_key
748
749
749
750
@@ -781,7 +782,7 @@ def test_jmespath_with_powertools_json(
781
782
idempotency_config : IdempotencyConfig , persistence_store : DynamoDBPersistenceLayer , lambda_context
782
783
):
783
784
# GIVEN an event_key_jmespath with powertools_json custom function
784
- persistence_store .configure (idempotency_config )
785
+ persistence_store .configure (idempotency_config , "handler" )
785
786
sub_attr_value = "cognito_user"
786
787
static_pk_value = "some_key"
787
788
expected_value = [sub_attr_value , static_pk_value ]
@@ -794,14 +795,14 @@ def test_jmespath_with_powertools_json(
794
795
result = persistence_store ._get_hashed_idempotency_key (api_gateway_proxy_event )
795
796
796
797
# THEN the hashed idempotency key should match the extracted values generated hash
797
- assert result == "test-func#" + persistence_store ._generate_hash (expected_value )
798
+ assert result == "test-func.handler #" + persistence_store ._generate_hash (expected_value )
798
799
799
800
800
801
@pytest .mark .parametrize ("config_with_jmespath_options" , ["powertools_json(data).payload" ], indirect = True )
801
802
def test_custom_jmespath_function_overrides_builtin_functions (
802
803
config_with_jmespath_options : IdempotencyConfig , persistence_store : DynamoDBPersistenceLayer , lambda_context
803
804
):
804
- # GIVEN an persistence store with a custom jmespath_options
805
+ # GIVEN a persistence store with a custom jmespath_options
805
806
# AND use a builtin powertools custom function
806
807
persistence_store .configure (config_with_jmespath_options )
807
808
@@ -871,7 +872,9 @@ def _delete_record(self, data_record: DataRecord) -> None:
871
872
def test_idempotent_lambda_event_source (lambda_context ):
872
873
# Scenario to validate that we can use the event_source decorator before or after the idempotent decorator
873
874
mock_event = load_event ("apiGatewayProxyV2Event.json" )
874
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ())
875
+ persistence_layer = MockPersistenceLayer (
876
+ "test-func.lambda_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
877
+ )
875
878
expected_result = {"message" : "Foo" }
876
879
877
880
# GIVEN an event_source decorator
@@ -891,7 +894,9 @@ def lambda_handler(event, _):
891
894
def test_idempotent_function ():
892
895
# Scenario to validate we can use idempotent_function with any function
893
896
mock_event = {"data" : "value" }
894
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ())
897
+ persistence_layer = MockPersistenceLayer (
898
+ "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
899
+ )
895
900
expected_result = {"message" : "Foo" }
896
901
897
902
@idempotent_function (persistence_store = persistence_layer , data_keyword_argument = "record" )
@@ -908,7 +913,9 @@ def test_idempotent_function_arbitrary_args_kwargs():
908
913
# Scenario to validate we can use idempotent_function with a function
909
914
# with an arbitrary number of args and kwargs
910
915
mock_event = {"data" : "value" }
911
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ())
916
+ persistence_layer = MockPersistenceLayer (
917
+ "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
918
+ )
912
919
expected_result = {"message" : "Foo" }
913
920
914
921
@idempotent_function (persistence_store = persistence_layer , data_keyword_argument = "record" )
@@ -923,7 +930,9 @@ def record_handler(arg_one, arg_two, record, is_record):
923
930
924
931
def test_idempotent_function_invalid_data_kwarg ():
925
932
mock_event = {"data" : "value" }
926
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ())
933
+ persistence_layer = MockPersistenceLayer (
934
+ "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
935
+ )
927
936
expected_result = {"message" : "Foo" }
928
937
keyword_argument = "payload"
929
938
@@ -940,7 +949,9 @@ def record_handler(record):
940
949
941
950
def test_idempotent_function_arg_instead_of_kwarg ():
942
951
mock_event = {"data" : "value" }
943
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ())
952
+ persistence_layer = MockPersistenceLayer (
953
+ "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
954
+ )
944
955
expected_result = {"message" : "Foo" }
945
956
keyword_argument = "record"
946
957
@@ -958,13 +969,19 @@ def record_handler(record):
958
969
def test_idempotent_function_and_lambda_handler (lambda_context ):
959
970
# Scenario to validate we can use both idempotent_function and idempotent decorators
960
971
mock_event = {"data" : "value" }
961
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ())
972
+ persistence_layer = MockPersistenceLayer (
973
+ "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
974
+ )
962
975
expected_result = {"message" : "Foo" }
963
976
964
977
@idempotent_function (persistence_store = persistence_layer , data_keyword_argument = "record" )
965
978
def record_handler (record ):
966
979
return expected_result
967
980
981
+ persistence_layer = MockPersistenceLayer (
982
+ "test-func.lambda_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
983
+ )
984
+
968
985
@idempotent (persistence_store = persistence_layer )
969
986
def lambda_handler (event , _ ):
970
987
return expected_result
@@ -986,7 +1003,9 @@ def test_idempotent_data_sorting():
986
1003
data_two = {"more_data" : "more data 1" , "data" : "test message 1" }
987
1004
988
1005
# Assertion will happen in MockPersistenceLayer
989
- persistence_layer = MockPersistenceLayer ("test-func#" + hashlib .md5 (json .dumps (data_one ).encode ()).hexdigest ())
1006
+ persistence_layer = MockPersistenceLayer (
1007
+ "test-func.dummy#" + hashlib .md5 (json .dumps (data_one ).encode ()).hexdigest ()
1008
+ )
990
1009
991
1010
# GIVEN
992
1011
@idempotent_function (data_keyword_argument = "payload" , persistence_store = persistence_layer )
@@ -1017,3 +1036,24 @@ def dummy_handler(event, context):
1017
1036
dummy_handler (mock_event , lambda_context )
1018
1037
1019
1038
assert len (persistence_store .table .method_calls ) == 0
1039
+
1040
+
1041
+ @pytest .mark .parametrize ("idempotency_config" , [{"use_local_cache" : True }], indirect = True )
1042
+ def test_idempotent_function_duplicates (
1043
+ idempotency_config : IdempotencyConfig , persistence_store : DynamoDBPersistenceLayer
1044
+ ):
1045
+ # Scenario to validate the both methods are called
1046
+ mock_event = {"data" : "value" }
1047
+ persistence_store .table = MagicMock ()
1048
+
1049
+ @idempotent_function (data_keyword_argument = "data" , persistence_store = persistence_store , config = idempotency_config )
1050
+ def one (data ):
1051
+ return "one"
1052
+
1053
+ @idempotent_function (data_keyword_argument = "data" , persistence_store = persistence_store , config = idempotency_config )
1054
+ def two (data ):
1055
+ return "two"
1056
+
1057
+ assert one (data = mock_event ) == "one"
1058
+ assert two (data = mock_event ) == "two"
1059
+ assert len (persistence_store .table .method_calls ) == 4
0 commit comments