@@ -7,48 +7,103 @@ import (
77 "context"
88 "encoding/json"
99 "errors"
10+ "fmt"
1011 "io/ioutil" //nolint: staticcheck
1112 "net/http"
1213 "testing"
1314
14- "github.com/aws/aws-lambda-go/lambdacontext"
1515 "github.com/stretchr/testify/assert"
1616)
1717
1818var testEvent = & Event {
19- RequestType : RequestCreate ,
20- RequestID : "unique id for this create request" ,
21- ResponseURL : "http://pre-signed-S3-url-for-response" ,
22- LogicalResourceID : "MyTestResource" ,
23- StackID : "arn:aws:cloudformation:us-west-2:EXAMPLE/stack-name/guid" ,
19+ RequestType : RequestUpdate ,
20+ RequestID : "unique id for this create request" ,
21+ ResponseURL : "http://pre-signed-S3-url-for-response" ,
22+ LogicalResourceID : "MyTestResource" ,
23+ PhysicalResourceID : "prevPhysicalResourceID" ,
24+ StackID : "arn:aws:cloudformation:us-west-2:EXAMPLE/stack-name/guid" ,
2425}
2526
26- func TestCopyLambdaLogStream (t * testing.T ) {
27- lgs := lambdacontext .LogStreamName
28- lambdacontext .LogStreamName = "DUMMYLOGSTREAMNAME"
27+ func TestLambdaPhysicalResourceId (t * testing.T ) {
28+
29+ tests := []struct {
30+ // Input to the lambda
31+ inputRequestType RequestType
32+
33+ // Output from the lambda
34+ returnErr error
35+ returnPhysicalResourceID string
36+
37+ // The PhysicalResourceID to test
38+ expectedPhysicalResourceID string
39+ }{
40+ // For Create with no returned PhysicalResourceID
41+ {RequestCreate , nil , "" , testEvent .RequestID }, // Use RequestID as default for PhysicalResourceID
42+ {RequestCreate , fmt .Errorf ("dummy error" ), "" , testEvent .RequestID },
43+
44+ // For Create with PhysicalResourceID
45+ {RequestCreate , nil , "newPhysicalResourceID" , "newPhysicalResourceID" },
46+ {RequestCreate , fmt .Errorf ("dummy error" ), "newPhysicalResourceID" , "newPhysicalResourceID" },
47+
48+ // For Update with no returned PhysicalResourceID
49+ {RequestUpdate , nil , "" , "prevPhysicalResourceID" },
50+ {RequestUpdate , fmt .Errorf ("dummy error" ), "" , "prevPhysicalResourceID" },
51+
52+ // For Update with returned PhysicalResourceID
53+ {RequestUpdate , nil , "newPhysicalResourceID" , "newPhysicalResourceID" },
54+ {RequestUpdate , fmt .Errorf ("dummy error" ), "newPhysicalResourceID" , "newPhysicalResourceID" },
55+
56+ // For Delete with no returned PhysicalResourceID
57+ {RequestDelete , nil , "" , "prevPhysicalResourceID" },
58+ {RequestDelete , fmt .Errorf ("dummy error" ), "" , "prevPhysicalResourceID" },
59+
60+ // For Delete with returned PhysicalResourceID = old PhysicalResourceID
61+ {RequestDelete , nil , "prevPhysicalResourceID" , "prevPhysicalResourceID" },
62+ {RequestDelete , fmt .Errorf ("dummy error" ), "prevPhysicalResourceID" , "prevPhysicalResourceID" },
63+
64+ // For Delete with returned PhysicalResourceID != old PhysicalResourceID
65+ // Technically, lambda handlers shouldn't return a different physical resource id upon deletion.
66+ // Typescript CDK implementation for handlers would return an error here.
67+ // But CFn ignores the returned PhysicalResourceID for deletion so it doesn't matter.
68+ {RequestDelete , nil , "newPhysicalResourceID" , "newPhysicalResourceID" },
69+ {RequestDelete , fmt .Errorf ("dummy error" ), "newPhysicalResourceID" , "newPhysicalResourceID" },
70+ }
71+ for _ , test := range tests {
2972
30- client := & mockClient {
31- DoFunc : func (req * http.Request ) (* http.Response , error ) {
32- response := extractResponseBody (t , req )
73+ curTestEvent := * testEvent
74+ curTestEvent .RequestType = test .inputRequestType
3375
34- assert . Equal ( t , StatusSuccess , response . Status )
35- assert . Equal ( t , testEvent . LogicalResourceID , response . LogicalResourceID )
36- assert . Equal ( t , "DUMMYLOGSTREAMNAME" , response . PhysicalResourceID )
76+ if curTestEvent . RequestType == RequestCreate {
77+ curTestEvent . PhysicalResourceID = ""
78+ }
3779
38- return & http.Response {
39- StatusCode : http .StatusOK ,
40- Body : nopCloser {bytes .NewBufferString ("" )},
41- }, nil
42- },
43- }
80+ client := & mockClient {
81+ DoFunc : func (req * http.Request ) (* http.Response , error ) {
82+ response := extractResponseBody (t , req )
4483
45- fn := func (ctx context.Context , event Event ) (physicalResourceID string , data map [string ]interface {}, err error ) {
46- return
47- }
84+ if test .returnErr == nil {
85+ assert .Equal (t , StatusSuccess , response .Status )
86+ } else {
87+ assert .Equal (t , StatusFailed , response .Status )
88+ }
4889
49- _ , err := lambdaWrapWithClient (fn , client )(context .TODO (), * testEvent )
50- assert .NoError (t , err )
51- lambdacontext .LogStreamName = lgs
90+ assert .Equal (t , curTestEvent .LogicalResourceID , response .LogicalResourceID )
91+ assert .Equal (t , test .expectedPhysicalResourceID , response .PhysicalResourceID )
92+
93+ return & http.Response {
94+ StatusCode : http .StatusOK ,
95+ Body : nopCloser {bytes .NewBufferString ("" )},
96+ }, nil
97+ },
98+ }
99+
100+ fn := func (ctx context.Context , event Event ) (physicalResourceID string , data map [string ]interface {}, err error ) {
101+ return test .returnPhysicalResourceID , nil , test .returnErr
102+ }
103+
104+ _ , err := lambdaWrapWithClient (fn , client )(context .TODO (), curTestEvent )
105+ assert .NoError (t , err )
106+ }
52107}
53108
54109func TestPanicSendsFailure (t * testing.T ) {
@@ -58,6 +113,9 @@ func TestPanicSendsFailure(t *testing.T) {
58113 DoFunc : func (req * http.Request ) (* http.Response , error ) {
59114 response := extractResponseBody (t , req )
60115 assert .Equal (t , StatusFailed , response .Status )
116+
117+ // Even in a panic, a dummy PhysicalResourceID should be returned to ensure the error is surfaced correctly
118+ assert .Equal (t , testEvent .PhysicalResourceID , response .PhysicalResourceID )
61119 didSendStatus = response .Status == StatusFailed
62120
63121 return & http.Response {
@@ -111,7 +169,7 @@ func TestWrappedError(t *testing.T) {
111169 response := extractResponseBody (t , req )
112170
113171 assert .Equal (t , StatusFailed , response .Status )
114- assert .Empty ( t , response .PhysicalResourceID )
172+ assert .Equal ( t , testEvent . PhysicalResourceID , response .PhysicalResourceID )
115173 assert .Equal (t , "failed to create resource" , response .Reason )
116174
117175 return & http.Response {
0 commit comments