Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
aws-sdk-mock
Advanced tools
The aws-sdk-mock npm package is a tool for mocking AWS SDK methods for unit testing purposes. It allows developers to simulate AWS service responses and behaviors without making actual calls to AWS services, which can save time and cost during development and testing.
Mocking AWS SDK Methods
This feature allows you to mock specific methods of AWS services. In this example, the `getObject` method of the S3 service is mocked to return 'mocked data' instead of making an actual call to AWS.
const AWS = require('aws-sdk');
const AWSMock = require('aws-sdk-mock');
AWSMock.mock('S3', 'getObject', (params, callback) => {
callback(null, { Body: 'mocked data' });
});
const s3 = new AWS.S3();
s3.getObject({ Bucket: 'example-bucket', Key: 'example-key' }, (err, data) => {
if (err) console.log(err);
else console.log(data.Body.toString()); // Output: mocked data
});
AWSMock.restore('S3');
Restoring Mocked Methods
This feature allows you to restore the original AWS SDK methods after they have been mocked. In this example, the `putItem` method of the DynamoDB service is mocked and then restored to its original state.
const AWS = require('aws-sdk');
const AWSMock = require('aws-sdk-mock');
AWSMock.mock('DynamoDB', 'putItem', (params, callback) => {
callback(null, { Attributes: { id: { S: '123' } } });
});
const dynamoDB = new AWS.DynamoDB();
dynamoDB.putItem({ TableName: 'example-table', Item: { id: { S: '123' } } }, (err, data) => {
if (err) console.log(err);
else console.log(data.Attributes); // Output: { id: { S: '123' } }
});
AWSMock.restore('DynamoDB');
Mocking Multiple Methods
This feature allows you to mock multiple methods of the same AWS service. In this example, both the `putObject` and `deleteObject` methods of the S3 service are mocked.
const AWS = require('aws-sdk');
const AWSMock = require('aws-sdk-mock');
AWSMock.mock('S3', 'putObject', (params, callback) => {
callback(null, { ETag: '"mocked-etag"' });
});
AWSMock.mock('S3', 'deleteObject', (params, callback) => {
callback(null, { DeleteMarker: true });
});
const s3 = new AWS.S3();
s3.putObject({ Bucket: 'example-bucket', Key: 'example-key', Body: 'data' }, (err, data) => {
if (err) console.log(err);
else console.log(data.ETag); // Output: "mocked-etag"
});
s3.deleteObject({ Bucket: 'example-bucket', Key: 'example-key' }, (err, data) => {
if (err) console.log(err);
else console.log(data.DeleteMarker); // Output: true
});
AWSMock.restore('S3');
Sinon is a popular JavaScript library for creating spies, stubs, and mocks. It can be used to mock AWS SDK methods, but it requires more manual setup compared to aws-sdk-mock. Sinon is more general-purpose and can be used to mock any JavaScript function, not just AWS SDK methods.
Jest is a JavaScript testing framework that includes built-in mocking capabilities. It can be used to mock AWS SDK methods, but like Sinon, it requires more manual setup. Jest is a comprehensive testing solution that includes test runners, assertion libraries, and mocking capabilities.
Nock is an HTTP mocking and expectations library for Node.js. It can be used to intercept and mock HTTP requests made by the AWS SDK. Nock is useful for testing HTTP interactions, but it operates at a lower level compared to aws-sdk-mock, which directly mocks AWS SDK methods.
This module was created to help test AWS Lambda functions but can be used in any situation where the AWS SDK needs to be mocked.
This library is best suited for AWS SDK for Javascript (v2)
- see the introductory post on the AWS blog for more context.
If you are using AWS SDK v3
you might not need this library, see:
aws-sdk-mock/issues#209
If you are new to Amazon WebServices Lambda
(or need a refresher),
please checkout our our
Beginners Guide to AWS Lambda:
https://github.com/dwyl/learn-aws-lambda
Testing your code is essential everywhere you need reliability.
Using stubs means you can prevent a specific method from being called directly. In our case we want to prevent the actual AWS services to be called while testing functions that use the AWS SDK.
Uses Sinon.js under the hood to mock the AWS SDK services and their associated methods.
AWS.mock(service, method, replace)
Replaces a method on an AWS service with a replacement function or string.
Param | Type | Optional/Required | Description |
---|---|---|---|
service | string | Required | AWS service to mock e.g. SNS, DynamoDB, S3 |
method | string | Required | method on AWS service to mock e.g. 'publish' (for SNS), 'putItem' for 'DynamoDB' |
replace | string or function | Required | A string or function to replace the method |
AWS.restore(service, method)
Removes the mock to restore the specified AWS service
Param | Type | Optional/Required | Description |
---|---|---|---|
service | string | Optional | AWS service to restore - If only the service is specified, all the methods are restored |
method | string | Optional | Method on AWS service to restore |
If AWS.restore
is called without arguments (AWS.restore()
) then all the services and their associated methods are restored
i.e. equivalent to a 'restore all' function.
AWS.remock(service, method, replace)
Updates the replace
method on an existing mocked service.
Param | Type | Optional/Required | Description |
---|---|---|---|
service | string | Required | AWS service to mock e.g. SNS, DynamoDB, S3 |
method | string | Required | method on AWS service to mock e.g. 'publish' (for SNS), 'putItem' for 'DynamoDB' |
replace | string or function | Required | A string or function to replace the method |
AWS.setSDK(path)
Explicitly set the require path for the aws-sdk
Param | Type | Optional/Required | Description |
---|---|---|---|
path | string | Required | Path to a nested AWS SDK node module |
AWS.setSDKInstance(sdk)
Explicitly set the aws-sdk
instance to use
Param | Type | Optional/Required | Description |
---|---|---|---|
sdk | object | Required | The AWS SDK object |
aws-sdk-mock
from NPMnpm install aws-sdk-mock --save-dev
const AWS = require('aws-sdk-mock');
AWS.mock('DynamoDB', 'putItem', function (params, callback){
callback(null, 'successfully put item in database');
});
AWS.mock('SNS', 'publish', 'test-message');
// S3 getObject mock - return a Buffer object with file data
AWS.mock('S3', 'getObject', Buffer.from(require('fs').readFileSync('testFile.csv')));
/**
TESTS
**/
AWS.restore('SNS', 'publish');
AWS.restore('DynamoDB');
AWS.restore('S3');
// or AWS.restore(); this will restore all the methods and services
import AWSMock from 'aws-sdk-mock';
import AWS from 'aws-sdk';
import { GetItemInput } from 'aws-sdk/clients/dynamodb';
beforeAll(async (done) => {
//get requires env vars
done();
});
describe('the module', () => {
/**
TESTS below here
**/
it('should mock getItem from DynamoDB', async () => {
// Overwriting DynamoDB.getItem()
AWSMock.setSDKInstance(AWS);
AWSMock.mock('DynamoDB', 'getItem', (params: GetItemInput, callback: Function) => {
console.log('DynamoDB', 'getItem', 'mock called');
callback(null, {pk: 'foo', sk: 'bar'});
})
const input:GetItemInput = { TableName: '', Key: {} };
const dynamodb = new AWS.DynamoDB({apiVersion: '2012-08-10'});
expect(await dynamodb.getItem(input).promise()).toStrictEqual({ pk: 'foo', sk: 'bar' });
AWSMock.restore('DynamoDB');
});
it('should mock reading from DocumentClient', async () => {
// Overwriting DynamoDB.DocumentClient.get()
AWSMock.setSDKInstance(AWS);
AWSMock.mock('DynamoDB.DocumentClient', 'get', (params: GetItemInput, callback: Function) => {
console.log('DynamoDB.DocumentClient', 'get', 'mock called');
callback(null, {pk: 'foo', sk: 'bar'});
});
const input:GetItemInput = { TableName: '', Key: {} };
const client = new AWS.DynamoDB.DocumentClient({apiVersion: '2012-08-10'});
expect(await client.get(input).promise()).toStrictEqual({ pk: 'foo', sk: 'bar' });
AWSMock.restore('DynamoDB.DocumentClient');
});
});
You can also pass Sinon spies to the mock:
const updateTableSpy = sinon.spy();
AWS.mock('DynamoDB', 'updateTable', updateTableSpy);
// Object under test
myDynamoManager.scaleDownTable();
// Assert on your Sinon spy as normal
assert.isTrue(updateTableSpy.calledOnce, 'should update dynamo table via AWS SDK');
const expectedParams = {
TableName: 'testTableName',
ProvisionedThroughput: {
ReadCapacityUnits: 1,
WriteCapacityUnits: 1
}
};
assert.isTrue(updateTableSpy.calledWith(expectedParams), 'should pass correct parameters');
NB: The AWS Service needs to be initialised inside the function being tested in order for the SDK method to be mocked e.g for an AWS Lambda function example 1 will cause an error ConfigError: Missing region in config
whereas in example 2 the sdk will be successfully mocked.
Example 1:
const AWS = require('aws-sdk');
const sns = AWS.SNS();
const dynamoDb = AWS.DynamoDB();
exports.handler = function(event, context) {
// do something with the services e.g. sns.publish
}
Example 2:
const AWS = require('aws-sdk');
exports.handler = function(event, context) {
const sns = AWS.SNS();
const dynamoDb = AWS.DynamoDB();
// do something with the services e.g. sns.publish
}
Also note that if you initialise an AWS service inside a callback from an async function inside the handler function, that won't work either.
Example 1 (won't work):
exports.handler = function(event, context) {
someAsyncFunction(() => {
const sns = AWS.SNS();
const dynamoDb = AWS.DynamoDB();
// do something with the services e.g. sns.publish
});
}
Example 2 (will work):
exports.handler = function(event, context) {
const sns = AWS.SNS();
const dynamoDb = AWS.DynamoDB();
someAsyncFunction(() => {
// do something with the services e.g. sns.publish
});
}
It is possible to mock nested services like DynamoDB.DocumentClient
. Simply use this dot-notation name as the service
parameter to the mock()
and restore()
methods:
AWS.mock('DynamoDB.DocumentClient', 'get', function(params, callback) {
callback(null, {Item: {Key: 'Value'}});
});
NB: Use caution when mocking both a nested service and its parent service. The nested service should be mocked before and restored after its parent:
// OK
AWS.mock('DynamoDB.DocumentClient', 'get', 'message');
AWS.mock('DynamoDB', 'describeTable', 'message');
AWS.restore('DynamoDB');
AWS.restore('DynamoDB.DocumentClient');
// Not OK
AWS.mock('DynamoDB', 'describeTable', 'message');
AWS.mock('DynamoDB.DocumentClient', 'get', 'message');
// Not OK
AWS.restore('DynamoDB.DocumentClient');
AWS.restore('DynamoDB');
Some constructors of the aws-sdk will require you to pass through a configuration object.
const csd = new AWS.CloudSearchDomain({
endpoint: 'your.end.point',
region: 'eu-west'
});
Most mocking solutions with throw an InvalidEndpoint: AWS.CloudSearchDomain requires an explicit 'endpoint' configuration option
when you try to mock this.
aws-sdk-mock will take care of this during mock creation so you won't get any configuration errors!
If configurations errors still occur it means you passed wrong configuration in your implementation.
aws-sdk
module explicitlyProject structures that don't include the aws-sdk
at the top level node_modules
project folder will not be properly mocked. An example of this would be installing the aws-sdk
in a nested project directory. You can get around this by explicitly setting the path to a nested aws-sdk
module using setSDK()
.
Example:
const path = require('path');
const AWS = require('aws-sdk-mock');
AWS.setSDK(path.resolve('../../functions/foo/node_modules/aws-sdk'));
/**
TESTS
**/
aws-sdk
object explicitlyDue to transpiling, code written in TypeScript or ES6 may not correctly mock because the aws-sdk
object created within aws-sdk-mock
will not be equal to the object created within the code to test. In addition, it is sometimes convenient to have multiple SDK instances in a test. For either scenario, it is possible to pass in the SDK object directly using setSDKInstance()
.
Example:
// test code
const AWSMock = require('aws-sdk-mock');
import AWS from 'aws-sdk';
AWSMock.setSDKInstance(AWS);
AWSMock.mock('SQS', /* ... */);
// implementation code
const sqs = new AWS.SQS();
If your environment lacks a global Promise constructor (e.g. nodejs 0.10), you can explicitly set the promises on aws-sdk-mock
. Set the value of AWS.Promise
to the constructor for your chosen promise library.
Example (if Q is your promise library of choice):
const AWS = require('aws-sdk-mock'),
Q = require('q');
AWS.Promise = Q.Promise;
/**
TESTS
**/
Contributions welcome! Please submit issues or PRs if you think of anything that needs updating/improving
FAQs
Functions to mock the JavaScript aws-sdk
We found that aws-sdk-mock demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 5 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.