@@ -27,16 +27,21 @@ describe('#compileNotifications', () => {
27
27
serverlessStepFunctions = new ServerlessStepFunctions ( serverless , options ) ;
28
28
} ) ;
29
29
30
- const validateCloudWatchEvent = ( event , status ) => {
30
+ const validateCloudWatchEvent = ( resources , logicalId , status ) => {
31
+ expect ( resources ) . to . haveOwnProperty ( logicalId ) ;
32
+ const event = resources [ logicalId ] ;
31
33
expect ( event . Type ) . to . equal ( 'AWS::Events::Rule' ) ;
32
34
expect ( event . Properties . EventPattern . source ) . to . deep . equal ( [ 'aws.states' ] ) ;
33
35
expect ( event . Properties . EventPattern . detail . status ) . to . deep . equal ( [ status ] ) ;
34
36
expect ( event . Properties . Targets ) . to . have . lengthOf ( 8 ) ;
35
37
36
38
for ( const target of event . Properties . Targets ) {
37
- expect ( _ . isString ( target . Arn ) ) . to . equal ( true ) ;
38
- expect ( typeof target . Arn ) . to . equal ( 'string' ) ;
39
- expect ( _ . isString ( target . Id ) ) . to . equal ( true ) ;
39
+ const isStringOrFn =
40
+ _ . isString ( target . Arn ) ||
41
+ ( target . Arn . Ref && _ . isString ( target . Arn . Ref ) ) ||
42
+ ( target . Arn [ 'Fn::GetAtt' ] && _ . isArray ( target . Arn [ 'Fn::GetAtt' ] ) ) ;
43
+
44
+ expect ( isStringOrFn ) . to . equal ( true ) ;
40
45
}
41
46
42
47
const sqsWithParam = event . Properties . Targets . find ( t => t . SqsParameters ) ;
@@ -47,33 +52,22 @@ describe('#compileNotifications', () => {
47
52
48
53
const validateHasPermission = ( iamRole , action , resource ) => {
49
54
const statements = iamRole . Properties . Policies [ 0 ] . PolicyDocument . Statement ;
50
- expect ( statements . find ( x => x . Action === action && x . Resource === resource ) )
55
+ expect ( statements . find ( x => x . Action === action && _ . isEqual ( x . Resource , resource ) ) )
51
56
. to . not . equal ( undefined ) ;
52
57
} ;
53
58
54
- const validateCloudWatchIamRole = ( iamRole ) => {
55
- // 8 targets, 5 event rules = 5 * 8 = 40 statements
56
- expect ( iamRole . Properties . Policies [ 0 ] . PolicyDocument . Statement ) . to . have . lengthOf ( 40 ) ;
57
- validateHasPermission ( iamRole , 'sns:Publish' , 'SNS_TOPIC_ARN' ) ;
58
- validateHasPermission ( iamRole , 'sqs:SendMessage' , 'SQS_QUEUE_ARN' ) ;
59
- validateHasPermission ( iamRole , 'kinesis:PutRecord' , 'KINESIS_STREAM_ARN' ) ;
60
- validateHasPermission ( iamRole , 'firehose:PutRecord' , 'FIREHOSE_STREAM_ARN' ) ;
61
- validateHasPermission ( iamRole , 'lambda:InvokeFunction' , 'LAMBDA_FUNCTION_ARN' ) ;
62
- validateHasPermission ( iamRole , 'states:StartExecution' , 'STATE_MACHINE_ARN' ) ;
63
- } ;
59
+ it ( 'should generate CloudWatch Event Rules with strig ARNs' , ( ) => {
60
+ const targets = [
61
+ { sns : 'SNS_TOPIC_ARN' } ,
62
+ { sqs : 'SQS_QUEUE_ARN' } ,
63
+ { sqs : { arn : 'SQS_QUEUE_ARN' , messageGroupId : '12345' } } ,
64
+ { lambda : 'LAMBDA_FUNCTION_ARN' } ,
65
+ { kinesis : 'KINESIS_STREAM_ARN' } ,
66
+ { kinesis : { arn : 'KINESIS_STREAM_ARN' , partitionKeyPath : '$.id' } } ,
67
+ { firehose : 'FIREHOSE_STREAM_ARN' } ,
68
+ { stepFunctions : 'STATE_MACHINE_ARN' } ,
69
+ ] ;
64
70
65
- const targets = [
66
- { sns : 'SNS_TOPIC_ARN' } ,
67
- { sqs : 'SQS_QUEUE_ARN' } ,
68
- { sqs : { arn : 'SQS_QUEUE_ARN' , messageGroupId : '12345' } } ,
69
- { lambda : 'LAMBDA_FUNCTION_ARN' } ,
70
- { kinesis : 'KINESIS_STREAM_ARN' } ,
71
- { kinesis : { arn : 'KINESIS_STREAM_ARN' , partitionKeyPath : '$.id' } } ,
72
- { firehose : 'FIREHOSE_STREAM_ARN' } ,
73
- { stepFunctions : 'STATE_MACHINE_ARN' } ,
74
- ] ;
75
-
76
- it ( 'should generate CloudWatch Event Rules' , ( ) => {
77
71
const genStateMachine = ( name ) => ( {
78
72
id : name ,
79
73
name,
@@ -105,18 +99,109 @@ describe('#compileNotifications', () => {
105
99
serverlessStepFunctions . compileNotifications ( ) ;
106
100
const resources = serverlessStepFunctions . serverless . service
107
101
. provider . compiledCloudFormationTemplate . Resources ;
108
- validateCloudWatchEvent ( resources . Beta1NotificationsABORTEDEventRule , 'ABORTED' ) ;
109
- validateCloudWatchEvent ( resources . Beta1NotificationsFAILEDEventRule , 'FAILED' ) ;
110
- validateCloudWatchEvent ( resources . Beta1NotificationsRUNNINGEventRule , 'RUNNING' ) ;
111
- validateCloudWatchEvent ( resources . Beta1NotificationsSUCCEEDEDEventRule , 'SUCCEEDED' ) ;
112
- validateCloudWatchEvent ( resources . Beta1NotificationsTIMEDOUTEventRule , 'TIMED_OUT' ) ;
113
- validateCloudWatchIamRole ( resources . Beta1NotificationsIamRole ) ;
114
- validateCloudWatchEvent ( resources . Beta2NotificationsABORTEDEventRule , 'ABORTED' ) ;
115
- validateCloudWatchEvent ( resources . Beta2NotificationsFAILEDEventRule , 'FAILED' ) ;
116
- validateCloudWatchEvent ( resources . Beta2NotificationsRUNNINGEventRule , 'RUNNING' ) ;
117
- validateCloudWatchEvent ( resources . Beta2NotificationsSUCCEEDEDEventRule , 'SUCCEEDED' ) ;
118
- validateCloudWatchEvent ( resources . Beta2NotificationsTIMEDOUTEventRule , 'TIMED_OUT' ) ;
119
- validateCloudWatchIamRole ( resources . Beta2NotificationsIamRole ) ;
102
+
103
+ const validateCloudWatchEvents = ( prefix ) => {
104
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsABORTEDEventRule` , 'ABORTED' ) ;
105
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsFAILEDEventRule` , 'FAILED' ) ;
106
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsRUNNINGEventRule` , 'RUNNING' ) ;
107
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsSUCCEEDEDEventRule` , 'SUCCEEDED' ) ;
108
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsTIMEDOUTEventRule` , 'TIMED_OUT' ) ;
109
+ } ;
110
+
111
+ validateCloudWatchEvents ( 'Beta1' ) ;
112
+ validateCloudWatchEvents ( 'Beta2' ) ;
113
+
114
+ const validateIamRole = ( iamRole ) => {
115
+ // 8 targets, 5 event rules = 5 * 8 = 40 statements
116
+ expect ( iamRole . Properties . Policies [ 0 ] . PolicyDocument . Statement ) . to . have . lengthOf ( 40 ) ;
117
+ validateHasPermission ( iamRole , 'sns:Publish' , 'SNS_TOPIC_ARN' ) ;
118
+ validateHasPermission ( iamRole , 'sqs:SendMessage' , 'SQS_QUEUE_ARN' ) ;
119
+ validateHasPermission ( iamRole , 'kinesis:PutRecord' , 'KINESIS_STREAM_ARN' ) ;
120
+ validateHasPermission ( iamRole , 'firehose:PutRecord' , 'FIREHOSE_STREAM_ARN' ) ;
121
+ validateHasPermission ( iamRole , 'lambda:InvokeFunction' , 'LAMBDA_FUNCTION_ARN' ) ;
122
+ validateHasPermission ( iamRole , 'states:StartExecution' , 'STATE_MACHINE_ARN' ) ;
123
+ } ;
124
+
125
+ validateIamRole ( resources . Beta1NotificationsIamRole ) ;
126
+ validateIamRole ( resources . Beta2NotificationsIamRole ) ;
127
+
128
+ expect ( consoleLogSpy . callCount ) . equal ( 0 ) ;
129
+ } ) ;
130
+
131
+ it ( 'should generate CloudWatch Event Rules with Ref ang Fn::GetAtt' , ( ) => {
132
+ const snsArn = { Ref : 'MyTopic' } ;
133
+ const sqsArn = { 'Fn::GetAtt' : [ 'MyQueue' , 'Arn' ] } ;
134
+ const lambdaArn = { 'Fn::GetAtt' : [ 'MyFunction' , 'Arn' ] } ;
135
+ const kinesisArn = { 'Fn::GetAtt' : [ 'MyStream' , 'Arn' ] } ;
136
+ const firehoseArn = { 'Fn::GetAtt' : [ 'MyDeliveryStream' , 'Arn' ] } ;
137
+ const stepFunctionsArn = { Ref : 'MyStateMachine' } ;
138
+ const targets = [
139
+ { sns : snsArn } ,
140
+ { sqs : sqsArn } ,
141
+ { sqs : { arn : sqsArn , messageGroupId : '12345' } } ,
142
+ { lambda : lambdaArn } ,
143
+ { kinesis : kinesisArn } ,
144
+ { kinesis : { arn : kinesisArn , partitionKeyPath : '$.id' } } ,
145
+ { firehose : firehoseArn } ,
146
+ { stepFunctions : stepFunctionsArn } ,
147
+ ] ;
148
+
149
+ const genStateMachine = ( name ) => ( {
150
+ id : name ,
151
+ name,
152
+ definition : {
153
+ StartAt : 'A' ,
154
+ States : {
155
+ A : {
156
+ Type : 'Pass' ,
157
+ End : true ,
158
+ } ,
159
+ } ,
160
+ } ,
161
+ notifications : {
162
+ ABORTED : targets ,
163
+ FAILED : targets ,
164
+ RUNNING : targets ,
165
+ SUCCEEDED : targets ,
166
+ TIMED_OUT : targets ,
167
+ } ,
168
+ } ) ;
169
+
170
+ serverless . service . stepFunctions = {
171
+ stateMachines : {
172
+ beta1 : genStateMachine ( 'Beta1' ) ,
173
+ beta2 : genStateMachine ( 'Beta2' ) ,
174
+ } ,
175
+ } ;
176
+
177
+ serverlessStepFunctions . compileNotifications ( ) ;
178
+ const resources = serverlessStepFunctions . serverless . service
179
+ . provider . compiledCloudFormationTemplate . Resources ;
180
+
181
+ const validateCloudWatchEvents = ( prefix ) => {
182
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsABORTEDEventRule` , 'ABORTED' ) ;
183
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsFAILEDEventRule` , 'FAILED' ) ;
184
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsRUNNINGEventRule` , 'RUNNING' ) ;
185
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsSUCCEEDEDEventRule` , 'SUCCEEDED' ) ;
186
+ validateCloudWatchEvent ( resources , `${ prefix } NotificationsTIMEDOUTEventRule` , 'TIMED_OUT' ) ;
187
+ } ;
188
+
189
+ validateCloudWatchEvents ( 'Beta1' ) ;
190
+ validateCloudWatchEvents ( 'Beta2' ) ;
191
+
192
+ const validateIamRole = ( iamRole ) => {
193
+ // 8 targets, 5 event rules = 5 * 8 = 40 statements
194
+ expect ( iamRole . Properties . Policies [ 0 ] . PolicyDocument . Statement ) . to . have . lengthOf ( 40 ) ;
195
+ validateHasPermission ( iamRole , 'sns:Publish' , snsArn ) ;
196
+ validateHasPermission ( iamRole , 'sqs:SendMessage' , sqsArn ) ;
197
+ validateHasPermission ( iamRole , 'kinesis:PutRecord' , kinesisArn ) ;
198
+ validateHasPermission ( iamRole , 'firehose:PutRecord' , firehoseArn ) ;
199
+ validateHasPermission ( iamRole , 'lambda:InvokeFunction' , lambdaArn ) ;
200
+ validateHasPermission ( iamRole , 'states:StartExecution' , stepFunctionsArn ) ;
201
+ } ;
202
+
203
+ validateIamRole ( resources . Beta1NotificationsIamRole ) ;
204
+ validateIamRole ( resources . Beta2NotificationsIamRole ) ;
120
205
121
206
expect ( consoleLogSpy . callCount ) . equal ( 0 ) ;
122
207
} ) ;
@@ -217,6 +302,9 @@ describe('#compileNotifications', () => {
217
302
} ) ;
218
303
219
304
it ( 'should log the validation errors if notifications contains non-existent status' , ( ) => {
305
+ const targets = [
306
+ { sns : 'SNS_TOPIC_ARN' } ,
307
+ ] ;
220
308
const genStateMachine = ( name ) => ( {
221
309
id : name ,
222
310
name,
0 commit comments