8000 order input for snapshot-match to fix reference-replacement (#6598) · localstack/localstack@5948256 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5948256

Browse files
authored
order input for snapshot-match to fix reference-replacement (#6598)
1 parent 18dea69 commit 5948256

File tree

5 files changed

+119
-61
lines changed

5 files changed

+119
-61
lines changed

localstack/testing/snapshots/prototype.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ def match(self, key: str, obj: dict) -> None:
138138

139139
self.called_keys.add(key)
140140

141-
self.observed_state[
142-
key
143-
] = obj # TODO: track them separately since the transformation is now done *just* before asserting
141+
# order the obj to guarantee reference replacement works as expected
142+
self.observed_state[key] = self._order_dict(obj)
143+
# TODO: track them separately since the transformation is now done *just* before asserting
144144

145145
if not self.update and (not self.recorded_state or not self.recorded_state.get(key)):
146146
raise Exception("Please run the test first with --snapshot-update")
@@ -217,7 +217,6 @@ def _transform_dict_to_parseable_values(self, original):
217217
def _transform(self, tmp: dict) -> dict:
218218
"""build a persistable state definition that can later be compared against"""
219219
self._transform_dict_to_parseable_values(tmp)
220-
221220
if not self.update:
222221
self._remove_skip_verification_paths(tmp)
223222

@@ -239,8 +238,21 @@ def _transform(self, tmp: dict) -> dict:
239238

240239
return tmp
241240

242-
# LEGACY API
241+
def _order_dict(self, response) -> dict:
242+
if isinstance(response, dict):
243+
ordered_dict = {}
244+
for key, val in sorted(response.items()):
245+
if isinstance(val, dict):
246+
ordered_dict[key] = self._order_dict(val)
247+
elif isinstance(val, list):
248+
ordered_dict[key] = [self._order_dict(entry) for entry in val]
249+
else:
250+
ordered_dict[key] = val
251+
return ordered_dict
252+
else:
253+
return response
243254

255+
# LEGACY API
244256
def register_replacement(self, pattern: Pattern[str], value: str):
245257
self.add_transformer(RegexTransformer(pattern, value))
246258

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
{
22
"tests/integration/cloudformation/test_cloudformation_stacks.py::test_stack_description_special_chars": {
3-
"recorded-date": "03-08-2022, 13:35:51",
3+
"recorded-date": "05-08-2022, 13:03:43",
44
"recorded-content": {
55
"describe_stack": {
6-
"StackId": "arn:aws:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:1>",
7-
"StackName": "<stack-name:1>",
8-
"ChangeSetId": "arn:aws:cloudformation:<region>:111111111111:changeSet/<resource:2>",
9-
"Description": "test <env>.test.net",
10-
"CreationTime": "datetime",
11-
"LastUpdatedTime": "datetime",
12-
"RollbackConfiguration": {},
13-
"StackStatus": "CREATE_COMPLETE",
14-
"DisableRollback": false,
15-
"NotificationARNs": [],
166
"Capabilities": [
177
"CAPABILITY_AUTO_EXPAND",
188
"CAPABILITY_IAM",
199
"CAPABILITY_NAMED_IAM"
2010
],
21-
"Tags": [],
22-
"EnableTerminationProtection": false,
11+
"ChangeSetId": "arn:aws:cloudformation:<region>:111111111111:changeSet/<resource:1>",
12+
"CreationTime": "datetime",
13+
"Description": "test <env>.test.net",
14+
"DisableRollback": false,
2315
"DriftInformation": {
2416
"StackDriftStatus": "NOT_CHECKED"
25-
}
17+
},
18+
"EnableTerminationProtection": false,
19+
"LastUpdatedTime": "datetime",
20+
"NotificationARNs": [],
21+
"RollbackConfiguration": {},
22+
"StackId": "arn:aws:cloudformation:<region>:111111111111:stack/<stack-name:1>/<resource:2>",
23+
"StackName": "<stack-name:1>",
24+
"StackStatus": "CREATE_COMPLETE",
25+
"Tags": []
2626
}
2727
}
2828
}
29-
}
29+
}

tests/integration/s3/test_s3_notifications_sns.snapshot.json

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
{
22
"tests/integration/s3/test_s3_notifications_sns.py::TestS3NotificationsToSns::test_object_created_put": {
3-
"recorded-date": "07-06-2022, 16:15:43",
3+
"recorded-date": "08-08-2022, 17:51:20",
44
"recorded-content": {
55
"receive_messages": {
66
"messages": [
77
{
8-
"Type": "Notification",
9-
"MessageId": "<uuid:1>",
10-
"TopicArn": "arn:aws:sns:<region>:111111111111:<resource:1>",
11-
"Subject": "Amazon S3 Notification",
128
"Message": {
139
"Records": [
1410
{
@@ -31,11 +27,11 @@
3127
"s3SchemaVersion": "1.0",
3228
"configurationId": "<config-id:1>",
3329
"bucket": {
34-
"name": "<resource:2>",
30+
"name": "<resource:1>",
3531
"ownerIdentity": {
3632
"principalId": "<principal-id:1>"
3733
},
38-
"arn": "arn:aws:s3:::<resource:2>"
34+
"arn": "arn:aws:s3:::<resource:1>"
3935
},
4036
"object": {
4137
"key": "bucket-key",
@@ -47,17 +43,17 @@
4743
}
4844
]
4945
},
50-
"Timestamp": "date",
51-
"SignatureVersion": "1",
46+
"MessageId": "<uuid:1>",
5247
"Signature": "signature",
48+
"SignatureVersion": "1",
5349
"SigningCertURL": "https://sns.<region>.amazonaws.com/SimpleNotificationService-<signing-cert-file:1>.pem",
54-
"UnsubscribeURL": "<unsubscribe-domain>/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:<region>:111111111111:<resource:1>:<token:1>"
50+
"Subject": "Amazon S3 Notification",
51+
"Timestamp": "date",
52+
"TopicArn": "arn:aws:sns:<region>:111111111111:<resource:2>",
53+
"Type": "Notification",
54+
"UnsubscribeURL": "<unsubscribe-domain>/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:<region>:111111111111:<resource:2>:<token:1>"
5555
},
5656
{
57-
"Type": "Notification",
58-
"MessageId": "<uuid:2>",
59-
"TopicArn": "arn:aws:sns:<region>:111111111111:<resource:1>",
60-
"Subject": "Amazon S3 Notification",
6157
"Message": {
6258
"Records": [
6359
{
@@ -80,11 +76,11 @@
8076
"s3SchemaVersion": "1.0",
8177
"configurationId": "<config-id:1>",
8278
"bucket": {
83-
"name": "<resource:2>",
79+
"name": "<resource:1>",
8480
"ownerIdentity": {
8581
"principalId": "<principal-id:1>"
8682
},
87-
"arn": "arn:aws:s3:::<resource:2>"
83+
"arn": "arn:aws:s3:::<resource:1>"
8884
},
8985
"object": {
9086
"key": "bucket-key",
@@ -96,11 +92,15 @@
9692
}
9793
]
9894
},
99-
"Timestamp": "date",
100-
"SignatureVersion": "1",
95+
"MessageId": "<uuid:2>",
10196
"Signature": "signature",
97+
"SignatureVersion": "1",
10298
"SigningCertURL": "https://sns.<region>.amazonaws.com/SimpleNotificationService-<signing-cert-file:1>.pem",
103-
"UnsubscribeURL": "<unsubscribe-domain>/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:<region>:111111111111:<resource:1>:<token:1>"
99+
"Subject": "Amazon S3 Notification",
100+
"Timestamp": "date",
101+
"TopicArn": "arn:aws:sns:<region>:111111111111:<resource:2>",
102+
"Type": "Notification",
103+
"UnsubscribeURL": "<unsubscribe-domain>/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:<region>:111111111111:<resource:2>:<token:1>"
104104
}
105105
]
106106
}

tests/integration/test_sns.snapshot.json

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,15 @@
114114
}
115115
},
116116
"tests/integration/test_sns.py::TestSNSProvider::test_redrive_policy_sqs_queue_subscription[True]": {
117-
"recorded-date": "03-08-2022, 16:38:45",
117+
"recorded-date": "08-08-2022, 17:49:05",
118118
"recorded-content": {
119119
"raw_message_delivery": {
120120
"Messages": [
121121
{
122-
"MessageId": "<uuid:1>",
123-
"ReceiptHandle": "<receipt-handle:1>",
122+
"Body": "test_dlq_after_sqs_endpoint_deleted",
124123
"MD5OfBody": "<md5-hash>",
125-
"Body": "test_dlq_after_sqs_endpoint_deleted"
124+
"MessageId": "<uuid:1>",
125+
"ReceiptHandle": "<receipt-handle:1>"
126126
}
127127
],
128128
"ResponseMetadata": {
@@ -133,35 +133,35 @@
133133
}
134134
},
135135
"tests/integration/test_sns.py::TestSNSProvider::test_redrive_policy_sqs_queue_subscription[False]": {
136-
"recorded-date": "03-08-2022, 16:38:48",
136+
"recorded-date": "08-08-2022, 17:49:08",
137137
"recorded-content": {
138138
"json_encoded_delivery": {
139139
"Messages": [
140140
{
141-
"MessageId": "<uuid:1>",
142-
"ReceiptHandle": "<receipt-handle:1>",
143-
"MD5OfBody": "<md5-hash>",
144141
"Body": {
145-
"Type": "Notification",
146-
"MessageId": "<uuid:2>",
147-
"TopicArn": "arn:aws:sns:<region>:111111111111:<resource:1>",
148142
"Message": "test_dlq_after_sqs_endpoint_deleted",
149-
"Timestamp": "date",
150-
"SignatureVersion": "1",
151-
"Signature": "<signature>",
152-
"SigningCertURL": "https://sns.<region>.amazonaws.com/SimpleNotificationService-<signing-cert-file:1>.pem",
153-
"UnsubscribeURL": "<unsubscribe-domain>/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:<region>:111111111111:<resource:1>:<token:1>",
154143
"MessageAttributes": {
155-
"attr2": {
156-
"Type": "Binary",
157-
"Value": "AgME"
158-
},
159144
"attr1": {
160145
"Type": "Number",
161146
"Value": "111"
147+
},
148+
"attr2": {
149+
"Type": "Binary",
150+
"Value": "AgME"
162151
}
163-
}
164-
}
152+
},
153+
"MessageId": "<uuid:1>",
154+
"Signature": "<signature>",
155+
"SignatureVersion": "1",
156+
"SigningCertURL": "https://sns.<region>.amazonaws.com/SimpleNotificationService-<signing-cert-file:1>.pem",
157+
"Timestamp": "date",
158+
"TopicArn": "arn:aws:sns:<region>:111111111111:<resource:1>",
159+
"Type": "Notification",
160+
"UnsubscribeURL": "<unsubscribe-domain>/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:<region>:111111111111:<resource:1>:<token:1>"
161+
},
162+
"MD5OfBody": "<md5-hash>",
163+
"MessageId": "<uuid:2>",
164+
"ReceiptHandle": "<receipt-handle:1>"
165165
}
166166
],
167167
"ResponseMetadata": {

tests/unit/utils/testing/test_snapshots.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from localstack.testing.snapshots import SnapshotSession
44
from localstack.testing.snapshots.transformer import KeyValueBasedTransformer
5+
from localstack.testing.snapshots.transformer_utility import _resource_name_transformer
56

67

78
class TestSnapshotManager:
@@ -35,3 +36,48 @@ def test_context_replacement(self):
3536
sm.recorded_state = {"key_a": {"aaa": "<A:1>", "bbb": "<A:1> hello"}}
3637
sm.match("key_a", {"aaa": "something", "bbb": "something hello"})
3738
sm._assert_all()
39+
40+
def test_match_order_reference_replacement(self):
41+
"""tests if the reference-replacement works as expected, e.g., using alphabetical order of keys"""
42+
sm = SnapshotSession(scope_key="A", verify=True, file_path="", update=False)
43+
44+
sm.add_transformer(KeyValueBasedTransformer(_resource_name_transformer, "resource"))
45+
46+
sm.recorded_state = {
47+
"subscription-attributes": {
48+
"Attributes": {
49+
"ConfirmationWasAuthenticated": "true",
50+
"Endpoint": "arn:aws:lambda:region:111111111111:function:<resource:1>",
51+
"Owner": "111111111111",
52+
"PendingConfirmation": "false",
53+
"Protocol": "lambda",
54+
"RawMessageDelivery": "false",
55+
"RedrivePolicy": {
56+
"deadLetterTargetArn": "arn:aws:sqs:region:111111111111:<resource:2>"
57+
},
58+
"SubscriptionArn": "arn:aws:sns:region:111111111111:<resource:4>:<resource:3>",
59+
"TopicArn": "arn:aws:sns:region:111111111111:<resource:4>",
60+
},
61+
"ResponseMetadata": {"HTTPHeaders": {}, "HTTPStatusCode": 200},
62+
}
63+
}
64+
sm.match(
65+
"subscription-attributes",
66+
{
67+
"Attributes": {
68+
"ConfirmationWasAuthenticated": "true",
69+
"Owner": "111111111111",
70+
"PendingConfirmation": "false",
71+
"Protocol": "lambda",
72+
"RawMessageDelivery": "false",
73+
"RedrivePolicy": {
74+
"deadLetterTargetArn": "arn:aws:sqs:region:111111111111:111112222233333"
75+
},
76+
"TopicArn": "arn:aws:sns:region:111111111111:rrrrrrrrrrrrrrrrr",
77+
"SubscriptionArn": "arn:aws:sns:region:111111111111:rrrrrrrrrrrrrrrrr:azazazazazazazaza",
78+
"Endpoint": "arn:aws:lambda:region:111111111111:function:aaaaabbbbb",
79+
},
80+
"ResponseMetadata": {"HTTPHeaders": {}, "HTTPStatusCode": 200},
81+
},
82+
)
83+
sm._assert_all()

0 commit comments

Comments
 (0)
0