1
1
import copy
2
- import hashlib
3
- import json
4
2
import sys
5
3
from hashlib import md5
6
4
from unittest .mock import MagicMock
24
22
from aws_lambda_powertools .utilities .idempotency .idempotency import idempotent , idempotent_function
25
23
from aws_lambda_powertools .utilities .idempotency .persistence .base import BasePersistenceLayer , DataRecord
26
24
from aws_lambda_powertools .utilities .validation import envelopes , validator
27
- from tests .functional .idempotency .conftest import serialize
28
- from tests .functional .utils import load_event
25
+ from tests .functional .utils import hash_idempotency_key , json_serialize , load_event
29
26
30
27
TABLE_NAME = "TEST_TABLE"
31
28
@@ -753,7 +750,7 @@ def test_default_no_raise_on_missing_idempotency_key(
753
750
hashed_key = persistence_store ._get_hashed_idempotency_key ({})
754
751
755
752
# THEN return the hash of None
756
- expected_value = f"test-func.{ function_name } #" + md5 (serialize (None ).encode ()).hexdigest ()
753
+ expected_value = f"test-func.{ function_name } #" + md5 (json_serialize (None ).encode ()).hexdigest ()
757
754
assert expected_value == hashed_key
758
755
759
756
@@ -797,7 +794,7 @@ def test_jmespath_with_powertools_json(
797
794
expected_value = [sub_attr_value , static_pk_value ]
798
795
api_gateway_proxy_event = {
799
796
"requestContext" : {"authorizer" : {"claims" : {"sub" : sub_attr_value }}},
800
- "body" : serialize ({"id" : static_pk_value }),
797
+ "body" : json_serialize ({"id" : static_pk_value }),
801
798
}
802
799
803
800
# WHEN calling _get_hashed_idempotency_key
@@ -881,9 +878,7 @@ def _delete_record(self, data_record: DataRecord) -> None:
881
878
def test_idempotent_lambda_event_source (lambda_context ):
882
879
# Scenario to validate that we can use the event_source decorator before or after the idempotent decorator
883
880
mock_event = load_event ("apiGatewayProxyV2Event.json" )
884
- persistence_layer = MockPersistenceLayer (
885
- "test-func.lambda_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
886
- )
881
+ persistence_layer = MockPersistenceLayer ("test-func.lambda_handler#" + hash_idempotency_key (mock_event ))
887
882
expected_result = {"message" : "Foo" }
888
883
889
884
# GIVEN an event_source decorator
@@ -903,9 +898,8 @@ def lambda_handler(event, _):
903
898
def test_idempotent_function ():
904
899
# Scenario to validate we can use idempotent_function with any function
905
900
mock_event = {"data" : "value" }
906
- persistence_layer = MockPersistenceLayer (
907
- "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
908
- )
901
+ idempotency_key = "test-func.record_handler#" + hash_idempotency_key (mock_event )
902
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
909
903
expected_result = {"message" : "Foo" }
910
904
911
905
@idempotent_function (persistence_store = persistence_layer , data_keyword_argument = "record" )
@@ -922,9 +916,8 @@ def test_idempotent_function_arbitrary_args_kwargs():
922
916
# Scenario to validate we can use idempotent_function with a function
923
917
# with an arbitrary number of args and kwargs
924
918
mock_event = {"data" : "value" }
925
- persistence_layer = MockPersistenceLayer (
926
- "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
927
- )
919
+ idempotency_key = "test-func.record_handler#" + hash_idempotency_key (mock_event )
920
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
928
921
expected_result = {"message" : "Foo" }
929
922
930
923
@idempotent_function (persistence_store = persistence_layer , data_keyword_argument = "record" )
@@ -939,9 +932,8 @@ def record_handler(arg_one, arg_two, record, is_record):
939
932
940
933
def test_idempotent_function_invalid_data_kwarg ():
941
934
mock_event = {"data" : "value" }
942
- persistence_layer = MockPersistenceLayer (
943
- "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
944
- )
935
+ idempotency_key = "test-func.record_handler#" + hash_idempotency_key (mock_event )
936
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
945
937
expected_result = {"message" : "Foo" }
946
938
keyword_argument = "payload"
947
939
@@ -958,9 +950,8 @@ def record_handler(record):
958
950
959
951
def test_idempotent_function_arg_instead_of_kwarg ():
960
952
mock_event = {"data" : "value" }
961
- persistence_layer = MockPersistenceLayer (
962
- "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
963
- )
953
+ idempotency_key = "test-func.record_handler#" + hash_idempotency_key (mock_event )
954
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
964
955
expected_result = {"message" : "Foo" }
965
956
keyword_argument = "record"
966
957
@@ -978,18 +969,15 @@ def record_handler(record):
978
969
def test_idempotent_function_and_lambda_handler (lambda_context ):
979
970
# Scenario to validate we can use both idempotent_function and idempotent decorators
980
971
mock_event = {"data" : "value" }
981
- persistence_layer = MockPersistenceLayer (
982
- "test-func.record_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
983
- )
972
+ idempotency_key = "test-func.record_handler#" + hash_idempotency_key (mock_event )
973
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
984
974
expected_result = {"message" : "Foo" }
985
975
986
976
@idempotent_function (persistence_store = persistence_layer , data_keyword_argument = "record" )
987
977
def record_handler (record ):
988
978
return expected_result
989
979
990
- persistence_layer = MockPersistenceLayer (
991
- "test-func.lambda_handler#" + hashlib .md5 (serialize (mock_event ).encode ()).hexdigest ()
992
- )
980
+ persistence_layer = MockPersistenceLayer ("test-func.lambda_handler#" + hash_idempotency_key (mock_event ))
993
981
994
982
@idempotent (persistence_store = persistence_layer )
995
983
def lambda_handler (event , _ ):
@@ -1010,18 +998,16 @@ def test_idempotent_data_sorting():
1010
998
# Scenario to validate same data in different order hashes to the same idempotency key
1011
999
data_one = {"data" : "test message 1" , "more_data" : "more data 1" }
1012
1000
data_two = {"more_data" : "more data 1" , "data" : "test message 1" }
1013
-
1001
+ idempotency_key = "test-func.dummy#" + hash_idempotency_key ( data_one )
1014
1002
# Assertion will happen in MockPersistenceLayer
1015
- persistence_layer = MockPersistenceLayer (
1016
- "test-func.dummy#" + hashlib .md5 (json .dumps (data_one ).encode ()).hexdigest ()
1017
- )
1003
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
1018
1004
1019
1005
# GIVEN
1020
1006
@idempotent_function (data_keyword_argument = "payload" , persistence_store = persistence_layer )
1021
1007
def dummy (payload ):
1022
1008
return {"message" : "hello" }
1023
1009
1024
- # WHEN
1010
+ # WHEN/THEN assertion will happen at MockPersistenceLayer
1025
1011
dummy (payload = data_two )
1026
1012
1027
1013
@@ -1120,10 +1106,8 @@ def test_idempotent_function_dataclass_with_jmespath():
1120
1106
dataclasses = get_dataclasses_lib ()
1121
1107
config = IdempotencyConfig (event_key_jmespath = "transaction_id" , use_local_cache = True )
1122
1108
mock_event = {"customer_id" : "fake" , "transaction_id" : "fake-id" }
1123
- persistence_layer = MockPersistenceLayer (
1124
- expected_idempotency_key = "test-func.collect_payment#"
1125
- + hashlib .md5 (serialize (mock_event ["transaction_id" ]).encode ()).hexdigest ()
1126
- )
1109
+ idempotency_key = "test-func.collect_payment#" + hash_idempotency_key (mock_event ["transaction_id" ])
1110
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
1127
1111
1128
1112
@dataclasses .dataclass
1129
1113
class Payment :
@@ -1147,10 +1131,8 @@ def test_idempotent_function_pydantic_with_jmespath():
1147
1131
# GIVEN
1148
1132
config = IdempotencyConfig (event_key_jmespath = "transaction_id" , use_local_cache = True )
1149
1133
mock_event = {"customer_id" : "fake" , "transaction_id" : "fake-id" }
1150
- persistence_layer = MockPersistenceLayer (
1151
- expected_idempotency_key = "test-func.collect_payment#"
1152
- + hashlib .md5 (serialize (mock_event ["transaction_id" ]).encode ()).hexdigest ()
1153
- )
1134
+ idempotency_key = "test-func.collect_payment#" + hash_idempotency_key (mock_event ["transaction_id" ])
1135
+ persistence_layer = MockPersistenceLayer (expected_idempotency_key = idempotency_key )
1154
1136
1155
1137
class Payment (BaseModel ):
1156
1138
customer_id : str
0 commit comments