From e7c58f3c4fbfe46ca483bf23247fb30ff2db617a Mon Sep 17 00:00:00 2001 From: Mariusz Nowak Date: Fri, 10 Dec 2021 15:12:44 +0100 Subject: [PATCH] test(AWS Stream): Prepare tests refactor plan --- .../aws/package/compile/events/stream.test.js | 527 +++++++++++++----- 1 file changed, 377 insertions(+), 150 deletions(-) diff --git a/test/unit/lib/plugins/aws/package/compile/events/stream.test.js b/test/unit/lib/plugins/aws/package/compile/events/stream.test.js index 8dcfcf7a1..08fa07a2f 100644 --- a/test/unit/lib/plugins/aws/package/compile/events/stream.test.js +++ b/test/unit/lib/plugins/aws/package/compile/events/stream.test.js @@ -32,58 +32,7 @@ describe('AwsCompileStreamEvents', () => { awsCompileStreamEvents.serverless.service.service = 'new-service'; }); - describe('#constructor()', () => { - it('should set the provider variable to be an instance of AwsProvider', () => - expect(awsCompileStreamEvents.provider).to.be.instanceof(AwsProvider)); - }); - describe('#compileStreamEvents()', () => { - it('should throw an error if the "consumer" property is not a string, object, or boolean', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [ - { - stream: { - type: 'kinesis', - arn: 'arn:aws:kinesis:us-east-1:123456789012:stream/myStream', - consumer: 42, - }, - }, - ], - }, - }; - }); - - it('should throw an error if stream event type is not a string or an object', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [ - { - stream: 42, - }, - ], - }, - }; - - expect(() => awsCompileStreamEvents.compileStreamEvents()).to.throw(Error); - }); - - it('should throw an error if the "arn" property is not given', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [ - { - stream: { - arn: null, - }, - }, - ], - }, - }; - - expect(() => awsCompileStreamEvents.compileStreamEvents()).to.throw(Error); - }); - it('should not throw error or merge role statements if default policy is not present', () => { awsCompileStreamEvents.serverless.service.functions = { first: { @@ -989,70 +938,6 @@ describe('AwsCompileStreamEvents', () => { expect(() => awsCompileStreamEvents.compileStreamEvents()).to.throw(Error); }); - it('fails if onFailure ARN is given as a variable type other than string or object', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [ - { - stream: { - arn: 'arn:aws:dynamodb:region:account:table/foo/stream/1', - destinations: { - onFailure: 3, - }, - }, - }, - ], - }, - }; - - expect(() => awsCompileStreamEvents.compileStreamEvents()).to.throw(Error); - }); - - it('fails if no arn key is given for a dynamic onFailure ARN', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [ - { - stream: { - arn: 'arn:aws:dynamodb:region:account:table/foo/stream/1', - destinations: { - onFailure: { - notarn: ['SomeSNS', 'Arn'], - }, - }, - }, - }, - ], - }, - }; - - expect(() => awsCompileStreamEvents.compileStreamEvents()).to.throw(Error); - }); - - it('fails if destinations structure is wrong', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [ - { - stream: { - arn: 'arn:aws:dynamodb:region:account:table/foo/stream/1', - destinations: { - notOnFailure: { - arn: { - 'Fn::GetAtt': ['SomeSNS', 'Arn'], - 'batchSize': 1, - }, - }, - }, - }, - }, - ], - }, - }; - - expect(() => awsCompileStreamEvents.compileStreamEvents()).to.throw(Error); - }); - it('should add the necessary IAM role statements', () => { awsCompileStreamEvents.serverless.service.functions = { first: { @@ -1538,39 +1423,6 @@ describe('AwsCompileStreamEvents', () => { }); }); - it('should not create event source mapping when stream events are not given', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [], - }, - }; - - awsCompileStreamEvents.compileStreamEvents(); - - // should be 1 because we've mocked the IamRoleLambdaExecution above - expect( - Object.keys( - awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate - .Resources - ).length - ).to.equal(1); - }); - - it('should not add the IAM role statements when stream events are not given', () => { - awsCompileStreamEvents.serverless.service.functions = { - first: { - events: [], - }, - }; - - awsCompileStreamEvents.compileStreamEvents(); - - expect( - awsCompileStreamEvents.serverless.service.provider.compiledCloudFormationTemplate.Resources - .IamRoleLambdaExecution.Properties.Policies[0].PolicyDocument.Statement.length - ).to.equal(0); - }); - it('should remove all non-alphanumerics from stream names for the resource logical ids', () => { awsCompileStreamEvents.serverless.service.functions = { first: { @@ -1604,10 +1456,170 @@ describe('test/unit/lib/plugins/aws/package/compile/events/stream.test.js', () = events: [ { stream: { - arn: 'arn:aws:kinesis:us-east-1:123456789012:stream/myStream', + arn: 'arn:aws:kinesis:us-east-1:123456789012:stream/some-long-name', functionResponseType: 'ReportBatchItemFailures', tumblingWindowInSeconds: 30, filterPatterns: [{ eventName: ['INSERT'] }, { eventName: ['MODIFY'] }], + parallelizationFactor: 10, + bisectBatchOnFunctionError: true, + consumer: true, + }, + }, + ], + }, + dynamo: { + handler: 'basic.handler', + events: [ + { + stream: { + arn: 'arn:aws:dynamodb:region:account:table/foo/stream/1', + batchSize: 1, + startingPosition: 'LATEST', + enabled: false, + batchWindow: 15, + maximumRetryAttempts: 4, + maximumRecordAgeInSeconds: 120, + destinations: { + onFailure: 'arn:aws:sns:region:account:snstopic', + }, + }, + }, + ], + }, + kinesisImportCustomIam: { + handler: 'basic.handler', + role: { + 'Fn::Sub': 'arn:aws:iam::${AWS::AccountId}:role/iam-role-name', + }, + events: [ + { + stream: { + arn: { 'Fn::ImportValue': 'ForeignKinesis' }, + type: 'kinesis', + consumer: + 'arn:aws:kinesis:region:account:stream/xyz/consumer/foobar:1558544531', + }, + }, + ], + }, + arnVariants: { + handler: 'basic.handler', + events: [ + { + stream: { + arn: { 'Fn::GetAtt': ['SomeDdbTable', 'StreamArn'] }, + type: 'dynamodb', + destinations: { + onFailure: { + arn: { 'Fn::ImportValue': 'ForeignSQS' }, + type: 'sqs', + }, + }, + }, + }, + { + stream: { + arn: { + 'Fn::Join': [ + ':', + [ + 'arn', + 'aws', + 'kinesis', + { + Ref: 'AWS::Region', + }, + { + Ref: 'AWS::AccountId', + }, + 'stream/MyStream', + ], + ], + }, + type: 'kinesis', + }, + }, + { + stream: { + arn: { Ref: 'SomeDdbTableStreamArn' }, + type: 'dynamodb', + destinations: { + onFailure: { + arn: { 'Fn::ImportValue': 'ForeignSQS' }, + type: 'sqs', + }, + }, + }, + }, + { + stream: { + arn: { Ref: 'ForeignKinesisStreamArn' }, + type: 'kinesis', + }, + }, + ], + }, + destinationVariants: { + handler: 'basic.handler', + events: [ + { + stream: { + arn: 'arn:aws:dynamodb:region:account:table/foo/stream/1', + destinations: { + onFailure: { + arn: { 'Fn::GetAtt': ['SomeSNS', 'Arn'] }, + type: 'sns', + }, + }, + }, + }, + { + stream: { + arn: 'arn:aws:dynamodb:region:account:table/foo/stream/1', + destinations: { + onFailure: { + arn: { + 'Fn::Join': [ + ':', + [ + 'arn', + 'aws', + 'sqs', + { + Ref: 'AWS::Region', + }, + { + Ref: 'AWS::AccountId', + }, + 'MyQueue', + ], + ], + }, + type: 'sqs', + }, + }, + }, + }, + { + stream: { + arn: 'arn:aws:dynamodb:region:account:table/buzz/stream/1', + destinations: { + onFailure: { + arn: { Ref: 'SomeSNSArn' }, + type: 'sns', + }, + }, + }, + }, + { + stream: { + arn: 'arn:aws:dynamodb:region:account:table/fizz/stream/1', + destinations: { + onFailure: { + arn: { Ref: 'ForeignSQSArn' }, + type: 'sqs', + }, + }, }, }, ], @@ -1616,10 +1628,159 @@ describe('test/unit/lib/plugins/aws/package/compile/events/stream.test.js', () = }, command: 'package', }); - const streamLogicalId = awsNaming.getStreamLogicalId('basic', 'kinesis', 'myStream'); + const streamLogicalId = awsNaming.getStreamLogicalId('basic', 'kinesis', 'some-long-name'); eventSourceMappingResource = cfTemplate.Resources[streamLogicalId]; }); + it.skip('TODO: should support ARN String for `arn`', () => { + // Replaces + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 (partially) + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1574-L1591 + // + // Confirm effect of: + // - `functions.basic.events[0].stream.arn` + // - `functions.dynamodb.events[0].stream.arn` + }); + + it.skip('TODO: should support Fn::GetAtt for `arn`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L586-L741 + // + // Confirm effect of `functions.arnVariants.events[0].stream.arn` + }); + + it.skip('TODO: should support Fn::ImportValue for `arn`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L586-L741 + // + // Confirm effect of `functions.kinesisImportCustomIam.events[0].stream.arn` + }); + + it.skip('TODO: should support Fn::Join for `arn`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L586-L741 + // + // Confirm effect of `functions.arnVariants.events[1].stream.arn` + }); + + it.skip('TODO: should support Ref for `arn`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L586-L741 + // + // Confirm effect of: + // - `functions.arnVariants.events[2].stream.arn` + // - `functions.arnVariants.events[3].stream.arn` + }); + + it.skip('TODO: should support `batchSize`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.dynamo.events[0].stream.batchSize` + }); + + it.skip('TODO: should support `startingPosition`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.dynamo.events[0].stream.startingPosition` + }); + + it.skip('TODO: should support `enabled`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.dynamo.events[0].stream.enabled` + }); + + it.skip('TODO: should support `batchWindow`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.dynamo.events[0].stream.batchWindow` + }); + + it.skip('TODO: should support `maximumRetryAttempts`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.dynamo.events[0].stream.maximumRetryAttempts` + }); + + it.skip('TODO: should support `maximumRecordAgeInSeconds`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.dynamo.events[0].stream.maximumRecordAgeInSeconds` + }); + + it.skip('TODO: should support `parallelizationFactor`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.basic.events[0].stream.parallelizationFactor` + }); + + it.skip('TODO: should support `bisectBatchOnFunctionError`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1106-L1453 + // + // Confirm effect of `functions.basic.events[0].stream.bisectBatchOnFunctionError` + }); + + it.skip('TODO: should support `consumer`', () => { + // Replaces + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1437-L1465 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1467-L1539 (partially) + // + // Confirm effect of: + // - `functions.basic.events[0].stream.consumer` + // - `functions.kinesisImportCustomIam.events[0].stream.consumer` + }); + + it.skip('TODO: should support ARN string for `destinations.onFailure`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L370-L584 + // + // Confirm effect of: `functions.dynamo.events[0].stream.destinations` + }); + + it.skip('TODO: should support Fn::GetAtt for `destinations.onFailure`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L743-L916 + // + // Confirm effect of: `functions.destinationVariants.events[0].stream.destinations` + }); + + it.skip('TODO: should support Fn::ImportValue for `destinations.onFailure`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L743-L916 + // + // Confirm effect of: `functions.arnVariants.events[2].stream.destinations` + }); + + it.skip('TODO: should support Fn::Join for `destinations.onFailure`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L743-L916 + // + // Confirm effect of: `functions.destinationVariants.events[1].stream.destinations` + }); + + it.skip('TODO: should support Ref for `destinations.onFailure`', () => { + // Replaces partially + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L743-L916 + // + // Confirm effect of: + // - `functions.destinationVariants.events[2].stream.destinations` + // - `functions.destinationVariants.events[3].stream.destinations` + }); + it('should support `functionResponseType`', () => { expect(eventSourceMappingResource.Properties.FunctionResponseTypes).to.include.members([ 'ReportBatchItemFailures', @@ -1642,6 +1803,72 @@ describe('test/unit/lib/plugins/aws/package/compile/events/stream.test.js', () = ], }); }); + + it.skip('TODO: should ensure necessary IAM statememnts', () => { + // Replaces + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L87-L366 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1056-L1103 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L1467-L1539 (partially) + // + // Confirm expected IAM statements on final role + }); + }); + + describe.skip('TODO: failures', () => { + it("should fail if stream `type` is not set and couldn't be assumed", async () => { + // Replaces + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L918-L932 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L955-L969 + await expect( + runServerless({ + fixture: 'function', + command: 'package', + configExt: { + functions: { + basic: { + events: [ + { + stream: { + arn: { Ref: 'SomeDdbTableStreamArn' }, + }, + }, + ], + }, + }, + }, + }) + ).to.be.eventually.rejected.and.have.property('code', 'TODO'); + }); + + it("should fail if destination `type` is not set and couldn't be assumed", async () => { + // Replaces + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L934-L953 + // https://github.com/serverless/serverless/blob/f64f7c68abb1d6837ecaa6173f4b605cf3975acf/test/unit/lib/plugins/aws/package/compile/events/stream.test.js#L971-L990 + await expect( + runServerless({ + fixture: 'function', + command: 'package', + configExt: { + functions: { + basic: { + events: [ + { + stream: { + arn: 'arn:aws:dynamodb:region:account:table/fizz/stream/1', + destinations: { + onFailure: { + arn: { Ref: 'ForeignSQSArn' }, + }, + }, + }, + }, + ], + }, + }, + }, + }) + ).to.be.eventually.rejected.and.have.property('code', 'TODO'); + }); }); describe('with provisioned concurrency', () => {