From 9feac3b438c196dc87224b730a18afb6e93f56ec Mon Sep 17 00:00:00 2001 From: abetomo Date: Thu, 7 Dec 2017 10:53:29 +0900 Subject: [PATCH 1/4] Update lint and test settings --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4484ac54..ae6cff4d 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "test": "test" }, "scripts": { - "test": "standard && standard bin/node-lambda && mocha" + "lint": "standard && standard bin/node-lambda", + "test": "npm run lint && npm run unit", + "unit": "mocha" }, "bin": { "node-lambda": "./bin/node-lambda" From 016ddc55216e708a2a66cf197aa5a554cc93f85f Mon Sep 17 00:00:00 2001 From: abetomo Date: Thu, 7 Dec 2017 13:36:27 +0900 Subject: [PATCH 2/4] Add S3Events class --- lib/s3_events.js | 82 ++++++++++++++++++++++++++ test/s3_events.js | 147 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 lib/s3_events.js create mode 100644 test/s3_events.js diff --git a/lib/s3_events.js b/lib/s3_events.js new file mode 100644 index 00000000..7bd1d444 --- /dev/null +++ b/lib/s3_events.js @@ -0,0 +1,82 @@ +'use strict' + +/** + * Do not create Bucket of S3 + * Put the Notification Configuration in the existing Bucket. + */ +class S3Events { + constructor (aws) { + // Authenticated `aws` object in `lib/main.js` + this.lambda = new aws.Lambda({ + apiVersion: '2015-03-31' + }) + this.s3 = new aws.S3({ + apiVersion: '2006-03-01' + }) + } + + _functionName (params) { + return params.FunctionArn.split(':').pop() + } + + _addPermissionParams (params) { + return { + Action: 'lambda:InvokeFunction', + FunctionName: this._functionName(params), + Principal: 's3.amazonaws.com', + SourceArn: 'arn:aws:s3:::' + params.Bucket, + StatementId: params.Bucket + } + } + + _addPermission (params) { + return new Promise((resolve, reject) => { + const _params = this._addPermissionParams(params) + this.lambda.addPermission(_params, (err, data) => { + if (err) { + if (err.code !== 'ResourceConflictException') reject(err) + // If it exists it will result in an error but there is no problem. + resolve('Already exists permission') + } + resolve(data) + }) + }) + } + + _putBucketNotificationConfigurationParams (params) { + const lambdaFunctionConfiguration = { + Events: params.Events, + LambdaFunctionArn: params.FunctionArn + } + if (params.Filter != null) { + lambdaFunctionConfiguration.Filter = params.Filter + } + + return { + Bucket: params.Bucket, + NotificationConfiguration: { + LambdaFunctionConfigurations: [ + lambdaFunctionConfiguration + ] + } + } + } + + _putBucketNotificationConfiguration (params) { + return new Promise((resolve, reject) => { + const _params = this._putBucketNotificationConfigurationParams(params) + this.s3.putBucketNotificationConfiguration(_params, (err, data) => { + if (err) reject(err) + resolve(data) + }) + }) + } + + add (params) { + return this._addPermission(params).then(() => { + return this._putBucketNotificationConfiguration(params) + }) + } +} + +module.exports = S3Events diff --git a/test/s3_events.js b/test/s3_events.js new file mode 100644 index 00000000..86c09080 --- /dev/null +++ b/test/s3_events.js @@ -0,0 +1,147 @@ +'use strict' + +const assert = require('chai').assert +const path = require('path') +const aws = require('aws-sdk-mock') +aws.setSDK(path.resolve('node_modules/aws-sdk')) +const S3Events = require('../lib/s3_events') + +const params = { + FunctionArn: 'arn:aws:lambda:us-west-2:XXX:function:node-lambda-test-function', + Bucket: 'node-lambda-test-bucket', + Events: ['s3:ObjectCreated:*'], + Filter: null +} + +const mockResponse = { + addPermission: { + Statement: JSON.stringify({ + Sid: 'node-lambda-test-bucket', + Resource: 'arn:aws:lambda:node-lambda-test-function', + Effect: 'Allow', + Principal: { Service: 's3.amazonaws.com' }, + Action: [ 'lambda:InvokeFunction' ], + Condition: { ArnLike: { 'AWS:SourceArn': 'arn:aws:s3:::node-lambda-test-bucket' } } + }) + }, + + putBucketNotificationConfiguration: {} +} + +var s3Events = null + +/* global before, after, describe, it */ +describe('lib/s3_events', () => { + before(() => { + aws.mock('Lambda', 'addPermission', (params, callback) => { + callback(null, mockResponse.addPermission) + }) + aws.mock('S3', 'putBucketNotificationConfiguration', (params, callback) => { + callback(null, mockResponse.putBucketNotificationConfiguration) + }) + + s3Events = new S3Events(require('aws-sdk')) + }) + + after(() => { + aws.restore('Lambda') + aws.restore('S3') + }) + + describe('_functionName', () => { + it('Extract name from FunctionArn', () => { + assert.equal( + s3Events._functionName(params), + 'node-lambda-test-function' + ) + }) + }) + + describe('_addPermissionParams', () => { + it('Return parameters for lambda.addPermission()', () => { + const expected = { + Action: 'lambda:InvokeFunction', + FunctionName: 'node-lambda-test-function', + Principal: 's3.amazonaws.com', + SourceArn: 'arn:aws:s3:::node-lambda-test-bucket', + StatementId: 'node-lambda-test-bucket' + } + assert.deepEqual(s3Events._addPermissionParams(params), expected) + }) + }) + + describe('_putBucketNotificationConfigurationParams', () => { + it('Return parameters for s3.putBucketNotificationConfiguration(). No Filter', () => { + const expected = { + Bucket: 'node-lambda-test-bucket', + NotificationConfiguration: { + LambdaFunctionConfigurations: [{ + Events: ['s3:ObjectCreated:*'], + LambdaFunctionArn: 'arn:aws:lambda:us-west-2:XXX:function:node-lambda-test-function' + }] + } + } + assert.deepEqual( + s3Events._putBucketNotificationConfigurationParams(params), + expected + ) + }) + + it('Return parameters for s3.putBucketNotificationConfiguration(). Use Filter', () => { + const expected = { + Bucket: 'node-lambda-test-bucket', + NotificationConfiguration: { + LambdaFunctionConfigurations: [{ + Events: ['s3:ObjectCreated:*'], + LambdaFunctionArn: 'arn:aws:lambda:us-west-2:XXX:function:node-lambda-test-function', + Filter: { + Key: { + FilterRules: [{ + Name: 'prefix', + Value: 'test-prefix' + }] + } + } + }] + } + } + const _params = Object.assign({}, params) + _params.Filter = { + Key: { + FilterRules: [{ + Name: 'prefix', + Value: 'test-prefix' + }] + } + } + assert.deepEqual( + s3Events._putBucketNotificationConfigurationParams(_params), + expected + ) + }) + }) + + describe('_addPermission', () => { + it('using mock', () => { + return s3Events._addPermission(params).then(data => { + assert.deepEqual(data, mockResponse.addPermission) + }) + }) + }) + + describe('_putBucketNotificationConfiguration', () => { + it('using mock', () => { + return s3Events._putBucketNotificationConfiguration(params).then(data => { + assert.deepEqual(data, mockResponse.putBucketNotificationConfiguration) + }) + }) + }) + + describe('add', () => { + it('using mock', () => { + return s3Events.add(params).then(data => { + assert.deepEqual(data, mockResponse.putBucketNotificationConfiguration) + }) + }) + }) +}) From 011aa79e033bef0c9ea50c0bf997bdf398fa584d Mon Sep 17 00:00:00 2001 From: abetomo Date: Thu, 7 Dec 2017 13:57:03 +0000 Subject: [PATCH 3/4] Fix comment --- lib/s3_events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/s3_events.js b/lib/s3_events.js index 7bd1d444..f48fddaa 100644 --- a/lib/s3_events.js +++ b/lib/s3_events.js @@ -1,7 +1,7 @@ 'use strict' /** - * Do not create Bucket of S3 + * Do not create S3 bucket. * Put the Notification Configuration in the existing Bucket. */ class S3Events { From 145f8d6c9b7242a6e7c308bad687d950a5fa587a Mon Sep 17 00:00:00 2001 From: abetomo Date: Thu, 7 Dec 2017 13:58:53 +0000 Subject: [PATCH 4/4] Fix info message --- lib/s3_events.js | 2 +- lib/schedule_events.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/s3_events.js b/lib/s3_events.js index f48fddaa..bee8e99c 100644 --- a/lib/s3_events.js +++ b/lib/s3_events.js @@ -36,7 +36,7 @@ class S3Events { if (err) { if (err.code !== 'ResourceConflictException') reject(err) // If it exists it will result in an error but there is no problem. - resolve('Already exists permission') + resolve('Permission already set') } resolve(data) }) diff --git a/lib/schedule_events.js b/lib/schedule_events.js index ac40db84..51bee5d3 100644 --- a/lib/schedule_events.js +++ b/lib/schedule_events.js @@ -59,7 +59,7 @@ class ScheduleEvents { if (err) { if (err.code !== 'ResourceConflictException') throw err // If it exists it will result in an error but there is no problem. - resolve('Already exists permission') + resolve('Permission already set') } resolve(data) })