66from cloudformation_cli_python_lib .interface import (
77 BaseModel ,
88 HandlerErrorCode ,
9+ HookAnnotation ,
10+ HookAnnotationSeverityLevel ,
11+ HookAnnotationStatus ,
912 HookProgressEvent ,
1013 HookStatus ,
1114 OperationStatus ,
1215 ProgressEvent ,
1316)
17+ from cloudformation_cli_python_lib .utils import KitchenSinkEncoder
1418
1519import hypothesis .strategies as s # pylint: disable=C0411
1620import json
@@ -140,6 +144,80 @@ def test_hook_progress_event_failed_is_json_serializable(error_code, message):
140144 }
141145
142146
147+ @given (
148+ s .sampled_from (HandlerErrorCode ),
149+ s .text (ascii_letters ),
150+ s .sampled_from (HookAnnotationSeverityLevel ),
151+ )
152+ def test_hook_progress_event_failed_with_annotations_is_json_serializable (
153+ error_code ,
154+ message ,
155+ annotation_severity_level ,
156+ ):
157+ event = HookProgressEvent (
158+ hookStatus = OperationStatus .FAILED ,
159+ message = message ,
160+ errorCode = error_code ,
161+ annotations = [
162+ HookAnnotation (
163+ annotationName = "test_annotation_name_1" ,
164+ status = HookAnnotationStatus .FAILED ,
165+ statusMessage = "test_status_message_1" ,
166+ remediationMessage = "test_remediation_message" ,
167+ remediationLink = "https://localhost/test-1" ,
168+ severityLevel = annotation_severity_level ,
169+ ),
170+ HookAnnotation (
171+ annotationName = "test_annotation_name_2" ,
172+ status = HookAnnotationStatus .PASSED ,
173+ statusMessage = "test_status_message_2" ,
174+ ),
175+ ],
176+ )
177+
178+ assert event .hookStatus == HookStatus .FAILED
179+ assert event .errorCode == error_code
180+ assert event .message == message
181+
182+ assert event .annotations [0 ].annotationName == "test_annotation_name_1"
183+ assert event .annotations [0 ].status == HookAnnotationStatus .FAILED .name
184+ assert event .annotations [0 ].statusMessage == "test_status_message_1"
185+ assert event .annotations [0 ].remediationMessage == "test_remediation_message"
186+ assert event .annotations [0 ].remediationLink == "https://localhost/test-1"
187+ assert event .annotations [0 ].severityLevel == annotation_severity_level
188+
189+ assert event .annotations [1 ].annotationName == "test_annotation_name_2"
190+ assert event .annotations [1 ].status == HookAnnotationStatus .PASSED .name
191+ assert event .annotations [1 ].statusMessage == "test_status_message_2"
192+
193+ assert json .loads (
194+ json .dumps (
195+ event ._serialize (),
196+ cls = KitchenSinkEncoder ,
197+ )
198+ ) == {
199+ "hookStatus" : HookStatus .FAILED .value ,
200+ "errorCode" : error_code .value ,
201+ "message" : message ,
202+ "callbackDelaySeconds" : 0 ,
203+ "annotations" : [
204+ {
205+ "annotationName" : "test_annotation_name_1" ,
206+ "status" : "FAILED" ,
207+ "statusMessage" : "test_status_message_1" ,
208+ "remediationMessage" : "test_remediation_message" ,
209+ "remediationLink" : "https://localhost/test-1" ,
210+ "severityLevel" : annotation_severity_level .name ,
211+ },
212+ {
213+ "annotationName" : "test_annotation_name_2" ,
214+ "status" : "PASSED" ,
215+ "statusMessage" : "test_status_message_2" ,
216+ },
217+ ],
218+ }
219+
220+
143221@given (s .text (ascii_letters ))
144222def test_hook_progress_event_serialize_to_response_with_context (message ):
145223 event = HookProgressEvent (
@@ -154,6 +232,43 @@ def test_hook_progress_event_serialize_to_response_with_context(message):
154232 }
155233
156234
235+ @given (s .text (ascii_letters ))
236+ def test_hook_progress_event_serialize_to_response_with_context_with_annotation (
237+ message ,
238+ ):
239+ event = HookProgressEvent (
240+ hookStatus = HookStatus .SUCCESS ,
241+ message = message ,
242+ callbackContext = {"a" : "b" },
243+ annotations = [
244+ HookAnnotation (
245+ annotationName = "test_annotation_name" ,
246+ status = HookAnnotationStatus .PASSED ,
247+ statusMessage = "test_status_message" ,
248+ ),
249+ ],
250+ )
251+
252+ assert json .loads (
253+ json .dumps (
254+ event ._serialize (),
255+ cls = KitchenSinkEncoder ,
256+ )
257+ ) == {
258+ "hookStatus" : HookStatus .SUCCESS .name , # pylint: disable=no-member
259+ "message" : message ,
260+ "callbackContext" : {"a" : "b" },
261+ "callbackDelaySeconds" : 0 ,
262+ "annotations" : [
263+ {
264+ "annotationName" : "test_annotation_name" ,
265+ "status" : "PASSED" ,
266+ "statusMessage" : "test_status_message" ,
267+ },
268+ ],
269+ }
270+
271+
157272@given (s .text (ascii_letters ))
158273def test_hook_progress_event_serialize_to_response_with_data (message ):
159274 result = "My hook data"
@@ -169,6 +284,42 @@ def test_hook_progress_event_serialize_to_response_with_data(message):
169284 }
170285
171286
287+ @given (s .text (ascii_letters ))
288+ def test_hook_progress_event_serialize_to_response_with_data_with_annotation (message ):
289+ result = "My hook data"
290+ event = HookProgressEvent (
291+ hookStatus = HookStatus .SUCCESS ,
292+ message = message ,
293+ result = result ,
294+ annotations = [
295+ HookAnnotation (
296+ annotationName = "test_annotation_name" ,
297+ status = HookAnnotationStatus .PASSED ,
298+ statusMessage = "test_status_message" ,
299+ ),
300+ ],
301+ )
302+
303+ assert json .loads (
304+ json .dumps (
305+ event ._serialize (),
306+ cls = KitchenSinkEncoder ,
307+ )
308+ ) == {
309+ "hookStatus" : HookStatus .SUCCESS .name , # pylint: disable=no-member
310+ "message" : message ,
311+ "callbackDelaySeconds" : 0 ,
312+ "result" : result ,
313+ "annotations" : [
314+ {
315+ "annotationName" : "test_annotation_name" ,
316+ "status" : "PASSED" ,
317+ "statusMessage" : "test_status_message" ,
318+ },
319+ ],
320+ }
321+
322+
172323@given (s .text (ascii_letters ))
173324def test_hook_progress_event_serialize_to_response_with_error_code (message ):
174325 event = HookProgressEvent (
@@ -185,6 +336,43 @@ def test_hook_progress_event_serialize_to_response_with_error_code(message):
185336 }
186337
187338
339+ @given (s .text (ascii_letters ))
340+ def test_hook_progress_event_serialize_to_response_with_error_code_with_annotation (
341+ message ,
342+ ):
343+ event = HookProgressEvent (
344+ hookStatus = HookStatus .FAILED ,
345+ message = message ,
346+ errorCode = HandlerErrorCode .InvalidRequest ,
347+ annotations = [
348+ HookAnnotation (
349+ annotationName = "test_annotation_name" ,
350+ status = HookAnnotationStatus .FAILED ,
351+ statusMessage = "test_status_message" ,
352+ ),
353+ ],
354+ )
355+
356+ assert json .loads (
357+ json .dumps (
358+ event ._serialize (),
359+ cls = KitchenSinkEncoder ,
360+ )
361+ ) == {
362+ "hookStatus" : HookStatus .FAILED .name , # pylint: disable=no-member
363+ "message" : message ,
364+ "errorCode" : HandlerErrorCode .InvalidRequest .name , # pylint: disable=no-member
365+ "callbackDelaySeconds" : 0 ,
366+ "annotations" : [
367+ {
368+ "annotationName" : "test_annotation_name" ,
369+ "status" : "FAILED" ,
370+ "statusMessage" : "test_status_message" ,
371+ },
372+ ],
373+ }
374+
375+
188376def test_operation_status_enum_matches_sdk (client ):
189377 sdk = set (client .meta .service_model .shape_for ("OperationStatus" ).enum )
190378 enum = set (OperationStatus .__members__ )
0 commit comments