Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
language: node_js
node_js:
- '10'
- '8'
- '6'
- '4'
- 'lts/erbium'
- 'lts/dubnium'
10 changes: 7 additions & 3 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@ interface ContextOptions {
timeout?: number;
}

declare var mockContext: {
(options?: ContextOptions): Context;
};
interface MockContext extends Context {
Promise: Promise<any>;
}

type MockInitialize = (options?: ContextOptions) => MockContext;

declare const mockContext: MockInitialize;

export = mockContext;
54 changes: 33 additions & 21 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
'use strict';
const uuid = require('uuid');
const moment = require('moment');
const uuidv1 = require('uuid/v1');
const uuidv4 = require('uuid/v4');
const defer = require('pinkie-defer');
const pkg = require('./package.json');

module.exports = options => {
const id = uuid.v1();
const stream = uuid.v4().replace(/-/g, '');
const mockContext = userOptions => {
const id = uuidv1();
const stream = uuidv4().replace(/-/g, '');

const opts = Object.assign({
const options = {
region: 'us-west-1',
account: '123456789012',
functionName: pkg.name,
functionVersion: '$LATEST',
memoryLimitInMB: '128',
timeout: 3
}, options);
timeout: 3,
...userOptions
};

const deferred = defer();

const start = Date.now();
const d = new Date();
const logDateString = [
d.getFullYear(),
('0' + (d.getMonth() + 1)).slice(-2),
('0' + d.getDate()).slice(-2)
].join('/');
const start = d.getTime();
let end;

let timeout = null;
const context = {
callbackWaitsForEmptyEventLoop: true,
functionName: opts.functionName,
functionVersion: opts.functionVersion,
invokedFunctionArn: `arn:aws:lambda:${opts.region}:${opts.account}:function:${opts.functionName}:${opts.alias || opts.functionVersion}`,
memoryLimitInMB: opts.memoryLimitInMB,
functionName: options.functionName,
functionVersion: options.functionVersion,
invokedFunctionArn: `arn:aws:lambda:${options.region}:${options.account}:function:${options.functionName}:${options.alias || options.functionVersion}`,
memoryLimitInMB: options.memoryLimitInMB,
awsRequestId: id,
invokeid: id,
logGroupName: `/aws/lambda/${opts.functionName}`,
logStreamName: `${moment().format('YYYY/MM/DD')}/[${opts.functionVersion}]/${stream}`,
logGroupName: `/aws/lambda/${options.functionName}`,
logStreamName: `${logDateString}/[${options.functionVersion}]/${stream}`,
getRemainingTimeInMillis: () => {
const endTime = end || Date.now();
const remainingTime = (opts.timeout * 1000) - (endTime - start);
const remainingTime = (options.timeout * 1000) - (endTime - start);

return Math.max(0, remainingTime);
},
Expand All @@ -53,6 +59,10 @@ module.exports = options => {
deferred.reject(err);
},
done: (err, result) => {
if (timeout) {
clearTimeout(timeout);
}

if (err) {
context.fail(err);
return;
Expand All @@ -63,11 +73,13 @@ module.exports = options => {
Promise: new Promise(deferred)
};

setTimeout(() => {
timeout = setTimeout(() => {
if (context.getRemainingTimeInMillis() === 0) {
context.fail(new Error(`Task timed out after ${opts.timeout}.00 seconds`));
context.fail(new Error(`Task timed out after ${options.timeout}.00 seconds`));
}
}, opts.timeout * 1000);
}, options.timeout * 1000);

return context;
};

module.exports = mockContext;
22 changes: 13 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aws-lambda-mock-context",
"version": "3.2.1",
"version": "4.0.0",
"description": "AWS Lambda mock context object",
"license": "MIT",
"author": {
Expand All @@ -9,11 +9,16 @@
"url": "https://github.com/SamVerschueren"
},
"engines": {
"node": ">=4"
"node": ">=10.18.0"
},
"scripts": {
"test": "xo && ava"
},
"ava": {
"require": [
"esm"
]
},
"files": [
"index.js",
"index.d.ts"
Expand All @@ -29,16 +34,15 @@
"promise"
],
"dependencies": {
"moment": "^2.10.5",
"pinkie-defer": "^1.0.0",
"uuid": "^3.0.1"
"uuid": "3.4.0"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.7",
"ava": "*",
"delay": "^2.0.0",
"in-range": "^1.0.0",
"xo": "^0.20.3"
"@types/aws-lambda": "^8.10.46",
"ava": "^3.5.1",
"delay": "^4.3.0",
"in-range": "^2.0.0",
"xo": "^0.28.1"
},
"types": "index.d.ts"
}
35 changes: 18 additions & 17 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import test from 'ava';
import delay from 'delay';
import inRange from 'in-range';
import m from '.';
const test = require('ava');
const delay = require('delay');
const inRange = require('in-range');
const m = require('.');

function invokeAsync(method, result, opts) {
opts = Object.assign({
const invokeAsync = (method, result, options) => {
options = {
ms: 500,
timeout: 3
}, opts);
timeout: 3,
...options
};

const ctx = m({
timeout: opts.timeout
timeout: options.timeout
});

setTimeout(() => {
Expand All @@ -20,20 +21,20 @@ function invokeAsync(method, result, opts) {
}

ctx[method](result);
}, opts.ms);
}, options.ms);

return ctx.Promise;
}
};

test('succeed', async t => {
t.is(await invokeAsync('succeed', 'baz'), 'baz');
t.is(await invokeAsync('done', [undefined, 'baz']), 'baz');
});

test('fail', async t => {
await t.throws(invokeAsync('fail', 'promise fail'), 'promise fail');
await t.throws(invokeAsync('fail', new Error('promise fail')), 'promise fail');
await t.throws(invokeAsync('done', new Error('promise fail')), 'promise fail');
await t.throwsAsync(invokeAsync('fail', 'promise fail'), null, 'promise fail');
await t.throwsAsync(invokeAsync('fail', new Error('promise fail')), null, 'promise fail');
await t.throwsAsync(invokeAsync('done', new Error('promise fail')), null, 'promise fail');
});

test('result', t => {
Expand Down Expand Up @@ -74,7 +75,7 @@ test('remaining time', async t => {

const ms = ctx.getRemainingTimeInMillis();

t.true(inRange(ctx.getRemainingTimeInMillis(), 1950, 2050));
t.true(inRange(ctx.getRemainingTimeInMillis(), {start: 1950, end: 2050}));

await delay(10);

Expand All @@ -96,10 +97,10 @@ test('set function timeout', async t => {

await delay(1000);

t.true(inRange(ctx.getRemainingTimeInMillis(), 8950, 9050));
t.true(inRange(ctx.getRemainingTimeInMillis(), {start: 8950, end: 9050}));
ctx.succeed();
});

test('timeout throws error', async t => {
await t.throws(invokeAsync('succeed', 'foo', {ms: 2000, timeout: 1}), 'Task timed out after 1.00 seconds');
await t.throwsAsync(invokeAsync('succeed', 'foo', {ms: 2000, timeout: 1}), null, 'Task timed out after 1.00 seconds');
});