Not able to test Stepfunction Execution via Lambda - node.js

I am trying to test my lambda function which invokes Step Function using AWS mock, but it is giving UnknownEndpoint: Inaccessible host: states.local-env.amazonaws.com
Here is my sample lambda function:
const AWS = require("aws-sdk");
const stepFunctions = new AWS.StepFunctions({region: 'local-env'});
exports.handler = async (event, context, config) => {
const response = {
statusCode: 200,
body: event,
};
var params = {
stateMachineArn: process.env.StateMachineARN,
input: JSON.stringify(event.body),
name: 'Testing2'
};
stepFunctions.startExecution(params, function(err, data) {
if (err) console.log(err, err.stack);
});
return response;
};
and there is my test file:
const index = require('./index')
var AWS = require('aws-sdk-mock');
const AWS_SDK = require('aws-sdk');
AWS.mock('StepFunctions', 'startExecution', function (params, callback){
callback(null, "successfully started the execution");
});
const isTest = process.env.JEST_WORKER_ID;
const config = {
convertEmptyValues: true,
...(isTest && {endpoint: 'localhost:8000', sslEnabled: false,region:'local-env'})
};
describe('Test Step Function Invocation', function () {
it('verifies successful response', async () => {
process.env.StateMachineARN = 'arn:aws:states:us-east-1:12345678:stateMachine:Testing';
var event = {
"payload": "my_payload",
"data": "some-data",
"MVId": "00156"
};
const result = await index.handler(event,{},config);
expect(result.statusCode).toEqual(200);
expect(result.body).toBe(event);
});
});
AWS.restore('StepFunctions');
I've been searching about this in the documentation and other resources but haven't found any solutions yet.

Related

sinon stub for lambda function which is inside another lambda

Am writing unit test case for my code, as am calling another lambda function inside my lambda am not sure how to mock the inner lambda value, so because of this my test case is getting timed out. Attaching my code below
Test case file
"use strict";
const sinon = require("sinon");
const AWS = require("aws-sdk");
const expect = require("chai").expect;
const models = require("common-lib").models;
const { Organization } = models;
const DATA_CONSTANTS = require("./data/deleteOrganization");
const wrapper = require("../../admin/deleteOrganization");
const sandbox = sinon.createSandbox();
describe("Start Test updateOrganization", () => {
beforeEach(() => {
sandbox.stub(Organization, "update").resolves([1]);
});
afterEach(async () => {
sandbox.restore();
});
it("Test 03: Test to check success returned by handler", async () => {
const mLambda = {
invoke: sinon.stub().returnsThis(),
promise: sinon.stub(),
};
const response = await wrapper.handler(
DATA_CONSTANTS.API_REQUEST_OBJECT_FOR_200
);
console.log({ response });
expect(response.statusCode).to.be.equal(200);
const body = JSON.parse(response.body);
expect(body.message).to.be.equal("Updated successfully");
});
});
Code function
exports.handler = asyncHandler(async (event) => {
InitLambda("userService-deleteOrganization", event);
const { id } = event.pathParameters;
if (isEmpty(id)) {
return badRequest({
message: userMessages[1021],
});
}
try {
const orgrepo = getRepo(Organization);
const [rowsUpdated] = await orgrepo.update(
{ isDeleted: true },
{ org_id: id }
);
if (!rowsUpdated) {
return notFound({
message: userMessages[1022],
});
}
const lambda = new AWS.Lambda({
region: process.env.region,
});
await lambda
.invoke({
FunctionName:
"user-service-" + process.env.stage + "-deleteOrganizationDetail",
InvocationType: "Event",
Payload: JSON.stringify({
pathParameters: { id },
headers: event.headers,
}),
})
.promise();
return success({
message: userMessages[1023],
});
} catch (err) {
log.error(err);
return failure({
error: err,
message: err.message,
});
}
});
It seems that you are not properly stubbing the AWS.Lambda object.
try this,
const sinon = require("sinon");
const AWS = require("aws-sdk");
const expect = require("chai").expect;
const models = require("common-lib").models;
const { Organization } = models;
const DATA_CONSTANTS = require("./data/deleteOrganization");
const wrapper = require("../../admin/deleteOrganization");
const sandbox = sinon.createSandbox();
describe("Start Test updateOrganization", () => {
beforeEach(() => {
sandbox.stub(Organization, "update").resolves([1]);
});
afterEach(async () => {
sandbox.restore();
});
it("Test 03: Test to check success returned by handler", async () => {
const mLambda = { invoke: sinon.stub().returnsThis(), promise: sinon.stub() };
// you missed the below line
sinon.stub(AWS, 'Lambda').callsFake(() => mLambda);
const response = await wrapper.handler(
DATA_CONSTANTS.API_REQUEST_OBJECT_FOR_200
);
console.log({ response });
expect(response.statusCode).to.be.equal(200);
const body = JSON.parse(response.body);
expect(body.message).to.be.equal("Updated successfully");
sinon.assert.calledOnce(AWS.Lambda);
sinon.assert.calledWith(mLambda.invoke, {});
sinon.assert.calledOnce(mLambda.promise);
});
});
I can see that,
You are writing entire logic inside your handler function. This makes it less testable.
To overcome this you can write your code in such a way that is divided into small functions, which are easy to mock in test case files or testable independently. Handler function should only make call to those functions and return the result to the caller.
for Eg.
Lambda Handler:
exports.lambdaHandler = async (event) => {
// do some init work here
const lambdaInvokeResponse = await exports.invokeLambda(params);
}
exports.invokeLambda = async (params) {
const response = await lambda.invoke(params).promise();
return response;
}
test cases:
it('My Test Case - Success', async () => {
const result = await app.lambdaHandler(event);
const invikeLambdaResponse = {
// some dummy response
};
sinon.replace(app, 'invokeLambda', sinon.fake.returns(invikeLambdaResponse ));
});
This is now mocking the only lambda invoke part.
You can mock all the external calls like this (dynamodb, invoke, sns, etc.)
You can set spy and check if the called method is called as per desired arguments

s3.listObjectsV2 is not a function NodeJs

I've following lambda function for fetching list of all the keys from S3, however, it ends up in error message as s3.listObjectsV2 is not a function. Not sure what's wrong. The code is taken from another SO post, however it doesn't seem to be working.
Code:
const AWS = require('aws-sdk');
var request=true;
const awsOptions = {
region: "us-east-1"
};
const s3 = new AWS.S3(awsOptions);
exports.handler = async (event, context, callback) => {
const SrcBucket = event.Records[0].s3.bucket.name;
const trigger_file = event.Records[0].s3.object.key;
var bucketParams = {
Bucket: SrcBucket,
Prefix: 'Temp/',
};
var allKeys = [];
listAllKeys();
function listAllKeys()
{
s3.listObjectsV2(bucketParams, function (err, data)
{
if (err)
{
console.log(err, err.stack); // an error occurred
}
else
{
var contents = data.Contents;
contents.forEach(function (content) {
allKeys.push(content.Key);
});
if (data.IsTruncated) {
bucketParams.ContinuationToken = data.NextContinuationToken;
console.log("get further list...");
listAllKeys();
}
}
});
}
console.log(allKeys.length);
}

context.hasRole is not a function in Nodejs sinon testing issue

I had made function to fetch cloudwatch details from AWS.I trying to create a testcase in node.js and using sinon but i am getting a context.hasRole is not defined because i am checking this in my function file which is cloudwatch.js.
Can you please help me to fake this test
"-----cloudwatch.spec.js-------"
describe('cloudwatch', () => {
let sandbox = null;
beforeEach(() => {
sandbox = sinon.createSandbox(AWS.config);
})
afterEach(() => {
sandbox.restore()
})
it('Should return queryid', async () => {
let queryId = {
queryId: "12ab3456-12ab-123a-789e-1234567890ab"
};
const body = {
endTime: 34568765,
queryString: 'filter #message like /Audit/',
startTime: 34565678,
limit: 100,
logGroupName: '/aws/lambda/dev-api--service-sandbox-api'
};
let params = {}
let queryid = {
queryId: 6786971301298309123
};
await cloudwatch.startQuery(context, params, body, callback);
sinon.match(queryId)
})
})
"------Cloudwatch.js----"
let cloudwatch = module.exports = {};
const AWS = require('aws-sdk');
const nconf = require('nconf');
const {
HttpResult,
HttpUnauthorizedError,
AmazonCloudWatchLogsClient
} = require('api-lib');
AWS.config = nconf.get('amazonCloudWatchLogsClient');
cloudwatch.startQuery = async function(context, params, body,
callback) {
body.startTime = new Date(body.startTime).valueOf();
body.endTime = new Date(body.endTime).valueOf();
if (!context.hasRole("read:cloudwatch"))
return callback(new HttpUnauthorizedError("context missing role
read:cloudwatch"));
const amazonCloudWatchLogsClient = new
AmazonCloudWatchLogsClient(AWS.config);
let result = await amazonCloudWatchLogsClient.startQuery(body,
function(err) {
console.log("Error", err);
});
callback(null, new HttpResult(result));
};
cloudwatch.getQueryResults = async function(context, params,
requestBody, callback) {
console.log(requestBody)
let test = requestBody.queryId;
test = test.toString();
requestBody.queryId = test;
if (!context.hasRole("read:cloudwatch"))
return callback(new HttpUnauthorizedError("context missing role
read:cloudwatch"));
const amazonCloudWatchLogsClient = new
AmazonCloudWatchLogsClient(AWS.config);
let result2 = await
amazonCloudWatchLogsClient.getQueryResults(requestBody.queryId,
function(err) {
console.log("Error", err);
});
callback(null, new HttpResult(result2));
};
I am using eslint and except from chai for comparing the output to the sample output.

AWS Lambda using s3 getObject function and putItem function to insert it into DynamoDB but nothing happens

this is the node.js code:
'use strict';
const AWS = require("aws-sdk");
AWS.config.update({
region: 'eu-west-1'});
const docClient = new AWS.DynamoDB.DocumentClient();
const tableName = 'Fair';
const s3 = new AWS.S3();
exports.handler = async (event) => {
var getParams = {
Bucket: 'dataforfair', //s3 bucket name
Key: 'fairData.json' //s3 file location
}
const data = await s3.getObject(getParams).promise()
.then( (data) => {
//parse JSON
let fairInformations = JSON.parse(data.Body.toString());
fairInformations.forEach(function(fairInformationEntry) {
console.log(fairInformationEntry);
var params = {
TableName: tableName,
Item: {
"year": fairInformationEntry.year,
"fairName": fairInformationEntry.fairName,
"info": fairInformationEntry.info
}
};
docClient.put(params, function(err, data) {
console.log('*****test');
if (err) {
console.error("Unable to add fairInformation", fairInformationEntry.fairName, ". Error JSON:", JSON.stringify(err, null, 2));
} else {
console.log("PutItem succeeded:", fairInformationEntry.fairName);
}
});
});
})
.catch((err) => {
console.log(err);
});
const response = {
statusCode: 200,
body: JSON.stringify(data),
};
return response;
};
Hello everyone,
I want to put the data into the Dynamo DB after getting the JSON file from the s3 Bucket. Getting the JSON works and the console.log(fairInformationEntry); is also still triggered, but the docClient.put() never gets called. I am getting no error, nothing. I do not know what is wrong and why it is not working. I have the right IAM role and access to everything I need.
I hope you can help me!
The problem is mixup of promise, callback and async/await. You are also trying to do asynchronous operation inside foreach. The code should look something like this
"use strict";
const AWS = require("aws-sdk");
AWS.config.update({
region: "eu-west-1"
});
const docClient = new AWS.DynamoDB.DocumentClient();
const tableName = "Fair";
const s3 = new AWS.S3();
exports.handler = async event => {
var getParams = {
Bucket: "dataforfair", //s3 bucket name
Key: "fairData.json" //s3 file location
};
const data = await s3.getObject(getParams).promise();
//parse JSON
let fairInformations = JSON.parse(data.Body.toString());
await Promise.all(
fairInformations.map(fairInformationEntry => {
console.log(fairInformationEntry);
var params = {
TableName: tableName,
Item: {
year: fairInformationEntry.year,
fairName: fairInformationEntry.fairName,
info: fairInformationEntry.info
}
};
return docClient.put(params).promise();
})
);
const response = {
statusCode: 200,
body: JSON.stringify(data)
};
return response;
};
Hope this helps

Unable to access dynamodb from nodejs code through lambda

I have been trying to test this from lambda but unable to proceed.
var Alexa = require("alexa-sdk");
var dynamoDBConfiguration = {
"accessKeyId": "useraccess",
"secretAccessKey": "usersecretkey",
"region": "us-east-1"
};
var AWS = require("aws-sdk");
AWS.config.update(dynamoDBConfiguration);
var promisify = require("es6-promisify");
var dynClient = new AWS.DynamoDB.DocumentClient({"region":"us-east-
1"});
//convert callback style functions to promises
const dbGet = promisify(dynClient.get,dynClient);
const dbPut = promisify(dynClient.put,dynClient);
const dbDelete = promisify(dynClient.delete,dynClient);
var startStateHandlers = (GAME_STATES.STARt, {
"StartGame": function (isNewGame,context) {
const dynamoParams = {
TableName: "Userdata",
Key: {
"UserId":"test"
}
}
dbGet(dynamoParams)
.then(data => {
console.log('Get user succeeded', data);
const userId = data.UserId;
if (userId != null) {
console.log(data.UserName);
}
else {
// no match, add the user
return dbPut(dynamoParams);
}
})
.then(data => {
console.log('Add user succeeded', data);
})
.catch(err => {
console.error(err);
});
this.emit(":tell", speechOutput, speechOutput);
}
});
var handlers = {
"LaunchRequest": function () {
var speechOutput = "hello";
this.emit(":tell", speechOutput, speechOutput);
}
};
var handler = (function () {
function handler(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = "appid";
alexa.registerHandlers(handlers, startStateHandlers);
alexa.execute();
}
return handler;
})();
exports.handler = handler;
It doesnt throw any error in the lamda logs and not able to see any log in Cloudwatch. It just executes the other lines of code.
I have attached all permission policy to the user and setup the lamda function as lambda_dynamo.
Unable to understand what is the issue with it.
Appreciate your help.
var dynamoDBConfiguration = {
"accessKeyId": "useraccess",
"secretAccessKey": "usersecretkey",
"region": "us-east-1"
};
var AWS = require("aws-sdk");
// update the AWS.Config global configuration object
AWS.config.update(dynamoDBConfiguration)
// Create DynamoDB document client
var dynClient = new AWS.DynamoDB.DocumentClient()

Resources