aws-core-utils
Advanced tools
Comparing version 0.9.0 to 1.0.0
'use strict'; | ||
/** | ||
* Utilities for working with AWS Lambda - enables extraction of function names, versions and, most importantly, aliases | ||
* from AWS contexts and their invoked function ARNs. | ||
* @module aws-core-utils/lambdas.js | ||
* @author Byron du Preez | ||
*/ | ||
module.exports = { | ||
@@ -4,0 +11,0 @@ getFunctionName: getFunctionName, |
{ | ||
"name": "aws-core-utils", | ||
"version": "0.9.0", | ||
"version": "1.0.0", | ||
"description": "Core utilities for working with Amazon Web Services (AWS), including arns, regions, stages, lambdas, etc.", | ||
@@ -14,5 +14,5 @@ "author": "Byron du Preez", | ||
"dependencies": { | ||
"core-functions": "^1.1.0" | ||
"core-functions": "^1.1.1" | ||
}, | ||
"repository": "https://github.com/byron-dupreez/task-utils" | ||
"repository": "https://github.com/byron-dupreez/aws-core-utils" | ||
} |
@@ -1,2 +0,2 @@ | ||
# aws-core-utils v0.9.0 | ||
# aws-core-utils v1.0.0 | ||
@@ -15,3 +15,6 @@ Core utilities for working with Amazon Web Services (AWS), including arns, regions, stages, etc. | ||
- lambdas.js | ||
- Utilities for working with AWS Lambdas. | ||
- Utilities for working with AWS Lambda, which enable extraction of function names, versions and, most importantly, | ||
aliases from AWS contexts and their invoked function ARNs. | ||
- aws-errors.js | ||
- Utilities for working with AWS errors. | ||
@@ -38,2 +41,8 @@ This module is exported as a [Node.js](https://nodejs.org/) module. | ||
const stages = require('aws-core-utils/stages'); | ||
// To use the L from AWS events | ||
const lambdas = require('aws-core-utils/lambdas'); | ||
// To use the AWS errors utilities | ||
const awsErros = require('aws-core-utils/aws-errors'); | ||
``` | ||
@@ -59,1 +68,12 @@ | ||
See the [package source](https://github.com/byron-dupreez/aws-core-utils) for more details. | ||
## Changes | ||
### 0.9.0 | ||
- Initial commit | ||
### 1.0.0 | ||
- Completed changes needed to release 1.0.0 | ||
- Added unit tests for stages.js | ||
- Simplified regions.js API down to relevant methods | ||
- Fixed defects attempting to source awsRegion and eventSourceARN from event instead of Kinesis records within event. | ||
- Patched repository in package.json |
177
regions.js
@@ -9,13 +9,13 @@ 'use strict'; | ||
module.exports = { | ||
getAwsRegion: getAwsRegion, | ||
getAwsDefaultRegion: getAwsDefaultRegion, | ||
getAwsRegionOrDefault: getAwsRegionOrDefault, | ||
getRegion: getRegion, | ||
getDefaultRegion: getDefaultRegion, | ||
//getRegionOrDefault: getRegionOrDefault, | ||
getInvokedFunctionArnRegion: getInvokedFunctionArnRegion, | ||
getEventAwsRegion: getEventAwsRegion, | ||
getEventSourceArnRegion: getEventSourceArnRegion, | ||
resolveRegion: resolveRegion, | ||
getEventAwsRegions: getEventAwsRegions, | ||
getEventSourceArnRegions: getEventSourceArnRegions, | ||
//resolveRegion: resolveRegion, | ||
ONLY_FOR_TESTING: { | ||
getAwsRegionRaw: getAwsRegionRaw, | ||
getAwsDefaultRegionRaw: getAwsDefaultRegionRaw, | ||
setAwsRegionIfNotSet: setAwsRegionIfNotSet | ||
getRegionRaw: getRegionRaw, | ||
getDefaultRegionRaw: getDefaultRegionRaw, | ||
setRegionIfNotSet: setRegionIfNotSet | ||
} | ||
@@ -47,3 +47,3 @@ }; | ||
*/ | ||
function getAwsRegion() { | ||
function getRegion() { | ||
return trimOrEmpty(process.env.AWS_REGION); | ||
@@ -56,3 +56,3 @@ } | ||
*/ | ||
function getAwsDefaultRegion() { | ||
function getDefaultRegion() { | ||
return trimOrEmpty(process.env.AWS_DEFAULT_REGION); | ||
@@ -62,13 +62,2 @@ } | ||
/** | ||
* Gets the region from the AWS_REGION environment variable if it exists; otherwise from the AWS_DEFAULT_REGION | ||
* environment variable. | ||
* @returns {string} the AWS region (if it exists); otherwise the AWS default region (if that exists; otherwise an empty | ||
* string. | ||
*/ | ||
function getAwsRegionOrDefault() { | ||
const awsRegion = getAwsRegion(); | ||
return isNotBlank(awsRegion) ? awsRegion : getAwsDefaultRegion(); | ||
} | ||
/** | ||
* Sets the process.env.AWS_REGION environment variable to the given region, but ONLY if is is not already set! | ||
@@ -78,3 +67,3 @@ * NB: This only sets the region temporarily on the current process and should probably only be used for testing purposes. | ||
*/ | ||
function setAwsRegionIfNotSet(awsRegion) { | ||
function setRegionIfNotSet(awsRegion) { | ||
// Replaces an undefined or null awsRegion with '', otherwise it will become 'undefined' or 'null' on process.env | ||
@@ -84,3 +73,3 @@ const newRegion = trimOrEmpty(awsRegion); | ||
// Check if AWS region is already set or not | ||
const region = getAwsRegion(); | ||
const region = getRegion(); | ||
if (isBlank(region)) { | ||
@@ -111,78 +100,80 @@ // Attempt to set the AWS_REGION | ||
/** | ||
* Extracts the region from the given event's awsRegion property (if any); otherwise returns an empty string. | ||
* Extracts the regions from the given event's record's awsRegion properties (if any); otherwise returns an empty array. | ||
* | ||
* Note that for this to work rhe given event should have an awsRegion property, which is the case for AWS Kinesis and | ||
* DynamoDB stream events and for S3 Put and Delete events (and possibly for other AWS events as well). | ||
* Note that for this to work rhe given event should have records with an awsRegion property, which is the case for AWS | ||
* Kinesis and DynamoDB stream events and for S3 Put and Delete events (and possibly for other AWS events as well). | ||
* | ||
* @param event the event from which to extract the awsRegion | ||
* @returns {string} the AWS region (if extracted) or an empty string | ||
* @param event the event from which to extract its records' AWS regions | ||
* @returns {string[]} the event's records' AWS regions (if any) or an empty array | ||
*/ | ||
function getEventAwsRegion(event) { | ||
return event && event.awsRegion ? trimOrEmpty(event.awsRegion) : ''; | ||
function getEventAwsRegions(event) { | ||
return event && event.Records ? | ||
event.Records.map(record => record.awsRegion ? trimOrEmpty(event.awsRegion) : '') : []; | ||
} | ||
/** | ||
* Extracts the region from the given event's eventSourceARN property (if any); otherwise returns an empty string. | ||
* Extracts the regions from the given event's record's eventSourceARN properties (if any); otherwise returns an empty | ||
* array. | ||
* | ||
* Note that for this to work the given event should have an eventSourceARN property, which is the case for AWS Kinesis | ||
* and DynamoDB stream events. | ||
* Note that for this to work the given event should have records with an eventSourceARN property, which is the case for | ||
* AWS Kinesis and DynamoDB stream events. | ||
* | ||
* @param event the event from which to access the eventSourceARN property | ||
* @returns {string} the AWS region (if extracted) or an empty string | ||
* @param event the event from which to extract its records' event source ARN regions | ||
* @returns {string[]} the event's records' event source ARN regions (if any) or an empty array | ||
*/ | ||
function getEventSourceArnRegion(event) { | ||
return event && isNotBlank(event.eventSourceARN) ? getArnRegion(event.eventSourceARN) : ''; | ||
function getEventSourceArnRegions(event) { | ||
return event && event.Records ? | ||
event.Records.map(record => record.eventSourceARN ? getArnRegion(record.eventSourceARN) : '') : []; | ||
} | ||
/** | ||
* Extracts a region from the following resources in the following order: | ||
* 1. Using {@linkcode getAwsRegion} | ||
* 2. awsContext.invokedFunctionArn | ||
* 3. event.awsRegion | ||
* 4. awsContext.eventSourceARN | ||
* | ||
* The detailed process followed is as follows: | ||
* 1. Attempts to get the region using {@linkcode getAwsRegion} (i.e. from AWS-specific environment variables). | ||
* | ||
* 2. Extracts and returns the region from the given awsContext's invokedFunctionArn, if it contains an | ||
* invokedFunctionArn in the form of "arn:aws:lambda:<region>:<accountId>:function:<functionName>[:functionAlias]". | ||
* The ARN might be either a function ARN or an alias ARN (prefer the latter!). An unqualified ARN executes the | ||
* $LATEST version (and cannot be used to extract an alias) and aliases execute the function version to which it they | ||
* are pointing. | ||
* | ||
* 3. Returns the awsRegion from the given event's awsRegion, if it contains an awsRegion property. | ||
* | ||
* 4. Extracts and returns the region from the given event's eventSourceARN, if it contains an eventSourceARN | ||
* in the form of "arn:aws:kinesis:<region>:<accountId>:stream/<streamName>". | ||
* | ||
* 5. Gives up and returns an empty string. | ||
* | ||
* @param {Object} event the Kinesis event to be checked | ||
* @param {Object} awsContext the AWS context | ||
* @return {string} the region if found; otherwise an empty string | ||
*/ | ||
function resolveRegion(event, awsContext) { | ||
// Attempt 1 | ||
let region = getAwsRegion(); | ||
if (isNotBlank(region)) { | ||
return region; | ||
} | ||
// Attempt 2 | ||
region = getInvokedFunctionArnRegion(awsContext); | ||
if (isNotBlank(region)) { | ||
return region; | ||
} | ||
// Attempt 3 | ||
region = getEventAwsRegion(event); | ||
if (isNotBlank(region)) { | ||
return region; | ||
} | ||
// Attempt 4 | ||
region = getEventSourceArnRegion(event); | ||
if (isNotBlank(region)) { | ||
return region; | ||
} | ||
// Give up | ||
return ''; | ||
} | ||
// /** | ||
// * Extracts a region from the following resources in the following order: | ||
// * 1. Using {@linkcode getRegion} | ||
// * 2. The region extracted from the given AWS context's invokedFunctionArn (if any) | ||
// * 3. The first non-blank awsRegion (if any) extracted from the event's records | ||
// * 4. The first non-blank eventSourceARN region (if any) extracted from the event's records | ||
// * | ||
// * The detailed process followed is as follows: | ||
// * 1. Attempts to get the region using {@linkcode getRegion} (i.e. from AWS-specific environment variables). | ||
// * | ||
// * 2. Extracts and returns the region from the given awsContext's invokedFunctionArn, if it contains an | ||
// * invokedFunctionArn in the form of "arn:aws:lambda:<region>:<accountId>:function:<functionName>[:functionAlias]". | ||
// * | ||
// * 3. Returns the first non-blank awsRegion (if any) extracted from the event's records, if any of them contain an awsRegion property. | ||
// * | ||
// * 4. Returns the first non-blank eventSourceARN region (if any) extracted from the event's records, if any of them contain an | ||
// * | ||
// * Extracts and returns the region from the given event's eventSourceARN, if it contains an eventSourceARN | ||
// * in the form of "arn:aws:kinesis:<region>:<accountId>:stream/<streamName>". | ||
// * | ||
// * 5. Gives up and returns an empty string. | ||
// * | ||
// * @param {Object} event the Kinesis event to be checked | ||
// * @param {Object} awsContext the AWS context | ||
// * @return {string} the region if found; otherwise an empty string | ||
// */ | ||
// function resolveRegion(event, awsContext) { | ||
// // Attempt 1 | ||
// let region = getRegion(); | ||
// if (isNotBlank(region)) { | ||
// return region; | ||
// } | ||
// // Attempt 2 | ||
// region = getInvokedFunctionArnRegion(awsContext); | ||
// if (isNotBlank(region)) { | ||
// return region; | ||
// } | ||
// // Attempt 3 | ||
// region = getEventAwsRegions(event).find(r => isNotBlank(r)); | ||
// if (isNotBlank(region)) { | ||
// return region; | ||
// } | ||
// // Attempt 4 | ||
// region = getEventSourceArnRegions(event).find(r => isNotBlank(r)); | ||
// if (isNotBlank(region)) { | ||
// return region; | ||
// } | ||
// // Give up | ||
// return ''; | ||
// } | ||
@@ -194,7 +185,7 @@ | ||
* | ||
* Note: Added for testing, use {@linkcode getAwsRegion} instead, which also converts undefined and null to empty strings | ||
* Note: Added for testing, use {@linkcode getRegion} instead, which also converts undefined and null to empty strings | ||
* | ||
* @returns {string|undefined|null} the AWS region (if it exists); otherwise an empty string, undefined or null. | ||
*/ | ||
function getAwsRegionRaw() { | ||
function getRegionRaw() { | ||
return trim(process.env.AWS_REGION); | ||
@@ -207,3 +198,3 @@ } | ||
* | ||
* Note: Added for testing, use {@linkcode getAwsDefaultRegion} instead, which also converts undefined and null to empty | ||
* Note: Added for testing, use {@linkcode getDefaultRegion} instead, which also converts undefined and null to empty | ||
* strings | ||
@@ -213,5 +204,5 @@ * | ||
*/ | ||
function getAwsDefaultRegionRaw() { | ||
function getDefaultRegionRaw() { | ||
return trim(process.env.AWS_DEFAULT_REGION); | ||
} | ||
242
stages.js
@@ -10,12 +10,15 @@ 'use strict'; | ||
module.exports = { | ||
isResolveStageConfigured: isResolveStageConfigured, | ||
configureResolveStage: configureResolveStage, | ||
configureResolveStageWithDefaults: configureResolveStageWithDefaults, | ||
resolveStage: resolveStage, | ||
resolveRawStage: resolveRawStage, | ||
resolveStageUsingDefaultFunctions: resolveStageUsingDefaultFunctions, | ||
getResolveStageSetting: getResolveStageSetting, | ||
appendStage: appendStage, | ||
convertAliasToStage: convertAliasToStage, | ||
convertStreamNameSuffixToStage: convertStreamNameSuffixToStage | ||
convertStreamNameSuffixToStage: convertStreamNameSuffixToStage, | ||
FOR_TESTING_ONLY: { | ||
toCase: toCase | ||
} | ||
}; | ||
const config = require('./config'); | ||
const Strings = require('core-functions/strings'); | ||
@@ -36,60 +39,126 @@ const trim = Strings.trim; | ||
const DEFAULT_STREAM_NAME_STAGE_SEPARATOR = '_'; | ||
const DEFAULT_IN_CASE = 'lowercase'; | ||
/** | ||
* Attempts to resolve the raw stage (see {@linkcode resolveRawStage}) and then converts the resolved raw stage into | ||
* lowercase or uppercase (if context.useUpperCaseForStages is true). | ||
* Returns true if resolve stage settings are already configured on the given context; false otherwise. | ||
* @param context the context to check | ||
* @returns {boolean} true if configured; false otherwise | ||
*/ | ||
function isResolveStageConfigured(context) { | ||
return context && typeof context.resolveStageConfig === 'object'; | ||
} | ||
/** | ||
* Configures the given context with the given resolve stage settings, but only if there are no resolve stage settings | ||
* already configured on the given context OR if forceConfiguration is true. The resolve stage settings determine how | ||
* {@linkcode resolveStage} will behave when invoked. | ||
* | ||
* @param {Object} event - the AWS event | ||
* @param {Object} awsContext - the AWS context, which was passed to your lambda | ||
* @param {Function|undefined} convertAliasToStage - an optional function that accepts: the extracted alias (if any); the | ||
* AWS event; the AWS context; and the context, and converts the alias into a stage or returns an empty string | ||
* @param {Function|undefined} convertStreamNameToStage - an optional function that accepts: the stream name; the AWS | ||
* event; the AWS context; and the context, and extracts a stage from the stream name or returns an empty string | ||
* @param {Object} context - the context, which can be used to pass additional configuration through to the given functions | ||
* @param {string|undefined} [context.stage] - an optional stage on the given context | ||
* @param {string|undefined} [context.defaultStage] - an optional default stage on the given context | ||
* @param {boolean|undefined} [context.useUpperCaseForStages] - an optional flag on the given context, which if present | ||
* indicates whether to convert the resolved stage to uppercase rather than to lowercase | ||
* @returns {string} the resolved stage (if non-blank) in lowercase or uppercase; otherwise an empty string | ||
* @param {Object} context the context onto which to configure resolve stage settings | ||
* @param {Function|undefined} convertAliasToStage - an optional function that accepts: an extracted alias (if any); | ||
* an AWS event; an AWS context; and a context, and converts the alias into a stage or returns an empty string | ||
* @param {Function|undefined} convertStreamNameToStage - an optional function that accepts: a stream name; an AWS | ||
* event; an AWS context; and a context, and extracts a stage from the stream name or returns an empty string | ||
* @param {string|undefined} streamNameStageSeparator - an optional non-blank separator to use instead of '_' to | ||
* extract a stage from a stream name | ||
* @param {string|undefined} defaultStage - an optional default stage to use as a last resort if all other attempts fail | ||
* @param {string|undefined} inCase - specifies whether to convert a resolved stage to uppercase (if 'uppercase' or | ||
* 'upper') or to lowercase (if 'lowercase' or 'lower') or keep it as resolved (if anything else) | ||
* @param {boolean|undefined} forceConfiguration whether or not to force configuration of the given settings, which will | ||
* override any previously configured resolve stage settings on the given context | ||
* @return {Object} the updated context object | ||
*/ | ||
function resolveStage(event, awsContext, convertAliasToStage, convertStreamNameToStage, context) { | ||
// Resolve the raw stage | ||
const stage = resolveRawStage(event, awsContext, convertAliasToStage, convertStreamNameToStage, context); | ||
function configureResolveStage(context, convertAliasToStage, convertStreamNameToStage, streamNameStageSeparator, | ||
defaultStage, inCase, forceConfiguration) { | ||
// Convert the raw stage (if any) to lowercase or uppercase (if context.useUpperCaseForStages is true) | ||
return toLowerOrUpperCase(trimOrEmpty(stage), context && context.useUpperCaseForStages); | ||
// If forceConfiguration is false check if the given context already has stage resolution configured on it | ||
// and, if so, do nothing more and simply return the context as is (to prevent overriding an earlier configuration) | ||
if (!forceConfiguration && isResolveStageConfigured(context)) { | ||
return context; | ||
} | ||
// Configure the resolve stage settings | ||
context.resolveStageConfig = { | ||
convertAliasToStage: convertAliasToStage, | ||
convertStreamNameToStage: convertStreamNameToStage, | ||
streamNameStageSeparator: streamNameStageSeparator, | ||
defaultStage: defaultStage, | ||
inCase: inCase | ||
}; | ||
return context; | ||
} | ||
/** | ||
* Attempts to resolve the raw stage from the following resources in the following order: | ||
* Configures the given context with the default resolve stage settings, but only if there are no resolve stage settings | ||
* already configured on the given context OR if forceConfiguration is true. The resolve stage settings determine how | ||
* {@linkcode resolveStage} will behave when invoked. | ||
* | ||
* @param {Object} context the context onto which to configure resolve stage settings | ||
* @param {boolean|undefined} forceConfiguration whether or not to force configuration of the given settings, which will | ||
* override any previously configured resolve stage settings on the given context | ||
* @return {Object} the updated context object | ||
*/ | ||
function configureResolveStageWithDefaults(context, forceConfiguration) { | ||
return configureResolveStage(context, convertAliasToStage, convertStreamNameSuffixToStage, | ||
DEFAULT_STREAM_NAME_STAGE_SEPARATOR, undefined, DEFAULT_IN_CASE, forceConfiguration); | ||
} | ||
/** | ||
* Attempts to resolve the stage from the given AWS event, AWS context and context using the following process: | ||
* 1. Uses context.stage (if non-blank). | ||
* | ||
* 2. Uses the AWS event's stage (if non-blank). | ||
* NB: event.stage is NOT a standard AWS event property, but it may be set by API Gateway or tools like serverless. | ||
* TODO check whether API Gateway sets the stage on the event and if so confirm WHERE it sets it! | ||
* | ||
* 3. Extracts the alias from the AWS context's invokedFunctionArn (if any) and then uses the given convertAliasToStage | ||
* function (if provided) to convert the extracted alias (if any) into a stage. | ||
* 3. Extracts the alias from the AWS context's invokedFunctionArn (if any) and then uses the given context's | ||
* resolveStageConfig.convertAliasToStage function (if any) to convert the extracted alias (if any) into a stage. | ||
* | ||
* 4. Extracts the stream name from the AWS event's eventSourceARN (if any) and then uses the given convertStreamNameToStage | ||
* function (if provided) to convert the extracted stream name (if any) into a stage. | ||
* NB: This step relies on a convention of using stages as Lambda aliases and, hence, should be skipped, if you | ||
* are NOT using such a convention, by simply NOT configuring a resolveStageConfig.convertAliasToStage function | ||
* on the given context. | ||
* | ||
* 4. Extracts the stream names from the AWS event's records' eventSourceARNs (if any) and then uses the given context's | ||
* resolveStageConfig.convertStreamNameToStage function (if any) to convert the extracted stream names into stages | ||
* and returns the first non-blank stage (if any). | ||
* | ||
* NB: This step relies on a convention of qualifying stream names with a stage and, hence, should be skipped, if you | ||
* are NOT using such a convention, by simply NOT providing a convertStreamNameToStage function. | ||
* are NOT using such a convention, by simply NOT configuring a resolveStageConfig.convertStreamNameToStage function | ||
* on the given context. | ||
* | ||
* 5. Uses context.defaultStage (if non-blank). | ||
* 5. Uses context.resolveStageConfig.defaultStage (if non-blank). | ||
* | ||
* 6. Gives up and returns an empty string. | ||
* | ||
* NB: If no resolve stage settings have been configured by the time this function is first called, then the given | ||
* context will be configured with the default resolve stage settings (see {@linkcode configureResolveStageWithDefaults}). | ||
* | ||
* @param {Object} event - the AWS event | ||
* @param {Object} awsContext - the AWS context, which was passed to your lambda | ||
* @param {Function|undefined} convertAliasToStage - an optional function that accepts: the extracted alias (if any); the | ||
* AWS event; the AWS context; and the context, and converts the alias into a stage or returns an empty string | ||
* @param {Function|undefined} convertStreamNameToStage - an optional function that accepts: the stream name; the AWS | ||
* event; the AWS context; and the context, and extracts a stage from the stream name or returns an empty string | ||
* @param {Object} context - the context, which can be used to pass additional configuration through to the given functions | ||
* @param {string|undefined} [context.stage] - an optional stage on the given context | ||
* @param {string|undefined} [context.defaultStage] - an optional default stage on the given context | ||
* @returns {string} the resolved raw stage (if non-blank); otherwise an empty string | ||
* @param {Object} context - the context, which can also be used to pass additional configuration through to any custom | ||
* convertAliasToStage or convertStreamNameToStage functions that you configured | ||
* @param {string|undefined} [context.stage] - an optional stage on the given context, which will short-circuit | ||
* resolution to this stage (if non-blank) | ||
* @param {Function|undefined} [context.resolveStageConfig.convertAliasToStage] - an optional function on the given | ||
* context that accepts: an extracted alias (if any); an AWS event; an AWS context; and a context, and converts the | ||
* alias into a stage or returns an empty string | ||
* @param {Function|undefined} [context.resolveStageConfig.convertStreamNameToStage] - an optional function on the given | ||
* context that accepts: a Kinesis stream name; an AWS event; an AWS context; and a context, and extracts a stage from | ||
* the stream name or returns an empty string | ||
* @param {string|undefined} [context.resolveStageConfig.defaultStage] - an optional default stage on the given context | ||
* to use as a last resort if all other attempts fail | ||
* @param {string|undefined} [context.resolveStageConfig.inCase] - specifies whether to convert the resolved stage to | ||
* uppercase (if 'uppercase' or 'upper') or to lowercase (if 'lowercase' or 'lower') or keep it as resolved (if anything else) | ||
* @returns {string} the resolved stage (if non-blank); otherwise an empty string | ||
*/ | ||
function resolveRawStage(event, awsContext, convertAliasToStage, convertStreamNameToStage, context) { | ||
function resolveStage(event, awsContext, context) { | ||
// If no resolve stage settings have been configured yet, then configure the given context with the default settings | ||
if (!isResolveStageConfigured(context)) { | ||
configureResolveStageWithDefaults(context, true); | ||
} | ||
const inCase = getResolveStageSetting(context, 'inCase'); | ||
// Attempt 1 | ||
if (context && isNotBlank(context.stage)) { | ||
return context.stage; | ||
return toCase(trim(context.stage), inCase); | ||
} | ||
@@ -99,3 +168,3 @@ | ||
if (event && isNotBlank(event.stage)) { | ||
return event.stage; | ||
return toCase(trim(event.stage), inCase); | ||
} | ||
@@ -105,2 +174,4 @@ | ||
// Check have all the pieces needed to extract an alias and apply the given convertAliasToStage function to it | ||
const convertAliasToStage = getResolveStageSetting(context, 'convertAliasToStage'); | ||
if (awsContext && isNotBlank(awsContext.functionVersion) && isNotBlank(awsContext.invokedFunctionArn) && | ||
@@ -114,3 +185,3 @@ isFunction(convertAliasToStage)) { | ||
if (isNotBlank(stage)) { | ||
return stage; | ||
return toCase(trim(stage), inCase); | ||
} | ||
@@ -120,11 +191,20 @@ } | ||
// Attempt 4 | ||
function extractStageFromEventSourceARN(record) { | ||
if (record && isNotBlank(record.eventSourceARN)) { | ||
// Extract the stream name | ||
const streamName = getArnResources(record.eventSourceARN).resource; | ||
// If the stream name is not blank, apply the convertStreamNameToStage function to it to derive a stage | ||
return isNotBlank(streamName) ? convertStreamNameToStage(streamName, event, awsContext, context) : ''; | ||
} | ||
return ''; | ||
} | ||
// Check have all the pieces needed to extract a stream name and apply the given convertStreamNameToStage function to it | ||
if (event && isNotBlank(event.eventSourceARN) && isFunction(convertStreamNameToStage)) { | ||
// Extract the stream name | ||
const streamName = getArnResources(event.eventSourceARN).resource; | ||
const convertStreamNameToStage = getResolveStageSetting(context, 'convertStreamNameToStage'); | ||
// If the stream name is not blank, apply the convertStreamNameToStage function to it to derive a stage | ||
const stage = isNotBlank(streamName) ? convertStreamNameToStage(streamName, event, awsContext, context) : ''; | ||
if (event && event.Records && event.Records.length > 0 && isFunction(convertStreamNameToStage)) { | ||
const stage = event.Records.map(extractStageFromEventSourceARN).find(s => isNotBlank(s)); | ||
if (isNotBlank(stage)) { | ||
return stage; | ||
return toCase(trim(stage), inCase); | ||
} | ||
@@ -134,4 +214,5 @@ } | ||
// Attempt 5 | ||
if (context && isNotBlank(context.defaultStage)) { | ||
return context.defaultStage; | ||
const defaultStage = getResolveStageSetting(context, 'defaultStage'); | ||
if (isNotBlank(defaultStage)) { | ||
return toCase(trim(defaultStage), inCase); | ||
} | ||
@@ -144,11 +225,10 @@ | ||
/** | ||
* A short-cut to resolving the stage, which uses the default {@linkcode convertAliasToStage} and | ||
* {@linkcode convertStreamNameSuffixToStage} functions. | ||
* @param {Object} event - the AWS event | ||
* @param {Object} awsContext - the AWS context | ||
* @param {Object} context - the context | ||
* @returns {string} the resolved stage (if non-blank); otherwise an empty string | ||
* Returns the value of the named resolve stage setting (if any) on the given context. | ||
* @param context the context from which to fetch the named setting's value | ||
* @param settingName the name of the resolve stage setting | ||
* @returns {*|undefined} the value of the named setting (if any); otherwise undefined | ||
*/ | ||
function resolveStageUsingDefaultFunctions(event, awsContext, context) { | ||
return resolveStage(event, awsContext, convertAliasToStage, convertStreamNameSuffixToStage, context); | ||
function getResolveStageSetting(context, settingName) { | ||
return context && context.resolveStageConfig && isNotBlank(settingName) && context.resolveStageConfig[settingName] ? | ||
context.resolveStageConfig[settingName] : undefined; | ||
} | ||
@@ -171,3 +251,3 @@ | ||
* stream name. The suffix is extracted from the given stream name by taking everything after the last occurrence of | ||
* the context.streamNameStageSeparator (if any) or the default ('_') separator. | ||
* the configured streamNameStageSeparator (if any) or the default separator ('_'). | ||
* @param {string} streamName the name of the source stream (originally extracted from the AWS event's eventSourceArn) | ||
@@ -177,3 +257,4 @@ * @param {Object} event the AWS event | ||
* @param {Object} context the context | ||
* @param {string|undefined} [context.streamNameStageSeparator] - an optional separator to use instead of '_' | ||
* @param {string|undefined} [context.resolveStageConfig.streamNameStageSeparator] - an optional non-blank separator to | ||
* use instead of '_' | ||
* @returns {string} the stage or an empty string | ||
@@ -183,3 +264,4 @@ */ | ||
if (isNotBlank(streamName)) { | ||
const separator = context && context.streamNameStageSeparator ? context.streamNameStageSeparator : '_'; | ||
const separatorSetting = getResolveStageSetting(context, 'streamNameStageSeparator'); | ||
const separator = isNotBlank(separatorSetting) ? separatorSetting : '_'; | ||
const suffixStartPos = streamName.lastIndexOf(separator); | ||
@@ -192,12 +274,2 @@ return suffixStartPos !== -1 ? trimOrEmpty(streamName.substring(suffixStartPos + 1)) : ''; | ||
/** | ||
* Converts the given string to uppercase, if toUpper is true; otherwise to lowercase. | ||
* @param {string} s - the string to convert | ||
* @param {boolean|*} toUpper - if true, convert to uppercase; otherwise to lowercase | ||
* @returns {string} the upper or lowercase version of the string | ||
*/ | ||
function toLowerOrUpperCase(s, toUpper) { | ||
return s ? toUpper === true ? s.toUpperCase() : s.toLowerCase() : ''; | ||
} | ||
/** | ||
* Returns a stage-qualified version of the given base resource name with an appended "stage" suffix, which will contain | ||
@@ -216,13 +288,23 @@ * the given separator followed by the given stage, which will be appended in uppercase, lowercase or as is according to | ||
function appendStage(resourceName, separator, stage, inCase) { | ||
if (isNotBlank(stage)) { | ||
// Convert the given inCase argument to lowercase to facilitate matching | ||
const inCaseToUse = trimOrEmpty(inCase && inCase.toLowerCase ? inCase.toLowerCase() : inCase); | ||
return isNotBlank(stage) ? `${resourceName}${trimOrEmpty(separator)}${toCase(trim(stage), inCase)}` : resourceName; | ||
} | ||
/** | ||
* Converts the given value to uppercase, lowercase or keeps it as is according to the given asCase argument. | ||
* @param value the value to convert or keep as is | ||
* @param {string} asCase - specifies whether to convert the value to uppercase (if 'uppercase' or 'upper') or to | ||
* lowercase (if 'lowercase' or 'lower') or to keep it as provided (if anything else) | ||
* @return {string} the converted or given value | ||
*/ | ||
function toCase(value, asCase) { | ||
if (isNotBlank(value)) { | ||
// Convert the given asCase argument to lowercase to facilitate matching | ||
const caseToUse = trimOrEmpty(asCase && asCase.toLowerCase ? asCase.toLowerCase() : asCase); | ||
// Convert the given stage into the requested case | ||
const stageInRightCase = trim(inCaseToUse === 'lowercase' || inCaseToUse === 'lower' ? stage.toLowerCase() : | ||
inCaseToUse === 'uppercase' || inCaseToUse === 'upper' ? stage.toUpperCase() : stage); | ||
return`${resourceName}${trimOrEmpty(separator)}${stageInRightCase}`; | ||
return caseToUse === 'lowercase' || caseToUse === 'lower' ? value.toLowerCase() : | ||
caseToUse === 'uppercase' || caseToUse === 'upper' ? value.toUpperCase() : value; | ||
} | ||
return resourceName; | ||
return value; | ||
} | ||
@@ -18,13 +18,13 @@ 'use strict'; | ||
const getAlias = lambdas.getAlias; | ||
const getInvokedFunctionArn = lambdas.getInvokedFunctionArn; | ||
//const getInvokedFunctionArn = lambdas.getInvokedFunctionArn; | ||
const getInvokedFunctionArnFunctionName = lambdas.getInvokedFunctionArnFunctionName; | ||
const Strings = require('core-functions/strings'); | ||
const isBlank = Strings.isBlank; | ||
const isNotBlank = Strings.isNotBlank; | ||
const trim = Strings.trim; | ||
const trimOrEmpty = Strings.trimOrEmpty; | ||
// const Strings = require('core-functions/strings'); | ||
// const isBlank = Strings.isBlank; | ||
// const isNotBlank = Strings.isNotBlank; | ||
// const trim = Strings.trim; | ||
// const trimOrEmpty = Strings.trimOrEmpty; | ||
const samples = require('./samples'); | ||
const sampleInvokedFunctionArn = samples.sampleInvokedFunctionArn; | ||
//const sampleInvokedFunctionArn = samples.sampleInvokedFunctionArn; | ||
const sampleAwsContext = samples.sampleAwsContext; | ||
@@ -31,0 +31,0 @@ |
{ | ||
"name": "aws-core-utils-tests", | ||
"description": "Unit tests for aws-core-utils modules", | ||
"version": "0.9.0", | ||
"version": "1.0.0", | ||
"author": "Byron du Preez", | ||
@@ -6,0 +6,0 @@ "license": "Apache-2.0", |
@@ -14,35 +14,27 @@ 'use strict'; | ||
const regions = require('../regions'); | ||
const getAwsRegion = regions.getAwsRegion; | ||
const getAwsRegionRaw = regions.ONLY_FOR_TESTING.getAwsRegionRaw; | ||
// const getAwsDefaultRegion = regions.getAwsDefaultRegion; | ||
const getRegion = regions.getRegion; | ||
const getRegionRaw = regions.ONLY_FOR_TESTING.getRegionRaw; | ||
// const getDefaultRegion = regions.getDefaultRegion; | ||
// const resolveRegion = regions.resolveRegion; | ||
const setAwsRegionIfNotSet = regions.ONLY_FOR_TESTING.setAwsRegionIfNotSet; | ||
const setRegionIfNotSet = regions.ONLY_FOR_TESTING.setRegionIfNotSet; | ||
const Strings = require('core-functions/strings'); | ||
const isBlank = Strings.isBlank; | ||
const isNotBlank = Strings.isNotBlank; | ||
const trim = Strings.trim; | ||
const trimOrEmpty = Strings.trimOrEmpty; | ||
// const isNotBlank = Strings.isNotBlank; | ||
// const trim = Strings.trim; | ||
// const trimOrEmpty = Strings.trimOrEmpty; | ||
const INVOKED_FUNCTION_ARN_REGION = 'INVOKED_FUNCTION_ARN_REGION'; | ||
const EVENT_AWS_REGION = 'EVENT_AWS_REGION'; | ||
const EVENT_SOURCE_ARN_REGION = 'EVENT_SOURCE_ARN_REGION'; | ||
// function sampleRegion(region) { | ||
// return region ? region : defaultAwsRegion; | ||
// } | ||
// ===================================================================================================================== | ||
// Tests for getAwsRegion | ||
// Tests for getRegion | ||
// ===================================================================================================================== | ||
test('getAwsRegion and setAwsRegionIfNotSet', t => { | ||
test('getRegion and setRegionIfNotSet', t => { | ||
// Attempt to preserve the original AWS_REGION setting (unfortunately cannot preserve undefined or null) | ||
const origAwsRegion = getAwsRegionRaw(); | ||
const origRegion = getRegionRaw(); | ||
// check orig | ||
if (isBlank(origAwsRegion)) { | ||
t.equal(origAwsRegion, process.env.AWS_REGION, `original raw must be '${process.env.AWS_REGION}'`); | ||
t.equal(getAwsRegion(), '', `original must be empty string '${process.env.AWS_REGION}'`); | ||
if (isBlank(origRegion)) { | ||
t.equal(origRegion, process.env.AWS_REGION, `original raw must be '${process.env.AWS_REGION}'`); | ||
t.equal(getRegion(), '', `original must be empty string '${process.env.AWS_REGION}'`); | ||
} | ||
@@ -57,27 +49,27 @@ | ||
process.env.AWS_REGION = unset; | ||
console.log(`AFTER reset process.env.AWS_REGION = '${process.env.AWS_REGION}' (orig was ${origAwsRegion})`); | ||
console.log(`AFTER reset process.env.AWS_REGION = '${process.env.AWS_REGION}' (orig was ${origRegion})`); | ||
t.equal(process.env.AWS_REGION, unset, `process.env.AWS_REGION must be '${unset}' after reset`); | ||
// check get when not set | ||
t.equal(getAwsRegion(), unset, `must be '${unset}'`); | ||
t.equal(getRegion(), unset, `must be '${unset}'`); | ||
// check will set, when not set | ||
const expected = 'TEST_REGION_1'; | ||
t.ok(setAwsRegionIfNotSet(expected), `must set successfully`); | ||
t.equal(getAwsRegion(), expected, `must be ${expected}`); | ||
t.ok(setRegionIfNotSet(expected), `must set successfully`); | ||
t.equal(getRegion(), expected, `must be ${expected}`); | ||
// check was NOT set, when already set set | ||
t.notOk(setAwsRegionIfNotSet('TEST_REGION_3'), `must NOT set successfully`); | ||
t.equal(getAwsRegion(), expected, `must still be ${expected}`); | ||
t.notOk(setRegionIfNotSet('TEST_REGION_3'), `must NOT set successfully`); | ||
t.equal(getRegion(), expected, `must still be ${expected}`); | ||
} finally { | ||
// "Restore" original aws region | ||
console.log(`BEFORE restore process.env.AWS_REGION = '${process.env.AWS_REGION}' (orig was ${origAwsRegion})`); | ||
process.env.AWS_REGION = isBlank(origAwsRegion) ? unset : origAwsRegion; | ||
console.log(`AFTER restore process.env.AWS_REGION = '${process.env.AWS_REGION}' (orig was ${origAwsRegion})`); | ||
console.log(`BEFORE restore process.env.AWS_REGION = '${process.env.AWS_REGION}' (orig was ${origRegion})`); | ||
process.env.AWS_REGION = isBlank(origRegion) ? unset : origRegion; | ||
console.log(`AFTER restore process.env.AWS_REGION = '${process.env.AWS_REGION}' (orig was ${origRegion})`); | ||
// Check "restore" worked | ||
if (isBlank(origAwsRegion)) { | ||
t.equal(getAwsRegion(), unset, `must be "restored" to '${unset}' (orig was ${origAwsRegion})`); | ||
if (isBlank(origRegion)) { | ||
t.equal(getRegion(), unset, `must be "restored" to '${unset}' (orig was ${origRegion})`); | ||
} else { | ||
t.equal(getAwsRegion(), origAwsRegion, `must be restored to ${origAwsRegion}`); | ||
t.equal(getRegion(), origRegion, `must be restored to ${origRegion}`); | ||
} | ||
@@ -98,5 +90,5 @@ t.end(); | ||
// // Configure different regions to each of the 3 sources | ||
// // const eventSourceArnRegion = EVENT_SOURCE_ARN_REGION; | ||
// // const eventAwsRegion = EVENT_AWS_REGION; | ||
// // const invokedFunctionArnRegion = INVOKED_FUNCTION_ARN_REGION; | ||
// // const eventSourceArnRegion = 'ES_ARN_REGION'; | ||
// // const eventAwsRegion = 'EVENT_AWS_REGION'; | ||
// // const invokedFunctionArnRegion = 'IF_ARN_REGION'; | ||
// | ||
@@ -103,0 +95,0 @@ // const eventSourceArn = sampleEventSourceArn(streamName); //, eventSourceArnRegion); |
@@ -16,6 +16,2 @@ 'use strict'; | ||
const INVOKED_FUNCTION_ARN_REGION = 'INVOKED_FUNCTION_ARN_REGION'; | ||
const EVENT_AWS_REGION = 'EVENT_AWS_REGION'; | ||
const EVENT_SOURCE_ARN_REGION = 'EVENT_SOURCE_ARN_REGION'; | ||
const sampleMessage = { | ||
@@ -34,6 +30,2 @@ key1: 'value1', | ||
INVOKED_FUNCTION_ARN_REGION: INVOKED_FUNCTION_ARN_REGION, | ||
EVENT_AWS_REGION: EVENT_AWS_REGION, | ||
EVENT_SOURCE_ARN_REGION: EVENT_SOURCE_ARN_REGION, | ||
// General | ||
@@ -84,3 +76,3 @@ sampleNumberString: sampleNumberString, | ||
function sampleInvokedFunctionArn(invokedFunctionArnRegion, functionName, functionAlias) { | ||
const region = isNotBlank(invokedFunctionArnRegion) ? invokedFunctionArnRegion : INVOKED_FUNCTION_ARN_REGION; | ||
const region = isNotBlank(invokedFunctionArnRegion) ? invokedFunctionArnRegion : 'IF_ARN_REGION'; | ||
const funcName = isNotBlank(functionName) ? functionName : sampleFunctionName; | ||
@@ -92,3 +84,3 @@ const aliasSuffix = isNotBlank(functionAlias) ? `:${functionAlias}` : ''; | ||
function sampleEventSourceArn(eventSourceArnRegion, streamName) { | ||
const region = isNotBlank(eventSourceArnRegion) ? eventSourceArnRegion : EVENT_SOURCE_ARN_REGION; | ||
const region = isNotBlank(eventSourceArnRegion) ? eventSourceArnRegion : 'EF_ARN_REGION'; | ||
const streamName1 = isNotBlank(streamName) ? streamName : sampleStreamName(); | ||
@@ -130,3 +122,3 @@ return `arn:aws:kinesis:${region}:${sampleAwsAccountId}:stream/${streamName1}`; | ||
const sequenceNumber = sampleNumberString(56); | ||
const awsRegion = eventAwsRegion ? eventAwsRegion : EVENT_AWS_REGION; | ||
const awsRegion = eventAwsRegion ? eventAwsRegion : 'EVENT_AWS_REGION'; | ||
return { | ||
@@ -133,0 +125,0 @@ eventID: `shardId-000000000000:${shardId}`, |
@@ -12,9 +12,514 @@ 'use strict'; | ||
const stages = require('../stages'); | ||
const isResolveStageConfigured = stages.isResolveStageConfigured; | ||
const configureResolveStage = stages.configureResolveStage; | ||
const configureResolveStageWithDefaults = stages.configureResolveStageWithDefaults; | ||
const resolveStage = stages.resolveStage; | ||
const resolveRawStage = stages.resolveRawStage; | ||
const resolveStageUsingDefaultFunctions = stages.resolveStageUsingDefaultFunctions; | ||
const getResolveStageSetting = stages.getResolveStageSetting; | ||
const convertAliasToStage = stages.convertAliasToStage; | ||
const convertStreamNameSuffixToStage = stages.convertStreamNameSuffixToStage; | ||
const appendStage = stages.appendStage; | ||
//const appendStage = stages.appendStage; | ||
const toCase = stages.FOR_TESTING_ONLY.toCase; | ||
//TODO add unit test for stages | ||
const Strings = require('core-functions/strings'); | ||
const trim = Strings.trim; | ||
const trimOrEmpty = Strings.trimOrEmpty; | ||
//const isBlank = Strings.isBlank; | ||
const isNotBlank = Strings.isNotBlank; | ||
const stringify = Strings.stringify; | ||
const samples = require('./samples'); | ||
// Constants | ||
const latestFunctionVersion = samples.latestFunctionVersion; | ||
// General | ||
const sampleNumberString = samples.sampleNumberString; | ||
// For AWS contexts | ||
const sampleInvokedFunctionArn = samples.sampleInvokedFunctionArn; | ||
const sampleAwsContext = samples.sampleAwsContext; | ||
// For Kinesis events | ||
const sampleStreamName = samples.sampleStreamName; | ||
const sampleEventSourceArn = samples.sampleEventSourceArn; | ||
const sampleEventSourceArnFromPrefixSuffix = samples.sampleEventSourceArnFromPrefixSuffix; | ||
const sampleBase64Data = samples.sampleBase64Data; | ||
const sampleKinesisEventWithSampleRecord = samples.sampleKinesisEventWithSampleRecord; | ||
const sampleKinesisEventWithRecord = samples.sampleKinesisEventWithRecord; | ||
const sampleKinesisEventWithRecords = samples.sampleKinesisEventWithRecords; | ||
function checkConvertAliasToStage(alias, expected, t) { | ||
t.equal(convertAliasToStage(alias, undefined, undefined, undefined), expected, `'${alias}' must be '${expected}'`); | ||
} | ||
function checkConvertStreamNameSuffixToStage(streamName, context, expected, t) { | ||
t.equal(convertStreamNameSuffixToStage(streamName, undefined, undefined, context), expected | ||
, `'${streamName}' must be '${expected}'`); | ||
} | ||
function checkResolveStage(eventStage, functionVersion, functionAlias, streamName, context, expected, t) { | ||
// Create an AWS context | ||
const invokedFunctionArn = sampleInvokedFunctionArn('invokedFunctionArnRegion', 'functionName', functionAlias); | ||
const awsContext = sampleAwsContext('functionName', functionVersion, invokedFunctionArn); | ||
// Create a Kinesis event | ||
const eventSourceArn = sampleEventSourceArn('eventSourceArnRegion', streamName); | ||
const event = sampleKinesisEventWithSampleRecord(undefined, undefined, eventSourceArn, 'eventAwsRegion'); | ||
if (isNotBlank(eventStage)) { | ||
event.stage = eventStage; | ||
} | ||
// Resolve the stage | ||
const actual = resolveStage(event, awsContext, context); | ||
t.equal(actual, expected, `resolve: alias(${functionAlias}) stream(${streamName}) context(${context.stage}, ${context.defaultStage}) -> '${actual}' must be '${expected}'`); | ||
} | ||
function checkConfigureResolveStage(context, convertAliasToStage, convertStreamNameToStage, streamNameStageSeparator, | ||
defaultStage, inCase, forceConfiguration, t) { | ||
const before = context.resolveStageConfig; | ||
const convertAliasToStageBefore = before ? before.convertAliasToStage : undefined; | ||
const convertStreamNameToStageBefore = before ? before.convertStreamNameToStage : undefined; | ||
const streamNameStageSeparatorBefore = before ? before.streamNameStageSeparator : undefined; | ||
const defaultStageBefore = before ? before.defaultStage : undefined; | ||
const inCaseBefore = before ? before.inCase : undefined; | ||
const mustChange = forceConfiguration || !before; | ||
// Configure it | ||
configureResolveStage(context, convertAliasToStage, convertStreamNameToStage, streamNameStageSeparator, defaultStage, | ||
inCase, forceConfiguration, t); | ||
const after = context.resolveStageConfig; | ||
const convertAliasToStageAfter = after ? after.convertAliasToStage : undefined; | ||
const convertStreamNameToStageAfter = after ? after.convertStreamNameToStage : undefined; | ||
const streamNameStageSeparatorAfter = after ? after.streamNameStageSeparator : undefined; | ||
const defaultStageAfter = after ? after.defaultStage : undefined; | ||
const inCaseAfter = after ? after.inCase : undefined; | ||
t.ok(isResolveStageConfigured(context), `resolve stage settings must be configured now`); | ||
// Set up the right expectations | ||
const convertAliasToStageExpected = mustChange ? convertAliasToStage : convertAliasToStageBefore; | ||
const convertStreamNameToStageExpected = mustChange ? convertStreamNameToStage : convertStreamNameToStageBefore; | ||
const streamNameStageSeparatorExpected = mustChange ? streamNameStageSeparator : streamNameStageSeparatorBefore; | ||
const defaultStageExpected = mustChange ? defaultStage : defaultStageBefore; | ||
const inCaseExpected = mustChange ? inCase : inCaseBefore; | ||
t.deepEqual(getResolveStageSetting(context, 'convertAliasToStage'), convertAliasToStageExpected, `convertAliasToStage (${stringify(convertAliasToStageAfter)}) must be ${stringify(convertAliasToStageExpected)}`); | ||
t.deepEqual(getResolveStageSetting(context, 'convertStreamNameToStage'), convertStreamNameToStageExpected, `convertStreamNameToStage (${stringify(convertStreamNameToStageAfter)}) must be ${stringify(convertStreamNameToStageExpected)}`); | ||
t.equal(getResolveStageSetting(context, 'streamNameStageSeparator'), streamNameStageSeparatorExpected, `streamNameStageSeparator (${stringify(streamNameStageSeparatorAfter)}) must be ${stringify(streamNameStageSeparatorExpected)}`); | ||
t.equal(getResolveStageSetting(context, 'defaultStage'), defaultStageExpected, `defaultStage (${stringify(defaultStageAfter)}) must be ${stringify(defaultStageExpected)}`); | ||
t.equal(getResolveStageSetting(context, 'inCase'), inCaseExpected, `inCase (${stringify(inCaseAfter)}) must be ${stringify(inCaseExpected)}`); | ||
// Check whether resolve stage works with this configuration | ||
const expected = mustChange ? toCase(trimOrEmpty(defaultStageExpected), inCaseExpected) : toCase(trimOrEmpty(defaultStageBefore), inCaseBefore); | ||
checkResolveStage('', '', '', '', context, expected, t); | ||
} | ||
function checkConfigureResolveStageWithDefaults(context, forceConfiguration, t) { | ||
const before = context.resolveStageConfig; | ||
const convertAliasToStageBefore = before ? before.convertAliasToStage : undefined; | ||
const convertStreamNameToStageBefore = before ? before.convertStreamNameToStage : undefined; | ||
const streamNameStageSeparatorBefore = before ? before.streamNameStageSeparator : undefined; | ||
const defaultStageBefore = before ? before.defaultStage : undefined; | ||
const inCaseBefore = before ? before.inCase : undefined; | ||
const mustChange = forceConfiguration || !before; | ||
// Configure it | ||
configureResolveStageWithDefaults(context, forceConfiguration, t); | ||
const after = context.resolveStageConfig; | ||
const convertAliasToStageAfter = after ? after.convertAliasToStage : undefined; | ||
const convertStreamNameToStageAfter = after ? after.convertStreamNameToStage : undefined; | ||
const streamNameStageSeparatorAfter = after ? after.streamNameStageSeparator : undefined; | ||
const defaultStageAfter = after ? after.defaultStage : undefined; | ||
const inCaseAfter = after ? after.inCase : undefined; | ||
t.ok(isResolveStageConfigured(context), `resolve stage settings must be configured now`); | ||
// Expect the defaults to be in place | ||
const convertAliasToStageExpected = mustChange ? convertAliasToStage : convertAliasToStageBefore; | ||
const convertStreamNameToStageExpected = mustChange ? convertStreamNameSuffixToStage : convertStreamNameToStageBefore; | ||
const streamNameStageSeparatorExpected = mustChange ? '_' : streamNameStageSeparatorBefore; | ||
const defaultStageExpected = mustChange ? undefined : defaultStageBefore; | ||
const inCaseExpected = mustChange ? 'lowercase' : inCaseBefore; | ||
t.deepEqual(getResolveStageSetting(context, 'convertAliasToStage'), convertAliasToStageExpected, `convertAliasToStage (${stringify(convertAliasToStageAfter)}) must be ${stringify(convertAliasToStageExpected)}`); | ||
t.deepEqual(getResolveStageSetting(context, 'convertStreamNameToStage'), convertStreamNameToStageExpected, `convertStreamNameToStage (${stringify(convertStreamNameToStageAfter)}) must be ${stringify(convertStreamNameToStageExpected)}`); | ||
t.equal(getResolveStageSetting(context, 'streamNameStageSeparator'), streamNameStageSeparatorExpected, `streamNameStageSeparator (${stringify(streamNameStageSeparatorAfter)}) must be ${stringify(streamNameStageSeparatorExpected)}`); | ||
t.equal(getResolveStageSetting(context, 'defaultStage'), defaultStageExpected, `defaultStage (${stringify(defaultStageAfter)}) must be ${stringify(defaultStageExpected)}`); | ||
t.equal(getResolveStageSetting(context, 'inCase'), inCaseExpected, `inCase (${stringify(inCaseAfter)}) must be ${stringify(inCaseExpected)}`); | ||
// Check whether resolve stage works with this configuration | ||
const expected = toCase(trimOrEmpty(defaultStageExpected), inCaseExpected); | ||
checkResolveStage('', '', '', '', context, expected, t); | ||
} | ||
// ===================================================================================================================== | ||
// Tests for configureResolveStage and isResolveStageConfigured | ||
// ===================================================================================================================== | ||
test('configureResolveStage with all undefined', t => { | ||
const context = {}; | ||
t.notOk(isResolveStageConfigured(context), `resolve stage settings must not be configured yet`); | ||
// Configure it | ||
checkConfigureResolveStage(context, undefined, undefined, undefined, undefined, undefined, false, t); | ||
// Must NOT be able to reconfigure it with force false | ||
checkConfigureResolveStage(context, 'convertAliasToStage', 'convertStreamNameToStage', 'streamNameStageSeparator', 'defaultStage', | ||
'inCase', false, t); | ||
// Must be able to reconfigure it with force true | ||
checkConfigureResolveStage(context, 'convertAliasToStage', 'convertStreamNameToStage', 'streamNameStageSeparator', 'defaultStage', | ||
'inCase', true, t); | ||
t.end(); | ||
}); | ||
// ===================================================================================================================== | ||
// Tests for configureResolveStageWithDefaults and isResolveStageConfigured | ||
// ===================================================================================================================== | ||
test('configureResolveStageWithDefaults with all undefined', t => { | ||
const context = {}; | ||
t.notOk(isResolveStageConfigured(context), `resolve stage settings must not be configured yet`); | ||
// Configure it | ||
checkConfigureResolveStageWithDefaults(context, false, t); | ||
// Overwrite it with arbitrary values to be able to check if defaults are NOT re-instated in next step | ||
configureResolveStage(context, 'convertAliasToStage', 'convertStreamNameToStage', 'streamNameStageSeparator', | ||
'defaultStage', 'inCase', true); | ||
// Must NOT be able to reconfigure it with force false | ||
checkConfigureResolveStageWithDefaults(context, false, t); | ||
// Must be able to reconfigure it with force true | ||
checkConfigureResolveStageWithDefaults(context, true, t); | ||
t.end(); | ||
}); | ||
// ===================================================================================================================== | ||
// Tests for convertAliasToStage | ||
// ===================================================================================================================== | ||
test('convertAliasToStage', t => { | ||
checkConvertAliasToStage(undefined, '', t); | ||
checkConvertAliasToStage(null, '', t); | ||
checkConvertAliasToStage('', '', t); | ||
checkConvertAliasToStage('DEV', 'DEV', t); | ||
checkConvertAliasToStage('prod', 'prod', t); | ||
checkConvertAliasToStage('Prod', 'Prod', t); | ||
checkConvertAliasToStage(' QA ', 'QA', t); | ||
checkConvertAliasToStage(' PROD 2016-10-19 ', 'PROD 2016-10-19', t); | ||
t.end(); | ||
}); | ||
// ===================================================================================================================== | ||
// Tests for convertStreamNameSuffixToStage | ||
// ===================================================================================================================== | ||
test('convertStreamNameSuffixToStage with default settings, should use default "_" as separator', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
checkConvertStreamNameSuffixToStage(undefined, context, '', t); | ||
checkConvertStreamNameSuffixToStage(null, context, '', t); | ||
checkConvertStreamNameSuffixToStage('', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream1', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream2_', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream3_Dev', context, 'Dev', t); | ||
checkConvertStreamNameSuffixToStage('Stream4_QA', context, 'QA', t); | ||
checkConvertStreamNameSuffixToStage('Stream_5_qa', context, 'qa', t); | ||
checkConvertStreamNameSuffixToStage('Test_Stream_6_Prod', context, 'Prod', t); | ||
checkConvertStreamNameSuffixToStage(' Test_Stream_7_Prod-01 ', context, 'Prod-01', t); | ||
checkConvertStreamNameSuffixToStage('Stream_SS', context, 'SS', t); | ||
t.end(); | ||
}); | ||
test('convertStreamNameSuffixToStage with streamNameStageSeparator set to undefined, should use default "_" as separator', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.streamNameStageSeparator = undefined; | ||
checkConvertStreamNameSuffixToStage(undefined, context, '', t); | ||
checkConvertStreamNameSuffixToStage(null, context, '', t); | ||
checkConvertStreamNameSuffixToStage('', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream1', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream2_', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream3_Dev', context, 'Dev', t); | ||
checkConvertStreamNameSuffixToStage('Stream4_QA', context, 'QA', t); | ||
checkConvertStreamNameSuffixToStage('Stream_5_qa', context, 'qa', t); | ||
checkConvertStreamNameSuffixToStage('Test_Stream_6_Prod', context, 'Prod', t); | ||
checkConvertStreamNameSuffixToStage(' Test_Stream_7_Prod-01 ', context, 'Prod-01', t); | ||
checkConvertStreamNameSuffixToStage('Stream_SS', context, 'SS', t); | ||
t.end(); | ||
}); | ||
test('convertStreamNameSuffixToStage with streamNameStageSeparator set to "", should still use default "_" as separator', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.streamNameStageSeparator = ''; | ||
checkConvertStreamNameSuffixToStage(undefined, context, '', t); | ||
checkConvertStreamNameSuffixToStage(null, context, '', t); | ||
checkConvertStreamNameSuffixToStage('', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream1', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream2_', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream3_Dev', context, 'Dev', t); | ||
checkConvertStreamNameSuffixToStage('Stream4_QA', context, 'QA', t); | ||
checkConvertStreamNameSuffixToStage('Stream_5_qa', context, 'qa', t); | ||
checkConvertStreamNameSuffixToStage('Test_Stream_6_Prod', context, 'Prod', t); | ||
checkConvertStreamNameSuffixToStage(' Test_Stream_7_Prod-01 ', context, 'Prod-01', t); | ||
t.end(); | ||
}); | ||
test('convertStreamNameSuffixToStage with context.streamNameStageSeparator set to "-", should NOT use default "_" as separator', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.streamNameStageSeparator = '-'; | ||
checkConvertStreamNameSuffixToStage(undefined, context, '', t); | ||
checkConvertStreamNameSuffixToStage(null, context, '', t); | ||
checkConvertStreamNameSuffixToStage('', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream1', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream2_', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream3_Dev', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream3_QA', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream_3_qa', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Test_Stream3_Prod', context, '', t); | ||
checkConvertStreamNameSuffixToStage(' Test_Stream3_Prod_01 ', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream_2-', context, '', t); | ||
checkConvertStreamNameSuffixToStage('Stream_3-Dev', context, 'Dev', t); | ||
checkConvertStreamNameSuffixToStage('Stream_3-QA', context, 'QA', t); | ||
checkConvertStreamNameSuffixToStage('Stream_3-qa', context, 'qa', t); | ||
checkConvertStreamNameSuffixToStage('Test_Stream3-Prod', context, 'Prod', t); | ||
checkConvertStreamNameSuffixToStage(' Test_Stream3-Prod_01 ', context, 'Prod_01', t); | ||
t.end(); | ||
}); | ||
// ===================================================================================================================== | ||
// Tests for resolveStage | ||
// ===================================================================================================================== | ||
test('resolveStage with undefined/null/empty alias, stream name & context must return empty', t => { | ||
const context = {}; | ||
checkResolveStage(undefined, undefined, undefined, undefined, context, '', t); | ||
checkResolveStage(null, null, null, null, context, '', t); | ||
checkResolveStage('', '', '', '', context, '', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with no defaultStage', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.inCase = ''; | ||
// No default stage and nothing else | ||
checkResolveStage('', '', '', '', context, '', t); | ||
// No default stage and stream without suffix must be empty | ||
checkResolveStage('', '', '', 'Stream', context, '', t); | ||
// No default stage and stream with suffix must use suffix | ||
checkResolveStage('', '', '', 'Stream_SS', context, 'SS', t); | ||
// No default stage and Lambda without alias must be empty | ||
checkResolveStage('', '1.0.1', '1.0.1', '', context, '', t); | ||
// No default stage and Lambda with alias must use alias stage | ||
checkResolveStage('', '1.0.1', 'AS', '', context, 'AS', t); | ||
// No default stage and event with stage must use event stage | ||
checkResolveStage('ES', '', '', '', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with defaultStage', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.inCase = ''; | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
// Default stage and nothing else must be default stage | ||
checkResolveStage('', '', '', '', context, 'DS', t); | ||
// Default stage must override stream without suffix | ||
checkResolveStage('', '', '', 'Stream', context, 'DS', t); | ||
// Default stage must not override stream with suffix | ||
checkResolveStage('', '', '', 'Stream_SS', context, 'SS', t); | ||
// Default stage must override Lambda without alias | ||
checkResolveStage('', '1.0.1', '1.0.1', '', context, 'DS', t); | ||
// Default stage must not override Lambda with alias | ||
checkResolveStage('', '1.0.1', 'AS', '', context, 'AS', t); | ||
// Default stage must not override event stage | ||
checkResolveStage('ES', '', '', '', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with stream without suffix', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
// Stream without suffix must not override default stage | ||
checkResolveStage('', '', '', 'Stream', context, 'DS', t); | ||
// Stream without suffix must not override default stage when Lambda without alias | ||
checkResolveStage('', '1.0.1', '1.0.1', 'Stream', context, 'DS', t); | ||
// Stream without suffix must not override Lambda with alias | ||
checkResolveStage('', '1.0.1', 'AS', 'Stream', context, 'AS', t); | ||
// Stream without suffix must not override event stage | ||
checkResolveStage('ES', '', '', 'Stream', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with stream with suffix', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
// Stream with suffix must override default stage | ||
checkResolveStage('', '', '', 'Stream_SS', context, 'SS', t); | ||
// Stream with suffix must override default stage when Lambda without alias | ||
checkResolveStage('', '1.0.1', '1.0.1', 'Stream_SS', context, 'SS', t); | ||
// Stream with suffix must not override Lambda with alias | ||
checkResolveStage('', '1.0.1', 'AS', 'Stream_SS', context, 'AS', t); | ||
// Stream with suffix must not override event stage | ||
checkResolveStage('ES', '', '', 'Stream_SS', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with Lambda without alias', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
// Lambda without alias must not override default stage | ||
checkResolveStage('', '1.0.1', '1.0.1', '', context, 'DS', t); | ||
// Lambda without alias must not override default stage when stream without suffix | ||
checkResolveStage('', '1.0.1', '1.0.1', 'Stream', context, 'DS', t); | ||
// Lambda without alias must not override stream with suffix | ||
checkResolveStage('', '1.0.1', '1.0.1', 'Stream_SS', context, 'SS', t); | ||
// Lambda without alias must not override event stage | ||
checkResolveStage('ES', '1.0.1', '1.0.1', 'Stream_SS', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with Lambda with alias', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
// Lambda with alias must override default stage | ||
checkResolveStage('', '1.0.1', 'AS', '', context, 'AS', t); | ||
// Lambda with alias must override default stage when stream without suffix | ||
checkResolveStage('', '1.0.1', 'AS', 'Stream', context, 'AS', t); | ||
// Lambda with alias must override stream with suffix | ||
checkResolveStage('', '1.0.1', 'AS', 'Stream_SS', context, 'AS', t); | ||
// Lambda with alias must not override event stage | ||
checkResolveStage('ES', '1.0.1', 'AS', 'Stream_SS', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with event stage', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
// Event stage must override default stage | ||
checkResolveStage('ES', '', '', '', context, 'ES', t); | ||
// Event stage must override stream without suffix and default | ||
checkResolveStage('ES', '', '', 'Stream', context, 'ES', t); | ||
// Event stage must override stream with suffix and default | ||
checkResolveStage('ES', '', '', 'Stream_SS', context, 'ES', t); | ||
// Event stage must override Lambda without alias and default | ||
checkResolveStage('ES', '1.0.1', '1.01', '', context, 'ES', t); | ||
// Event stage must override Lambda without alias and stream without suffix and default | ||
checkResolveStage('ES', '1.0.1', '1.01', 'Stream', context, 'ES', t); | ||
// Event stage must override Lambda without alias and stream with suffix and default | ||
checkResolveStage('ES', '1.0.1', '1.01', 'Stream_SS', context, 'ES', t); | ||
// Event stage must override Lambda with alias and default | ||
checkResolveStage('ES', '1.0.1', 'AS', '', context, 'ES', t); | ||
// Event stage must override Lambda with alias and stream without suffix and default | ||
checkResolveStage('ES', '1.0.1', 'AS', 'Stream', context, 'ES', t); | ||
// Event stage must override Lambda with alias and stream with suffix and default | ||
checkResolveStage('ES', '1.0.1', 'AS', 'Stream_SS', context, 'ES', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with context stage and without event stage', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
context.stage = 'CS'; | ||
// Context stage must override default stage | ||
checkResolveStage('', '', '', '', context, 'CS', t); | ||
// Context stage must override stream without suffix and default | ||
checkResolveStage('', '', '', 'Stream', context, 'CS', t); | ||
// Context stage must override stream with suffix and default | ||
checkResolveStage('', '', '', 'Stream_SS', context, 'CS', t); | ||
// Context stage must override Lambda without alias and default | ||
checkResolveStage('', '1.0.1', '1.01', '', context, 'CS', t); | ||
// Context stage must override Lambda without alias and stream without suffix and default | ||
checkResolveStage('', '1.0.1', '1.01', 'Stream', context, 'CS', t); | ||
// Context stage must override Lambda without alias and stream with suffix and default | ||
checkResolveStage('', '1.0.1', '1.01', 'Stream_SS', context, 'CS', t); | ||
// Context stage must override Lambda with alias and default | ||
checkResolveStage('', '1.0.1', 'AS', '', context, 'CS', t); | ||
// Context stage must override Lambda with alias and stream without suffix and default | ||
checkResolveStage('', '1.0.1', 'AS', 'Stream', context, 'CS', t); | ||
// Context stage must override Lambda with alias and stream with suffix and default | ||
checkResolveStage('', '1.0.1', 'AS', 'Stream_SS', context, 'CS', t); | ||
t.end(); | ||
}); | ||
test('resolveStage with context stage and with event stage', t => { | ||
const context = configureResolveStageWithDefaults({}); | ||
context.resolveStageConfig.defaultStage = 'DS'; | ||
context.resolveStageConfig.inCase = ''; | ||
context.stage = 'CS'; | ||
// Context stage must override default stage | ||
checkResolveStage('ES', '', '', '', context, 'CS', t); | ||
// Context stage must override stream without suffix and default | ||
checkResolveStage('ES', '', '', 'Stream', context, 'CS', t); | ||
// Context stage must override stream with suffix and default | ||
checkResolveStage('ES', '', '', 'Stream_SS', context, 'CS', t); | ||
// Context stage must override event stage and Lambda without alias and default | ||
checkResolveStage('ES', '1.0.1', '1.01', '', context, 'CS', t); | ||
// Context stage must override event stage and Lambda without alias and stream without suffix and default | ||
checkResolveStage('ES', '1.0.1', '1.01', 'Stream', context, 'CS', t); | ||
// Context stage must override event stage and Lambda without alias and stream with suffix and default | ||
checkResolveStage('ES', '1.0.1', '1.01', 'Stream_SS', context, 'CS', t); | ||
// Context stage must override event stage and Lambda with alias and default | ||
checkResolveStage('ES', '1.0.1', 'AS', '', context, 'CS', t); | ||
// Context stage must override event stage and Lambda with alias and stream without suffix and default | ||
checkResolveStage('ES', '1.0.1', 'AS', 'Stream', context, 'CS', t); | ||
// Context stage must override event stage and Lambda with alias and stream with suffix and default | ||
checkResolveStage('ES', '1.0.1', 'AS', 'Stream_SS', context, 'CS', t); | ||
t.end(); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
106003
15
1648
1
77
Updatedcore-functions@^1.1.1