You're Invited:Meet the Socket Team at BlackHat and DEF CON in Las Vegas, Aug 4-6.RSVP
Socket
Book a DemoInstallSign in
Socket

lambda-tester

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

lambda-tester - npm Package Compare versions

Comparing version

to
2.3.0

docs/main.md

@@ -0,1 +1,12 @@

## 2.3.0 (TBD)
New:
* Automatically loads `.env` files when `lambda-tester` is loaded during `require()`.
* Handlers can be loaded and cleaned up after execution
Updated:
* Leak detector moved to `lambda-leak` and included as a dependency. Still experimental status
## 2.2.1 (2016-04-17)

@@ -2,0 +13,0 @@

162

lib/index.js
'use strict';
const handleState = require( './handle_state' );
const lambdaLeak = require( 'lambda-leak' );

@@ -9,2 +9,3 @@ const DEFAULT_TIMEOUT = 3000; // s3

function createContext( tester ) {

@@ -97,19 +98,2 @@

function addLegecyVerify( promise ) {
promise.verify = function( done ) {
return promise.then(
function() {
done();
},
function( err ) {
done( err );
}
);
}
}
function verifyResult( tester, result, verifier, resolve, reject, savedHandleState ) {

@@ -147,2 +131,70 @@

function resolveHandler( tester ) {
return new Promise( function( resolve, reject ) {
try {
if( tester._loadHandler ) {
tester._handler = tester._loadHandler()
}
if( !tester._handler ) {
throw new Error( 'no handler specified or returned from loadHandler()' );
}
resolve( tester._handler );
}
catch( err ) {
reject( err );
}
});
}
function addLegecyVerify( promise ) {
promise.verify = function( done ) {
return promise.then(
function() {
done();
},
function( err ) {
done( err );
}
);
}
}
function addCleanup( promise, tester ) {
let afterFunc = tester._afterFunc;
if( !afterFunc ) {
afterFunc = function() {};
}
promise.then(
function( result ) {
afterFunc( result, true );
return result;
},
function( err ) {
afterFunc( err, false );
return Promise.reject( err );
}
);
}
class LambdaTester {

@@ -152,4 +204,7 @@

this._handler = handler;
if( handler ) {
this._handler = handler;
}
this._event = {};

@@ -160,2 +215,16 @@

loadHandler( loaderFunc ) {
this._loadHandler = loaderFunc;
return this;
}
after( afterFunc ) {
this._afterFunc = afterFunc;
return this;
}
event( evt ) {

@@ -192,6 +261,6 @@

let succeedPromise = Promise.resolve()
let promise = resolveHandler( this )
.then( function() {
let savedHandleState = handleState.capture();
let savedHandleState = lambdaLeak.capture();

@@ -212,3 +281,3 @@ // need to do a nested promise because mocha injects a timer between the start of the

var failError = new Error( 'encountered error but expected the handler to succeed' );
var failError = new Error( 'encountered error but expected the handler to succeed - cause: ' + err.message );
failError.cause = err;

@@ -228,5 +297,7 @@

// support for v1 users
addLegecyVerify( succeedPromise );
addLegecyVerify( promise );
return succeedPromise;
addCleanup( promise, this );
return promise;
}

@@ -245,6 +316,6 @@

let failPromise = Promise.resolve()
let promise = resolveHandler( this )
.then( function() {
let savedHandleState = handleState.capture();
let savedHandleState = lambdaLeak.capture();

@@ -262,3 +333,3 @@ // need to do a nested promise because mocha injects a timer between the start of the

var failError = new Error( 'encountered successful operation but expected failure' );
var failError = new Error( 'encountered successful operation but expected failure - result: ' + result );
failError.result = result;

@@ -278,5 +349,7 @@

// support for v1 users
addLegecyVerify( failPromise );
addLegecyVerify( promise );
return failPromise;
addCleanup( promise, this );
return promise;
}

@@ -293,3 +366,3 @@

return Promise.resolve()
let promise = resolveHandler( this )
.then( function() {

@@ -299,3 +372,3 @@

// promise and .then()
let savedHandleState = handleState.capture();
let savedHandleState = lambdaLeak.capture();

@@ -315,3 +388,3 @@ return new Promise( function( resolve, reject ) {

let failError = new Error( 'expecting error' );
let failError = new Error( 'expecting error but got result: ' + result );
failError.result = result;

@@ -325,2 +398,6 @@

});
addCleanup( promise, this );
return promise;
}

@@ -337,3 +414,3 @@

return Promise.resolve()
let promise = resolveHandler( this )
.then( function() {

@@ -343,3 +420,3 @@

// promise and .then()
let savedHandleState = handleState.capture();
let savedHandleState = lambdaLeak.capture();

@@ -356,3 +433,3 @@ return new Promise( function( resolve, reject ) {

let failError = new Error( 'expecting result' );
let failError = new Error( 'expecting result but error was thrown - cause: ' + err.message );
failError.cause = err;

@@ -369,2 +446,6 @@

});
addCleanup( promise, this );
return promise;
}

@@ -375,7 +456,2 @@ }

if( !handler ) {
throw new Error( 'missing handler' );
}
return new LambdaTester( handler );

@@ -392,2 +468,8 @@ }

if( !process.env.LAMBDA_TESTER_NO_ENV ) {
// configure env varaiables
require( 'dotenv' ).config( { silent: true } );
}
module.exports = LambdaTesterModule;
{
"name": "lambda-tester",
"version": "2.2.1",
"version": "2.3.0",
"description": "Unit/Integration tests for AWS Lambda handlers",
"main": "index.js",
"main": "lib/index.js",
"keywords": [

@@ -16,3 +16,5 @@ "AWS",

"integration testing",
"serverless"
"serverless",
"environment",
"variables"
],

@@ -34,2 +36,3 @@ "engines": {

"chai": "^3.5.0",
"freshy": "^1.0.2",
"istanbul": "^0.4.2",

@@ -40,4 +43,6 @@ "mocha": "^2.4.5",

"dependencies": {
"app-root-path": "^1.0.0"
"app-root-path": "^1.0.0",
"dotenv": "^2.0.0",
"lambda-leak": "^1.0.0"
}
}

@@ -13,4 +13,6 @@ [![Build Status](https://travis-ci.org/vandium-io/lambda-tester.svg?branch=master)](https://travis-ci.org/vandium-io/lambda-tester)

* Easily integrates with test frameworks
* Handlers can be loaded and removed after execution
* Lightweight and won't impact performance
* Maps the environment variable `LAMBDA_TASK_ROOT` to the application's root
* Automatically loads .env files
* Works with Node 4.3.2+

@@ -76,249 +78,10 @@

## Documentation
## Verifying Callbacks
Complete documentation can be found in our [documentation](docs/main.md) page.
## Projects Using `lambda-tester`
To verify that `callback( null, result )` was called:
* [vandium](https://github.com/vandium-io/vandium-node) - Secures and simplifies AWS Lambda handlers
```js
const LambdaTester = require( 'lambda-tester' );
// your favorite validation tool here
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
describe( 'handler', function() {
it( 'test callback( null, result )', function() {
return LambdaTester( myHandler )
.event( { name: 'Fred' } )
.expectResult( function( result ) {
expect( result.userId ).to.exist;
expect( result.user ).to.equal( 'fredsmith' );
});
});
});
```
To verify that `callback( err )` was called:
```js
const LambdaTester = require( 'lambda-tester' );
// your favorite validation tool here
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
describe( 'handler', function() {
it( 'test callback( err )', function() {
return LambdaTester( myHandler )
.event( { name: 'Unknown' } )
.expectError( function( err ) {
expect( err.message ).to.equal( 'User not found' );
});
});
});
```
## Detecting Handlers than Run for Too Long
For Lambda handlers that must run within a specific time period, you can specify a timeout value. This value will not stop execution of your code, but will detect an error condition.
To use the timeout feature, specify a timeout value in seconds using `timeout()` as in the example below:
```js
const LambdaTester = require( 'lambda-tester' );
// your favorite validation tool here
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
describe( 'handler', function() {
it( 'test callback( null, result )', function() {
return LambdaTester( myHandler )
.event( { name: 'Fred' } )
.timeout( 1 /* fail if longer than 1 second */ )
.expectResult( function( result ) {
expect( result.userId ).to.exist;
expect( result.user ).to.equal( 'fredsmith' );
});
});
});
```
## Verifying `context.succeed()`, `context.fail` and `context.done()`
On April 8, 2016 AWS Lambda introduced support for Lambda callbacks that replace the need to call `context.fail()` or `context.succeed()`.
### Verifying `context.succeed()`
When `expectSucceed()` is called, one can pass a function to perform additional validation. For example:
```js
const LambdaTester = require( 'lambda-tester' );
// your favorite validation tool here
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
describe( 'handler', function() {
it( 'test success', function() {
return LambdaTester( myHandler )
.event( { name: 'Fred' } )
.expectSucceed( function( result ) {
expect( result.userId ).to.exist;
expect( result.user ).to.equal( 'fredsmith' );
});
});
});
```
### Verifying `context.fail()`
As with verifying success, `expectFail` has an optional parameter that can specify a function that will verify the error condition. For example:
```js
const LambdaTester = require( 'lambda-tester' );
// your favorite validation tool here
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
describe( 'handler', function() {
it( 'test failure', function() {
return LambdaTester( myHandler )
.event( { name: 'Unknown' } )
.expectFail( function( err ) {
expect( err.message ).to.equal( 'User not found' );
});
});
});
```
### Verifying `context.done()`
AWS Lambda routes `context.done()` to `context.succed()` and `context.fail()` for results or errors respectively, thus you can use the methods described above to verify those scenarios.
## Resource Leak detection
**Note**: This feature is experimental and disabled by default.
Resource leaks (i.e. streams and other callback events like timers) can be detected and reported. Timers or streams than continue to be active post `callback()` will cause the Lambda handler to execute in the AWS environment until a timeout condition is reached.
To enable leak detection:
```js
const LambdaTester = require( 'lambda-tester' );
LambdaTester.checkForResourceLeak( true );
```
When a leak is caught, it will cause an exception to be thrown on. For example, the following code will cause a timer to live past the callback:
```js
const LambdaTester = require( 'lambda-tester' );
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
LambdaTester.checkForResourceLeak( true );
describe( 'handler', function() {
it( 'test callback( null, result )', function() {
return LambdaTester( function( event, context, callback ) {
setTimeout( function() {}, 100 );
callback( null, 'ok' );
})
.expectResult( function( result ) {
// will never get here
});
});
});
```
Examining the exception thrown will indicate a leak was detected and the handles for the resources that are still open:
```js
{ [Error: Potential handle leakage detected]
handles:
[ Timer {
'0': [Function: listOnTimeout],
_idleNext: [Object],
_idlePrev: [Object],
msecs: 100 } ] }
```
If you are adding leak detection as one of your unit tests, then the previous code should be changed to:
```js
const LambdaTester = require( 'lambda-tester' );
const expect = require( 'chai' ).expect;
const myHandler = require( '../index' ).handler;
LambdaTester.checkForResourceLeak( true );
describe( 'handler', function() {
it( 'test callback( null, result )', function() {
return LambdaTester( function( event, context, callback ) {
setTimeout( function() {}, 100 );
callback( null, 'ok' );
})
.expectResult( function( result ) {
throw new Error( 'should not produce a result' );
})
.catch( function( err ) {
/* err will be:
{ [Error: Potential handle leakage detected]
handles:
[ Timer {
'0': [Function: listOnTimeout],
_idleNext: [Object],
_idlePrev: [Object],
msecs: 100 } ] }
*/
expect( err.message ).to.contain( 'Potential handle leakage detected' );
// TODO: add further validation here
});
});
});
```
## Feedback

@@ -328,3 +91,2 @@

## Compatibility

@@ -338,26 +100,1 @@

[BSD-3-Clause](https://en.wikipedia.org/wiki/BSD_licenses)
Copyright (c) 2016, Vandium Software Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Vandium Software Inc. nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.