From 61efd35850bb8cf7a930a95d02c51083ab4ec988 Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Wed, 9 Nov 2016 19:31:08 +0700 Subject: [PATCH 1/6] added logical id names in naming-js file --- .../compile/events/apiGateway/lib/apiKeys.js | 5 +- .../events/apiGateway/lib/authorizers.js | 4 +- .../compile/events/apiGateway/lib/cors.js | 4 +- .../events/apiGateway/lib/deployment.js | 2 +- .../apiGateway/lib/method/authorization.js | 4 +- .../events/apiGateway/lib/method/index.js | 4 +- .../apiGateway/lib/method/integration.js | 5 +- .../events/apiGateway/lib/permissions.js | 14 +- .../events/apiGateway/lib/resources.js | 13 +- .../compile/events/apiGateway/lib/restApi.js | 2 +- .../compile/events/apiGateway/lib/validate.js | 8 +- .../aws/deploy/compile/events/s3/index.js | 29 ++- .../deploy/compile/events/schedule/index.js | 23 +-- .../aws/deploy/compile/events/sns/index.js | 27 ++- .../aws/deploy/compile/events/stream/index.js | 22 +-- .../aws/deploy/compile/functions/index.js | 8 +- lib/plugins/aws/deploy/lib/createStack.js | 4 +- .../aws/deploy/lib/mergeIamTemplates.js | 9 +- lib/plugins/aws/info/index.js | 12 +- lib/plugins/aws/lib/naming.js | 170 ++++++++++++++++++ lib/plugins/aws/lib/updateStack.js | 4 +- lib/plugins/aws/provider/awsProvider.js | 83 ++++++--- 22 files changed, 327 insertions(+), 129 deletions(-) create mode 100644 lib/plugins/aws/lib/naming.js 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..86558f479 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 + .getLogicalApiGatewayApiKeyName(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..48ccf1771 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.getLogicalAuthorizerName(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..be1c79af3 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 + .getLogicalApiGatewayMethodName(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..8312b88c8 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,7 @@ const BbPromise = require('bluebird'); module.exports = { compileDeployment() { - this.apiGatewayDeploymentLogicalId = `ApiGatewayDeployment${(new Date()).getTime().toString()}`; + this.apiGatewayDeploymentLogicalId = this.provider.naming.getApiGatewayDeploymentId(); _.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..19fac0e4d 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 @@ -5,8 +5,8 @@ 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 + .getLogicalAuthorizerName(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..ebe85dd7f 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 + .getLogicalApiGatewayMethodName(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..37a76a530 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 + .getLogicalLambdaName(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..e3c152021 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 + .getLambdaApiGatewayPermissionName(event.functionName); + const lambdaLogicalId = this.provider.naming + .getLogicalLambdaName(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 + .getLambdaApiGatewayPermissionName(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..bf63accbc 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.getNormalizedApiGatewayResourceName(path); + const resourceLogicalId = this.provider.naming.getLogicalApiGatewayResourceName(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..b0b2c38b3 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.getLogicalApiGatewayName(); _.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..cb122c29e 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.extractLambdaNameFromArn(arn); } } else if (typeof authorizer === 'object') { if (authorizer.arn) { arn = authorizer.arn; - name = this.getLambdaName(arn); + name = this.provider.naming.extractLambdaNameFromArn(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.getLogicalLambdaName(name); + return { 'Fn::GetAtt': [lambdaLogicalId, 'Arn'] }; }, getLambdaName(arn) { diff --git a/lib/plugins/aws/deploy/compile/events/s3/index.js b/lib/plugins/aws/deploy/compile/events/s3/index.js index 11c8bd76f..b3c8a809a 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 + .getLogicalLambdaName(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 + .getLogicalBucketName(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 + .getLogicalLambdaName(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 + .getLambdaS3PermissionName(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..79d5c19d4 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 + .getLogicalLambdaName(functionName); + const scheduleLogicalId = this.provider.naming + .getCloudWatchEventName(functionName, scheduleNumberInFunction); + const lambdaPermissionLogicalId = this.provider.naming + .getLambdaCloudWatchEventPermissionName(functionName, scheduleNumberInFunction); + const scheduleId = this.provider.naming.getCloudWatchEventId(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..194c0730c 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 + .getLogicalLambdaName(functionName); + const topicLogicalId = this.provider.naming + .getLogicalSnsTopicName(topicName); + const lambdaPermissionLogicalId = this.provider.naming + .getLambdaSnsTopicPermissionName(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..feaa09ab4 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 + .getLogicalLambdaName(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..a7953ad56 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 + .getLogicalLambdaName(functionName); + const functionOutputLogicalId = this.provider.naming + .getLogicalLambdaArnName(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..f22dee26c 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 + .getLogicalLogGroupName(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/info/index.js b/lib/plugins/aws/info/index.js index 915c87462..83b85681b 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 + .getLogicalLambdaArnNameRegex(); + + 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/lib/naming.js b/lib/plugins/aws/lib/naming.js new file mode 100644 index 000000000..17e779866 --- /dev/null +++ b/lib/plugins/aws/lib/naming.js @@ -0,0 +1,170 @@ +'use strict'; + +const _ = require('lodash'); + +module.exports = { + /* + * General Name Normalization + */ + normalizeName(name) { + return `${_.upperFirst(name)}`; + }, + normalizeNameToAlphaNumericOnly(name) { + return this.normalizeName(name.replace(/[^0-9A-Za-z]/g, '')); + }, + normalizePathtoCapitalAlphaNumbericOnlyWithReplacement(path) { + return this.normalizeNameToAlphaNumericOnly( + path.replace(/-/g, 'Dash') + .replace(/\{(.*)\}/g, '$1Var')); + }, + + getServiceEndpointRegex() { + return /^ServiceEndpoint/; + }, + + /* + * Stack Naming + */ + getStackName() { + return `${this.sdk.serverless.service.service}-${this.sdk.getStage()}`; + }, + + getLogicalLogGroupName(functionName) { + return `${this.getNormalizedLambdaName(functionName)}LogGroup`; + }, + + /* + * Lambda Function Naming + */ + getNormalizedLambdaName(functionName) { + return this.normalizeName(functionName); + }, + extractLambdaNameFromArn(functionArn) { + return functionArn.substring(functionArn.lastIndexOf(':') + 1); + }, + getLogicalLambdaName(functionName) { + return `${this.getNormalizedLambdaName(functionName)}LambdaFunction`; + }, + getLogicalLambdaNameRegex() { + return /LambdaFunction$/; + }, + getLogicalLambdaArnName(functionName) { + return `${this.getLogicalLambdaName(functionName)}Arn`; + }, + getLogicalLambdaArnNameRegex() { + return /LambdaFunctionArn$/; + }, + + /* + * ApiGateway Authorizer Lambda & Method Naming + */ + getApiGatewayName() { + return `${this.sdk.getStage()}-${this.sdk.serverless.service.service}`; + }, + getApiGatewayDeploymentId() { + return `ApiGatewayDeployment${(new Date()).getTime().toString()}`; + }, + getLogicalApiGatewayName() { + return 'ApiGatewayRestApi'; + }, + getNormalizedAuthorizerName(functionName) { + return this.getNormalizedLambdaName(functionName); + }, + getLogicalAuthorizerName(functionName) { + return `${this.getNormalizedAuthorizerName(functionName)}ApiGatewayAuthorizer`; + }, + extractAuthorizerIdFromArn(authorizerArn) { + return this.extractLambdaNameFromArn(authorizerArn); + }, + getLogicalAuthorizerArnName(functionName) { + return `${this.getLogicalAuthorizerName(functionName)}Arn`; + }, + getNormalizedApiGatewayResourceName(resourcePath) { + return resourcePath.split('/').map( + this.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement.bind(this) + ).join(''); + }, + getLogicalApiGatewayResourceName(resourcePath) { + return `ApiGatewayResource${this.getNormalizedApiGatewayResourceName(resourcePath)}`; + }, + extractResourceId(logicalApiGatewayResourceName) { + return logicalApiGatewayResourceName.match(/ApiGatewayResource(.*)/)[1]; + }, + getNormalizedApiGatewayMethodName(methodName) { + return this.normalizeName(methodName.toLowerCase()); + }, + getLogicalApiGatewayMethodName(resourceId, methodName) { + return `ApiGatewayMethod${resourceId}${this.getNormalizedApiGatewayMethodName(methodName)}`; + }, + getLogicalApiGatewayApiKeyName(apiKeyNumber) { + return `ApiGatewayApiKey${apiKeyNumber}`; + }, + getLogicalApiGatewayApiKeyRegex() { + return /^ApiGatewayApiKey/; + }, + + /* + * S3 Bucket Naming + */ + getLogicalDeploymentBucketName() { + return 'ServerlessDeploymentBucket'; + }, + getLogicalDeploymentBucketOutputVariableName() { + return 'ServerlessDeploymentBucketName'; + }, + getNormalizedBucketName(bucketName) { + return this.normalizeNameToAlphaNumericOnly(bucketName); + }, + getLogicalBucketName(bucketName) { + return `S3Bucket${this.getNormalizedBucketName(bucketName)}`; + }, + + /* + * SNS Topic Naming + */ + getNormalizedSnsTopicName(topicName) { + return this.normalizeNameToAlphaNumericOnly(topicName); + }, + getLogicalSnsTopicName(topicName) { + return `SNSTopic${this.getNormalizedSnsTopicName(topicName)}`; + }, + + /* + * CloudWatch Event Naming + */ + getCloudWatchEventId(functionName) { + return `${functionName}Schedule`; + }, + getCloudWatchEventName(functionName, scheduleIndex) { + return `${this.getNormalizedLambdaName(functionName)}EventsRuleSchedule${scheduleIndex}`; + }, + + /* + * Stream Event Naming + */ + getStreamLogicalId(functionName, streamType, streamName) { + return `${ + this.getNormalizedLambdaName(functionName) + }EventSourceMapping${ + this.normalizeName(streamType) + }${this.normalizeNameToAlphaNumericOnly(streamName)}`; + }, + + /* + * Lambda to S3 Bucket/SNS Topic/CloudWatch Event/ApiGateway Permissions Naming + */ + getLambdaS3PermissionName(functionName) { + return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionS3`; + }, + getLambdaSnsTopicPermissionName(functionName, topicName) { + return `${this.getNormalizedLambdaName(functionName)}LambdaPermission${ + this.getNormalizedSnsTopicName(topicName)}`; + }, + getLambdaCloudWatchEventPermissionName(functionName, scheduleIndex) { + return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionEventsRuleSchedule${ + scheduleIndex}`; + }, + getLambdaApiGatewayPermissionName(functionName) { + return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionApiGateway`; + }, +}; \ No newline at end of file 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..0e34d6665 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) => { @@ -135,7 +145,7 @@ class AwsProvider { const errorMessage = [ 'AWS provider credentials not found.', ' You can find more info on how to set up provider', - ' credentials in our docs here: https://git.io/vXsdd', + ' credentials in our docs here: https://git.io/viZAC', ].join(''); err.message = errorMessage; } @@ -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 ret = { 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 @@ -174,25 +182,42 @@ class AwsProvider { return ret; } - getServerlessDeploymentBucketName(stage, region) { + getRegion() { + let ret = 'us-east-1'; + if (this.options && this.options.region) { + ret = this.options.region; + } else if (this.serverless.config.region) { + ret = this.serverless.config.region; + } else if (this.serverless.service.provider.region) { + ret = this.serverless.service.provider.region; + } + return ret; + } + + 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.getLogicalDeploymentBucketName(), + } ).then((result) => result.StackResourceDetail.PhysicalResourceId); } - getStackName(stage) { - return `${this.serverless.service.service}-${stage}`; + getStage() { + let ret = 'dev'; + if (this.options && this.options.stage) { + ret = this.options.stage; + } else if (this.serverless.config.stage) { + ret = this.serverless.config.stage; + } else if (this.serverless.service.provider.stage) { + ret = this.serverless.service.provider.stage; + } + return ret; } } -module.exports = AwsProvider; +module.exports = AwsProvider; \ No newline at end of file From 1a02e15d9b9bc2e529e9e84ad962b371cb69fe3f Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Thu, 10 Nov 2016 15:14:33 +0700 Subject: [PATCH 2/6] updated tests using name-js --- .../apiGateway/lib/method/authorization.js | 2 - .../compile/events/apiGateway/lib/validate.js | 4 +- .../events/apiGateway/tests/apiKeys.js | 2 + .../events/apiGateway/tests/authorizers.js | 3 + .../compile/events/apiGateway/tests/cors.js | 2 + .../events/apiGateway/tests/deployment.js | 2 + .../events/apiGateway/tests/methods.js | 2 + .../events/apiGateway/tests/permissions.js | 2 + .../events/apiGateway/tests/resources.js | 2 + .../events/apiGateway/tests/restApi.js | 2 + .../events/apiGateway/tests/validate.js | 2 + .../aws/deploy/tests/mergeIamTemplates.js | 2 + lib/plugins/aws/info/tests/index.js | 2 +- lib/plugins/aws/lib/naming.js | 9 +- lib/plugins/aws/provider/awsProvider.js | 2 +- lib/plugins/aws/provider/awsProvider.test.js | 188 ++++++++++++------ 16 files changed, 164 insertions(+), 64 deletions(-) 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 19fac0e4d..13530b9b2 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,7 +1,5 @@ 'use strict'; -const _ = require('lodash'); - module.exports = { getMethodAuthorization(http) { if (http.authorizer) { 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 cb122c29e..19d601371 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.provider.naming.extractLambdaNameFromArn(arn); + name = this.provider.naming.extractAuthorizerNameFromArn(arn); } } else if (typeof authorizer === 'object') { if (authorizer.arn) { arn = authorizer.arn; - name = this.provider.naming.extractLambdaNameFromArn(arn); + name = this.provider.naming.extractAuthorizerNameFromArn(arn); } else if (authorizer.name) { name = authorizer.name; arn = this.getLambdaArn(name); 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/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/tests/index.js b/lib/plugins/aws/info/tests/index.js index 757049512..76a374440 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 index 17e779866..20e9197a0 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -42,6 +42,13 @@ module.exports = { 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]; + }, getLogicalLambdaName(functionName) { return `${this.getNormalizedLambdaName(functionName)}LambdaFunction`; }, @@ -167,4 +174,4 @@ module.exports = { getLambdaApiGatewayPermissionName(functionName) { return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionApiGateway`; }, -}; \ No newline at end of file +}; diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js index 0e34d6665..f0985eb39 100644 --- a/lib/plugins/aws/provider/awsProvider.js +++ b/lib/plugins/aws/provider/awsProvider.js @@ -220,4 +220,4 @@ class AwsProvider { } } -module.exports = AwsProvider; \ No newline at end of file +module.exports = AwsProvider; diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js index 204f07640..b9e2fda8e 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,10 +180,10 @@ 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'); + expect(err.message).to.contain('https://git.io/viZAC'); done(); }) .catch(done); @@ -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,60 @@ 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('#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 options = { - stage: 'dev', - region: 'us-east-1', - }; - const describeStackResourcesStub = sinon .stub(awsProvider, 'request') .returns(BbPromise.resolve({ @@ -365,7 +409,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 +417,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 +427,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 +436,56 @@ 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'); + }); }); }); }); From 08156924d5c5e712d6ff3fe6a35cdab194b2803d Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Thu, 10 Nov 2016 16:17:42 +0700 Subject: [PATCH 3/6] added tests for naming-js --- lib/plugins/aws/lib/naming.js | 3 - lib/plugins/aws/tests/naming.js | 309 ++++++++++++++++++++++++++++++++ tests/all.js | 1 + 3 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 lib/plugins/aws/tests/naming.js diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js index 20e9197a0..c04663241 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -80,9 +80,6 @@ module.exports = { getLogicalAuthorizerName(functionName) { return `${this.getNormalizedAuthorizerName(functionName)}ApiGatewayAuthorizer`; }, - extractAuthorizerIdFromArn(authorizerArn) { - return this.extractLambdaNameFromArn(authorizerArn); - }, getLogicalAuthorizerArnName(functionName) { return `${this.getLogicalAuthorizerName(functionName)}Arn`; }, diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js new file mode 100644 index 000000000..b0a6ddf24 --- /dev/null +++ b/lib/plugins/aws/tests/naming.js @@ -0,0 +1,309 @@ +'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.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + 'a-path' + )).to.equal('ADashpath'); + }); + it('converts variable declarations (`${var}`) to `VariableVar`', () => { + expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + '${variable}' + )).to.equal('VariableVar'); + }); + it('converts variable declarations prefixes to `VariableVarPath`', () => { + expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + '${variable}Path' + )).to.equal('VariableVarPath'); + }); + it('converts variable declarations suffixes to `PathvariableVar`', () => { + expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + 'path${variable}' + )).to.equal('PathvariableVar'); + }); + it('converts variable declarations in center to `PathvariableVarDir`', () => { + expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + '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('#getNormalizedLambdaName()', () => { + it('should normalize the given functionName', () => { + expect(sdk.naming.getNormalizedLambdaName('functionName')) + .to.equal('FunctionName'); + }); + }); + 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('#getLogicalLambdaName()', () => { + it('should normalize the function name and add the logical suffix', () => { + expect(sdk.naming.getLogicalLambdaName('functionName')) + .to.equal('FunctionNameLambdaFunction'); + }); + }); + describe('#getLogicalLambdaNameRegex()', () => { + it('should match the suffix', () => { + expect(sdk.naming.getLogicalLambdaNameRegex() + .test('LambdaFunction')).to.equal(true); + }); + it('should not match a name without the suffix', () => { + expect(sdk.naming.getLogicalLambdaNameRegex() + .test('LambdaFunctionNotTheSuffix')).to.equal(false); + }); + it('should match a name with the suffix', () => { + expect(sdk.naming.getLogicalLambdaNameRegex() + .test('AFunctionNameLambdaFunction')).to.equal(true); + }); + }); + describe('#getLogicalLambdaArnName()', () => { + it('should normalize the function name and add the logical arn suffix', () => { + expect( + sdk.naming.getLogicalLambdaArnName('functionName') + ).to.equal('FunctionNameLambdaFunctionArn'); + }); + }); + describe('#getLogicalLambdaArnNameRegex()', () => { + it('should match the suffix', () => { + expect(sdk.naming.getLogicalLambdaArnNameRegex() + .test('aLambdaFunctionArn')).to.equal(true); + }); + it('should not match a name without the suffix', () => { + expect(sdk.naming.getLogicalLambdaArnNameRegex() + .test('LambdaFunctionArnNotTheSuffix')) + .to.equal(false); + }); + it('should match a name with the suffix', () => { + expect(sdk.naming.getLogicalLambdaArnNameRegex() + .test('AFunctionArnNameLambdaFunctionArn')) + .to.equal(true); + }); + }); + describe('#getApiGatewayName()', () => { + it('should return the composition of stage and service name', () => { + serverless.service.service = 'myService'; + expect(sdk.naming.getApiGatewayName()) + .to.equal(`dev-${serverless.service.service}`); + }); + }); + describe('#getApiGatewayDeploymentId()', () => { + it('should return ApiGatewayDeployment with a date based suffix', () => { + expect(sdk.naming.getApiGatewayDeploymentId().match(/ApiGatewayDeployment(.*)/).length) + .to.be.greaterThan(1); + }); + }); + describe('#getLogicalApiGatewayName()', () => { + it('should return ApiGatewayRestApi', () => { + expect(sdk.naming.getLogicalApiGatewayName()).to.equal('ApiGatewayRestApi'); + }); + }); + describe('#getNormalizedAuthorizerName()', () => { + it('normalize the authorizer name', () => { + expect(sdk.naming.getNormalizedAuthorizerName('authorizerName')) + .to.equal('AuthorizerName'); + }); + }); + describe('#getLogicalAuthorizerName()', () => { + it('should normalize the authorizer name and add the standard suffix', () => { + expect(sdk.naming.getLogicalAuthorizerName('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('#getLogicalAuthorizerArnName()', () => { + it('should normalize the authorizer name and add the standard arn suffix', () => { + expect(sdk.naming.getLogicalAuthorizerArnName('authorizerName')) + .to.equal('AuthorizerNameApiGatewayAuthorizerArn'); + }); + }); + describe('#getNormalizedApiGatewayResourceName()', () => { + it('should normalize each part of the resource path and remove non-alpha-numeric characters', + () => { + expect(sdk.naming.getNormalizedApiGatewayResourceName( + 'my/path/to/a-${var}-resource' + )).to.equal('MyPathToADashvarVarDashresource'); + }); + }); + describe('#getLogicalApiGatewayResourceName()', () => { + it('should normalize the resource and add the standard suffix', () => { + expect(sdk.naming.getLogicalApiGatewayResourceName( + '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('#getNormalizedApiGatewayMethodName()', () => { + it('should capitalize the first letter and lowercase any other characters', () => { + expect(sdk.naming.getNormalizedApiGatewayMethodName('gET')).to.equal('Get'); + }); + }); + describe('#getLogicalApiGatewayMethodName()', () => { + it('', () => { + expect(sdk.naming.getLogicalApiGatewayMethodName( + 'ResourceId', 'get' + )).to.equal('ApiGatewayMethodResourceIdGet'); + }); + }); + describe('#getLogicalApiGatewayApiKeyRegex()', () => { + it('should match the prefix', () => { + expect(sdk.naming.getLogicalApiGatewayApiKeyRegex() + .test('ApiGatewayApiKey')).to.equal(true); + }); + it('should not match a name without the prefix', () => { + expect(sdk.naming.getLogicalApiGatewayApiKeyRegex() + .test('NotThePrefixApiGatewayApiKey')).to.equal(false); + }); + it('should match a name with the prefix', () => { + expect(sdk.naming.getLogicalApiGatewayApiKeyRegex() + .test('ApiGatewayApiKeySuffix')).to.equal(true); + }); + }); + + describe('#getLogicalDeploymentBucketName()', () => { + it('should return "ServerlessDeploymentBucket"', () => { + expect(sdk.naming.getLogicalDeploymentBucketName()).to.equal('ServerlessDeploymentBucket'); + }); + }); + describe('#getLogicalDeploymentBucketOutputVariableName()', () => { + it('should return "ServerlessDeploymentBucketName"', () => { + expect(sdk.naming.getLogicalDeploymentBucketOutputVariableName()) + .to.equal('ServerlessDeploymentBucketName'); + }); + }); + describe('#getNormalizedBucketName()', () => { + it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { + expect(sdk.naming.getNormalizedBucketName('b!u@c#k$e%t^N&a*m(e')).to.equal('BucketName'); + }); + }); + describe('#getLogicalBucketName()', () => { + it('should normalize the bucket name and add the standard prefix', () => { + expect(sdk.naming.getLogicalBucketName('b!u@c#k$e%t^N&a*m(e')).to.equal('S3BucketBucketName'); + }); + }); + describe('#getNormalizedSnsTopicName()', () => { + it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { + expect(sdk.naming.getNormalizedSnsTopicName('t!o@p#i$c%N^a&m*e')).to.equal('TopicName'); + }); + }); + describe('#getLogicalSnsTopicName()', () => { + it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { + expect(sdk.naming.getLogicalSnsTopicName('t!o@p#i$c%N^a&m*e')).to.equal('SNSTopicTopicName'); + }); + }); + describe('#getCloudWatchEventId()', () => { + it('should add the standard suffix', () => { + expect(sdk.naming.getCloudWatchEventId('functionName')).to.equal('functionNameSchedule'); + }); + }); + describe('#getCloudWatchEventName()', () => { + it('should normalize the function name and add the standard suffix including the index', () => { + expect(sdk.naming.getCloudWatchEventName('functionName', 0)) + .to.equal('FunctionNameEventsRuleSchedule0'); + }); + }); + describe('#getLambdaS3PermissionName()', () => { + it('should normalize the function name and add the standard suffix', () => { + expect(sdk.naming.getLambdaS3PermissionName('functionName')) + .to.equal('FunctionNameLambdaPermissionS3'); + }); + }); + describe('#getLambdaSnsTopicPermissionName()', () => { + it('should normalize the function and topic names and add them as prefix and suffix to the ' + + 'standard permission center', () => { + expect(sdk.naming.getLambdaSnsTopicPermissionName('functionName', 'topicName')) + .to.equal('FunctionNameLambdaPermissionTopicName'); + }); + }); + describe('#getLambdaCloudWatchEventPermissionName()', () => { + it('should normalize the function name and add the standard suffix including event index', + () => { + expect(sdk.naming.getLambdaCloudWatchEventPermissionName('functionName', 0)) + .to.equal('FunctionNameLambdaPermissionEventsRuleSchedule0'); + }); + }); + describe('#getLambdaApiGatewayPermissionName()', () => { + it('should normalize the function name and append the standard suffix', () => { + expect(sdk.naming.getLambdaApiGatewayPermissionName('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'); From fef9b68e5a453ea56bb1cd7d68f790789f404b6c Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Thu, 10 Nov 2016 19:05:02 +0700 Subject: [PATCH 4/6] refactored naming-js method naming --- .../compile/events/apiGateway/lib/apiKeys.js | 2 +- .../events/apiGateway/lib/authorizers.js | 2 +- .../compile/events/apiGateway/lib/cors.js | 2 +- .../events/apiGateway/lib/deployment.js | 3 +- .../apiGateway/lib/method/authorization.js | 2 +- .../events/apiGateway/lib/method/index.js | 2 +- .../apiGateway/lib/method/integration.js | 2 +- .../events/apiGateway/lib/permissions.js | 6 +- .../events/apiGateway/lib/resources.js | 4 +- .../compile/events/apiGateway/lib/restApi.js | 2 +- .../compile/events/apiGateway/lib/validate.js | 2 +- .../aws/deploy/compile/events/s3/index.js | 8 +- .../deploy/compile/events/schedule/index.js | 8 +- .../aws/deploy/compile/events/sns/index.js | 6 +- .../aws/deploy/compile/events/stream/index.js | 2 +- .../aws/deploy/compile/functions/index.js | 4 +- .../aws/deploy/lib/mergeIamTemplates.js | 2 +- lib/plugins/aws/info/index.js | 2 +- lib/plugins/aws/lib/naming.js | 135 ++++++++--------- lib/plugins/aws/provider/awsProvider.js | 34 ++--- lib/plugins/aws/provider/awsProvider.test.js | 11 +- lib/plugins/aws/tests/naming.js | 136 ++++++++---------- 22 files changed, 173 insertions(+), 204 deletions(-) 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 86558f479..646fa14aa 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/apiKeys.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/apiKeys.js @@ -18,7 +18,7 @@ module.exports = { } const apiKeyLogicalId = this.provider.naming - .getLogicalApiGatewayApiKeyName(apiKeyNumber); + .getApiKeyLogicalId(apiKeyNumber); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [apiKeyLogicalId]: { 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 48ccf1771..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,7 +31,7 @@ module.exports = { }); } - const authorizerLogicalId = this.provider.naming.getLogicalAuthorizerName(authorizer.name); + const authorizerLogicalId = this.provider.naming.getAuthorizerLogicalId(authorizer.name); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [authorizerLogicalId]: { 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 be1c79af3..465cfcda4 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/cors.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/cors.js @@ -10,7 +10,7 @@ module.exports = { const resourceName = this.getResourceName(path); const resourceRef = this.getResourceId(path); const corsMethodLogicalId = this.provider.naming - .getLogicalApiGatewayMethodName(resourceName, 'options'); + .getMethodLogicalId(resourceName, 'options'); const preflightHeaders = { 'Access-Control-Allow-Origin': `'${config.origins.join(',')}'`, 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 8312b88c8..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 = this.provider.naming.getApiGatewayDeploymentId(); + 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 13530b9b2..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 @@ -4,7 +4,7 @@ module.exports = { getMethodAuthorization(http) { if (http.authorizer) { const authorizerLogicalId = this.provider.naming - .getLogicalAuthorizerName(http.authorizer.name); + .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 ebe85dd7f..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 @@ -34,7 +34,7 @@ module.exports = { ); const methodLogicalId = this.provider.naming - .getLogicalApiGatewayMethodName(resourceName, event.http.method); + .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 37a76a530..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 @@ -5,7 +5,7 @@ const _ = require('lodash'); module.exports = { getMethodIntegration(http, functionName) { const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); const integration = { IntegrationHttpMethod: 'POST', Type: http.integration, 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 e3c152021..3085327cf 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/permissions.js @@ -8,9 +8,9 @@ module.exports = { compilePermissions() { this.validated.events.forEach((event) => { const lambdaPermissionLogicalId = this.provider.naming - .getLambdaApiGatewayPermissionName(event.functionName); + .getLambdaApiGatewayPermissionLogicalId(event.functionName); const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(event.functionName); + .getLambdaLogicalId(event.functionName); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [lambdaPermissionLogicalId]: { @@ -28,7 +28,7 @@ module.exports = { if (event.http.authorizer) { const authorizer = event.http.authorizer; const authorizerPermissionLogicalId = this.provider.naming - .getLambdaApiGatewayPermissionName(authorizer.name); + .getLambdaApiGatewayPermissionLogicalId(authorizer.name); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { [authorizerPermissionLogicalId]: { 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 bf63accbc..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 = this.provider.naming.getNormalizedApiGatewayResourceName(path); - const resourceLogicalId = this.provider.naming.getLogicalApiGatewayResourceName(path); + 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); 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 b0b2c38b3..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 = this.provider.naming.getLogicalApiGatewayName(); + 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 19d601371..9c974f3da 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js @@ -375,7 +375,7 @@ module.exports = { getLambdaArn(name) { this.serverless.service.getFunction(name); - const lambdaLogicalId = this.provider.naming.getLogicalLambdaName(name); + const lambdaLogicalId = this.provider.naming.getLambdaLogicalId(name); return { 'Fn::GetAtt': [lambdaLogicalId, 'Arn'] }; }, diff --git a/lib/plugins/aws/deploy/compile/events/s3/index.js b/lib/plugins/aws/deploy/compile/events/s3/index.js index b3c8a809a..e98e883df 100644 --- a/lib/plugins/aws/deploy/compile/events/s3/index.js +++ b/lib/plugins/aws/deploy/compile/events/s3/index.js @@ -79,7 +79,7 @@ class AwsCompileS3Events { } const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); // check if the bucket already defined // in another S3 event in the service @@ -139,7 +139,7 @@ class AwsCompileS3Events { }; const bucketLogicalId = this.provider.naming - .getLogicalBucketName(bucketName); + .getBucketLogicalId(bucketName); const bucketCFResource = { [bucketLogicalId]: bucketTemplate, }; @@ -152,7 +152,7 @@ class AwsCompileS3Events { // by adding Lambda::Permission resource for each s3EnabledFunctions.forEach(functionName => { const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); const permissionTemplate = { Type: 'AWS::Lambda::Permission', Properties: { @@ -167,7 +167,7 @@ class AwsCompileS3Events { }, }; const lambdaPermissionLogicalId = this.provider.naming - .getLambdaS3PermissionName(functionName); + .getLambdaS3PermissionLogicalId(functionName); const permissionCFResource = { [lambdaPermissionLogicalId]: permissionTemplate, }; diff --git a/lib/plugins/aws/deploy/compile/events/schedule/index.js b/lib/plugins/aws/deploy/compile/events/schedule/index.js index 79d5c19d4..a2814f922 100644 --- a/lib/plugins/aws/deploy/compile/events/schedule/index.js +++ b/lib/plugins/aws/deploy/compile/events/schedule/index.js @@ -75,12 +75,12 @@ class AwsCompileScheduledEvents { } const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); const scheduleLogicalId = this.provider.naming - .getCloudWatchEventName(functionName, scheduleNumberInFunction); + .getScheduleLogicalId(functionName, scheduleNumberInFunction); const lambdaPermissionLogicalId = this.provider.naming - .getLambdaCloudWatchEventPermissionName(functionName, scheduleNumberInFunction); - const scheduleId = this.provider.naming.getCloudWatchEventId(functionName); + .getLambdaSchedulePermissionLogicalId(functionName, scheduleNumberInFunction); + const scheduleId = this.provider.naming.getScheduleId(functionName); const scheduleTemplate = ` { diff --git a/lib/plugins/aws/deploy/compile/events/sns/index.js b/lib/plugins/aws/deploy/compile/events/sns/index.js index 194c0730c..83995d4c0 100644 --- a/lib/plugins/aws/deploy/compile/events/sns/index.js +++ b/lib/plugins/aws/deploy/compile/events/sns/index.js @@ -51,11 +51,11 @@ class AwsCompileSNSEvents { } const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); const topicLogicalId = this.provider.naming - .getLogicalSnsTopicName(topicName); + .getTopicLogicalId(topicName); const lambdaPermissionLogicalId = this.provider.naming - .getLambdaSnsTopicPermissionName(functionName, topicName); + .getLambdaSnsPermissionLogicalId(functionName, topicName); const snsTemplate = ` { diff --git a/lib/plugins/aws/deploy/compile/events/stream/index.js b/lib/plugins/aws/deploy/compile/events/stream/index.js index feaa09ab4..0b878fdd2 100644 --- a/lib/plugins/aws/deploy/compile/events/stream/index.js +++ b/lib/plugins/aws/deploy/compile/events/stream/index.js @@ -61,7 +61,7 @@ class AwsCompileStreamEvents { const streamName = EventSourceArn.split('/')[1]; const lambdaLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); const streamLogicalId = this.provider.naming .getStreamLogicalId(functionName, streamType, streamName); diff --git a/lib/plugins/aws/deploy/compile/functions/index.js b/lib/plugins/aws/deploy/compile/functions/index.js index a7953ad56..7a2c28dd7 100644 --- a/lib/plugins/aws/deploy/compile/functions/index.js +++ b/lib/plugins/aws/deploy/compile/functions/index.js @@ -104,9 +104,9 @@ class AwsCompileFunctions { } const functionLogicalId = this.provider.naming - .getLogicalLambdaName(functionName); + .getLambdaLogicalId(functionName); const functionOutputLogicalId = this.provider.naming - .getLogicalLambdaArnName(functionName); + .getLambdaOutputLogicalId(functionName); const newFunctionObject = { [functionLogicalId]: newFunction, }; diff --git a/lib/plugins/aws/deploy/lib/mergeIamTemplates.js b/lib/plugins/aws/deploy/lib/mergeIamTemplates.js index f22dee26c..3df6998b5 100644 --- a/lib/plugins/aws/deploy/lib/mergeIamTemplates.js +++ b/lib/plugins/aws/deploy/lib/mergeIamTemplates.js @@ -80,7 +80,7 @@ module.exports = { this.serverless.service.getAllFunctions().forEach((functionName) => { const functionObject = this.serverless.service.getFunction(functionName); const logGroupLogicalId = this.provider.naming - .getLogicalLogGroupName(functionName); + .getLogGroupLogicalId(functionName); const logGroupTemplate = ` { "${logGroupLogicalId}": { diff --git a/lib/plugins/aws/info/index.js b/lib/plugins/aws/info/index.js index 83b85681b..b3fb39a1b 100644 --- a/lib/plugins/aws/info/index.js +++ b/lib/plugins/aws/info/index.js @@ -55,7 +55,7 @@ class AwsInfo { outputs = result.Stacks[0].Outputs; const lambdaArnOutputRegex = this.provider.naming - .getLogicalLambdaArnNameRegex(); + .getLambdaOutputLogicalIdRegex(); const serviceEndpointOutputRegex = this.provider.naming .getServiceEndpointRegex(); diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js index c04663241..beb7fcda2 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -3,16 +3,15 @@ const _ = require('lodash'); module.exports = { - /* - * General Name Normalization - */ + + // General normalizeName(name) { return `${_.upperFirst(name)}`; }, normalizeNameToAlphaNumericOnly(name) { return this.normalizeName(name.replace(/[^0-9A-Za-z]/g, '')); }, - normalizePathtoCapitalAlphaNumbericOnlyWithReplacement(path) { + normalizePathPart(path) { return this.normalizeNameToAlphaNumericOnly( path.replace(/-/g, 'Dash') .replace(/\{(.*)\}/g, '$1Var')); @@ -22,21 +21,17 @@ module.exports = { return /^ServiceEndpoint/; }, - /* - * Stack Naming - */ + // Stack getStackName() { return `${this.sdk.serverless.service.service}-${this.sdk.getStage()}`; }, - getLogicalLogGroupName(functionName) { - return `${this.getNormalizedLambdaName(functionName)}LogGroup`; + getLogGroupLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LogGroup`; }, - /* - * Lambda Function Naming - */ - getNormalizedLambdaName(functionName) { + // Lambda + getNormalizedFunctionName(functionName) { return this.normalizeName(functionName); }, extractLambdaNameFromArn(functionArn) { @@ -49,126 +44,108 @@ module.exports = { const splitName = splitArn[splitArn.length - 1].split('-'); return splitName[splitName.length - 1]; }, - getLogicalLambdaName(functionName) { - return `${this.getNormalizedLambdaName(functionName)}LambdaFunction`; + getLambdaLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaFunction`; }, - getLogicalLambdaNameRegex() { + getLambdaLogicalIdRegex() { return /LambdaFunction$/; }, - getLogicalLambdaArnName(functionName) { - return `${this.getLogicalLambdaName(functionName)}Arn`; + getLambdaOutputLogicalId(functionName) { + return `${this.getLambdaLogicalId(functionName)}Arn`; }, - getLogicalLambdaArnNameRegex() { + getLambdaOutputLogicalIdRegex() { return /LambdaFunctionArn$/; }, - /* - * ApiGateway Authorizer Lambda & Method Naming - */ - getApiGatewayName() { - return `${this.sdk.getStage()}-${this.sdk.serverless.service.service}`; - }, - getApiGatewayDeploymentId() { + // API Gateway + generateApiGatewayDeploymentLogicalId() { return `ApiGatewayDeployment${(new Date()).getTime().toString()}`; }, - getLogicalApiGatewayName() { + getRestApiLogicalId() { return 'ApiGatewayRestApi'; }, getNormalizedAuthorizerName(functionName) { - return this.getNormalizedLambdaName(functionName); + return this.getNormalizedFunctionName(functionName); }, - getLogicalAuthorizerName(functionName) { + getAuthorizerLogicalId(functionName) { return `${this.getNormalizedAuthorizerName(functionName)}ApiGatewayAuthorizer`; }, - getLogicalAuthorizerArnName(functionName) { - return `${this.getLogicalAuthorizerName(functionName)}Arn`; - }, - getNormalizedApiGatewayResourceName(resourcePath) { + normalizePath(resourcePath) { return resourcePath.split('/').map( - this.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement.bind(this) + this.normalizePathPart.bind(this) ).join(''); }, - getLogicalApiGatewayResourceName(resourcePath) { - return `ApiGatewayResource${this.getNormalizedApiGatewayResourceName(resourcePath)}`; + getResourceLogicalId(resourcePath) { + return `ApiGatewayResource${this.normalizePath(resourcePath)}`; }, - extractResourceId(logicalApiGatewayResourceName) { - return logicalApiGatewayResourceName.match(/ApiGatewayResource(.*)/)[1]; + extractResourceId(resourceLogicalId) { + return resourceLogicalId.match(/ApiGatewayResource(.*)/)[1]; }, - getNormalizedApiGatewayMethodName(methodName) { + normalizeMethodName(methodName) { return this.normalizeName(methodName.toLowerCase()); }, - getLogicalApiGatewayMethodName(resourceId, methodName) { - return `ApiGatewayMethod${resourceId}${this.getNormalizedApiGatewayMethodName(methodName)}`; + getMethodLogicalId(resourceId, methodName) { + return `ApiGatewayMethod${resourceId}${this.normalizeMethodName(methodName)}`; }, - getLogicalApiGatewayApiKeyName(apiKeyNumber) { + getApiKeyLogicalId(apiKeyNumber) { return `ApiGatewayApiKey${apiKeyNumber}`; }, - getLogicalApiGatewayApiKeyRegex() { + getApiKeyLogicalIdRegex() { return /^ApiGatewayApiKey/; }, - /* - * S3 Bucket Naming - */ - getLogicalDeploymentBucketName() { + // S3 + getDeploymentBucketLogicalId() { return 'ServerlessDeploymentBucket'; }, - getLogicalDeploymentBucketOutputVariableName() { + getDeploymentBucketOutputLogicalId() { return 'ServerlessDeploymentBucketName'; }, - getNormalizedBucketName(bucketName) { + normalizeBucketName(bucketName) { return this.normalizeNameToAlphaNumericOnly(bucketName); }, - getLogicalBucketName(bucketName) { - return `S3Bucket${this.getNormalizedBucketName(bucketName)}`; + getBucketLogicalId(bucketName) { + return `S3Bucket${this.normalizeBucketName(bucketName)}`; }, - /* - * SNS Topic Naming - */ - getNormalizedSnsTopicName(topicName) { + // SNS + normalizeTopicName(topicName) { return this.normalizeNameToAlphaNumericOnly(topicName); }, - getLogicalSnsTopicName(topicName) { - return `SNSTopic${this.getNormalizedSnsTopicName(topicName)}`; + getTopicLogicalId(topicName) { + return `SNSTopic${this.normalizeTopicName(topicName)}`; }, - /* - * CloudWatch Event Naming - */ - getCloudWatchEventId(functionName) { + // Schedule + getScheduleId(functionName) { return `${functionName}Schedule`; }, - getCloudWatchEventName(functionName, scheduleIndex) { - return `${this.getNormalizedLambdaName(functionName)}EventsRuleSchedule${scheduleIndex}`; + getScheduleLogicalId(functionName, scheduleIndex) { + return `${this.getNormalizedFunctionName(functionName)}EventsRuleSchedule${scheduleIndex}`; }, - /* - * Stream Event Naming - */ + // Stream getStreamLogicalId(functionName, streamType, streamName) { return `${ - this.getNormalizedLambdaName(functionName) + this.getNormalizedFunctionName(functionName) }EventSourceMapping${ this.normalizeName(streamType) }${this.normalizeNameToAlphaNumericOnly(streamName)}`; }, - /* - * Lambda to S3 Bucket/SNS Topic/CloudWatch Event/ApiGateway Permissions Naming - */ - getLambdaS3PermissionName(functionName) { - return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionS3`; + // Permissions + getLambdaS3PermissionLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionS3`; }, - getLambdaSnsTopicPermissionName(functionName, topicName) { - return `${this.getNormalizedLambdaName(functionName)}LambdaPermission${ - this.getNormalizedSnsTopicName(topicName)}`; + getLambdaSnsPermissionLogicalId(functionName, topicName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermission${ + this.normalizeTopicName(topicName)}`; }, - getLambdaCloudWatchEventPermissionName(functionName, scheduleIndex) { - return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionEventsRuleSchedule${ + getLambdaSchedulePermissionLogicalId(functionName, scheduleIndex) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionEventsRuleSchedule${ scheduleIndex}`; }, - getLambdaApiGatewayPermissionName(functionName) { - return `${this.getNormalizedLambdaName(functionName)}LambdaPermissionApiGateway`; + getLambdaApiGatewayPermissionLogicalId(functionName) { + return `${this.getNormalizedFunctionName(functionName)}LambdaPermissionApiGateway`; }, }; diff --git a/lib/plugins/aws/provider/awsProvider.js b/lib/plugins/aws/provider/awsProvider.js index f0985eb39..af0dc9199 100644 --- a/lib/plugins/aws/provider/awsProvider.js +++ b/lib/plugins/aws/provider/awsProvider.js @@ -5,7 +5,7 @@ const BbPromise = require('bluebird'); const HttpsProxyAgent = require('https-proxy-agent'); const url = require('url'); -const Naming = require('../lib/naming.js'); +const naming = require('../lib/naming.js'); const constants = { providerName: 'aws', @@ -89,7 +89,7 @@ class AwsProvider { this.sdk = AWS; this.serverless.setProvider(constants.providerName, this); - Object.assign(this.naming, Naming); + Object.assign(this.naming, naming); // Use HTTPS Proxy (Optional) const proxy = process.env.proxy @@ -145,7 +145,7 @@ class AwsProvider { const errorMessage = [ 'AWS provider credentials not found.', ' You can find more info on how to set up provider', - ' credentials in our docs here: https://git.io/viZAC', + ' credentials in our docs here: https://git.io/vXsdd', ].join(''); err.message = errorMessage; } @@ -164,7 +164,7 @@ class AwsProvider { * @returns {{region: *}} */ getCredentials() { - const ret = { region: this.getRegion() }; + const returnValue = { region: this.getRegion() }; const credentials = {}; const stageUpper = this.getStage() ? this.getStage().toUpperCase() : null; @@ -177,21 +177,21 @@ class AwsProvider { impl.addEnvironmentProfile(credentials, `AWS_${stageUpper}`); if (Object.keys(credentials).length) { - ret.credentials = credentials; + returnValue.credentials = credentials; } - return ret; + return returnValue; } getRegion() { - let ret = 'us-east-1'; + let returnValue = 'us-east-1'; if (this.options && this.options.region) { - ret = this.options.region; + returnValue = this.options.region; } else if (this.serverless.config.region) { - ret = this.serverless.config.region; + returnValue = this.serverless.config.region; } else if (this.serverless.service.provider.region) { - ret = this.serverless.service.provider.region; + returnValue = this.serverless.service.provider.region; } - return ret; + return returnValue; } getServerlessDeploymentBucketName() { @@ -202,21 +202,21 @@ class AwsProvider { 'describeStackResource', { StackName: this.naming.getStackName(), - LogicalResourceId: this.naming.getLogicalDeploymentBucketName(), + LogicalResourceId: this.naming.getDeploymentBucketLogicalId(), } ).then((result) => result.StackResourceDetail.PhysicalResourceId); } getStage() { - let ret = 'dev'; + let returnValue = 'dev'; if (this.options && this.options.stage) { - ret = this.options.stage; + returnValue = this.options.stage; } else if (this.serverless.config.stage) { - ret = this.serverless.config.stage; + returnValue = this.serverless.config.stage; } else if (this.serverless.service.provider.stage) { - ret = this.serverless.service.provider.stage; + returnValue = this.serverless.service.provider.stage; } - return ret; + return returnValue; } } diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js index b9e2fda8e..d23974672 100644 --- a/lib/plugins/aws/provider/awsProvider.test.js +++ b/lib/plugins/aws/provider/awsProvider.test.js @@ -183,7 +183,7 @@ describe('AwsProvider', () => { awsProvider.request('S3', 'error', {}) .then(() => done('Should not succeed')) .catch((err) => { - expect(err.message).to.contain('https://git.io/viZAC'); + expect(err.message).to.contain('https://git.io/vXsdd'); done(); }) .catch(done); @@ -353,7 +353,7 @@ describe('AwsProvider', () => { }); }); - describe('#getRegion', () => { + describe('#getRegion()', () => { let newAwsProvider; it('should prefer options over config or provider', () => { @@ -369,6 +369,7 @@ describe('AwsProvider', () => { expect(newAwsProvider.getRegion()).to.equal(newOptions.region); }); + it('should prefer config over provider in lieu of options', () => { const newOptions = {}; const config = { @@ -380,6 +381,7 @@ describe('AwsProvider', () => { expect(newAwsProvider.getRegion()).to.equal(config.region); }); + it('should use provider in lieu of options and config', () => { const newOptions = {}; const config = {}; @@ -389,6 +391,7 @@ describe('AwsProvider', () => { 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 = {}; @@ -399,7 +402,7 @@ describe('AwsProvider', () => { }); }); - describe('#getServerlessDeploymentBucketName', () => { + describe('#getServerlessDeploymentBucketName()', () => { it('should return the name of the serverless deployment bucket', () => { const describeStackResourcesStub = sinon .stub(awsProvider, 'request') @@ -444,7 +447,7 @@ describe('AwsProvider', () => { }); }); - describe('#getStage', () => { + describe('#getStage()', () => { it('should prefer options over config or provider', () => { const newOptions = { stage: 'optionsStage', diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js index b0a6ddf24..741a71f0b 100644 --- a/lib/plugins/aws/tests/naming.js +++ b/lib/plugins/aws/tests/naming.js @@ -41,27 +41,27 @@ describe('#naming()', () => { }); describe('#normalizeNameToCapitalAlphaNumbericOnly()', () => { it('converts `-` to `Dash`', () => { - expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + expect(sdk.naming.normalizePathPart( 'a-path' )).to.equal('ADashpath'); }); it('converts variable declarations (`${var}`) to `VariableVar`', () => { - expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + expect(sdk.naming.normalizePathPart( '${variable}' )).to.equal('VariableVar'); }); it('converts variable declarations prefixes to `VariableVarPath`', () => { - expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + expect(sdk.naming.normalizePathPart( '${variable}Path' )).to.equal('VariableVarPath'); }); it('converts variable declarations suffixes to `PathvariableVar`', () => { - expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + expect(sdk.naming.normalizePathPart( 'path${variable}' )).to.equal('PathvariableVar'); }); it('converts variable declarations in center to `PathvariableVarDir`', () => { - expect(sdk.naming.normalizePathtoCapitalAlphaNumbericOnlyWithReplacement( + expect(sdk.naming.normalizePathPart( 'path${variable}Dir' )).to.equal('PathvariableVarDir'); }); @@ -86,9 +86,9 @@ describe('#naming()', () => { expect(sdk.naming.getStackName()).to.equal(`${serverless.service.service}-${options.stage}`); }); }); - describe('#getNormalizedLambdaName()', () => { + describe('#getNormalizedFunctionName()', () => { it('should normalize the given functionName', () => { - expect(sdk.naming.getNormalizedLambdaName('functionName')) + expect(sdk.naming.getNormalizedFunctionName('functionName')) .to.equal('FunctionName'); }); }); @@ -104,65 +104,59 @@ describe('#naming()', () => { expect(sdk.naming.extractLambdaNameFromArn(arn)).to.equal('my-dev-lambda'); }); }); - describe('#getLogicalLambdaName()', () => { + describe('#getLambdaLogicalId()', () => { it('should normalize the function name and add the logical suffix', () => { - expect(sdk.naming.getLogicalLambdaName('functionName')) + expect(sdk.naming.getLambdaLogicalId('functionName')) .to.equal('FunctionNameLambdaFunction'); }); }); - describe('#getLogicalLambdaNameRegex()', () => { + describe('#getLambdaLogicalIdRegex()', () => { it('should match the suffix', () => { - expect(sdk.naming.getLogicalLambdaNameRegex() + expect(sdk.naming.getLambdaLogicalIdRegex() .test('LambdaFunction')).to.equal(true); }); it('should not match a name without the suffix', () => { - expect(sdk.naming.getLogicalLambdaNameRegex() + expect(sdk.naming.getLambdaLogicalIdRegex() .test('LambdaFunctionNotTheSuffix')).to.equal(false); }); it('should match a name with the suffix', () => { - expect(sdk.naming.getLogicalLambdaNameRegex() + expect(sdk.naming.getLambdaLogicalIdRegex() .test('AFunctionNameLambdaFunction')).to.equal(true); }); }); - describe('#getLogicalLambdaArnName()', () => { + describe('#getLambdaOutputLogicalId()', () => { it('should normalize the function name and add the logical arn suffix', () => { expect( - sdk.naming.getLogicalLambdaArnName('functionName') + sdk.naming.getLambdaOutputLogicalId('functionName') ).to.equal('FunctionNameLambdaFunctionArn'); }); }); - describe('#getLogicalLambdaArnNameRegex()', () => { + describe('#getLambdaOutputLogicalIdRegex()', () => { it('should match the suffix', () => { - expect(sdk.naming.getLogicalLambdaArnNameRegex() + expect(sdk.naming.getLambdaOutputLogicalIdRegex() .test('aLambdaFunctionArn')).to.equal(true); }); it('should not match a name without the suffix', () => { - expect(sdk.naming.getLogicalLambdaArnNameRegex() + expect(sdk.naming.getLambdaOutputLogicalIdRegex() .test('LambdaFunctionArnNotTheSuffix')) .to.equal(false); }); it('should match a name with the suffix', () => { - expect(sdk.naming.getLogicalLambdaArnNameRegex() + expect(sdk.naming.getLambdaOutputLogicalIdRegex() .test('AFunctionArnNameLambdaFunctionArn')) .to.equal(true); }); }); - describe('#getApiGatewayName()', () => { - it('should return the composition of stage and service name', () => { - serverless.service.service = 'myService'; - expect(sdk.naming.getApiGatewayName()) - .to.equal(`dev-${serverless.service.service}`); - }); - }); - describe('#getApiGatewayDeploymentId()', () => { + describe('#generateApiGatewayDeploymentLogicalId()', () => { it('should return ApiGatewayDeployment with a date based suffix', () => { - expect(sdk.naming.getApiGatewayDeploymentId().match(/ApiGatewayDeployment(.*)/).length) + expect(sdk.naming.generateApiGatewayDeploymentLogicalId() + .match(/ApiGatewayDeployment(.*)/).length) .to.be.greaterThan(1); }); }); - describe('#getLogicalApiGatewayName()', () => { + describe('#getRestApiLogicalId()', () => { it('should return ApiGatewayRestApi', () => { - expect(sdk.naming.getLogicalApiGatewayName()).to.equal('ApiGatewayRestApi'); + expect(sdk.naming.getRestApiLogicalId()).to.equal('ApiGatewayRestApi'); }); }); describe('#getNormalizedAuthorizerName()', () => { @@ -171,9 +165,9 @@ describe('#naming()', () => { .to.equal('AuthorizerName'); }); }); - describe('#getLogicalAuthorizerName()', () => { + describe('#getAuthorizerLogicalId()', () => { it('should normalize the authorizer name and add the standard suffix', () => { - expect(sdk.naming.getLogicalAuthorizerName('authorizerName')) + expect(sdk.naming.getAuthorizerLogicalId('authorizerName')) .to.equal('AuthorizerNameApiGatewayAuthorizer'); }); }); @@ -183,23 +177,17 @@ describe('#naming()', () => { expect(sdk.naming.extractAuthorizerNameFromArn(arn)).to.equal('lambda'); }); }); - describe('#getLogicalAuthorizerArnName()', () => { - it('should normalize the authorizer name and add the standard arn suffix', () => { - expect(sdk.naming.getLogicalAuthorizerArnName('authorizerName')) - .to.equal('AuthorizerNameApiGatewayAuthorizerArn'); - }); - }); - describe('#getNormalizedApiGatewayResourceName()', () => { + describe('#normalizePath()', () => { it('should normalize each part of the resource path and remove non-alpha-numeric characters', () => { - expect(sdk.naming.getNormalizedApiGatewayResourceName( + expect(sdk.naming.normalizePath( 'my/path/to/a-${var}-resource' )).to.equal('MyPathToADashvarVarDashresource'); }); }); - describe('#getLogicalApiGatewayResourceName()', () => { + describe('#getResourceLogicalId()', () => { it('should normalize the resource and add the standard suffix', () => { - expect(sdk.naming.getLogicalApiGatewayResourceName( + expect(sdk.naming.getResourceLogicalId( 'my/path/to/a-${var}-resource' )).to.equal('ApiGatewayResourceMyPathToADashvarVarDashresource'); }); @@ -211,98 +199,98 @@ describe('#naming()', () => { )).to.equal('MyPathToADashvarVarDashResource'); }); }); - describe('#getNormalizedApiGatewayMethodName()', () => { + describe('#normalizeMethodName()', () => { it('should capitalize the first letter and lowercase any other characters', () => { - expect(sdk.naming.getNormalizedApiGatewayMethodName('gET')).to.equal('Get'); + expect(sdk.naming.normalizeMethodName('gET')).to.equal('Get'); }); }); - describe('#getLogicalApiGatewayMethodName()', () => { + describe('#getMethodLogicalId()', () => { it('', () => { - expect(sdk.naming.getLogicalApiGatewayMethodName( + expect(sdk.naming.getMethodLogicalId( 'ResourceId', 'get' )).to.equal('ApiGatewayMethodResourceIdGet'); }); }); - describe('#getLogicalApiGatewayApiKeyRegex()', () => { + describe('#getApiKeyLogicalIdRegex()', () => { it('should match the prefix', () => { - expect(sdk.naming.getLogicalApiGatewayApiKeyRegex() + expect(sdk.naming.getApiKeyLogicalIdRegex() .test('ApiGatewayApiKey')).to.equal(true); }); it('should not match a name without the prefix', () => { - expect(sdk.naming.getLogicalApiGatewayApiKeyRegex() + expect(sdk.naming.getApiKeyLogicalIdRegex() .test('NotThePrefixApiGatewayApiKey')).to.equal(false); }); it('should match a name with the prefix', () => { - expect(sdk.naming.getLogicalApiGatewayApiKeyRegex() + expect(sdk.naming.getApiKeyLogicalIdRegex() .test('ApiGatewayApiKeySuffix')).to.equal(true); }); }); - describe('#getLogicalDeploymentBucketName()', () => { + describe('#getDeploymentBucketLogicalId()', () => { it('should return "ServerlessDeploymentBucket"', () => { - expect(sdk.naming.getLogicalDeploymentBucketName()).to.equal('ServerlessDeploymentBucket'); + expect(sdk.naming.getDeploymentBucketLogicalId()).to.equal('ServerlessDeploymentBucket'); }); }); - describe('#getLogicalDeploymentBucketOutputVariableName()', () => { + describe('#getDeploymentBucketOutputLogicalId()', () => { it('should return "ServerlessDeploymentBucketName"', () => { - expect(sdk.naming.getLogicalDeploymentBucketOutputVariableName()) + expect(sdk.naming.getDeploymentBucketOutputLogicalId()) .to.equal('ServerlessDeploymentBucketName'); }); }); - describe('#getNormalizedBucketName()', () => { + describe('#normalizeBucketName()', () => { it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { - expect(sdk.naming.getNormalizedBucketName('b!u@c#k$e%t^N&a*m(e')).to.equal('BucketName'); + expect(sdk.naming.normalizeBucketName('b!u@c#k$e%t^N&a*m(e')).to.equal('BucketName'); }); }); - describe('#getLogicalBucketName()', () => { + describe('#getBucketLogicalId()', () => { it('should normalize the bucket name and add the standard prefix', () => { - expect(sdk.naming.getLogicalBucketName('b!u@c#k$e%t^N&a*m(e')).to.equal('S3BucketBucketName'); + expect(sdk.naming.getBucketLogicalId('b!u@c#k$e%t^N&a*m(e')).to.equal('S3BucketBucketName'); }); }); - describe('#getNormalizedSnsTopicName()', () => { + describe('#normalizeTopicName()', () => { it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { - expect(sdk.naming.getNormalizedSnsTopicName('t!o@p#i$c%N^a&m*e')).to.equal('TopicName'); + expect(sdk.naming.normalizeTopicName('t!o@p#i$c%N^a&m*e')).to.equal('TopicName'); }); }); - describe('#getLogicalSnsTopicName()', () => { + describe('#getTopicLogicalId()', () => { it('should remove all non-alpha-numeric characters and capitalize the first letter', () => { - expect(sdk.naming.getLogicalSnsTopicName('t!o@p#i$c%N^a&m*e')).to.equal('SNSTopicTopicName'); + expect(sdk.naming.getTopicLogicalId('t!o@p#i$c%N^a&m*e')).to.equal('SNSTopicTopicName'); }); }); - describe('#getCloudWatchEventId()', () => { + describe('#getScheduleId()', () => { it('should add the standard suffix', () => { - expect(sdk.naming.getCloudWatchEventId('functionName')).to.equal('functionNameSchedule'); + expect(sdk.naming.getScheduleId('functionName')).to.equal('functionNameSchedule'); }); }); - describe('#getCloudWatchEventName()', () => { + describe('#getScheduleLogicalId()', () => { it('should normalize the function name and add the standard suffix including the index', () => { - expect(sdk.naming.getCloudWatchEventName('functionName', 0)) + expect(sdk.naming.getScheduleLogicalId('functionName', 0)) .to.equal('FunctionNameEventsRuleSchedule0'); }); }); - describe('#getLambdaS3PermissionName()', () => { + describe('#getLambdaS3PermissionLogicalId()', () => { it('should normalize the function name and add the standard suffix', () => { - expect(sdk.naming.getLambdaS3PermissionName('functionName')) + expect(sdk.naming.getLambdaS3PermissionLogicalId('functionName')) .to.equal('FunctionNameLambdaPermissionS3'); }); }); - describe('#getLambdaSnsTopicPermissionName()', () => { + 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.getLambdaSnsTopicPermissionName('functionName', 'topicName')) + expect(sdk.naming.getLambdaSnsPermissionLogicalId('functionName', 'topicName')) .to.equal('FunctionNameLambdaPermissionTopicName'); }); }); - describe('#getLambdaCloudWatchEventPermissionName()', () => { + describe('#getLambdaSchedulePermissionLogicalId()', () => { it('should normalize the function name and add the standard suffix including event index', () => { - expect(sdk.naming.getLambdaCloudWatchEventPermissionName('functionName', 0)) + expect(sdk.naming.getLambdaSchedulePermissionLogicalId('functionName', 0)) .to.equal('FunctionNameLambdaPermissionEventsRuleSchedule0'); }); }); - describe('#getLambdaApiGatewayPermissionName()', () => { + describe('#getLambdaApiGatewayPermissionLogicalId()', () => { it('should normalize the function name and append the standard suffix', () => { - expect(sdk.naming.getLambdaApiGatewayPermissionName('functionName')) + expect(sdk.naming.getLambdaApiGatewayPermissionLogicalId('functionName')) .to.equal('FunctionNameLambdaPermissionApiGateway'); }); }); From 52f8f81dfdd227429f7358abc50e245ef6690d88 Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Fri, 11 Nov 2016 15:18:07 +0700 Subject: [PATCH 5/6] fix function name with underscore bug --- lib/plugins/aws/lib/naming.js | 4 +++- lib/plugins/aws/tests/naming.js | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/plugins/aws/lib/naming.js b/lib/plugins/aws/lib/naming.js index beb7fcda2..a77d14a8a 100644 --- a/lib/plugins/aws/lib/naming.js +++ b/lib/plugins/aws/lib/naming.js @@ -32,7 +32,9 @@ module.exports = { // Lambda getNormalizedFunctionName(functionName) { - return this.normalizeName(functionName); + return this.normalizeName(functionName + .replace(/-/g, 'Dash') + .replace(/_/g, 'Underscore')); }, extractLambdaNameFromArn(functionArn) { return functionArn.substring(functionArn.lastIndexOf(':') + 1); diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js index 741a71f0b..51049c5b7 100644 --- a/lib/plugins/aws/tests/naming.js +++ b/lib/plugins/aws/tests/naming.js @@ -91,6 +91,14 @@ describe('#naming()', () => { 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', () => { From 489dd0f4b5bcd81a3f60550c1ac8924dacd5066c Mon Sep 17 00:00:00 2001 From: "Eslam A. Hefnawy" Date: Fri, 11 Nov 2016 15:53:08 +0700 Subject: [PATCH 6/6] spacing up tests --- lib/plugins/aws/provider/awsProvider.test.js | 3 +++ lib/plugins/aws/tests/naming.js | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/lib/plugins/aws/provider/awsProvider.test.js b/lib/plugins/aws/provider/awsProvider.test.js index d23974672..f9bdcb0cd 100644 --- a/lib/plugins/aws/provider/awsProvider.test.js +++ b/lib/plugins/aws/provider/awsProvider.test.js @@ -461,6 +461,7 @@ describe('AwsProvider', () => { expect(awsProvider.getStage()).to.equal(newOptions.stage); }); + it('should prefer config over provider in lieu of options', () => { const newOptions = {}; const config = { @@ -472,6 +473,7 @@ describe('AwsProvider', () => { expect(awsProvider.getStage()).to.equal(config.stage); }); + it('should use provider in lieu of options and config', () => { const newOptions = {}; const config = {}; @@ -481,6 +483,7 @@ describe('AwsProvider', () => { 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 = {}; diff --git a/lib/plugins/aws/tests/naming.js b/lib/plugins/aws/tests/naming.js index 51049c5b7..7f4134d0a 100644 --- a/lib/plugins/aws/tests/naming.js +++ b/lib/plugins/aws/tests/naming.js @@ -23,9 +23,11 @@ describe('#naming()', () => { 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'); }); @@ -35,6 +37,7 @@ describe('#naming()', () => { expect(sdk.naming .normalizeNameToAlphaNumericOnly('`!@#$%^&*()-={}|[]\\:";\'<>?,./')).to.equal(''); }); + it('should apply normalizeName to the remaining characters', () => { expect(sdk.naming.normalizeNameToAlphaNumericOnly('a-b-c')).to.equal('Abc'); }); @@ -45,21 +48,25 @@ describe('#naming()', () => { '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' @@ -71,10 +78,12 @@ describe('#naming()', () => { 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); @@ -91,10 +100,12 @@ describe('#naming()', () => { 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'); @@ -123,10 +134,12 @@ describe('#naming()', () => { 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); @@ -144,11 +157,13 @@ describe('#naming()', () => { 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')) @@ -224,10 +239,12 @@ describe('#naming()', () => { 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);