diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/apiKeys.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/apiKeys.js index 9ac6cf3a2..646fa14aa 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/apiKeys.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/apiKeys.js @@ -17,8 +17,11 @@ module.exports = { throw new this.serverless.classes.Error('API Keys must be strings'); } + const apiKeyLogicalId = this.provider.naming + .getApiKeyLogicalId(apiKeyNumber); + _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { - [`ApiGatewayApiKey${apiKeyNumber}`]: { + [apiKeyLogicalId]: { Type: 'AWS::ApiGateway::ApiKey', Properties: { Enabled: true, diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js index 8308a48c0..e0649b617 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js @@ -31,10 +31,10 @@ module.exports = { }); } - const normalizedAuthorizerName = _.capitalize(authorizer.name); + const authorizerLogicalId = this.provider.naming.getAuthorizerLogicalId(authorizer.name); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { - [`${normalizedAuthorizerName}ApiGatewayAuthorizer`]: { + [authorizerLogicalId]: { Type: 'AWS::ApiGateway::Authorizer', Properties: authorizerProperties, }, diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/cors.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/cors.js index 3d0dbbf05..465cfcda4 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/cors.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/cors.js @@ -9,6 +9,8 @@ module.exports = { _.forEach(this.validated.corsPreflight, (config, path) => { const resourceName = this.getResourceName(path); const resourceRef = this.getResourceId(path); + const corsMethodLogicalId = this.provider.naming + .getMethodLogicalId(resourceName, 'options'); const preflightHeaders = { 'Access-Control-Allow-Origin': `'${config.origins.join(',')}'`, @@ -17,7 +19,7 @@ module.exports = { }; _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { - [`ApiGatewayMethod${resourceName}Options`]: { + [corsMethodLogicalId]: { Type: 'AWS::ApiGateway::Method', Properties: { AuthorizationType: 'NONE', diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/deployment.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/deployment.js index 0a2b4b05d..90b03aa87 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/deployment.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/deployment.js @@ -5,7 +5,8 @@ const BbPromise = require('bluebird'); module.exports = { compileDeployment() { - this.apiGatewayDeploymentLogicalId = `ApiGatewayDeployment${(new Date()).getTime().toString()}`; + this.apiGatewayDeploymentLogicalId = this.provider.naming + .generateApiGatewayDeploymentLogicalId(); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [this.apiGatewayDeploymentLogicalId]: { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/authorization.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/authorization.js index 8032b6afb..54b42a32b 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/authorization.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/authorization.js @@ -1,12 +1,10 @@ 'use strict'; -const _ = require('lodash'); - module.exports = { getMethodAuthorization(http) { if (http.authorizer) { - const normalizedAuthorizerName = _.capitalize(http.authorizer.name); - const authorizerLogicalId = `${normalizedAuthorizerName}ApiGatewayAuthorizer`; + const authorizerLogicalId = this.provider.naming + .getAuthorizerLogicalId(http.authorizer.name); return { Properties: { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js index f57a411b8..07190ad86 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js @@ -33,8 +33,8 @@ module.exports = { this.getMethodResponses(event.http) ); - const methodName = _.capitalize(event.http.method); - const methodLogicalId = `ApiGatewayMethod${resourceName}${methodName}`; + const methodLogicalId = this.provider.naming + .getMethodLogicalId(resourceName, event.http.method); this.apiGatewayMethodLogicalIds.push(methodLogicalId); diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js index f5f557416..2d429b180 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js @@ -4,7 +4,8 @@ const _ = require('lodash'); module.exports = { getMethodIntegration(http, functionName) { - const normalizedFunctionName = _.capitalize(functionName); + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); const integration = { IntegrationHttpMethod: 'POST', Type: http.integration, @@ -14,7 +15,7 @@ module.exports = { 'arn:aws:apigateway:', { Ref: 'AWS::Region' }, ':lambda:path/2015-03-31/functions/', - { 'Fn::GetAtt': [`${normalizedFunctionName}LambdaFunction`, 'Arn'] }, + { 'Fn::GetAtt': [lambdaLogicalId, 'Arn'] }, '/invocations', ], ], diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js index 06771882a..3085327cf 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js @@ -7,14 +7,17 @@ module.exports = { compilePermissions() { this.validated.events.forEach((event) => { - const normalizedFunctionName = _.capitalize(event.functionName); + const lambdaPermissionLogicalId = this.provider.naming + .getLambdaApiGatewayPermissionLogicalId(event.functionName); + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(event.functionName); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { - [`${normalizedFunctionName}LambdaPermissionApiGateway`]: { + [lambdaPermissionLogicalId]: { Type: 'AWS::Lambda::Permission', Properties: { FunctionName: { - 'Fn::GetAtt': [`${normalizedFunctionName}LambdaFunction`, 'Arn'], + 'Fn::GetAtt': [lambdaLogicalId, 'Arn'], }, Action: 'lambda:InvokeFunction', Principal: 'apigateway.amazonaws.com', @@ -24,10 +27,11 @@ module.exports = { if (event.http.authorizer) { const authorizer = event.http.authorizer; - const normalizedAuthorizerName = _.capitalize(authorizer.name); + const authorizerPermissionLogicalId = this.provider.naming + .getLambdaApiGatewayPermissionLogicalId(authorizer.name); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { - [`${normalizedAuthorizerName}LambdaPermissionApiGateway`]: { + [authorizerPermissionLogicalId]: { Type: 'AWS::Lambda::Permission', Properties: { FunctionName: authorizer.arn, diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/resources.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/resources.js index 953a784c9..ea714f170 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/resources.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/resources.js @@ -14,8 +14,8 @@ module.exports = { // ['users', 'users/create', 'users/create/something'] resourcePaths.forEach(path => { const pathArray = path.split('/'); - const resourceName = pathArray.map(this.capitalizeAlphaNumericPath).join(''); - const resourceLogicalId = `ApiGatewayResource${resourceName}`; + const resourceName = this.provider.naming.normalizePath(path); + const resourceLogicalId = this.provider.naming.getResourceLogicalId(path); const pathPart = pathArray.pop(); const parentPath = pathArray.join('/'); const parentRef = this.getResourceId(parentPath); @@ -56,15 +56,6 @@ module.exports = { return _.sortBy(paths, path => path.split('/').length); }, - capitalizeAlphaNumericPath(path) { - return _.upperFirst( - _.capitalize(path) - .replace(/-/g, 'Dash') - .replace(/\{(.*)\}/g, '$1Var') - .replace(/[^0-9A-Za-z]/g, '') - ); - }, - getResourceId(path) { if (path === '') { return { 'Fn::GetAtt': [this.apiGatewayRestApiLogicalId, 'RootResourceId'] }; diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/restApi.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/restApi.js index f051894e5..ce75a5527 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/restApi.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/restApi.js @@ -5,7 +5,7 @@ const BbPromise = require('bluebird'); module.exports = { compileRestApi() { - this.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi'; + this.apiGatewayRestApiLogicalId = this.provider.naming.getRestApiLogicalId(); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [this.apiGatewayRestApiLogicalId]: { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js index d76d7de64..9c974f3da 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js @@ -192,12 +192,12 @@ module.exports = { arn = this.getLambdaArn(authorizer); } else { arn = authorizer; - name = this.getLambdaName(arn); + name = this.provider.naming.extractAuthorizerNameFromArn(arn); } } else if (typeof authorizer === 'object') { if (authorizer.arn) { arn = authorizer.arn; - name = this.getLambdaName(arn); + name = this.provider.naming.extractAuthorizerNameFromArn(arn); } else if (authorizer.name) { name = authorizer.name; arn = this.getLambdaArn(name); @@ -375,8 +375,8 @@ module.exports = { getLambdaArn(name) { this.serverless.service.getFunction(name); - const normalizedName = _.capitalize(name); - return { 'Fn::GetAtt': [`${normalizedName}LambdaFunction`, 'Arn'] }; + const lambdaLogicalId = this.provider.naming.getLambdaLogicalId(name); + return { 'Fn::GetAtt': [lambdaLogicalId, 'Arn'] }; }, getLambdaName(arn) { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/apiKeys.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/apiKeys.js index a3eb38556..4265614f4 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/apiKeys.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/apiKeys.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#compileApiKeys()', () => { let serverless; @@ -10,6 +11,7 @@ describe('#compileApiKeys()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.service = 'first-service'; serverless.service.provider = { name: 'aws', diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/authorizers.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/authorizers.js index e96d40e1f..8b51b9072 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/authorizers.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/authorizers.js @@ -3,12 +3,15 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); + describe('#compileAuthorizers()', () => { let awsCompileApigEvents; beforeEach(() => { const serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.service = 'first-service'; serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} }; awsCompileApigEvents = new AwsCompileApigEvents(serverless); diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/cors.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/cors.js index 5ebe97a1d..584a1b1e8 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/cors.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/cors.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#compileCors()', () => { let serverless; @@ -10,6 +11,7 @@ describe('#compileCors()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.service = 'first-service'; serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} }; serverless.service.environment = { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/deployment.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/deployment.js index eb8624462..28e47b024 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/deployment.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/deployment.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#compileDeployment()', () => { let serverless; @@ -10,6 +11,7 @@ describe('#compileDeployment()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.provider.compiledCloudFormationTemplate = { Resources: {}, Outputs: {}, diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/methods.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/methods.js index aaa51c794..aa925cd2d 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/methods.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/methods.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#compileMethods()', () => { let serverless; @@ -10,6 +11,7 @@ describe('#compileMethods()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.service = 'first-service'; serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} }; serverless.service.environment = { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js index e90c8faff..6df28f264 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/permissions.js @@ -3,12 +3,14 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#awsCompilePermissions()', () => { let awsCompileApigEvents; beforeEach(() => { const serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} }; awsCompileApigEvents = new AwsCompileApigEvents(serverless); diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/resources.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/resources.js index 13ab06cb3..61c4eb46a 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/resources.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/resources.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#compileResources()', () => { let serverless; @@ -10,6 +11,7 @@ describe('#compileResources()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} }; awsCompileApigEvents = new AwsCompileApigEvents(serverless); awsCompileApigEvents.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi'; diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/restApi.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/restApi.js index 6c156d5ae..2ebf517fc 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/restApi.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/restApi.js @@ -3,6 +3,7 @@ const expect = require('chai').expect; const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#compileRestApi()', () => { let serverless; @@ -21,6 +22,7 @@ describe('#compileRestApi()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} }; const options = { stage: 'dev', diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/validate.js b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/validate.js index 5e0f6b72c..5d67839bb 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/tests/validate.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/tests/validate.js @@ -4,6 +4,7 @@ const expect = require('chai').expect; const sinon = require('sinon'); const AwsCompileApigEvents = require('../index'); const Serverless = require('../../../../../../../Serverless'); +const AwsProvider = require('../../../../../provider/awsProvider'); describe('#validate()', () => { let serverless; @@ -11,6 +12,7 @@ describe('#validate()', () => { beforeEach(() => { serverless = new Serverless(); + serverless.setProvider('aws', new AwsProvider(serverless)); const options = { stage: 'dev', region: 'us-east-1', diff --git a/lib/plugins/aws/deploy/compile/events/s3/index.js b/lib/plugins/aws/deploy/compile/events/s3/index.js index 11c8bd76f..e98e883df 100644 --- a/lib/plugins/aws/deploy/compile/events/s3/index.js +++ b/lib/plugins/aws/deploy/compile/events/s3/index.js @@ -78,8 +78,8 @@ class AwsCompileS3Events { .Error(errorMessage); } - const normalizedFunctionName = functionName[0].toUpperCase() + - functionName.substr(1); + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); // check if the bucket already defined // in another S3 event in the service @@ -88,7 +88,7 @@ class AwsCompileS3Events { Event: notificationEvent, Function: { 'Fn::GetAtt': [ - `${normalizedFunctionName}LambdaFunction`, + lambdaLogicalId, 'Arn', ], }, @@ -107,7 +107,7 @@ class AwsCompileS3Events { Event: notificationEvent, Function: { 'Fn::GetAtt': [ - `${normalizedFunctionName}LambdaFunction`, + lambdaLogicalId, 'Arn', ], }, @@ -138,13 +138,10 @@ class AwsCompileS3Events { }, }; - let normalizedBucketName = bucketName.replace(/[^0-9A-Za-z]/g, ''); - normalizedBucketName = normalizedBucketName[0].toUpperCase() + - normalizedBucketName.substr(1); - - const bucketLogicalID = `S3Bucket${normalizedBucketName}`; + const bucketLogicalId = this.provider.naming + .getBucketLogicalId(bucketName); const bucketCFResource = { - [bucketLogicalID]: bucketTemplate, + [bucketLogicalId]: bucketTemplate, }; _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, bucketCFResource); @@ -154,14 +151,14 @@ class AwsCompileS3Events { // and give S3 permission to invoke them all // by adding Lambda::Permission resource for each s3EnabledFunctions.forEach(functionName => { - const normalizedFunctionName = functionName[0].toUpperCase() + - functionName.substr(1); + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); const permissionTemplate = { Type: 'AWS::Lambda::Permission', Properties: { FunctionName: { 'Fn::GetAtt': [ - `${normalizedFunctionName}LambdaFunction`, + lambdaLogicalId, 'Arn', ], }, @@ -169,10 +166,10 @@ class AwsCompileS3Events { Principal: 's3.amazonaws.com', }, }; - - const permissionLogicalID = `${normalizedFunctionName}LambdaPermissionS3`; + const lambdaPermissionLogicalId = this.provider.naming + .getLambdaS3PermissionLogicalId(functionName); const permissionCFResource = { - [permissionLogicalID]: permissionTemplate, + [lambdaPermissionLogicalId]: permissionTemplate, }; _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, permissionCFResource); diff --git a/lib/plugins/aws/deploy/compile/events/schedule/index.js b/lib/plugins/aws/deploy/compile/events/schedule/index.js index 97677a219..a2814f922 100644 --- a/lib/plugins/aws/deploy/compile/events/schedule/index.js +++ b/lib/plugins/aws/deploy/compile/events/schedule/index.js @@ -74,7 +74,13 @@ class AwsCompileScheduledEvents { .Error(errorMessage); } - const normalizedFunctionName = functionName[0].toUpperCase() + functionName.substr(1); + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); + const scheduleLogicalId = this.provider.naming + .getScheduleLogicalId(functionName, scheduleNumberInFunction); + const lambdaPermissionLogicalId = this.provider.naming + .getLambdaSchedulePermissionLogicalId(functionName, scheduleNumberInFunction); + const scheduleId = this.provider.naming.getScheduleId(functionName); const scheduleTemplate = ` { @@ -85,8 +91,8 @@ class AwsCompileScheduledEvents { "Targets": [{ ${Input ? `"Input": "${Input}",` : ''} ${InputPath ? `"InputPath": "${InputPath}",` : ''} - "Arn": { "Fn::GetAtt": ["${normalizedFunctionName}LambdaFunction", "Arn"] }, - "Id": "${functionName}Schedule" + "Arn": { "Fn::GetAtt": ["${lambdaLogicalId}", "Arn"] }, + "Id": "${scheduleId}" }] } } @@ -97,23 +103,20 @@ class AwsCompileScheduledEvents { "Type": "AWS::Lambda::Permission", "Properties": { "FunctionName": { "Fn::GetAtt": ["${ - normalizedFunctionName}LambdaFunction", "Arn"] }, + lambdaLogicalId}", "Arn"] }, "Action": "lambda:InvokeFunction", "Principal": "events.amazonaws.com", - "SourceArn": { "Fn::GetAtt": ["${ - normalizedFunctionName}EventsRuleSchedule${scheduleNumberInFunction}", "Arn"] } + "SourceArn": { "Fn::GetAtt": ["${scheduleLogicalId}", "Arn"] } } } `; const newScheduleObject = { - [`${normalizedFunctionName}EventsRuleSchedule${ - scheduleNumberInFunction}`]: JSON.parse(scheduleTemplate), + [scheduleLogicalId]: JSON.parse(scheduleTemplate), }; const newPermissionObject = { - [`${normalizedFunctionName}LambdaPermissionEventsRuleSchedule${ - scheduleNumberInFunction}`]: JSON.parse(permissionTemplate), + [lambdaPermissionLogicalId]: JSON.parse(permissionTemplate), }; _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, diff --git a/lib/plugins/aws/deploy/compile/events/sns/index.js b/lib/plugins/aws/deploy/compile/events/sns/index.js index 4576949b7..83995d4c0 100644 --- a/lib/plugins/aws/deploy/compile/events/sns/index.js +++ b/lib/plugins/aws/deploy/compile/events/sns/index.js @@ -50,12 +50,12 @@ class AwsCompileSNSEvents { .Error(errorMessage); } - - const normalizedFunctionName = functionName[0].toUpperCase() + - functionName.substr(1); - let normalizedTopicName = topicName.replace(/[^0-9A-Za-z]/g, ''); - normalizedTopicName = normalizedTopicName[0].toUpperCase() + - normalizedTopicName.substr(1); + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); + const topicLogicalId = this.provider.naming + .getTopicLogicalId(topicName); + const lambdaPermissionLogicalId = this.provider.naming + .getLambdaSnsPermissionLogicalId(functionName, topicName); const snsTemplate = ` { @@ -65,8 +65,7 @@ class AwsCompileSNSEvents { "DisplayName": "${displayName}", "Subscription": [ { - "Endpoint": { "Fn::GetAtt": ["${ - normalizedFunctionName}LambdaFunction", "Arn"] }, + "Endpoint": { "Fn::GetAtt": ["${lambdaLogicalId}", "Arn"] }, "Protocol": "lambda" } ] @@ -78,8 +77,7 @@ class AwsCompileSNSEvents { { "Type": "AWS::Lambda::Permission", "Properties": { - "FunctionName": { "Fn::GetAtt": ["${ - normalizedFunctionName}LambdaFunction", "Arn"] }, + "FunctionName": { "Fn::GetAtt": ["${lambdaLogicalId}", "Arn"] }, "Action": "lambda:InvokeFunction", "Principal": "sns.amazonaws.com" } @@ -87,12 +85,11 @@ class AwsCompileSNSEvents { `; const newSNSObject = { - [`SNSTopic${normalizedTopicName}`]: JSON.parse(snsTemplate), + [topicLogicalId]: JSON.parse(snsTemplate), }; const newPermissionObject = { - [`${normalizedFunctionName}LambdaPermission${ - normalizedTopicName}`]: JSON.parse(permissionTemplate), + [lambdaPermissionLogicalId]: JSON.parse(permissionTemplate), }; // create new topic only if not created before @@ -106,13 +103,13 @@ class AwsCompileSNSEvents { Protocol: 'lambda', Endpoint: { 'Fn::GetAtt': [ - `${normalizedFunctionName}LambdaFunction`, + lambdaLogicalId, 'Arn', ], }, }; this.serverless.service.provider.compiledCloudFormationTemplate - .Resources[`SNSTopic${normalizedTopicName}`] + .Resources[topicLogicalId] .Properties.Subscription.push(newSubscription); } diff --git a/lib/plugins/aws/deploy/compile/events/stream/index.js b/lib/plugins/aws/deploy/compile/events/stream/index.js index bbbb278a5..0b878fdd2 100644 --- a/lib/plugins/aws/deploy/compile/events/stream/index.js +++ b/lib/plugins/aws/deploy/compile/events/stream/index.js @@ -57,7 +57,13 @@ class AwsCompileStreamEvents { .Error(errorMessage); } - const normalizedFunctionName = functionName[0].toUpperCase() + functionName.substr(1); + const streamType = EventSourceArn.split(':')[2]; + const streamName = EventSourceArn.split('/')[1]; + + const lambdaLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); + const streamLogicalId = this.provider.naming + .getStreamLogicalId(functionName, streamType, streamName); const streamTemplate = ` { @@ -68,7 +74,7 @@ class AwsCompileStreamEvents { "EventSourceArn": "${EventSourceArn}", "FunctionName": { "Fn::GetAtt": [ - "${normalizedFunctionName}LambdaFunction", + "${lambdaLogicalId}", "Arn" ] }, @@ -78,15 +84,6 @@ class AwsCompileStreamEvents { } `; - // get the type (DynamoDB or Kinesis) of the stream - const streamType = EventSourceArn.split(':')[2]; - const normalizedStreamType = streamType[0].toUpperCase() + streamType.substr(1); - - // get the name of the stream (and remove any non-alphanumerics in it) - const streamName = EventSourceArn.split('/')[1]; - const normalizedStreamName = streamName[0].toUpperCase() - + streamName.substr(1).replace(/[^A-Za-z0-9]/g, ''); - // create type specific PolicyDocument statements let streamStatement = {}; if (streamType === 'dynamodb') { @@ -132,8 +129,7 @@ class AwsCompileStreamEvents { } const newStreamObject = { - [`${normalizedFunctionName}EventSourceMapping${ - normalizedStreamType}${normalizedStreamName}`]: JSON.parse(streamTemplate), + [streamLogicalId]: JSON.parse(streamTemplate), }; _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, diff --git a/lib/plugins/aws/deploy/compile/functions/index.js b/lib/plugins/aws/deploy/compile/functions/index.js index 6a15b40b6..7a2c28dd7 100644 --- a/lib/plugins/aws/deploy/compile/functions/index.js +++ b/lib/plugins/aws/deploy/compile/functions/index.js @@ -103,8 +103,10 @@ class AwsCompileFunctions { delete newFunction.Properties.VpcConfig; } - const normalizedFunctionName = functionName[0].toUpperCase() + functionName.substr(1); - const functionLogicalId = `${normalizedFunctionName}LambdaFunction`; + const functionLogicalId = this.provider.naming + .getLambdaLogicalId(functionName); + const functionOutputLogicalId = this.provider.naming + .getLambdaOutputLogicalId(functionName); const newFunctionObject = { [functionLogicalId]: newFunction, }; @@ -117,7 +119,7 @@ class AwsCompileFunctions { newOutput.Value = { 'Fn::GetAtt': [functionLogicalId, 'Arn'] }; const newOutputObject = { - [`${functionLogicalId}Arn`]: newOutput, + [functionOutputLogicalId]: newOutput, }; _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Outputs, diff --git a/lib/plugins/aws/deploy/lib/createStack.js b/lib/plugins/aws/deploy/lib/createStack.js index 8258f364a..eea0bd428 100644 --- a/lib/plugins/aws/deploy/lib/createStack.js +++ b/lib/plugins/aws/deploy/lib/createStack.js @@ -7,7 +7,7 @@ const BbPromise = require('bluebird'); module.exports = { create() { this.serverless.cli.log('Creating Stack…'); - const stackName = `${this.serverless.service.service}-${this.options.stage}`; + const stackName = this.provider.naming.getStackName(); let stackTags = { STAGE: this.options.stage }; // Merge additional stack tags @@ -38,7 +38,7 @@ module.exports = { }, createStack() { - const stackName = `${this.serverless.service.service}-${this.options.stage}`; + const stackName = this.provider.naming.getStackName(); if (/^[^a-zA-Z].+|.*[^a-zA-Z0-9-].*/.test(stackName) || stackName.length > 128) { const errorMessage = [ `The stack service name "${stackName}" is not valid. `, diff --git a/lib/plugins/aws/deploy/lib/mergeIamTemplates.js b/lib/plugins/aws/deploy/lib/mergeIamTemplates.js index 1003e383c..3df6998b5 100644 --- a/lib/plugins/aws/deploy/lib/mergeIamTemplates.js +++ b/lib/plugins/aws/deploy/lib/mergeIamTemplates.js @@ -79,10 +79,11 @@ module.exports = { } else { this.serverless.service.getAllFunctions().forEach((functionName) => { const functionObject = this.serverless.service.getFunction(functionName); - const normalizedFunctionName = functionName[0].toUpperCase() + functionName.substr(1); + const logGroupLogicalId = this.provider.naming + .getLogGroupLogicalId(functionName); const logGroupTemplate = ` { - "${normalizedFunctionName}LogGroup": { + "${logGroupLogicalId}": { "Type" : "AWS::Logs::LogGroup", "Properties" : { "LogGroupName" : "/aws/lambda/${functionObject.name}" @@ -101,7 +102,7 @@ module.exports = { .PolicyDocument .Statement[0] .Resource - .push({ 'Fn::GetAtt': [`${normalizedFunctionName}LogGroup`, 'Arn'] }); + .push({ 'Fn::GetAtt': [`${logGroupLogicalId}`, 'Arn'] }); this.serverless.service.provider.compiledCloudFormationTemplate .Resources @@ -114,7 +115,7 @@ module.exports = { 'Fn::Join': [ ':', [ - { 'Fn::GetAtt': [`${normalizedFunctionName}LogGroup`, 'Arn'] }, + { 'Fn::GetAtt': [`${logGroupLogicalId}`, 'Arn'] }, '*', ], ], diff --git a/lib/plugins/aws/deploy/tests/mergeIamTemplates.js b/lib/plugins/aws/deploy/tests/mergeIamTemplates.js index b11b8d2f5..3336614a9 100644 --- a/lib/plugins/aws/deploy/tests/mergeIamTemplates.js +++ b/lib/plugins/aws/deploy/tests/mergeIamTemplates.js @@ -4,6 +4,7 @@ const path = require('path'); const expect = require('chai').expect; const Serverless = require('../../../../Serverless'); +const AwsProvider = require('../../provider/awsProvider'); const AwsDeploy = require('../'); describe('#mergeIamTemplates()', () => { @@ -17,6 +18,7 @@ describe('#mergeIamTemplates()', () => { stage: 'dev', region: 'us-east-1', }; + serverless.setProvider('aws', new AwsProvider(serverless)); awsDeploy = new AwsDeploy(serverless, options); awsDeploy.serverless.cli = new serverless.classes.CLI(); awsDeploy.serverless.service.provider.compiledCloudFormationTemplate = { diff --git a/lib/plugins/aws/info/index.js b/lib/plugins/aws/info/index.js index bc241a85e..5f73c1a11 100644 --- a/lib/plugins/aws/info/index.js +++ b/lib/plugins/aws/info/index.js @@ -35,7 +35,7 @@ class AwsInfo { * Gather information about the service */ gather() { - const stackName = this.provider.getStackName(this.options.stage); + const stackName = this.provider.naming.getStackName(this.options.stage); const info = { service: this.serverless.service.service, stage: this.options.stage, @@ -54,9 +54,15 @@ class AwsInfo { if (result) { outputs = result.Stacks[0].Outputs; + const lambdaArnOutputRegex = this.provider.naming + .getLambdaOutputLogicalIdRegex(); + + const serviceEndpointOutputRegex = this.provider.naming + .getServiceEndpointRegex(); + // Functions info.functions = []; - outputs.filter(x => x.OutputKey.match(/LambdaFunctionArn$/)) + outputs.filter(x => x.OutputKey.match(lambdaArnOutputRegex)) .forEach(x => { const functionInfo = {}; functionInfo.arn = x.OutputValue; @@ -65,7 +71,7 @@ class AwsInfo { }); // Endpoints - outputs.filter(x => x.OutputKey.match(/^ServiceEndpoint/)) + outputs.filter(x => x.OutputKey.match(serviceEndpointOutputRegex)) .forEach(x => { info.endpoint = x.OutputValue; }); diff --git a/lib/plugins/aws/info/tests/index.js b/lib/plugins/aws/info/tests/index.js index dd1a6749d..b149d1da9 100644 --- a/lib/plugins/aws/info/tests/index.js +++ b/lib/plugins/aws/info/tests/index.js @@ -170,7 +170,7 @@ describe('AwsInfo', () => { 'CloudFormation', 'describeStacks', { - StackName: awsInfo.provider.getStackName(awsInfo.options.stage), + StackName: awsInfo.provider.naming.getStackName(), }, awsInfo.options.stage, awsInfo.options.region diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js new file mode 100644 index 000000000..a77d14a8a --- /dev/null +++ b/lib/plugins/aws/lib/naming.js @@ -0,0 +1,153 @@ +'use strict'; + +const _ = require('lodash'); + +module.exports = { + + // General + normalizeName(name) { + return `${_.upperFirst(name)}`; + }, + normalizeNameToAlphaNumericOnly(name) { + return this.normalizeName(name.replace(/[^0-9A-Za-z]/g, '')); + }, + normalizePathPart(path) { + return this.normalizeNameToAlphaNumericOnly( + path.replace(/-/g, 'Dash') + .replace(/\{(.*)\}/g, '$1Var')); + }, + + getServiceEndpointRegex() { + return /^ServiceEndpoint/; + }, + + // Stack + getStackName() { + return `${this.sdk.serverless.service.service}-${this.sdk.getStage()}`; + }, + + getLogGroupLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LogGroup`; + }, + + // Lambda + getNormalizedFunctionName(functionName) { + return this.normalizeName(functionName + .replace(/-/g, 'Dash') + .replace(/_/g, 'Underscore')); + }, + extractLambdaNameFromArn(functionArn) { + return functionArn.substring(functionArn.lastIndexOf(':') + 1); + }, + extractAuthorizerNameFromArn(functionArn) { + const splitArn = functionArn.split(':'); + // TODO the following two lines assumes default function naming? Is there a better way? + // TODO (see ~/lib/classes/Service.js:~155) + const splitName = splitArn[splitArn.length - 1].split('-'); + return splitName[splitName.length - 1]; + }, + getLambdaLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaFunction`; + }, + getLambdaLogicalIdRegex() { + return /LambdaFunction$/; + }, + getLambdaOutputLogicalId(functionName) { + return `${this.getLambdaLogicalId(functionName)}Arn`; + }, + getLambdaOutputLogicalIdRegex() { + return /LambdaFunctionArn$/; + }, + + // API Gateway + generateApiGatewayDeploymentLogicalId() { + return `ApiGatewayDeployment${(new Date()).getTime().toString()}`; + }, + getRestApiLogicalId() { + return 'ApiGatewayRestApi'; + }, + getNormalizedAuthorizerName(functionName) { + return this.getNormalizedFunctionName(functionName); + }, + getAuthorizerLogicalId(functionName) { + return `${this.getNormalizedAuthorizerName(functionName)}ApiGatewayAuthorizer`; + }, + normalizePath(resourcePath) { + return resourcePath.split('/').map( + this.normalizePathPart.bind(this) + ).join(''); + }, + getResourceLogicalId(resourcePath) { + return `ApiGatewayResource${this.normalizePath(resourcePath)}`; + }, + extractResourceId(resourceLogicalId) { + return resourceLogicalId.match(/ApiGatewayResource(.*)/)[1]; + }, + normalizeMethodName(methodName) { + return this.normalizeName(methodName.toLowerCase()); + }, + getMethodLogicalId(resourceId, methodName) { + return `ApiGatewayMethod${resourceId}${this.normalizeMethodName(methodName)}`; + }, + getApiKeyLogicalId(apiKeyNumber) { + return `ApiGatewayApiKey${apiKeyNumber}`; + }, + getApiKeyLogicalIdRegex() { + return /^ApiGatewayApiKey/; + }, + + // S3 + getDeploymentBucketLogicalId() { + return 'ServerlessDeploymentBucket'; + }, + getDeploymentBucketOutputLogicalId() { + return 'ServerlessDeploymentBucketName'; + }, + normalizeBucketName(bucketName) { + return this.normalizeNameToAlphaNumericOnly(bucketName); + }, + getBucketLogicalId(bucketName) { + return `S3Bucket${this.normalizeBucketName(bucketName)}`; + }, + + // SNS + normalizeTopicName(topicName) { + return this.normalizeNameToAlphaNumericOnly(topicName); + }, + getTopicLogicalId(topicName) { + return `SNSTopic${this.normalizeTopicName(topicName)}`; + }, + + // Schedule + getScheduleId(functionName) { + return `${functionName}Schedule`; + }, + getScheduleLogicalId(functionName, scheduleIndex) { + return `${this.getNormalizedFunctionName(functionName)}EventsRuleSchedule${scheduleIndex}`; + }, + + // Stream + getStreamLogicalId(functionName, streamType, streamName) { + return `${ + this.getNormalizedFunctionName(functionName) + }EventSourceMapping${ + this.normalizeName(streamType) + }${this.normalizeNameToAlphaNumericOnly(streamName)}`; + }, + + // Permissions + getLambdaS3PermissionLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionS3`; + }, + getLambdaSnsPermissionLogicalId(functionName, topicName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${ + this.normalizeTopicName(topicName)}`; + }, + getLambdaSchedulePermissionLogicalId(functionName, scheduleIndex) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionEventsRuleSchedule${ + scheduleIndex}`; + }, + getLambdaApiGatewayPermissionLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`; + }, +}; diff --git a/lib/plugins/aws/lib/updateStack.js b/lib/plugins/aws/lib/updateStack.js index c0be9a84b..db04e6740 100644 --- a/lib/plugins/aws/lib/updateStack.js +++ b/lib/plugins/aws/lib/updateStack.js @@ -9,7 +9,7 @@ module.exports = { this.createLater = false; this.serverless.cli.log('Creating Stack...'); - const stackName = `${this.serverless.service.service}-${this.options.stage}`; + const stackName = this.provider.naming.getStackName(); let stackTags = { STAGE: this.options.stage }; const templateUrl = `https://s3.amazonaws.com/${ this.bucketName @@ -48,7 +48,7 @@ module.exports = { }/compiled-cloudformation-template.json`; this.serverless.cli.log('Updating Stack…'); - const stackName = `${this.serverless.service.service}-${this.options.stage}`; + const stackName = this.provider.naming.getStackName(); let stackTags = { STAGE: this.options.stage }; // Merge additional stack tags diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js index de67c16bb..af0dc9199 100644 --- a/lib/plugins/aws/provider/awsProvider.js +++ b/lib/plugins/aws/provider/awsProvider.js @@ -1,9 +1,15 @@ 'use strict'; +const AWS = require('aws-sdk'); const BbPromise = require('bluebird'); const HttpsProxyAgent = require('https-proxy-agent'); const url = require('url'); -const AWS = require('aws-sdk'); + +const naming = require('../lib/naming.js'); + +const constants = { + providerName: 'aws', +}; const impl = { /** @@ -13,11 +19,11 @@ const impl = { */ addCredentials: (credentials, config) => { if (credentials && - config && - config.accessKeyId && - config.accessKeyId !== 'undefined' && - config.secretAccessKey && - config.secretAccessKey !== 'undefined') { + config && + config.accessKeyId && + config.accessKeyId !== 'undefined' && + config.secretAccessKey && + config.secretAccessKey !== 'undefined') { if (config.accessKeyId) { credentials.accessKeyId = config.accessKeyId; // eslint-disable-line no-param-reassign } @@ -72,14 +78,18 @@ const impl = { class AwsProvider { static getProviderName() { - return 'aws'; + return constants.providerName; } - constructor(serverless) { + constructor(serverless, options) { + this.naming = { sdk: this }; + this.options = options; + this.provider = this; // only load plugin in an AWS service context this.serverless = serverless; this.sdk = AWS; - this.provider = this; // only load plugin in an AWS service context - this.serverless.setProvider(this.constructor.getProviderName(), this); + this.serverless.setProvider(constants.providerName, this); + + Object.assign(this.naming, naming); // Use HTTPS Proxy (Optional) const proxy = process.env.proxy @@ -101,9 +111,9 @@ class AwsProvider { } } - request(service, method, params, stage, region) { + request(service, method, params) { const that = this; - const credentials = that.getCredentials(stage, region); + const credentials = that.getCredentials(); const persistentRequest = (f) => new BbPromise((resolve, reject) => { const doCall = () => { f() @@ -124,7 +134,7 @@ class AwsProvider { const awsService = new that.sdk[service](credentials); const req = awsService[method](params); - // TODO: Add listeners, put Debug statments here… + // TODO: Add listeners, put Debug statments here... // req.on('send', function (r) {console.log(r)}); return new BbPromise((resolve, reject) => { @@ -151,14 +161,12 @@ class AwsProvider { /** * Fetch credentials directly or using a profile from serverless yml configuration or from the * well known environment variables - * @param stage - * @param region * @returns {{region: *}} */ - getCredentials(stage, region) { - const ret = { region }; + getCredentials() { + const returnValue = { region: this.getRegion() }; const credentials = {}; - const stageUpper = stage ? stage.toUpperCase() : null; + const stageUpper = this.getStage() ? this.getStage().toUpperCase() : null; // add specified credentials, overriding with more specific declarations impl.addCredentials(credentials, this.serverless.service.provider.credentials); // config creds @@ -169,29 +177,46 @@ class AwsProvider { impl.addEnvironmentProfile(credentials, `AWS_${stageUpper}`); if (Object.keys(credentials).length) { - ret.credentials = credentials; + returnValue.credentials = credentials; } - return ret; + return returnValue; } - getServerlessDeploymentBucketName(stage, region) { + getRegion() { + let returnValue = 'us-east-1'; + if (this.options && this.options.region) { + returnValue = this.options.region; + } else if (this.serverless.config.region) { + returnValue = this.serverless.config.region; + } else if (this.serverless.service.provider.region) { + returnValue = this.serverless.service.provider.region; + } + return returnValue; + } + + getServerlessDeploymentBucketName() { if (this.serverless.service.provider.deploymentBucket) { return BbPromise.resolve(this.serverless.service.provider.deploymentBucket); } - const stackName = `${this.serverless.service.service}-${stage}`; return this.request('CloudFormation', 'describeStackResource', { - StackName: stackName, - LogicalResourceId: 'ServerlessDeploymentBucket', - }, - stage, - region + StackName: this.naming.getStackName(), + LogicalResourceId: this.naming.getDeploymentBucketLogicalId(), + } ).then((result) => result.StackResourceDetail.PhysicalResourceId); } - getStackName(stage) { - return `${this.serverless.service.service}-${stage}`; + getStage() { + let returnValue = 'dev'; + if (this.options && this.options.stage) { + returnValue = this.options.stage; + } else if (this.serverless.config.stage) { + returnValue = this.serverless.config.stage; + } else if (this.serverless.service.provider.stage) { + returnValue = this.serverless.service.provider.stage; + } + return returnValue; } } diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js index 204f07640..f9bdcb0cd 100644 --- a/lib/plugins/aws/provider/awsProvider.test.js +++ b/lib/plugins/aws/provider/awsProvider.test.js @@ -1,21 +1,22 @@ 'use strict'; -const sinon = require('sinon'); const BbPromise = require('bluebird'); const expect = require('chai').expect; -const Serverless = require('../../../Serverless'); -const AwsProvider = require('./awsProvider'); const proxyquire = require('proxyquire'); +const sinon = require('sinon'); + +const AwsProvider = require('./awsProvider'); +const Serverless = require('../../../Serverless'); describe('AwsProvider', () => { let awsProvider; let serverless; + const options = { + stage: 'dev', + region: 'us-east-1', + }; beforeEach(() => { - const options = { - stage: 'dev', - region: 'us-east-1', - }; serverless = new Serverless(options); awsProvider = new AwsProvider(serverless, options); awsProvider.serverless.cli = new serverless.classes.CLI(); @@ -42,7 +43,7 @@ describe('AwsProvider', () => { it('should set AWS proxy', () => { process.env.proxy = 'http://a.b.c.d:n'; - const newAwsProvider = new AwsProvider(serverless); + const newAwsProvider = new AwsProvider(serverless, options); expect(typeof newAwsProvider.sdk.config.httpOptions.agent).to.not.equal('undefined'); @@ -52,7 +53,7 @@ describe('AwsProvider', () => { it('should set AWS timeout', () => { process.env.AWS_CLIENT_TIMEOUT = '120000'; - const newAwsProvider = new AwsProvider(serverless); + const newAwsProvider = new AwsProvider(serverless, options); expect(typeof newAwsProvider.sdk.config.httpOptions.timeout).to.not.equal('undefined'); @@ -90,7 +91,7 @@ describe('AwsProvider', () => { }, }; - return awsProvider.request('S3', 'putObject', {}, 'dev', 'us-east-1').then(data => { + return awsProvider.request('S3', 'putObject', {}).then(data => { expect(data.called).to.equal(true); }); }); @@ -123,12 +124,10 @@ describe('AwsProvider', () => { awsProvider.sdk = { S3: FakeS3, }; - awsProvider.request('S3', 'error', {}, 'dev', 'us-east-1') + awsProvider.request('S3', 'error', {}) .then(data => { - // eslint-disable-next-line no-unused-expressions - expect(data).to.exist; - // eslint-disable-next-line no-unused-expressions - expect(first).to.be.false; + expect(data).to.exist; // eslint-disable-line no-unused-expressions + expect(first).to.be.false; // eslint-disable-line no-unused-expressions done(); }) .catch(done); @@ -155,7 +154,7 @@ describe('AwsProvider', () => { awsProvider.sdk = { S3: FakeS3, }; - awsProvider.request('S3', 'error', {}, 'dev', 'us-east-1') + awsProvider.request('S3', 'error', {}) .then(() => done('Should not succeed')) .catch(() => done()); }); @@ -181,7 +180,7 @@ describe('AwsProvider', () => { awsProvider.sdk = { S3: FakeS3, }; - awsProvider.request('S3', 'error', {}, 'dev', 'us-east-1') + awsProvider.request('S3', 'error', {}) .then(() => done('Should not succeed')) .catch((err) => { expect(err.message).to.contain('https://git.io/vXsdd'); @@ -203,14 +202,18 @@ describe('AwsProvider', () => { }); let newAwsProvider; + const newOptions = { + stage: 'teststage', + region: 'testregion', + }; beforeEach(() => { - newAwsProvider = new AwsProviderProxyquired(serverless); + newAwsProvider = new AwsProviderProxyquired(serverless, newOptions); }); it('should set region for credentials', () => { - const credentials = newAwsProvider.getCredentials('teststage', 'testregion'); - expect(credentials.region).to.equal('testregion'); + const credentials = newAwsProvider.getCredentials(); + expect(credentials.region).to.equal(newOptions.region); }); it('should get credentials from provider', () => { @@ -221,14 +224,14 @@ describe('AwsProvider', () => { it('should not set credentials if empty profile is set', () => { serverless.service.provider.profile = ''; - const credentials = mockCreds(newAwsProvider.getCredentials('teststage', 'testregion')); - expect(credentials).to.eql({ region: 'testregion' }); + const credentials = mockCreds(newAwsProvider.getCredentials()); + expect(credentials).to.eql({ region: newOptions.region }); }); it('should not set credentials if credentials is an empty object', () => { serverless.service.provider.credentials = {}; - const credentials = mockCreds(newAwsProvider.getCredentials('teststage', 'testregion')); - expect(credentials).to.eql({ region: 'testregion' }); + const credentials = mockCreds(newAwsProvider.getCredentials()); + expect(credentials).to.eql({ region: newOptions.region }); }); it('should not set credentials if credentials has undefined values', () => { @@ -237,8 +240,8 @@ describe('AwsProvider', () => { secretAccessKey: undefined, sessionToken: undefined, }; - const credentials = mockCreds(newAwsProvider.getCredentials('teststage', 'testregion')); - expect(credentials).to.eql({ region: 'testregion' }); + const credentials = mockCreds(newAwsProvider.getCredentials()); + expect(credentials).to.eql({ region: newOptions.region }); }); it('should not set credentials if credentials has empty string values', () => { @@ -247,8 +250,8 @@ describe('AwsProvider', () => { secretAccessKey: '', sessionToken: '', }; - const credentials = mockCreds(newAwsProvider.getCredentials('teststage', 'testregion')); - expect(credentials).to.eql({ region: 'testregion' }); + const credentials = mockCreds(newAwsProvider.getCredentials()); + expect(credentials).to.eql({ region: newOptions.region }); }); it('should get credentials from provider declared credentials', () => { @@ -265,7 +268,7 @@ describe('AwsProvider', () => { secretAccessKey: 'secretAccessKey', sessionToken: 'sessionToken', }; - const credentials = newAwsProvider.getCredentials('teststage', 'testregion'); + const credentials = newAwsProvider.getCredentials(); expect(credentials.credentials).to.deep.eql(serverless.service.provider.credentials); process.env.AWS_ACCESS_KEY_ID = tmpAccessKeyID; @@ -287,7 +290,7 @@ describe('AwsProvider', () => { process.env.AWS_ACCESS_KEY_ID = testVal.accessKeyId; process.env.AWS_SECRET_ACCESS_KEY = testVal.secretAccessKey; process.env.AWS_SESSION_TOKEN = testVal.sessionToken; - const credentials = newAwsProvider.getCredentials('teststage', 'testregion'); + const credentials = newAwsProvider.getCredentials(); process.env.AWS_ACCESS_KEY_ID = prevVal.accessKeyId; process.env.AWS_SECRET_ACCESS_KEY = prevVal.secretAccessKey; process.env.AWS_SESSION_TOKEN = prevVal.sessionToken; @@ -308,7 +311,7 @@ describe('AwsProvider', () => { process.env.AWS_TESTSTAGE_ACCESS_KEY_ID = testVal.accessKeyId; process.env.AWS_TESTSTAGE_SECRET_ACCESS_KEY = testVal.secretAccessKey; process.env.AWS_TESTSTAGE_SESSION_TOKEN = testVal.sessionToken; - const credentials = newAwsProvider.getCredentials('teststage', 'testregion'); + const credentials = newAwsProvider.getCredentials(); process.env.AWS_TESTSTAGE_ACCESS_KEY_ID = prevVal.accessKeyId; process.env.AWS_TESTSTAGE_SECRET_ACCESS_KEY = prevVal.secretAccessKey; process.env.AWS_TESTSTAGE_SESSION_TOKEN = prevVal.sessionToken; @@ -317,14 +320,14 @@ describe('AwsProvider', () => { it('should not set credentials if profile is not set', () => { serverless.service.provider.profile = undefined; - const credentials = mockCreds(newAwsProvider.getCredentials('teststage', 'testregion')); - expect(credentials).to.eql({ region: 'testregion' }); + const credentials = mockCreds(newAwsProvider.getCredentials()); + expect(credentials).to.eql({ region: newOptions.region }); }); it('should not set credentials if empty profile is set', () => { serverless.service.provider.profile = ''; - const credentials = mockCreds(newAwsProvider.getCredentials('teststage', 'testregion')); - expect(credentials).to.eql({ region: 'testregion' }); + const credentials = mockCreds(newAwsProvider.getCredentials()); + expect(credentials).to.eql({ region: newOptions.region }); }); it('should get credentials from provider declared profile', () => { @@ -344,19 +347,63 @@ describe('AwsProvider', () => { it('should get credentials from environment declared stage-specific profile', () => { const prevVal = process.env.AWS_TESTSTAGE_PROFILE; process.env.AWS_TESTSTAGE_PROFILE = 'notDefault'; - const credentials = newAwsProvider.getCredentials('teststage', 'testregion'); + const credentials = newAwsProvider.getCredentials(); process.env.AWS_TESTSTAGE_PROFILE = prevVal; expect(credentials.credentials.profile).to.equal('notDefault'); }); }); - describe('#getServerlessDeploymentBucketName', () => { - it('should return the name of the serverless deployment bucket', () => { - const options = { - stage: 'dev', - region: 'us-east-1', - }; + describe('#getRegion()', () => { + let newAwsProvider; + it('should prefer options over config or provider', () => { + const newOptions = { + region: 'optionsRegion', + }; + const config = { + region: 'configRegion', + }; + serverless = new Serverless(config); + serverless.service.provider.region = 'providerRegion'; + newAwsProvider = new AwsProvider(serverless, newOptions); + + expect(newAwsProvider.getRegion()).to.equal(newOptions.region); + }); + + it('should prefer config over provider in lieu of options', () => { + const newOptions = {}; + const config = { + region: 'configRegion', + }; + serverless = new Serverless(config); + serverless.service.provider.region = 'providerRegion'; + newAwsProvider = new AwsProvider(serverless, newOptions); + + expect(newAwsProvider.getRegion()).to.equal(config.region); + }); + + it('should use provider in lieu of options and config', () => { + const newOptions = {}; + const config = {}; + serverless = new Serverless(config); + serverless.service.provider.region = 'providerRegion'; + newAwsProvider = new AwsProvider(serverless, newOptions); + + expect(newAwsProvider.getRegion()).to.equal(serverless.service.provider.region); + }); + + it('should use the default us-east-1 in lieu of options, config, and provider', () => { + const newOptions = {}; + const config = {}; + serverless = new Serverless(config); + newAwsProvider = new AwsProvider(serverless, newOptions); + + expect(newAwsProvider.getRegion()).to.equal('us-east-1'); + }); + }); + + describe('#getServerlessDeploymentBucketName()', () => { + it('should return the name of the serverless deployment bucket', () => { const describeStackResourcesStub = sinon .stub(awsProvider, 'request') .returns(BbPromise.resolve({ @@ -365,7 +412,7 @@ describe('AwsProvider', () => { }, })); - return awsProvider.getServerlessDeploymentBucketName(options.stage, options.region) + return awsProvider.getServerlessDeploymentBucketName() .then((bucketName) => { expect(bucketName).to.equal('serverlessDeploymentBucketName'); expect(describeStackResourcesStub.calledOnce).to.be.equal(true); @@ -373,11 +420,9 @@ describe('AwsProvider', () => { 'CloudFormation', 'describeStackResource', { - StackName: `${awsProvider.serverless.service.service}-${options.stage}`, + StackName: awsProvider.naming.getStackName(), LogicalResourceId: 'ServerlessDeploymentBucket', - }, - options.stage, - options.region + } )).to.be.equal(true); awsProvider.request.restore(); }); @@ -385,10 +430,6 @@ describe('AwsProvider', () => { it('should return the name of the custom deployment bucket', () => { awsProvider.serverless.service.provider.deploymentBucket = 'custom-bucket'; - const options = { - stage: 'dev', - region: 'us-east-1', - }; const describeStackResourcesStub = sinon .stub(awsProvider, 'request') @@ -398,20 +439,59 @@ describe('AwsProvider', () => { }, })); - return awsProvider.getServerlessDeploymentBucketName(options.stage, options.region) + return awsProvider.getServerlessDeploymentBucketName() .then((bucketName) => { expect(describeStackResourcesStub.called).to.be.equal(false); expect(bucketName).to.equal('custom-bucket'); awsProvider.request.restore(); }); }); - }); - describe('#getStackName', () => { - it('should return the stack name', () => { - serverless.service.service = 'myservice'; + describe('#getStage()', () => { + it('should prefer options over config or provider', () => { + const newOptions = { + stage: 'optionsStage', + }; + const config = { + stage: 'configStage', + }; + serverless = new Serverless(config); + serverless.service.provider.stage = 'providerStage'; + awsProvider = new AwsProvider(serverless, newOptions); - expect(awsProvider.getStackName('dev')).to.equal('myservice-dev'); + expect(awsProvider.getStage()).to.equal(newOptions.stage); + }); + + it('should prefer config over provider in lieu of options', () => { + const newOptions = {}; + const config = { + stage: 'configStage', + }; + serverless = new Serverless(config); + serverless.service.provider.stage = 'providerStage'; + awsProvider = new AwsProvider(serverless, newOptions); + + expect(awsProvider.getStage()).to.equal(config.stage); + }); + + it('should use provider in lieu of options and config', () => { + const newOptions = {}; + const config = {}; + serverless = new Serverless(config); + serverless.service.provider.stage = 'providerStage'; + awsProvider = new AwsProvider(serverless, newOptions); + + expect(awsProvider.getStage()).to.equal(serverless.service.provider.stage); + }); + + it('should use the default dev in lieu of options, config, and provider', () => { + const newOptions = {}; + const config = {}; + serverless = new Serverless(config); + awsProvider = new AwsProvider(serverless, newOptions); + + expect(awsProvider.getStage()).to.equal('dev'); + }); }); }); }); diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js new file mode 100644 index 000000000..7f4134d0a --- /dev/null +++ b/lib/plugins/aws/tests/naming.js @@ -0,0 +1,322 @@ +'use strict'; + +const expect = require('chai').expect; + +const SDK = require('../provider/awsProvider'); +const Serverless = require('../../../Serverless'); + +describe('#naming()', () => { + let options; + let serverless; + let sdk; + + beforeEach(() => { + options = { + stage: 'dev', + region: 'us-east-1', + }; + serverless = new Serverless(options); + sdk = new SDK(serverless, options); + }); + + describe('#normalizeName()', () => { + it('should capitalize the first letter', () => { + expect(sdk.naming.normalizeName('name')).to.equal('Name'); + }); + + it('should have no effect on caps', () => { + expect(sdk.naming.normalizeName('Name')).to.equal('Name'); + }); + + it('should have no effect on the rest of the name', () => { + expect(sdk.naming.normalizeName('nAME')).to.equal('NAME'); + }); + }); + describe('#normalizeNameToAlphaNumericOnly()', () => { + it('should strip non-alpha-numeric characters', () => { + expect(sdk.naming + .normalizeNameToAlphaNumericOnly('`!@#$%^&*()-={}|[]\\:";\'<>?,./')).to.equal(''); + }); + + it('should apply normalizeName to the remaining characters', () => { + expect(sdk.naming.normalizeNameToAlphaNumericOnly('a-b-c')).to.equal('Abc'); + }); + }); + describe('#normalizeNameToCapitalAlphaNumbericOnly()', () => { + it('converts `-` to `Dash`', () => { + expect(sdk.naming.normalizePathPart( + 'a-path' + )).to.equal('ADashpath'); + }); + + it('converts variable declarations (`${var}`) to `VariableVar`', () => { + expect(sdk.naming.normalizePathPart( + '${variable}' + )).to.equal('VariableVar'); + }); + + it('converts variable declarations prefixes to `VariableVarPath`', () => { + expect(sdk.naming.normalizePathPart( + '${variable}Path' + )).to.equal('VariableVarPath'); + }); + + it('converts variable declarations suffixes to `PathvariableVar`', () => { + expect(sdk.naming.normalizePathPart( + 'path${variable}' + )).to.equal('PathvariableVar'); + }); + + it('converts variable declarations in center to `PathvariableVarDir`', () => { + expect(sdk.naming.normalizePathPart( + 'path${variable}Dir' + )).to.equal('PathvariableVarDir'); + }); + }); + describe('#getServiceEndpointRegex()', () => { + it('should match the prefix', () => { + expect(sdk.naming.getServiceEndpointRegex().test('ServiceEndpoint')) + .to.equal(true); + }); + + it('should not match a name without the prefix', () => { + expect(sdk.naming.getServiceEndpointRegex() + .test('NotThePrefixServiceEndpoint')).to.equal(false); + }); + + it('should match a name with the prefix', () => { + expect(sdk.naming.getServiceEndpointRegex() + .test('ServiceEndpointForAService')).to.equal(true); + }); + }); + describe('#getStackName()', () => { + it('should use the service name and stage from the service and config', () => { + serverless.service.service = 'myService'; + expect(sdk.naming.getStackName()).to.equal(`${serverless.service.service}-${options.stage}`); + }); + }); + describe('#getNormalizedFunctionName()', () => { + it('should normalize the given functionName', () => { + expect(sdk.naming.getNormalizedFunctionName('functionName')) + .to.equal('FunctionName'); + }); + + it('should normalize the given functionName with an underscore', () => { + expect(sdk.naming.getNormalizedFunctionName('hello_world')) + .to.equal('HelloUnderscoreworld'); + }); + + it('should normalize the given functionName with a dash', () => { + expect(sdk.naming.getNormalizedFunctionName('hello-world')) + .to.equal('HelloDashworld'); + }); + }); + describe('#extractAuthorizerNameFromArn()', () => { + it('should extract everything after the last colon and dash', () => { + const arn = 'arn:aws:lambda:us-east-1:0123456789:my-dev-lambda'; + expect(sdk.naming.extractAuthorizerNameFromArn(arn)).to.equal('lambda'); + }); + }); + describe('#extractLambdaNameFromArn()', () => { + it('should extract everything after the last colon', () => { + const arn = 'arn:aws:lambda:us-east-1:0123456789:my-dev-lambda'; + expect(sdk.naming.extractLambdaNameFromArn(arn)).to.equal('my-dev-lambda'); + }); + }); + describe('#getLambdaLogicalId()', () => { + it('should normalize the function name and add the logical suffix', () => { + expect(sdk.naming.getLambdaLogicalId('functionName')) + .to.equal('FunctionNameLambdaFunction'); + }); + }); + describe('#getLambdaLogicalIdRegex()', () => { + it('should match the suffix', () => { + expect(sdk.naming.getLambdaLogicalIdRegex() + .test('LambdaFunction')).to.equal(true); + }); + + it('should not match a name without the suffix', () => { + expect(sdk.naming.getLambdaLogicalIdRegex() + .test('LambdaFunctionNotTheSuffix')).to.equal(false); + }); + + it('should match a name with the suffix', () => { + expect(sdk.naming.getLambdaLogicalIdRegex() + .test('AFunctionNameLambdaFunction')).to.equal(true); + }); + }); + describe('#getLambdaOutputLogicalId()', () => { + it('should normalize the function name and add the logical arn suffix', () => { + expect( + sdk.naming.getLambdaOutputLogicalId('functionName') + ).to.equal('FunctionNameLambdaFunctionArn'); + }); + }); + describe('#getLambdaOutputLogicalIdRegex()', () => { + it('should match the suffix', () => { + expect(sdk.naming.getLambdaOutputLogicalIdRegex() + .test('aLambdaFunctionArn')).to.equal(true); + }); + + it('should not match a name without the suffix', () => { + expect(sdk.naming.getLambdaOutputLogicalIdRegex() + .test('LambdaFunctionArnNotTheSuffix')) + .to.equal(false); + }); + + it('should match a name with the suffix', () => { + expect(sdk.naming.getLambdaOutputLogicalIdRegex() + .test('AFunctionArnNameLambdaFunctionArn')) + .to.equal(true); + }); + }); + describe('#generateApiGatewayDeploymentLogicalId()', () => { + it('should return ApiGatewayDeployment with a date based suffix', () => { + expect(sdk.naming.generateApiGatewayDeploymentLogicalId() + .match(/ApiGatewayDeployment(.*)/).length) + .to.be.greaterThan(1); + }); + }); + describe('#getRestApiLogicalId()', () => { + it('should return ApiGatewayRestApi', () => { + expect(sdk.naming.getRestApiLogicalId()).to.equal('ApiGatewayRestApi'); + }); + }); + describe('#getNormalizedAuthorizerName()', () => { + it('normalize the authorizer name', () => { + expect(sdk.naming.getNormalizedAuthorizerName('authorizerName')) + .to.equal('AuthorizerName'); + }); + }); + describe('#getAuthorizerLogicalId()', () => { + it('should normalize the authorizer name and add the standard suffix', () => { + expect(sdk.naming.getAuthorizerLogicalId('authorizerName')) + .to.equal('AuthorizerNameApiGatewayAuthorizer'); + }); + }); + describe('#extractAuthorizerNameFromArn()', () => { + it('should extract the authorizer name from an ARN', () => { + const arn = 'arn:aws:lambda:us-east-1:0123456789:my-dev-lambda'; + expect(sdk.naming.extractAuthorizerNameFromArn(arn)).to.equal('lambda'); + }); + }); + describe('#normalizePath()', () => { + it('should normalize each part of the resource path and remove non-alpha-numeric characters', + () => { + expect(sdk.naming.normalizePath( + 'my/path/to/a-${var}-resource' + )).to.equal('MyPathToADashvarVarDashresource'); + }); + }); + describe('#getResourceLogicalId()', () => { + it('should normalize the resource and add the standard suffix', () => { + expect(sdk.naming.getResourceLogicalId( + 'my/path/to/a-${var}-resource' + )).to.equal('ApiGatewayResourceMyPathToADashvarVarDashresource'); + }); + }); + describe('#extractResourceId()', () => { + it('should extract the normalized resource name', () => { + expect(sdk.naming.extractResourceId( + 'ApiGatewayResourceMyPathToADashvarVarDashResource' + )).to.equal('MyPathToADashvarVarDashResource'); + }); + }); + describe('#normalizeMethodName()', () => { + it('should capitalize the first letter and lowercase any other characters', () => { + expect(sdk.naming.normalizeMethodName('gET')).to.equal('Get'); + }); + }); + describe('#getMethodLogicalId()', () => { + it('', () => { + expect(sdk.naming.getMethodLogicalId( + 'ResourceId', 'get' + )).to.equal('ApiGatewayMethodResourceIdGet'); + }); + }); + describe('#getApiKeyLogicalIdRegex()', () => { + it('should match the prefix', () => { + expect(sdk.naming.getApiKeyLogicalIdRegex() + .test('ApiGatewayApiKey')).to.equal(true); + }); + + it('should not match a name without the prefix', () => { + expect(sdk.naming.getApiKeyLogicalIdRegex() + .test('NotThePrefixApiGatewayApiKey')).to.equal(false); + }); + + it('should match a name with the prefix', () => { + expect(sdk.naming.getApiKeyLogicalIdRegex() + .test('ApiGatewayApiKeySuffix')).to.equal(true); + }); + }); + + describe('#getDeploymentBucketLogicalId()', () => { + it('should return "ServerlessDeploymentBucket"', () => { + expect(sdk.naming.getDeploymentBucketLogicalId()).to.equal('ServerlessDeploymentBucket'); + }); + }); + describe('#getDeploymentBucketOutputLogicalId()', () => { + it('should return "ServerlessDeploymentBucketName"', () => { + expect(sdk.naming.getDeploymentBucketOutputLogicalId()) + .to.equal('ServerlessDeploymentBucketName'); + }); + }); + describe('#normalizeBucketName()', () => { + it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { + expect(sdk.naming.normalizeBucketName('b!u@c#k$e%t^N&a*m(e')).to.equal('BucketName'); + }); + }); + describe('#getBucketLogicalId()', () => { + it('should normalize the bucket name and add the standard prefix', () => { + expect(sdk.naming.getBucketLogicalId('b!u@c#k$e%t^N&a*m(e')).to.equal('S3BucketBucketName'); + }); + }); + describe('#normalizeTopicName()', () => { + it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { + expect(sdk.naming.normalizeTopicName('t!o@p#i$c%N^a&m*e')).to.equal('TopicName'); + }); + }); + describe('#getTopicLogicalId()', () => { + it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { + expect(sdk.naming.getTopicLogicalId('t!o@p#i$c%N^a&m*e')).to.equal('SNSTopicTopicName'); + }); + }); + describe('#getScheduleId()', () => { + it('should add the standard suffix', () => { + expect(sdk.naming.getScheduleId('functionName')).to.equal('functionNameSchedule'); + }); + }); + describe('#getScheduleLogicalId()', () => { + it('should normalize the function name and add the standard suffix including the index', () => { + expect(sdk.naming.getScheduleLogicalId('functionName', 0)) + .to.equal('FunctionNameEventsRuleSchedule0'); + }); + }); + describe('#getLambdaS3PermissionLogicalId()', () => { + it('should normalize the function name and add the standard suffix', () => { + expect(sdk.naming.getLambdaS3PermissionLogicalId('functionName')) + .to.equal('FunctionNameLambdaPermissionS3'); + }); + }); + describe('#getLambdaSnsPermissionLogicalId()', () => { + it('should normalize the function and topic names and add them as prefix and suffix to the ' + + 'standard permission center', () => { + expect(sdk.naming.getLambdaSnsPermissionLogicalId('functionName', 'topicName')) + .to.equal('FunctionNameLambdaPermissionTopicName'); + }); + }); + describe('#getLambdaSchedulePermissionLogicalId()', () => { + it('should normalize the function name and add the standard suffix including event index', + () => { + expect(sdk.naming.getLambdaSchedulePermissionLogicalId('functionName', 0)) + .to.equal('FunctionNameLambdaPermissionEventsRuleSchedule0'); + }); + }); + describe('#getLambdaApiGatewayPermissionLogicalId()', () => { + it('should normalize the function name and append the standard suffix', () => { + expect(sdk.naming.getLambdaApiGatewayPermissionLogicalId('functionName')) + .to.equal('FunctionNameLambdaPermissionApiGateway'); + }); + }); +}); diff --git a/tests/all.js b/tests/all.js index 938b256cd..b4661d2b6 100644 --- a/tests/all.js +++ b/tests/all.js @@ -25,6 +25,7 @@ require('../lib/plugins/rollback/tests/rollback'); // AWS Plugins Tests require('../lib/plugins/aws/provider/awsProvider.test'); require('../lib/plugins/aws/tests/validate'); +require('../lib/plugins/aws/tests/naming'); require('../lib/plugins/aws/tests/monitorStack'); require('../lib/plugins/aws/tests/setBucketName'); require('../lib/plugins/aws/tests/findAndGroupDeployments');