├── .npmignore ├── lib ├── templates │ ├── event-with-records.json │ ├── iot-button.json │ ├── kinesis-firehose.json │ ├── cloudwatch.json │ ├── cognito.json │ ├── cloudfront-record.json │ ├── cloudwatch-logs.json │ ├── cloudformation.json │ ├── apigateway.json │ ├── dynamodb-record.json │ ├── kinesis-firehose-record.json │ ├── lex.json │ ├── kinesis-record.json │ ├── sns-record.json │ ├── sqs-record.json │ ├── s3-record.json │ ├── config.json │ ├── ses-record.json │ └── index.js ├── constants.js ├── simple.js ├── kinesis.js ├── cloudwatch_logs.js ├── iot_button.js ├── lex.js ├── config.js ├── cloudwatch.js ├── cognito.js ├── firehose.js ├── s3.js ├── index.js ├── cloudformation.js ├── ses.js ├── sqs.js ├── utils.js ├── cloudfront.js ├── event.js ├── sns.js ├── apigateway.js ├── record.js ├── templater.js └── dynamodb.js ├── .travis.yml ├── .jshintrc ├── .gitignore ├── test └── lib │ ├── index.test.js │ ├── simple.test.js │ ├── iot_button.test.js │ ├── kinesis.test.js │ ├── cloudwatch_logs.test.js │ ├── firehose.test.js │ ├── cloudformation.test.js │ ├── lex.test.js │ ├── config.test.js │ ├── cognito.test.js │ ├── sqs.test.js │ ├── ses.test.js │ ├── cloudwatch.test.js │ ├── utils.test.js │ ├── s3.test.js │ ├── record.test.js │ ├── templater.test.js │ ├── cloudfront.test.js │ ├── sns.test.js │ ├── apigateway.test.js │ ├── dynamodb.test.js │ └── templates │ └── index.test.js ├── package.json ├── LICENSE ├── docs ├── cloudformation.md ├── cloudwatch_logs.md ├── README.md ├── apigateway.md └── cloudfront.md ├── README.md └── CODE_OF_CONDUCT.md /.npmignore: -------------------------------------------------------------------------------- 1 | * 2 | !lib/** 3 | -------------------------------------------------------------------------------- /lib/templates/event-with-records.json: -------------------------------------------------------------------------------- 1 | { 2 | "Records": [ 3 | ] 4 | } 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8.10" 4 | install: 5 | - npm install 6 | script: npm test 7 | -------------------------------------------------------------------------------- /lib/templates/iot-button.json: -------------------------------------------------------------------------------- 1 | { 2 | "serialNumber": "ABCDEFG12345", 3 | "clickType": "SINGLE", 4 | "batteryVoltage": "2000 mV" 5 | } 6 | -------------------------------------------------------------------------------- /lib/templates/kinesis-firehose.json: -------------------------------------------------------------------------------- 1 | { 2 | "invocationId": "invoked123", 3 | "deliveryStreamArn": "aws:lambda:events", 4 | "region": "us-east-1", 5 | "records": [] 6 | } 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "undef": true, 4 | "unused": true, 5 | "asi": true, 6 | "globals": { 7 | "Promise": true 8 | }, 9 | "esversion": 6, 10 | "mocha": true 11 | } 12 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const values = { 4 | 5 | KEYS_ONLY: 'KEYS_ONLY', 6 | 7 | NEW_AND_OLD_IMAGES: 'NEW_AND_OLD_IMAGES', 8 | 9 | NEW_IMAGE: 'NEW_IMAGE', 10 | 11 | OLD_IMAGE: 'OLD_IMAGE' 12 | } 13 | 14 | module.exports = values; 15 | -------------------------------------------------------------------------------- /lib/templates/cloudwatch.json: -------------------------------------------------------------------------------- 1 | { 2 | "account": "123456789012", 3 | "region": "us-east-1", 4 | "detail": {}, 5 | "detail-type": "unset", 6 | "source": "unset", 7 | "time": "{{UTC:milliseconds=false}}", 8 | "id": "{{UUID}}", 9 | "resources": [] 10 | } 11 | -------------------------------------------------------------------------------- /lib/templates/cognito.json: -------------------------------------------------------------------------------- 1 | { 2 | "datasetName": "datasetName", 3 | "eventType": "SyncTrigger", 4 | "region": "us-east-1", 5 | "identityId": "identityId", 6 | "datasetRecords": {}, 7 | "identityPoolId": "identityPoolId", 8 | "version": 2 9 | } 10 | -------------------------------------------------------------------------------- /lib/templates/cloudfront-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "cf": { 3 | "config": { 4 | "distributionId": "EDFDVBD6EXAMPLE" 5 | }, 6 | "request": { 7 | "clientIp": "2001:0db8:85a3:0:0:8a2e:0370:7334", 8 | "method": "GET", 9 | "uri": "/picture.jpg", 10 | "headers": {} 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/simple.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const EventMock = require( './event' ); 4 | 5 | const templates = require( './templates' ); 6 | 7 | class SimpleEventMock extends EventMock { 8 | 9 | constructor( templateName ) { 10 | 11 | super( templates[ templateName ] ); 12 | } 13 | } 14 | 15 | module.exports = SimpleEventMock; 16 | -------------------------------------------------------------------------------- /lib/templates/cloudwatch-logs.json: -------------------------------------------------------------------------------- 1 | { 2 | "awslogs": { 3 | "data": "H4sIAAAAAAAAAHWPwQqCQBCGX0Xm7EFtK+smZBEUgXoLCdMhFtKV3akI8d0bLYmibvPPN3wz00CJxmQnTO41whwWQRIctmEcB6sQbFC3CjW3XW8kxpOpP+OC22d1Wml1qZkQGtoMsScxaczKN3plG8zlaHIta5KqWsozoTYw3/djzwhpLwivWFGHGpAFe7DL68JlBUk+l7KSN7tCOEJ4M3/qOI49vMHj+zCKdlFqLaU2ZHV2a4Ct/an0/ivdX8oYc1UVX860fQDQiMdxRQEAAA==" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /lib/kinesis.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | class KinesisEventMock extends RecordEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'kinesis' ); 10 | } 11 | 12 | data( d ) { 13 | 14 | return this.putObjectValue( 'data', d ); 15 | } 16 | } 17 | 18 | module.exports = KinesisEventMock; 19 | -------------------------------------------------------------------------------- /lib/templates/cloudformation.json: -------------------------------------------------------------------------------- 1 | { 2 | "StackId": "stackidarn", 3 | "ResponseURL": "http://pre-signed-S3-url-for-response", 4 | "ResourceProperties": { 5 | "StackName": "stack-name" 6 | }, 7 | "RequestType": "Create", 8 | "ResourceType": "Custom::TestResource", 9 | "RequestId": "unique id for this create request", 10 | "LogicalResourceId": "MyTestResource" 11 | } 12 | -------------------------------------------------------------------------------- /lib/cloudwatch_logs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class CloudwatchLogsMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'cloudwatch-logs' ); 10 | } 11 | 12 | data( value ) { 13 | 14 | return super.putPropertyValue( 'awslogs', 'data', value ); 15 | } 16 | } 17 | 18 | module.exports = CloudwatchLogsMock; 19 | -------------------------------------------------------------------------------- /lib/templates/apigateway.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "resource": "/", 4 | "path": "/", 5 | "httpMethod": "GET", 6 | "headers": null, 7 | "queryStringParameters": null, 8 | "pathParameters": null, 9 | "stageVariables": null, 10 | "requestContext": { 11 | 12 | "resourcePath": "/", 13 | "apiId": "00aaa0a00a" 14 | }, 15 | "body": null, 16 | "isBase64Encoded": false 17 | } 18 | -------------------------------------------------------------------------------- /lib/templates/dynamodb-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventID": "1", 3 | "eventVersion": "1.0", 4 | "dynamodb": { 5 | "Keys": {}, 6 | "StreamViewType": "NEW_AND_OLD_IMAGES", 7 | "SequenceNumber": "111", 8 | "SizeBytes": 0 9 | }, 10 | "awsRegion": "us-east-1", 11 | "eventName": "INSERT", 12 | "eventSourceARN": "eventsourcearn", 13 | "eventSource": "aws:dynamodb" 14 | } 15 | -------------------------------------------------------------------------------- /lib/iot_button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class IoTButtonEventMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'iot-button' ); 10 | } 11 | } 12 | 13 | SimpleEventMock.addPutValueHelpers( IoTButtonEventMock, [ 14 | 15 | 'serialNumber', 16 | 'clickType', 17 | 'batteryVoltage' 18 | ]); 19 | 20 | module.exports = IoTButtonEventMock; 21 | -------------------------------------------------------------------------------- /lib/templates/kinesis-firehose-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": "", 3 | "recordId": "record1", 4 | "approximateArrivalTimestamp": "{{TIMESTAMP}}", 5 | "kinesisRecordMetadata": { 6 | "shardId": "shardId-000000000000", 7 | "partitionKey": "{{UUID}}", 8 | "approximateArrivalTimestamp": "{{UTC}}", 9 | "sequenceNumber": "49546986683135544286507457936321625675700192471156785154", 10 | "subsequenceNumber": "" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/templates/lex.json: -------------------------------------------------------------------------------- 1 | { 2 | "messageVersion": "1.0", 3 | "invocationSource": "Unknown", 4 | "userId": "user-id", 5 | "sessionAttributes": {}, 6 | "bot": { 7 | "name": "bot-name", 8 | "alias": "bot-alias", 9 | "version": "1.0" 10 | }, 11 | "outputDialogMode": "Text", 12 | "currentIntent": { 13 | "name": "intent-name", 14 | "slots": {}, 15 | "confirmationStatus": "None" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/lex.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class LexEventMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'lex' ); 10 | } 11 | } 12 | 13 | SimpleEventMock.addPutValueHelpers( LexEventMock, [ 14 | 15 | 'invocationSource', 16 | 'userId', 17 | 'sessionAttributes', 18 | 'outputDialogMode', 19 | 'bot', 20 | 'currentIntent' 21 | ]); 22 | 23 | module.exports = LexEventMock; 24 | -------------------------------------------------------------------------------- /lib/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class ConfigEventMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'config' ); 10 | } 11 | } 12 | 13 | SimpleEventMock.addPutValueHelpers( ConfigEventMock, [ 14 | 15 | 'configRuleArn', 16 | 'configRuleName', 17 | 'configRuleId', 18 | 'executionRoleArn', 19 | 'invokingEvent', 20 | 'resultToken', 21 | 'ruleParameters' 22 | ]); 23 | 24 | module.exports = ConfigEventMock; 25 | -------------------------------------------------------------------------------- /lib/cloudwatch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class CloudWatchEventMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'cloudwatch' ); 10 | } 11 | } 12 | 13 | SimpleEventMock.addPutValueHelpers( CloudWatchEventMock, [ 14 | 15 | 'account', 16 | 'region', 17 | [ 'detail', 'detail', true ], 18 | [ 'detailType', 'detail-type' ], 19 | 'source', 20 | 'time', 21 | 'id', 22 | 'resources' 23 | ]); 24 | 25 | module.exports = CloudWatchEventMock; 26 | -------------------------------------------------------------------------------- /lib/cognito.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class CognitoEventMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'cognito' ); 10 | } 11 | 12 | dataset( name, record ) { 13 | 14 | return super.putPropertyValue( 'datasetRecords', name, record ); 15 | } 16 | } 17 | 18 | SimpleEventMock.addPutValueHelpers( CognitoEventMock, [ 19 | 20 | 'datasetName', 21 | 'eventType', 22 | 'region', 23 | 'identityId', 24 | 'identityPoolId' 25 | ]); 26 | 27 | module.exports = CognitoEventMock; 28 | -------------------------------------------------------------------------------- /lib/templates/kinesis-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventID": "shardId-000000000000:49545115243490985018280067714973144582180062593244200961", 3 | "eventVersion": "1.0", 4 | "kinesis": { 5 | "partitionKey": "partitionKey-3", 6 | "data": "", 7 | "kinesisSchemaVersion": "1.0", 8 | "sequenceNumber": "49545115243490985018280067714973144582180062593244200961" 9 | }, 10 | "invokeIdentityArn": "identityarn", 11 | "eventName": "aws:kinesis:record", 12 | "eventSourceARN": "eventsourcearn", 13 | "eventSource": "aws:kinesis", 14 | "awsRegion": "us-east-1" 15 | } 16 | -------------------------------------------------------------------------------- /lib/firehose.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | class FirehoseEventMock extends RecordEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'kinesisRecordMetadata', 'kinesis-firehose' ); 10 | 11 | this._nextID =1; 12 | } 13 | 14 | data( d ) { 15 | 16 | return this.recordValue( 'data', d ); 17 | } 18 | 19 | _getRecordsArray( event ) { 20 | 21 | return event.records; 22 | } 23 | 24 | _createRecord() { 25 | 26 | let record = super._createRecord(); 27 | 28 | record.recordId = `record${this._nextID++}`; 29 | 30 | return record; 31 | } 32 | } 33 | 34 | module.exports = FirehoseEventMock; 35 | -------------------------------------------------------------------------------- /lib/s3.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | class S3EventMock extends RecordEventMock { 6 | 7 | constructor() { 8 | 9 | super( 's3' ); 10 | } 11 | 12 | configurationId( id ) { 13 | 14 | return this.putObjectValue( 'configurationId', id ); 15 | } 16 | 17 | object( key, additional = {} ) { 18 | 19 | return this.assignObjectValue( 'object', { key }, additional ); 20 | } 21 | 22 | bucket( name, additional = {} ) { 23 | 24 | return this.assignObjectValue( 'bucket', { name }, additional ); 25 | } 26 | 27 | eventName( name ) { 28 | 29 | return this.putObjectValue( 'eventName', name ); 30 | } 31 | } 32 | 33 | module.exports = S3EventMock; 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | .env 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directory 30 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 31 | node_modules 32 | 33 | # Debug log from npm 34 | npm-debug.log 35 | 36 | # Mac specific 37 | .DS_Store 38 | package-lock.json 39 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | [ 4 | ['apiGateway','apigateway'], 5 | 'cloudformation', 6 | 'cloudfront', 7 | 'cloudwatch', 8 | ['cloudwatchLogs', 'cloudwatch_logs'], 9 | 'cognito', 10 | 'config', 11 | 'dynamodb', 12 | 'firehose', 13 | ['iotButton', 'iot_button'], 14 | 'kinesis', 15 | 'lex', 16 | 's3', 17 | 'ses', 18 | 'sns', 19 | 'sqs' 20 | 21 | ].forEach( (moduleInfo) => { 22 | 23 | let name = moduleInfo; 24 | let mockModuleName = moduleInfo; 25 | 26 | if( Array.isArray( moduleInfo ) ) { 27 | 28 | name = moduleInfo[0]; 29 | mockModuleName = moduleInfo[1]; 30 | } 31 | 32 | let mockClass = require( `./${mockModuleName}` ); 33 | 34 | module.exports[ name ] = function() { 35 | 36 | return new mockClass(); 37 | } 38 | }); 39 | -------------------------------------------------------------------------------- /lib/cloudformation.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | class CloudformationEventMock extends SimpleEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'cloudformation' ); 10 | } 11 | } 12 | 13 | SimpleEventMock.addPutValueHelpers( CloudformationEventMock, [ 14 | 15 | ['stackId', 'StackId'], 16 | ['responseURL', 'ResponseURL'], 17 | ['requestType', 'RequestType'], 18 | ['resourceType', 'ResourceType'], 19 | ['requestId', 'RequestId'], 20 | ['logicalResourceId', 'LogicalResourceId'] 21 | ]); 22 | 23 | SimpleEventMock.addPutValueHelper( CloudformationEventMock, 'resourceProperties', 'ResourceProperties', true ); 24 | SimpleEventMock.addPutPropertyValueHelper( CloudformationEventMock, 'resourceProperty', 'ResourceProperties' ); 25 | 26 | module.exports = CloudformationEventMock; 27 | -------------------------------------------------------------------------------- /lib/templates/sns-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "EventVersion": "1.0", 3 | "EventSubscriptionArn": "eventsubscriptionarn", 4 | "EventSource": "aws:sns", 5 | "Sns": { 6 | "SignatureVersion": "1", 7 | "Timestamp": "{{UTC}}", 8 | "Signature": "EXAMPLE", 9 | "SigningCertUrl": "EXAMPLE", 10 | "MessageId": "{{UUID}}", 11 | "Message": "Hello from SNS!", 12 | "MessageAttributes": { 13 | "Test": { 14 | "Type": "String", 15 | "Value": "TestString" 16 | }, 17 | "TestBinary": { 18 | "Type": "Binary", 19 | "Value": "TestBinary" 20 | } 21 | }, 22 | "Type": "Notification", 23 | "UnsubscribeUrl": "EXAMPLE", 24 | "TopicArn": "topicarn", 25 | "Subject": "TestInvoke" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/lib/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventMock = require( '../../lib/index' ); 8 | 9 | describe( 'lib/index', function() { 10 | 11 | [ 12 | 'apiGateway', 13 | 'cloudformation', 14 | 'cloudfront', 15 | 'cloudwatch', 16 | 'cloudwatchLogs', 17 | 'cognito', 18 | 'config', 19 | 'dynamodb', 20 | 'firehose', 21 | 'iotButton', 22 | 'kinesis', 23 | 'lex', 24 | 's3', 25 | 'ses', 26 | 'sns', 27 | 'sqs' 28 | 29 | ].forEach( (type) => { 30 | 31 | describe( `.${type}`, function() { 32 | 33 | it( 'normal operation', function() { 34 | 35 | expect( eventMock[ type ] ).to.exist; 36 | 37 | let instance = eventMock[type](); 38 | 39 | instance.build(); 40 | }); 41 | }); 42 | }); 43 | }); 44 | -------------------------------------------------------------------------------- /lib/templates/sqs-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "messageId": "{{UUID}}", 3 | "receiptHandle": "AQEBJQ+/u6NsnT5t8Q/VbVxgdUl4TMKZ5FqhksRdIQvLBhwNvADoBxYSOVeCBXdnS9P+erlTtwEALHsnBXynkfPLH3BOUqmgzP25U8kl8eHzq6RAlzrSOfTO8ox9dcp6GLmW33YjO3zkq5VRYyQlJgLCiAZUpY2D4UQcE5D1Vm8RoKfbE+xtVaOctYeINjaQJ1u3mWx9T7tork3uAlOe1uyFjCWU5aPX/1OHhWCGi2EPPZj6vchNqDOJC/Y2k1gkivqCjz1CZl6FlZ7UVPOx3AMoszPuOYZ+Nuqpx2uCE2MHTtMHD8PVjlsWirt56oUr6JPp9aRGo6bitPIOmi4dX0FmuMKD6u/JnuZCp+AXtJVTmSHS8IXt/twsKU7A+fiMK01NtD5msNgVPoe9JbFtlGwvTQ==", 4 | "body": "{\"foo\":\"bar\"}", 5 | "attributes": { 6 | "ApproximateReceiveCount": "3", 7 | "SentTimestamp": "{{TIMESTAMP:string}}", 8 | "SenderId": "594035263019", 9 | "ApproximateFirstReceiveTimestamp": "{{TIMESTAMP:offset=250:string}}" 10 | }, 11 | "messageAttributes": {}, 12 | "md5OfBody": "f7711754904595658d024be246fbb24a", 13 | "eventSource": "aws:sqs", 14 | "eventSourceARN": "arn:aws:sqs:us-west-2:594035263019:NOTFIFOQUEUE", 15 | "awsRegion": "us-west-2" 16 | } 17 | -------------------------------------------------------------------------------- /lib/templates/s3-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventVersion": "2.0", 3 | "eventTime": "{{UTC}}", 4 | "requestParameters": { 5 | "sourceIPAddress": "127.0.0.1" 6 | }, 7 | "s3": { 8 | "configurationId": "testConfigRule", 9 | "object": { 10 | "eTag": "0123456789abcdef0123456789abcdef", 11 | "sequencer": "0A1B2C3D4E5F678901", 12 | "key": "picture.jpg", 13 | "size": 1024 14 | }, 15 | "bucket": { 16 | "arn": "bucketarn", 17 | "name": "sourcebucket", 18 | "ownerIdentity": { 19 | "principalId": "USER" 20 | } 21 | }, 22 | "s3SchemaVersion": "1.0" 23 | }, 24 | "responseElements": { 25 | "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", 26 | "x-amz-request-id": "EXAMPLE123456789" 27 | }, 28 | "awsRegion": "us-east-1", 29 | "eventName": "ObjectCreated:Put", 30 | "userIdentity": { 31 | "principalId": "USER" 32 | }, 33 | "eventSource": "aws:s3" 34 | } 35 | -------------------------------------------------------------------------------- /lib/ses.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | class SESEventMock extends RecordEventMock { 6 | 7 | constructor() { 8 | 9 | super( 'ses' ); 10 | } 11 | 12 | commonHeader( name, value ) { 13 | 14 | this.mail.commonHeaders[ name ] = value; 15 | 16 | return this; 17 | } 18 | 19 | header( name, value ) { 20 | 21 | this.mail.headers.push( { name, value } ); 22 | 23 | return this; 24 | } 25 | 26 | mailValue( name, value ) { 27 | 28 | this.mail[ name ] = value; 29 | 30 | return this; 31 | } 32 | 33 | receiptValue( name, value ) { 34 | 35 | this.receipt[ name ] = value; 36 | 37 | return this; 38 | } 39 | 40 | recipient( name ) { 41 | 42 | this.receipt.recipients.push( name ); 43 | 44 | return this; 45 | } 46 | 47 | get mail() { 48 | 49 | return this.objectValue.mail; 50 | } 51 | 52 | get receipt() { 53 | 54 | return this.objectValue.receipt; 55 | } 56 | } 57 | 58 | module.exports = SESEventMock; 59 | -------------------------------------------------------------------------------- /lib/templates/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "invokingEvent": "{\"configurationItem\":{\"configurationItemCaptureTime\":\"2016-02-17T01:36:34.043Z\",\"awsAccountId\":\"000000000000\",\"configurationItemStatus\":\"OK\",\"resourceId\":\"i-00000000\",\"ARN\":\"arn:aws:ec2:us-east-1:000000000000:instance/i-00000000\",\"awsRegion\":\"us-east-1\",\"availabilityZone\":\"us-east-1a\",\"resourceType\":\"AWS::EC2::Instance\",\"tags\":{\"Foo\":\"Bar\"},\"relationships\":[{\"resourceId\":\"eipalloc-00000000\",\"resourceType\":\"AWS::EC2::EIP\",\"name\":\"Is attached to ElasticIp\"}],\"configuration\":{\"foo\":\"bar\"}},\"messageType\":\"ConfigurationItemChangeNotification\"}", 3 | "ruleParameters": "{\"myParameterKey\":\"myParameterValue\"}", 4 | "resultToken": "myResultToken", 5 | "eventLeftScope": false, 6 | "executionRoleArn": "arn:aws:iam::012345678912:role/config-role", 7 | "configRuleArn": "arn:aws:config:us-east-1:012345678912:config-rule/config-rule-0123456", 8 | "configRuleName": "change-triggered-config-rule", 9 | "configRuleId": "config-rule-0123456", 10 | "accountId": "012345678912", 11 | "version": "1.0" 12 | } 13 | -------------------------------------------------------------------------------- /lib/sqs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | const crypto = require( 'crypto' ); 6 | 7 | class SQSEventMock extends RecordEventMock { 8 | 9 | constructor() { 10 | 11 | super( 'sqs' ); 12 | } 13 | 14 | messageId( id ) { 15 | 16 | return this.recordValue( 'messageId', id ); 17 | } 18 | 19 | receiptHandle( handle ) { 20 | 21 | return this.recordValue( 'receiptHandle', handle ); 22 | } 23 | 24 | eventSourceARN( arn ) { 25 | 26 | return this.recordValue( 'eventSourceARN', arn ); 27 | } 28 | 29 | body( body ) { 30 | 31 | if( body instanceof Buffer ) { 32 | 33 | body = body.toString( 'base64' ); 34 | } 35 | else { 36 | 37 | body = body.toString(); 38 | } 39 | 40 | this.recordValue( 'body', body ); 41 | this.recordValue( 'md5OfBody', crypto.createHash( 'md5' ) 42 | .update( body ) 43 | .digest( 'hex' ) ); 44 | 45 | return this; 46 | } 47 | } 48 | 49 | module.exports = SQSEventMock; 50 | -------------------------------------------------------------------------------- /lib/templates/ses-record.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventVersion": "1.0", 3 | "ses": { 4 | "mail": { 5 | "commonHeaders": {}, 6 | "source": "unknown@unknown.com", 7 | "timestamp": "{{UTC}}", 8 | "destination": [], 9 | "headers": [], 10 | "headersTruncated": false, 11 | "messageId": "o3vrnil0e2ic28trm7dfhrc2v0clambda4nbp0g1x" 12 | }, 13 | "receipt": { 14 | "recipients": [], 15 | "timestamp": "{{UTC}}", 16 | "spamVerdict": { 17 | "status": "PASS" 18 | }, 19 | "dkimVerdict": { 20 | "status": "PASS" 21 | }, 22 | "processingTimeMillis": 574, 23 | "action": { 24 | "type": "Lambda", 25 | "invocationType": "Event", 26 | "functionArn": "functionarn" 27 | }, 28 | "spfVerdict": { 29 | "status": "PASS" 30 | }, 31 | "virusVerdict": { 32 | "status": "PASS" 33 | } 34 | } 35 | }, 36 | "eventSource": "aws:ses" 37 | } 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lambda-event-mock", 3 | "version": "1.5.0", 4 | "description": "Mocks AWS Lambda events", 5 | "main": "lib/index.js", 6 | "keywords": [ 7 | "AWS Lambda", 8 | "AWS", 9 | "lambda", 10 | "serverless", 11 | "mock", 12 | "test", 13 | "event" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/vandium-io/lambda-event-mock.git" 18 | }, 19 | "engines": { 20 | "node": ">=12.13" 21 | }, 22 | "scripts": { 23 | "test": "nyc mocha --recursive" 24 | }, 25 | "nyc": { 26 | "check-coverage": true, 27 | "include": [ 28 | "lib/**/*.js" 29 | ], 30 | "reporter": [ 31 | "lcov", 32 | "text" 33 | ] 34 | }, 35 | "author": "Vandium Software Inc.", 36 | "license": "BSD-3-Clause", 37 | "dependencies": { 38 | "@extra-number/significant-digits": "^1.1.1", 39 | "clone-deep": "^4.0.1", 40 | "uuid": "^3.3.3", 41 | "vandium-utils": "^1.2.0" 42 | }, 43 | "devDependencies": { 44 | "@vandium/event-identifier": "^3.0.0", 45 | "chai": "^4.1.2", 46 | "mocha": "^6.2.2", 47 | "nyc": "^14.1.1", 48 | "proxyquire": "^2.1.3", 49 | "sinon": "^7.5.0" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const uuid = require( 'uuid' ); 4 | 5 | const utils = Object.assign( {}, require( 'vandium-utils' ) ); 6 | 7 | function isNullOrUndefined( value ) { 8 | 9 | return (value === null) || (value === undefined); 10 | } 11 | 12 | utils.isEmpty = function( obj ) { 13 | 14 | if( isNullOrUndefined( obj ) ) { 15 | 16 | return true; 17 | } 18 | 19 | return (Object.keys( obj ).length === 0 ); 20 | } 21 | 22 | utils.emptyIfNull = function( obj ) { 23 | 24 | if( isNullOrUndefined( obj ) ) { 25 | 26 | obj = {}; 27 | } 28 | 29 | return obj; 30 | } 31 | 32 | utils.dateToISOString = function( date, milliseconds = false ) { 33 | 34 | let str = date.toISOString(); 35 | 36 | if( !milliseconds ) { 37 | 38 | str = str.split('.')[0]+"Z"; 39 | } 40 | 41 | return str; 42 | } 43 | 44 | utils.booleanValue = function( value, defaultValue = false ) { 45 | 46 | if( isNullOrUndefined( value ) ) { 47 | 48 | value = defaultValue; 49 | } 50 | 51 | return value; 52 | } 53 | 54 | utils.lowercaseFirstLetter = function( str ) { 55 | 56 | return str.charAt( 0 ).toLowerCase() + str.slice( 1 ); 57 | } 58 | 59 | utils.uuid = uuid.v4; 60 | 61 | module.exports = utils; 62 | -------------------------------------------------------------------------------- /test/lib/simple.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const proxyquire = require( 'proxyquire' ).noCallThru(); 8 | 9 | const sinon = require( 'sinon' ); 10 | 11 | describe( 'lib/simple', function() { 12 | 13 | let SimpleEventMock; 14 | 15 | let templates; 16 | 17 | beforeEach( function() { 18 | 19 | templates = { 20 | 21 | test_template: { 22 | 23 | render: sinon.stub().returns( { one: 1 } ) 24 | } 25 | }; 26 | 27 | SimpleEventMock = proxyquire( '../../lib/simple', { 28 | 29 | './templates': templates 30 | }); 31 | }); 32 | 33 | describe( 'SimpleEventMock', function() { 34 | 35 | describe( 'constructor', function() { 36 | 37 | it( 'normal operation, no helpers', function() { 38 | 39 | let instance = new SimpleEventMock( 'test_template' ); 40 | 41 | expect( templates.test_template.render.calledOnce ).to.be.true; 42 | expect( templates.test_template.render.firstCall.args ).to.eql( [] ); 43 | 44 | expect( instance._event ).to.eql( { one: 1 } ); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /test/lib/iot_button.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const IoTButtonEventMock = require( '../../lib/iot_button' ); 10 | 11 | describe( 'lib/config', function() { 12 | 13 | describe( 'IoTButtonEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new IoTButtonEventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 'iot-button' ); 22 | }); 23 | 24 | it( 'normal operation', function() { 25 | 26 | 'serialNumber', 27 | 'clickType', 28 | 'batteryVoltage' 29 | 30 | let event = new IoTButtonEventMock() 31 | .serialNumber( 'my-serial-number' ) 32 | .clickType( 'DOUBLE' ) 33 | .batteryVoltage( '5000 mV' ) 34 | .build(); 35 | 36 | expect( event.serialNumber ).to.equal( 'my-serial-number' ); 37 | expect( event.clickType ).to.equal( 'DOUBLE' ); 38 | expect( event.batteryVoltage ).to.eql( '5000 mV' ); 39 | 40 | expect( eventIdentifier.identify( event ).type ).to.equal( 'iot-button' ); 41 | }); 42 | }); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /test/lib/kinesis.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const KinesisEventMock = require( '../../lib/kinesis' ); 10 | 11 | describe( 'lib/kinesis', function() { 12 | 13 | describe( 'KinesisEventMock', function() { 14 | 15 | describe( '.data', function() { 16 | 17 | it( 'normal operation', function() { 18 | 19 | let instance = new KinesisEventMock(); 20 | 21 | let returnValue = instance.data( 'dGVzdGluZw==' ); 22 | 23 | expect( returnValue ).to.equal( instance ); 24 | expect( instance._event.Records[0].kinesis.data ).to.equal( 'dGVzdGluZw==' ); 25 | }); 26 | }); 27 | 28 | describe( '.build', function() { 29 | 30 | it( 'defaults', function() { 31 | 32 | let event = new KinesisEventMock().build(); 33 | 34 | expect( eventIdentifier.identify( event ).type ).to.equal( 'kinesis' ); 35 | }); 36 | 37 | it( 'normal operation', function() { 38 | 39 | let event = new KinesisEventMock() 40 | .data( 'dGVzdGluZw==' ) 41 | .build(); 42 | 43 | expect( eventIdentifier.identify( event ).type ).to.equal( 'kinesis' ); 44 | 45 | expect( event.Records[0].kinesis.data ).to.equal( 'dGVzdGluZw==' ); 46 | }); 47 | }); 48 | }); 49 | }); 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2019, Vandium Software Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of Vandium Software Inc. nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL VANDIUM SOFTWARE INC. BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /lib/cloudfront.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | const utils = require( './utils' ); 6 | 7 | class CloudfrontEventMock extends RecordEventMock { 8 | 9 | constructor() { 10 | 11 | super( 'cf', 'cloudfront' ); 12 | } 13 | 14 | header( name, key, value ) { 15 | 16 | return this._headers( 'request', name, key, value ); 17 | } 18 | 19 | _headers( objectName, name, key, value ) { 20 | 21 | let headers = this.objectValue[objectName].headers; 22 | 23 | let headersList = headers[ name ]; 24 | 25 | if( !headersList ) { 26 | 27 | headersList = []; 28 | headers[ name ] = headersList; 29 | } 30 | 31 | headersList.push( { key, value } ); 32 | 33 | return this; 34 | } 35 | } 36 | 37 | [ 38 | [ 'config', 'distributionId' ], 39 | [ 'config', 'distributionDomainName' ], 40 | [ 'config', 'eventType' ], 41 | [ 'config', 'requestId' ], 42 | 43 | [ 'request', 'body' ], 44 | [ 'request', 'clientIp' ], 45 | [ 'request', 'method' ], 46 | [ 'request', 'uri' ], 47 | [ 'request', 'querystring' ], 48 | [ 'request', 'origin' ] 49 | ].forEach( (propertyParam) => { 50 | 51 | const objectName = propertyParam[0]; 52 | const propertyName = propertyParam[1]; 53 | 54 | CloudfrontEventMock.prototype[ utils.lowercaseFirstLetter( propertyName ) ] = function( value ) { 55 | 56 | if( utils.isObject( value ) ) { 57 | 58 | value = Object.assign( {}, value ); 59 | } 60 | 61 | return this.assignObjectValue( objectName, { [`${propertyName}`]: value } ); 62 | } 63 | }); 64 | 65 | 66 | module.exports = CloudfrontEventMock; 67 | -------------------------------------------------------------------------------- /docs/cloudformation.md: -------------------------------------------------------------------------------- 1 | # `CloudFormation` 2 | 3 | The `cloudformation` mock is used to simulate [CloudFormation](https://aws.amazon.com/cloudformation/) 4 | events. To create a CloudFormation event, use the `cloudformation()` builder: 5 | 6 | ```js 7 | const lambdaEventMock = require( 'lambda-event-mock' ); 8 | 9 | let myMock = lambdaEventMock.cloudformation() 10 | .stackId( 'arn:aws:cloudformation:us-east-2:123456789012:stack/myteststack/466df9e0-0dff-08e3-8e2f-5088487c4896' ) 11 | .responseURL( 'http://pre-signed-S3-url-for-response' ) 12 | .resourceType( 'AWS::S3::Bucket' ) 13 | .resourceProperty( 'StackName', 'myteststack' ) 14 | .logicalResourceId( 'S3Bucket' ) 15 | .build(); 16 | 17 | /* myMock will be: 18 | 19 | { 20 | "StackId": "arn:aws:cloudformation:us-east-2:123456789012:stack/myteststack/466df9e0-0dff-08e3-8e2f-5088487c4896", 21 | "ResponseURL": "http://pre-signed-S3-url-for-response", 22 | "ResourceProperties": { 23 | "StackName": "myteststack" 24 | }, 25 | "RequestType": "Create", 26 | "ResourceType": "AWS::S3::Bucket", 27 | "RequestId": "unique id for this create request", 28 | "LogicalResourceId": "S3Bucket" 29 | } 30 | 31 | */ 32 | ``` 33 | 34 | ## `stackId( id )` 35 | 36 | Sets the `StackId` property 37 | 38 | ## `responseURL( url )` 39 | 40 | Sets the `ResponseURL` property 41 | 42 | ## `resourceType( type )` 43 | 44 | Sets the `ResourceType` property 45 | 46 | ## `resourceProperty( name, value )` 47 | 48 | Adds a single resource property to the `ResourceProperties` object 49 | 50 | ## `resourceProperties( properties )` 51 | 52 | Sets one or more values of the `ResourceProperties` object 53 | -------------------------------------------------------------------------------- /test/lib/cloudwatch_logs.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const CloudwatchLogsMock = require( '../../lib/cloudwatch_logs' ); 10 | 11 | describe( 'lib/cloudwatch_logs', function() { 12 | 13 | describe( 'CloudwatchLogsMock', function() { 14 | 15 | describe( '.data', function() { 16 | 17 | it( 'normal operation', function() { 18 | 19 | let instance = new CloudwatchLogsMock(); 20 | 21 | let returnValue = instance.data( 'my-data' ); 22 | 23 | expect( returnValue ).to.equal( instance ); 24 | expect( instance._event.awslogs.data ).to.equal( 'my-data' ); 25 | }); 26 | }); 27 | 28 | describe( '.build', function() { 29 | 30 | it( 'defaults', function() { 31 | 32 | let event = new CloudwatchLogsMock().build(); 33 | 34 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudwatch' ); 35 | expect( eventIdentifier.identify( event ).source ).to.equal( 'logs' ); 36 | }); 37 | 38 | it( 'normal operation', function() { 39 | 40 | let event = new CloudwatchLogsMock() 41 | .data( 'my-data' ) 42 | .build(); 43 | 44 | expect( event.awslogs ).to.eql( { data: 'my-data' } ); 45 | 46 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudwatch' ); 47 | expect( eventIdentifier.identify( event ).source ).to.equal( 'logs' ); 48 | }); 49 | }); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /test/lib/firehose.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const FirehoseEventMock = require( '../../lib/firehose' ); 10 | 11 | describe( 'lib/firehose', function() { 12 | 13 | describe( 'FirehoseEventMock', function() { 14 | 15 | describe( '.data', function() { 16 | 17 | it( 'normal operation', function() { 18 | 19 | let instance = new FirehoseEventMock(); 20 | 21 | let returnValue = instance.data( 'dGVzdGluZw==' ); 22 | 23 | expect( returnValue ).to.equal( instance ); 24 | expect( instance._event.records[0].data ).to.equal( 'dGVzdGluZw==' ); 25 | }); 26 | }); 27 | 28 | describe( '.build', function() { 29 | 30 | it( 'defaults', function() { 31 | 32 | let event = new FirehoseEventMock().build(); 33 | 34 | expect( eventIdentifier.identify( event ).type ).to.equal( 'kinesis-firehose' ); 35 | 36 | expect( event.invocationId ).to.exist; 37 | expect( event.deliveryStreamArn ).to.exist; 38 | expect( event.region ).to.exist; 39 | expect( event.records ).to.exist; 40 | 41 | expect( event.Records ).to.not.exist; 42 | }); 43 | 44 | it( 'multiple records', function() { 45 | 46 | let event = new FirehoseEventMock().next().next().build(); 47 | 48 | expect( eventIdentifier.identify( event ).type ).to.equal( 'kinesis-firehose' ); 49 | 50 | expect( event.records.length ).to.equal( 2 ); 51 | expect( event.records[0].recordId ).to.equal( 'record1' ); 52 | expect( event.records[1].recordId ).to.equal( 'record2' ); 53 | }); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /lib/event.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const utils = require( './utils' ); 4 | 5 | class EventMock { 6 | 7 | constructor( template ) { 8 | 9 | this._event = template.render(); 10 | } 11 | 12 | putValue( name, value ) { 13 | 14 | this._event[ name ] = value; 15 | 16 | return this; 17 | } 18 | 19 | putPropertyValue( objectName, name, value ) { 20 | 21 | let obj = this._event[ objectName ]; 22 | 23 | if( !obj ) { 24 | 25 | obj = {}; 26 | 27 | this._event[ objectName ] = obj; 28 | } 29 | 30 | obj[ name ] = value; 31 | 32 | return this; 33 | } 34 | 35 | build() { 36 | 37 | return Object.assign( {}, this._event ); 38 | } 39 | 40 | static addPutValueHelpers( eventClass, helpers ) { 41 | 42 | for( let helper of helpers ) { 43 | 44 | if( Array.isArray( helper ) ) { 45 | 46 | EventMock.addPutValueHelper( eventClass, ...helper ); 47 | } 48 | else { 49 | 50 | EventMock.addPutValueHelper( eventClass, helper ); 51 | } 52 | } 53 | } 54 | 55 | static addPutValueHelper( eventClass, name, eventName, clone ) { 56 | 57 | if( !eventName ) { 58 | 59 | eventName = name; 60 | } 61 | 62 | eventClass.prototype[ utils.lowercaseFirstLetter( name ) ] = function( value ) { 63 | 64 | if( clone ) { 65 | 66 | value = Object.assign( {}, value ); 67 | } 68 | 69 | return this.putValue( eventName, value ); 70 | } 71 | } 72 | 73 | static addPutPropertyValueHelper( eventClass, eventPropertyName, objectName ) { 74 | 75 | eventClass.prototype[ utils.lowercaseFirstLetter( eventPropertyName ) ] = function( name, value ) { 76 | 77 | return this.putPropertyValue( objectName, name, value ); 78 | } 79 | } 80 | } 81 | 82 | module.exports = EventMock; 83 | -------------------------------------------------------------------------------- /test/lib/cloudformation.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const CloudformationEventMock = require( '../../lib/cloudformation' ); 10 | 11 | describe( 'lib/cloudformation', function() { 12 | 13 | describe( 'CloudformationEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new CloudformationEventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudformation' ); 22 | }); 23 | 24 | it( 'normal operation', function() { 25 | 26 | let event = new CloudformationEventMock() 27 | .stackId( 'my-stack-id' ) 28 | .responseURL( 'my-responseURL' ) 29 | .requestType( 'my-requestType' ) 30 | .requestId( 'my-requestId' ) 31 | .resourceProperty( 'StackName', 'my-stack' ) 32 | .resourceProperties( { other: 'test' } ) 33 | .logicalResourceId( 'my-requestId' ) 34 | .build(); 35 | 36 | expect( event.StackId ).to.equal( 'my-stack-id' ); 37 | expect( event.ResponseURL ).to.equal( 'my-responseURL' ); 38 | expect( event.RequestType ).to.eql( 'my-requestType' ); 39 | expect( event.RequestId ).to.equal( 'my-requestId'); 40 | expect( event.LogicalResourceId ).to.equal( 'my-requestId' ); 41 | expect( event.ResourceProperties ).to.eql( { other: 'test' } ); 42 | 43 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudformation' ); 44 | }); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /test/lib/lex.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const LexEventMock = require( '../../lib/lex' ); 10 | 11 | describe( 'lib/config', function() { 12 | 13 | describe( 'LexEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new LexEventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 'lex' ); 22 | }); 23 | 24 | it( 'normal operation', function() { 25 | 26 | let event = new LexEventMock() 27 | .invocationSource( 'FulfillmentCodeHook' ) 28 | .userId( 'my-user-id' ) 29 | .sessionAttributes( { test1: '1' } ) 30 | .outputDialogMode( 'VOICE' ) 31 | .bot( { name: 'test', alias: 'my-test', version: '2.0' } ) 32 | .currentIntent( { name: 'my-intent-name', slots: {}, confirmationStatus: 'Confirmed' } ) 33 | .build(); 34 | 35 | expect( event.messageVersion ).to.equal( '1.0' ); 36 | expect( event.invocationSource ).to.equal( 'FulfillmentCodeHook' ); 37 | expect( event.userId ).to.eql( 'my-user-id' ); 38 | expect( event.sessionAttributes ).to.eql( { test1: '1' } ); 39 | expect( event.outputDialogMode ).to.equal( 'VOICE' ); 40 | expect( event.bot ).to.eql( { name: 'test', alias: 'my-test', version: '2.0' } ); 41 | expect( event.currentIntent ).to.eql( { name: 'my-intent-name', slots: {}, confirmationStatus: 'Confirmed' } ); 42 | 43 | expect( eventIdentifier.identify( event ).type ).to.equal( 'lex' ); 44 | }); 45 | }); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /lib/templates/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Templater = require( '../templater' ); 4 | 5 | const utils = require( '../utils' ); 6 | 7 | function utc( options ) { 8 | 9 | return utils.dateToISOString( new Date(), 10 | utils.booleanValue( options.milliseconds, true ) ); 11 | } 12 | 13 | function timestamp( options ) { 14 | 15 | let time = Date.now(); 16 | 17 | if( options.offset ) { 18 | 19 | time += options.offset; 20 | } 21 | 22 | if( options.string ) { 23 | 24 | time = '' + time; 25 | } 26 | 27 | return time; 28 | } 29 | 30 | function newTemplate( json ) { 31 | 32 | return new Templater( json ) 33 | .transform( 'UTC', utc ) 34 | .transform( 'UUID', ()=> utils.uuid() ) 35 | .transform( 'TIMESTAMP', timestamp ); 36 | } 37 | 38 | module.exports.newTemplate = newTemplate; 39 | 40 | function templater( templateName ) { 41 | 42 | return newTemplate( require( `./${templateName}.json`) ); 43 | } 44 | 45 | /////////////////////////////// 46 | // simple events 47 | [ 48 | 'apigateway', 49 | 'cloudformation', 50 | 'cloudwatch-logs', 51 | 'cognito', 52 | 'config', 53 | 'iot-button', 54 | 'lex', 55 | 'cloudwatch' 56 | 57 | ].forEach( ( type ) => { 58 | 59 | let name = type; 60 | let templateName = type; 61 | 62 | module.exports[ name ] = templater( templateName ); 63 | }); 64 | 65 | /////////////////////////////// 66 | // Record based events 67 | [ 68 | 'cloudfront', 69 | 'dynamodb', 70 | 'kinesis', 71 | 'kinesis-firehose', 72 | 's3', 73 | 'ses', 74 | 'sns', 75 | 'sqs' 76 | 77 | ].forEach( ( type ) => { 78 | 79 | let name = type; 80 | let templateName = type; 81 | 82 | try { 83 | 84 | module.exports[ name ] = templater( templateName ); 85 | } 86 | catch( err ) { 87 | 88 | module.exports[ name ] = templater( 'event-with-records' ); 89 | } 90 | 91 | module.exports[ `${name}_record` ] = templater( `${templateName}-record` ); 92 | }); 93 | -------------------------------------------------------------------------------- /test/lib/config.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const ConfigEventMock = require( '../../lib/config' ); 10 | 11 | describe( 'lib/config', function() { 12 | 13 | describe( 'ConfigEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new ConfigEventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 'config' ); 22 | }); 23 | 24 | it( 'normal operation', function() { 25 | 26 | let event = new ConfigEventMock() 27 | .configRuleArn( 'my-config-rule-arn' ) 28 | .configRuleName( 'my-config-rule-name' ) 29 | .configRuleId( 'my-config-rule-id' ) 30 | .executionRoleArn( 'my-exection-role-arn' ) 31 | .invokingEvent( 'my-invoking-event' ) 32 | .resultToken( 'my-result-token' ) 33 | .ruleParameters( 'my-rule-parameters' ) 34 | .build(); 35 | 36 | expect( event.configRuleArn ).to.equal( 'my-config-rule-arn' ); 37 | expect( event.configRuleName ).to.equal( 'my-config-rule-name' ); 38 | expect( event.configRuleId ).to.eql( 'my-config-rule-id' ); 39 | expect( event.executionRoleArn ).to.equal( 'my-exection-role-arn' ); 40 | expect( event.invokingEvent ).to.equal( 'my-invoking-event' ); 41 | expect( event.resultToken ).to.equal( 'my-result-token' ); 42 | expect( event.ruleParameters ).to.equal( 'my-rule-parameters' ); 43 | 44 | expect( eventIdentifier.identify( event ).type ).to.equal( 'config' ); 45 | }); 46 | }); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /lib/sns.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | const utils = require( './utils' ); 6 | 7 | class SNSEventMock extends RecordEventMock { 8 | 9 | constructor() { 10 | 11 | super( 'Sns', 'sns' ); 12 | } 13 | 14 | signature( signatureValue ) { 15 | 16 | return this.putObjectValue( 'Signature', signatureValue ); 17 | } 18 | 19 | signingCert( url ) { 20 | 21 | return this.putObjectValue( 'SigningCertUrl', url ); 22 | } 23 | 24 | message( msg ) { 25 | 26 | return this.putObjectValue( 'Message', msg ); 27 | } 28 | 29 | messageId( id ) { 30 | 31 | return this.putObjectValue( 'MessageId', id ); 32 | } 33 | 34 | messageAttribute( name, value ) { 35 | 36 | return this.messageAttributes( { [name]: value } ); 37 | } 38 | 39 | messageAttributes( attributes ) { 40 | 41 | return this.assignObjectValue( 'MessageAttributes', attributes ); 42 | } 43 | 44 | subject( value ) { 45 | 46 | return this.putObjectValue( 'Subject', value ); 47 | } 48 | 49 | topic( topicArn ) { 50 | 51 | return this.putObjectValue( 'TopicArn', topicArn ); 52 | } 53 | 54 | type( value ) { 55 | 56 | return this.putObjectValue( 'Type', value ); 57 | } 58 | 59 | eventSubscription( eventArn ) { 60 | 61 | return this.recordValue( 'EventSubscriptionArn', eventArn ); 62 | } 63 | 64 | _createRecord() { 65 | 66 | let record = super._createRecord(); 67 | 68 | record.EventVersion = '1.0'; 69 | record.EventSubscriptionArn = 'eventsubscriptionarn'; 70 | record.EventSource = 'aws:sns' 71 | 72 | record.Sns = { 73 | 74 | SignatureVersion: '1', 75 | Timestamp: new Date().toISOString(), 76 | Signature: 'EXAMPLE', 77 | SigningCertUrl: 'SigningURLHere', 78 | MessageId: utils.uuid(), 79 | Message: 'Generated SNS message!', 80 | MessageAttributes: { }, 81 | Type: "Notification", 82 | UnsubscribeUrl: "EXAMPLE", 83 | TopicArn: "topicarn", 84 | Subject: "TestInvoke" 85 | }; 86 | 87 | return record; 88 | } 89 | } 90 | 91 | module.exports = SNSEventMock; 92 | -------------------------------------------------------------------------------- /lib/apigateway.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleEventMock = require( './simple' ); 4 | 5 | const utils = require( './utils' ); 6 | 7 | class APIGatewayEventMock extends SimpleEventMock { 8 | 9 | constructor() { 10 | 11 | super( 'apigateway' ); 12 | } 13 | 14 | path( path ) { 15 | 16 | this.putValue( 'path', path ); 17 | this.putValue( 'resource', path ); 18 | this.putPropertyValue( 'requestContext', 'resourcePath', path ); 19 | 20 | return this; 21 | } 22 | 23 | body( body = {}, base64Encoded = false ) { 24 | 25 | if( body ) { 26 | 27 | if( body instanceof Buffer ) { 28 | 29 | body = body.toString( 'base64' ); 30 | base64Encoded = true; 31 | } 32 | else { 33 | 34 | if( utils.isObject( body ) ) { 35 | 36 | body = JSON.stringify( body ); 37 | } 38 | else { 39 | 40 | body = body.toString(); 41 | } 42 | } 43 | } 44 | 45 | this.putValue( 'body', body ); 46 | this.putValue( 'isBase64Encoded', base64Encoded ); 47 | 48 | return this; 49 | } 50 | 51 | apiId( id ) { 52 | 53 | return this.putPropertyValue( 'requestContext', 'apiId', id ); 54 | } 55 | 56 | base64Encoded( encoded = true ) { 57 | 58 | return this.putValue( 'isBase64Encoded', encoded ); 59 | } 60 | } 61 | 62 | SimpleEventMock.addPutValueHelper( APIGatewayEventMock, 'method', 'httpMethod' ); 63 | 64 | SimpleEventMock.addPutValueHelper( APIGatewayEventMock, 'headers', 'headers', true ); 65 | SimpleEventMock.addPutPropertyValueHelper( APIGatewayEventMock, 'header', 'headers' ); 66 | 67 | SimpleEventMock.addPutValueHelper( APIGatewayEventMock, 'queryStringParameters', 'queryStringParameters', true ); 68 | SimpleEventMock.addPutPropertyValueHelper( APIGatewayEventMock, 'queryStringParameter', 'queryStringParameters' ); 69 | 70 | SimpleEventMock.addPutValueHelper( APIGatewayEventMock, 'stageVariables', 'stageVariables', true ); 71 | SimpleEventMock.addPutPropertyValueHelper( APIGatewayEventMock, 'stageVariable', 'stageVariables' ); 72 | 73 | SimpleEventMock.addPutValueHelper( APIGatewayEventMock, 'pathParameters', 'pathParameters', true ); 74 | SimpleEventMock.addPutPropertyValueHelper( APIGatewayEventMock, 'pathParameter', 'pathParameters' ); 75 | 76 | module.exports = APIGatewayEventMock; 77 | -------------------------------------------------------------------------------- /test/lib/cognito.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const CognitoEventMock = require( '../../lib/cognito' ); 10 | 11 | describe( 'lib/cognito', function() { 12 | 13 | describe( 'CognitoEventMock', function() { 14 | 15 | describe( '.dataset', function() { 16 | 17 | it( 'normal operation', function() { 18 | 19 | let instance = new CognitoEventMock(); 20 | 21 | let returnValue = instance.dataset( 'MyKey', { 22 | newValue: 'one', oldValue: '1', op: 'replace' } ); 23 | 24 | expect( returnValue ).to.equal( instance ); 25 | expect( instance._event.datasetRecords.MyKey ).to.eql( { 26 | newValue: 'one', oldValue: '1', op: 'replace' } ); 27 | }); 28 | }); 29 | 30 | describe( '.build', function() { 31 | 32 | it( 'defaults', function() { 33 | 34 | let event = new CognitoEventMock().build(); 35 | 36 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cognito' ); 37 | }); 38 | 39 | it( 'normal operation', function() { 40 | 41 | let event = new CognitoEventMock() 42 | .datasetName( 'my-dataset' ) 43 | .eventType( 'my-event-type' ) 44 | .region( 'us-west-1' ) 45 | .dataset( 'MyKey', { 46 | newValue: 'one', oldValue: '1', op: 'replace' } ) 47 | .identityId( 'my-id' ) 48 | .identityPoolId( 'my-id-pool' ) 49 | .build(); 50 | 51 | expect( event.datasetName ).to.equal( 'my-dataset' ); 52 | expect( event.eventType ).to.equal( 'my-event-type' ); 53 | expect( event.region ).to.equal( 'us-west-1' ); 54 | expect( event.datasetRecords ).to.eql( { 55 | 56 | MyKey: { 57 | newValue: 'one', oldValue: '1', op: 'replace' 58 | } 59 | }); 60 | expect( event.identityId ).to.equal( 'my-id' ); 61 | expect( event.identityPoolId ).to.equal( 'my-id-pool' ); 62 | }); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /lib/record.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EventMock = require( './event' ); 4 | 5 | const templates = require( './templates' ); 6 | 7 | class RecordEventMock extends EventMock { 8 | 9 | constructor( objectName, templateName = objectName ) { 10 | 11 | super( templates[ templateName ] ); 12 | 13 | this._objectName = objectName; 14 | 15 | this._recordTemplater = templates[ `${templateName}_record` ]; 16 | } 17 | 18 | next() { 19 | 20 | this.updateCurrentRecord(); 21 | 22 | let record = this._createRecord(); 23 | 24 | this.records.push( record ); 25 | 26 | return this; 27 | } 28 | 29 | get currentRecord() { 30 | 31 | this._initRecords(); 32 | 33 | return this._getCurrentRecord(); 34 | } 35 | 36 | get records() { 37 | 38 | return this._getRecordsArray( this._event ); 39 | } 40 | 41 | recordValue( name, value ) { 42 | 43 | this.currentRecord[ name ] = value; 44 | 45 | return this; 46 | } 47 | 48 | get objectValue() { 49 | 50 | return this.currentRecord[ this._objectName ]; 51 | } 52 | 53 | putObjectValue( name, value ) { 54 | 55 | this.objectValue[ name ] = value; 56 | 57 | return this; 58 | } 59 | 60 | assignObjectValue( objectName, ...updatedValues ) { 61 | 62 | let updatedValue = Object.assign( {}, this.objectValue[ objectName ], ...updatedValues ); 63 | 64 | return this.putObjectValue( objectName, updatedValue ); 65 | } 66 | 67 | updateCurrentRecord() { 68 | 69 | let current = this._getCurrentRecord(); 70 | 71 | if( current ) { 72 | 73 | this._updateRecord( current ); 74 | } 75 | } 76 | 77 | build() { 78 | 79 | this._initRecords(); 80 | 81 | this.updateCurrentRecord(); 82 | 83 | return super.build(); 84 | } 85 | 86 | _createRecord() { 87 | 88 | return this._recordTemplater.render(); 89 | } 90 | 91 | _updateRecord( /* record */ ) { 92 | 93 | // does nothing 94 | } 95 | 96 | _getCurrentRecord() { 97 | 98 | let records = this.records; 99 | 100 | return records[ records.length-1 ]; 101 | } 102 | 103 | _initRecords() { 104 | 105 | if( this.records.length === 0 ) { 106 | 107 | this.next(); 108 | } 109 | } 110 | 111 | _getRecordsArray( event ) { 112 | 113 | return event.Records; 114 | } 115 | 116 | } 117 | 118 | module.exports = RecordEventMock; 119 | -------------------------------------------------------------------------------- /docs/cloudwatch_logs.md: -------------------------------------------------------------------------------- 1 | # `CloudWatch` 2 | 3 | The `cloudwatch` mock is used to simulate [CloudWatch](https://aws.amazon.com/cloudwatch/) 4 | events. To create a CloudWatch event, use the `cloudwatch()` builder: 5 | 6 | ```js 7 | const lambdaEventMock = require( 'lambda-event-mock' ); 8 | 9 | let myMock = lambdaEventMock.cloudfront() 10 | .distributionDomainName( 'd123.cloudfront.net' ) 11 | .distributionId( 'EDFDVBD6EXAMPLE' ) 12 | .eventType( 'viewer-request' ) 13 | .requestId( 'MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==' ) 14 | .body( { 15 | action: 'read-only', 16 | data: 'eyJ1c2VybmFtZSI6IkxhbWJkYUBFZGdlIiwiY29tbWVudCI6IlRoaXMgaXMgcmVxdWVzdCBib2R5In0=', 17 | encoding: 'base64', 18 | inputTruncated: false 19 | }) 20 | .clientIp( '2001:0db8:85a3:0:0:8a2e:0370:7334' ) 21 | .querystring( 'size=large' ) 22 | .uri( '/picture.jpg' ) 23 | .method( 'GET' ) 24 | .header( 'host', 'Host', 'd111111abcdef8.cloudfront.net' ) 25 | .header( 'user-agent', 'User-Agent', 'curl/7.51.0' ) 26 | .build(); 27 | 28 | /* myMock will be: 29 | 30 | { 31 | "Records": [ 32 | { 33 | "cf": { 34 | "config": { 35 | "distributionId": "EDFDVBD6EXAMPLE", 36 | "distributionDomainName": "d123.cloudfront.net", 37 | "eventType": "viewer-request", 38 | "requestId": "MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==" 39 | }, 40 | "request": { 41 | "clientIp": "2001:0db8:85a3:0:0:8a2e:0370:7334", 42 | "method": "GET", 43 | "uri": "/picture.jpg", 44 | "headers": { 45 | "host": [ 46 | { 47 | "key": "Host", 48 | "value": "d111111abcdef8.cloudfront.net" 49 | } 50 | ], 51 | "user-agent": [ 52 | { 53 | "key": "User-Agent", 54 | "value": "curl/7.51.0" 55 | } 56 | ] 57 | }, 58 | "body": { 59 | "action": "read-only", 60 | "data": "eyJ1c2VybmFtZSI6IkxhbWJkYUBFZGdlIiwiY29tbWVudCI6IlRoaXMgaXMgcmVxdWVzdCBib2R5In0=", 61 | "encoding": "base64", 62 | "inputTruncated": false 63 | }, 64 | "querystring": "size=large" 65 | } 66 | } 67 | } 68 | ] 69 | } 70 | 71 | */ 72 | ``` 73 | -------------------------------------------------------------------------------- /test/lib/sqs.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const crypto = require( 'crypto' ); 8 | 9 | const eventIdentifier = require( '@vandium/event-identifier' ); 10 | 11 | const SQSEventMock = require( '../../lib/sqs' ); 12 | 13 | describe( 'lib/sqs', function() { 14 | 15 | describe( 'SQSEventMock', function() { 16 | 17 | describe( '.build', function() { 18 | 19 | it( 'defaults', function() { 20 | 21 | let event = new SQSEventMock().build(); 22 | 23 | expect( eventIdentifier.identify( event ).type ).to.equal( 'sqs' ); 24 | }); 25 | 26 | it( 'normal operation', function() { 27 | 28 | let event = new SQSEventMock() 29 | .messageId( '1234' ) 30 | .receiptHandle( 'handle-here' ) 31 | .eventSourceARN( 'arn-here' ) 32 | .body( 'body-here' ) 33 | .build(); 34 | 35 | expect( event.Records[0].messageId ).to.equal( '1234' ); 36 | expect( event.Records[0].receiptHandle ).to.equal( 'handle-here' ); 37 | expect( event.Records[0].eventSourceARN ).to.eql( 'arn-here' ); 38 | expect( event.Records[0].body ).to.equal( 'body-here' ); 39 | expect( event.Records[0].md5OfBody ).to.equal( crypto.createHash( 'md5' ).update( event.Records[0].body ).digest( 'hex' ) ); 40 | 41 | expect( eventIdentifier.identify( event ).type ).to.equal( 'sqs' ); 42 | }); 43 | 44 | it( 'normal operation, body is a buffer', function() { 45 | 46 | let event = new SQSEventMock() 47 | .messageId( '1234' ) 48 | .receiptHandle( 'handle-here' ) 49 | .eventSourceARN( 'arn-here' ) 50 | .body( new Buffer( 'body-here' ) ) 51 | .build(); 52 | 53 | expect( event.Records[0].messageId ).to.equal( '1234' ); 54 | expect( event.Records[0].receiptHandle ).to.equal( 'handle-here' ); 55 | expect( event.Records[0].eventSourceARN ).to.eql( 'arn-here' ); 56 | expect( event.Records[0].body ).to.equal( new Buffer( 'body-here' ).toString( 'base64') ); 57 | expect( event.Records[0].md5OfBody ).to.equal( crypto.createHash( 'md5' ).update( event.Records[0].body ).digest( 'hex' ) ); 58 | 59 | expect( eventIdentifier.identify( event ).type ).to.equal( 'sqs' ); 60 | }); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /test/lib/ses.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const SESEventMock = require( '../../lib/ses' ); 10 | 11 | describe( 'lib/ses', function() { 12 | 13 | describe( 'SESEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new SESEventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 'ses' ); 22 | 23 | expect( event.Records ).to.exist; 24 | expect( event.Records.length ).to.equal( 1 ); 25 | 26 | expect( event.Records[0].eventVersion ).to.exist; 27 | expect( event.Records[0].ses ).to.exist; 28 | expect( event.Records[0].ses.mail ).to.exist; 29 | expect( event.Records[0].ses.receipt ).to.exist; 30 | 31 | }); 32 | 33 | it( 'normal operation', function() { 34 | 35 | let event = new SESEventMock() 36 | .commonHeader( 'from', ['Jane Doe '] ) 37 | .commonHeader( 'subject', 'Test Subject' ) 38 | .header( 'Return-Path', '' ) 39 | .header( 'MIME-Version', '1.0' ) 40 | .mailValue( 'source', 'JaneDoe@example.com' ) 41 | .recipient( 'johndoe@example.com' ) 42 | .receiptValue( 'dkimVerdict', { status: 'PASS' } ) 43 | .build(); 44 | 45 | expect( eventIdentifier.identify( event ).type ).to.equal( 'ses' ); 46 | 47 | expect( event.Records.length ).to.equal( 1 ); 48 | expect( event.Records[0].ses.mail.commonHeaders ).to.eql( { 49 | from: ['Jane Doe '], 50 | subject: 'Test Subject' 51 | }); 52 | expect( event.Records[0].ses.mail.headers ).to.eql( [ 53 | { name: 'Return-Path', value: '' }, 54 | { name: 'MIME-Version', value: '1.0' } 55 | ]); 56 | expect( event.Records[0].ses.mail.source ).to.equal( 'JaneDoe@example.com' ); 57 | expect( event.Records[0].ses.receipt.recipients ).to.eql( [ 'johndoe@example.com' ] ); 58 | expect( event.Records[0].ses.receipt.dkimVerdict ).to.eql( { status: 'PASS' } ); 59 | 60 | // expect( event.records[1].recordId ).to.equal( 'record2' ); 61 | }); 62 | }); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/vandium-io/lambda-event.mock.svg?branch=master)](https://travis-ci.org/vandium-io/lambda-event-mock) 2 | [![npm version](https://badge.fury.io/js/lambda-event-mock.svg)](https://badge.fury.io/js/lambda-event-mock) 3 | 4 | # lambda-event-mock 5 | 6 | Mocking library for testing AWS Lambda events by creating realistic events that 7 | contain dynamic data. 8 | 9 | ## Features 10 | * Easy to use builder-pattern to create mock lambda events for testing 11 | * Works with [lambda-tester](https://github.com/vandium-io/lambda-tester) 12 | * Works with Node 8.x 13 | 14 | ## Installation 15 | Install via npm. 16 | 17 | npm install lambda-event-mock --save-dev 18 | 19 | 20 | ## Getting Started 21 | 22 | The following example code creates an `s3` lambda event for the object 23 | `picture1.gif` in the `my-bucket-uploaded-pictures` bucket. 24 | 25 | ```js 26 | const lambdaEventMock = require( 'lambda-event-mock' ); 27 | 28 | let myMock = lambdaEventMock.s3() 29 | .object( 'picture1.gif' ) 30 | .bucket( 'my-bucket-uploaded-pictures' ) 31 | .build(); 32 | 33 | // myMock contains an s3 event object: 34 | /* 35 | { 36 | "Records": [ 37 | { 38 | "eventVersion": "2.0", 39 | "eventTime": "2018-11-15T20:46:39.446Z", 40 | "requestParameters": { 41 | "sourceIPAddress": "127.0.0.1" 42 | }, 43 | "s3": { 44 | "configurationId": "testConfigRule", 45 | "object": { 46 | "eTag": "0123456789abcdef0123456789abcdef", 47 | "sequencer": "0A1B2C3D4E5F678901", 48 | "key": "picture1.gif", 49 | "size": 1024 50 | }, 51 | "bucket": { 52 | "arn": "bucketarn", 53 | "name": "my-bucket-uploaded-pictures", 54 | "ownerIdentity": { 55 | "principalId": "USER" 56 | } 57 | }, 58 | "s3SchemaVersion": "1.0" 59 | }, 60 | "responseElements": { 61 | "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", 62 | "x-amz-request-id": "EXAMPLE123456789" 63 | }, 64 | "awsRegion": "us-east-1", 65 | "eventName": "ObjectCreated:Put", 66 | "userIdentity": { 67 | "principalId": "USER" 68 | }, 69 | "eventSource": "aws:s3" 70 | } 71 | ] 72 | } 73 | */ 74 | ``` 75 | 76 | Note that `lambda-event-mock` fills in the time, date, and other properties of 77 | the event to create a realistic looking event. 78 | 79 | ## Documentation 80 | 81 | For documentation on how to use this module in your project, please see our 82 | [documentation](docs) page. 83 | 84 | ## Feedback 85 | 86 | We'd love to get feedback on how you're using lambda-event-mock and things we 87 | could add to make this tool better. Feel free to contact us at 88 | `feedback@vandium.io` 89 | 90 | 91 | ## License 92 | 93 | [BSD-3-Clause](https://en.wikipedia.org/wiki/BSD_licenses) 94 | -------------------------------------------------------------------------------- /test/lib/cloudwatch.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const CloudWatchEventMock = require( '../../lib/cloudwatch' ); 10 | 11 | describe( 'lib/cloudwatch', function() { 12 | 13 | describe( 'CloudWatchEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new CloudWatchEventMock() 20 | .detailType( 'Scheduled') 21 | .source( 'aws.events' ) 22 | .build(); 23 | 24 | expect( event.account ).to.equal( '123456789012' ); 25 | expect( event.region ).to.equal( 'us-east-1' ); 26 | expect( event.detail ).to.eql( {} ); 27 | expect( event[ 'detail-type' ] ).to.equal( 'Scheduled' ); 28 | expect( event.source ).to.equal( 'aws.events' ); 29 | expect( event.time ).to.exist; 30 | expect( event.id ).to.exist; 31 | expect( event.resources ).to.be.an( 'Array' ); 32 | expect( event.resources ).to.eql( [] ); 33 | 34 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudwatch' ); 35 | expect( eventIdentifier.identify( event ).source ).to.equal( 'scheduled' ); 36 | }); 37 | 38 | it( 'normal operation', function() { 39 | 40 | let event = new CloudWatchEventMock() 41 | .account( '1234') 42 | .region( 'canada-eh-1') 43 | .detail( { ok: true } ) 44 | .detailType( 'Scheduled') 45 | .source( 'aws.whatever' ) 46 | .id( '5678' ) 47 | .time( 'now' ) 48 | .resources( [] ) 49 | .build(); 50 | 51 | expect( event.account ).to.equal( '1234' ); 52 | expect( event.region ).to.equal( 'canada-eh-1' ); 53 | expect( event.detail ).to.eql( { ok: true } ); 54 | expect( event[ 'detail-type' ] ).to.equal( 'Scheduled' ); 55 | expect( event.source).to.equal( 'aws.whatever' ); 56 | expect( event.id ).to.equal( '5678' ); 57 | expect( event.time).to.equal( 'now' ); 58 | expect( event.resources ).to.eql( [] ); 59 | 60 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudwatch' ); 61 | expect( eventIdentifier.identify( event ).source ).to.equal( 'aws.whatever' ); 62 | }); 63 | }); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/vandium-io/lambda-event.mock.svg?branch=master)](https://travis-ci.org/vandium-io/lambda-event-mock) 2 | [![npm version](https://badge.fury.io/js/lambda-event-mock.svg)](https://badge.fury.io/js/lambda-event-mock) 3 | 4 | # lambda-event-mock 5 | 6 | Mocking library for testing AWS Lambda events by creating realistic events that 7 | contain dynamic data. 8 | 9 | # Features 10 | * Easy to use builder-pattern to create mock lambda events for testing 11 | * Works with [lambda-tester](https://github.com/vandium-io/lambda-tester) 12 | * Works with Node 8.x 13 | 14 | # Installation 15 | Install via npm. 16 | 17 | npm install lambda-event-mock --save-dev 18 | 19 | 20 | # Getting Started 21 | 22 | The following example code creates an `s3` lambda event for the object 23 | `picture1.gif` in the `my-bucket-uploaded-pictures` bucket. 24 | 25 | ```js 26 | const lambdaEventMock = require( 'lambda-event-mock' ); 27 | 28 | let myMock = lambdaEventMock.s3() 29 | .object( 'picture1.gif' ) 30 | .bucket( 'my-bucket-uploaded-pictures' ) 31 | .build(); 32 | 33 | // myMock contains an s3 event object: 34 | /* 35 | { 36 | "Records": [ 37 | { 38 | "eventVersion": "2.0", 39 | "eventTime": "2018-11-15T20:46:39.446Z", 40 | "requestParameters": { 41 | "sourceIPAddress": "127.0.0.1" 42 | }, 43 | "s3": { 44 | "configurationId": "testConfigRule", 45 | "object": { 46 | "eTag": "0123456789abcdef0123456789abcdef", 47 | "sequencer": "0A1B2C3D4E5F678901", 48 | "key": "picture1.gif", 49 | "size": 1024 50 | }, 51 | "bucket": { 52 | "arn": "bucketarn", 53 | "name": "my-bucket-uploaded-pictures", 54 | "ownerIdentity": { 55 | "principalId": "USER" 56 | } 57 | }, 58 | "s3SchemaVersion": "1.0" 59 | }, 60 | "responseElements": { 61 | "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH", 62 | "x-amz-request-id": "EXAMPLE123456789" 63 | }, 64 | "awsRegion": "us-east-1", 65 | "eventName": "ObjectCreated:Put", 66 | "userIdentity": { 67 | "principalId": "USER" 68 | }, 69 | "eventSource": "aws:s3" 70 | } 71 | ] 72 | } 73 | */ 74 | ``` 75 | 76 | Note that `lambda-event-mock` fills in the time, date, and other properties of 77 | the event to create a realistic looking event. 78 | 79 | # Event Types 80 | 81 | **Note:** Documentation is incomplete 82 | 83 | `lambda-event-mock` supports the following lambda events: 84 | 85 | - [API Gateway](apigateway.md) 86 | - [CloudFormation](cloudformation.md) 87 | - [CloudFront](cloudfront.md) 88 | 89 | 90 | 91 | # Feedback 92 | 93 | We'd love to get feedback on how to make this tool better. Feel free to contact 94 | us at `feedback@vandium.io` 95 | 96 | 97 | # License 98 | 99 | [BSD-3-Clause](https://en.wikipedia.org/wiki/BSD_licenses) 100 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback@vandium.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /test/lib/utils.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const utils = require( '../../lib/utils' ); 8 | 9 | describe( 'lib/utils', function() { 10 | 11 | describe( '.isEmpty', function() { 12 | 13 | it( 'normal operation', function() { 14 | 15 | expect( utils.isEmpty() ).to.be.true; 16 | expect( utils.isEmpty( undefined ) ).to.be.true; 17 | expect( utils.isEmpty( null ) ).to.be.true; 18 | expect( utils.isEmpty( {} ) ).to.be.true; 19 | 20 | expect( utils.isEmpty( { one: 1 } ) ).to.be.false; 21 | }); 22 | }); 23 | 24 | describe( '.emptyIfNull', function() { 25 | 26 | it( 'normal operation', function() { 27 | 28 | expect( utils.emptyIfNull() ).to.eql( {} ); 29 | expect( utils.emptyIfNull( undefined ) ).to.eql( {} ); 30 | expect( utils.emptyIfNull( null ) ).to.eql( {} ); 31 | 32 | expect( utils.emptyIfNull( { one: 1 } ) ).to.eql( { one: 1 } ); 33 | }); 34 | }); 35 | 36 | describe( '.dateToISOString', function() { 37 | 38 | it( 'normal operation', function() { 39 | 40 | let date = new Date(); 41 | 42 | let isoString1 = utils.dateToISOString( date ); 43 | let isoString2 = utils.dateToISOString( date, true ); 44 | 45 | expect( isoString1.length < isoString2.length ).to.be.true; 46 | }); 47 | }); 48 | 49 | describe( '.booleanValue', function() { 50 | 51 | it( 'normal operation', function() { 52 | 53 | expect( utils.booleanValue( undefined, true ) ).to.be.true; 54 | expect( utils.booleanValue( null, true ) ).to.be.true; 55 | expect( utils.booleanValue( true, true ) ).to.be.true; 56 | expect( utils.booleanValue( true, false ) ).to.be.true; 57 | 58 | expect( utils.booleanValue( undefined ) ).to.be.false; 59 | expect( utils.booleanValue( undefined, false ) ).to.be.false; 60 | expect( utils.booleanValue( null, false ) ).to.be.false; 61 | expect( utils.booleanValue( false, false ) ).to.be.false; 62 | expect( utils.booleanValue( false, true ) ).to.be.false; 63 | }); 64 | }); 65 | 66 | describe( '.lowercaseFirstLetter', function() { 67 | 68 | it( 'normal operation', function() { 69 | 70 | expect( utils.lowercaseFirstLetter( 'MyMethod' ) ).to.equal( 'myMethod' ); 71 | expect( utils.lowercaseFirstLetter( 'myOtherMethod' ) ).to.equal( 'myOtherMethod' ); 72 | expect( utils.lowercaseFirstLetter( 'X' ) ).to.equal( 'x' ); 73 | }); 74 | }); 75 | 76 | describe( '.uuid', function() { 77 | 78 | it( 'normal operation', function() { 79 | 80 | expect( utils.uuid ).to.exist; 81 | }); 82 | }); 83 | 84 | describe( 'inherited values', function() { 85 | 86 | it( 'normal operation', function() { 87 | 88 | let baseUtils = require( 'vandium-utils' ); 89 | 90 | for( let key in baseUtils ) { 91 | 92 | expect( utils[ key ] ).to.exist; 93 | expect( utils[ key ] ).to.be.a( 'function' ); 94 | } 95 | }); 96 | }); 97 | }); 98 | 99 | module.exports = utils; 100 | -------------------------------------------------------------------------------- /lib/templater.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const cloneDeep = require( 'clone-deep' ); 4 | 5 | const utils = require( 'vandium-utils' ); 6 | 7 | function parseOptionValue( value ) { 8 | 9 | if( value ) { 10 | 11 | value = value.trim(); 12 | 13 | if( value === 'true' ) { 14 | 15 | value = true; 16 | } 17 | else if( value === 'false' ) { 18 | 19 | value = false; 20 | } 21 | else { 22 | 23 | let num = +value; 24 | 25 | if( !isNaN( num ) ) { 26 | 27 | value = num; 28 | } 29 | } 30 | } 31 | else { 32 | 33 | value = true; 34 | } 35 | 36 | return value; 37 | } 38 | 39 | function getOptions( optionString ) { 40 | 41 | let options = {}; 42 | 43 | if( optionString.length > 0 ) { 44 | 45 | let optionParts = optionString.split( ',' ); 46 | 47 | for( let optionPart of optionParts ) { 48 | 49 | let parts = optionPart.trim().split( '=', 2 ); 50 | 51 | let option = parts[0].trim(); 52 | 53 | if( option.length > 0 ) { 54 | 55 | options[ option ] = parseOptionValue( parts[1] ); 56 | } 57 | } 58 | } 59 | 60 | return options; 61 | } 62 | 63 | function updateValue( value, replacements ) { 64 | 65 | let command = value.substring( 2, value.length - 2 ); 66 | 67 | let commands = command.split( ':' ); 68 | 69 | let key = commands[0]; 70 | 71 | let expression = replacements[ key ]; 72 | 73 | if( utils.isFunction( expression ) ) { 74 | 75 | value = expression( getOptions( commands[1] || '' ) ); 76 | } 77 | else if( expression !== undefined ) { 78 | 79 | value = expression; 80 | } 81 | 82 | return value; 83 | } 84 | 85 | function isTemplateValue( value ) { 86 | 87 | return utils.isString( value ) && 88 | value.startsWith( '{{' ) && 89 | value.endsWith( '}}' ); 90 | } 91 | 92 | class Templater { 93 | 94 | constructor( template ) { 95 | 96 | this.template = template; 97 | 98 | this.replacements = {}; 99 | } 100 | 101 | transform( name, replacement ) { 102 | 103 | this.replacements[ name ] = replacement; 104 | 105 | return this; 106 | } 107 | 108 | render() { 109 | 110 | let obj = cloneDeep( this.template ); 111 | 112 | this._processObject( obj ); 113 | 114 | return obj; 115 | } 116 | 117 | _processObject( obj ) { 118 | 119 | for( let prop in obj ) { 120 | 121 | let value = obj[ prop ]; 122 | 123 | if( isTemplateValue( value ) ) { 124 | 125 | obj[ prop ] = updateValue( value, this.replacements ); 126 | } 127 | else { 128 | 129 | this._processValue( value ); 130 | } 131 | } 132 | } 133 | 134 | _processArray( arr ) { 135 | 136 | for( let i = 0; i < arr.length; i++ ) { 137 | 138 | let value = arr[ i ]; 139 | 140 | if( isTemplateValue( value ) ) { 141 | 142 | arr[ i ] = updateValue( value, this.replacements ); 143 | } 144 | else { 145 | 146 | this._processValue( value ); 147 | } 148 | } 149 | } 150 | 151 | _processValue( value ) { 152 | 153 | if( utils.isArray( value ) ) { 154 | 155 | this._processArray( value ); 156 | } 157 | else if( utils.isObject( value ) ) { 158 | 159 | this._processObject( value ); 160 | } 161 | } 162 | } 163 | 164 | module.exports = Templater; 165 | -------------------------------------------------------------------------------- /docs/apigateway.md: -------------------------------------------------------------------------------- 1 | # `API Gateway` 2 | 3 | The `apiGateway` mock is used to simulate [AWS API Gateway](https://aws.amazon.com/api-gateway) events using the Lambda Proxy based method. To create an API Gateway mock event, use the `apiGateway()` builder: 4 | 5 | ```js 6 | const lambdaEventMock = require( 'lambda-event-mock' ); 7 | 8 | let myMock = lambdaEventMock.apiGateway() 9 | .path( '/things' ) 10 | .method( 'POST' ) 11 | .header( 'day', 'Friday' ) 12 | .body( { one: 1, two: 2 } ) 13 | .build(); 14 | 15 | /* myMock will be: 16 | 17 | { 18 | "resource": "/things", 19 | "path": "/things", 20 | "httpMethod": "POST", 21 | "headers": { 22 | "day": "Friday" 23 | }, 24 | "queryStringParameters": null, 25 | "pathParameters": null, 26 | "stageVariables": null, 27 | "requestContext": { 28 | "resourcePath": "/", 29 | "apiId": "00aaa0a00a" 30 | }, 31 | "body": "{\"one\":1,\"two\":2}", 32 | "isBase64Encoded": false 33 | } 34 | 35 | */ 36 | ``` 37 | 38 | ## `apiId( id )` 39 | 40 | Sets the event's `requestContext.apiId` property 41 | 42 | 43 | ## `body( value )` 44 | 45 | Sets the event's `body` and `isBase64Encoded` properties. `body()` will encode 46 | `Buffer` instances as `base64` encoded strings and set the `isBase64Encoded` 47 | property to true. `Object` instances are converted to strings using `JSON.stringify()`. 48 | All other types are converted, if required, and stored as strings. 49 | 50 | ## `header( name, value )` 51 | 52 | Sets an individual value in the event's `headers` property 53 | 54 | ## `headers( values )` 55 | 56 | Sets one or more header values in the event's `headers` property. The following 57 | sample code demonstrates how to set one or more headers: 58 | 59 | ```js 60 | const lambdaEventMock = require( '.' ); 61 | 62 | let myMock = lambdaEventMock.apiGateway() 63 | .headers( { 64 | 65 | day: 'Friday', 66 | happy: 'Yes' 67 | }) 68 | .header( 'age', '42' ) 69 | .build(); 70 | 71 | /* 72 | 73 | myMock.headers will equal: 74 | { 75 | "day": "Friday", 76 | "happy", "Yes", 77 | "age", "42" 78 | } 79 | 80 | */ 81 | ``` 82 | 83 | ## `method( m )` 84 | 85 | Sets the event's `httpMethod` property. 86 | 87 | ## `path( p )` 88 | 89 | Sets the event's `path` and `resource` properties. 90 | 91 | ## `queryStringParameter( name, value )` 92 | 93 | Sets an individual value in the event's `queryStringParameters` property. 94 | 95 | ## `queryStringParameters( values )` 96 | 97 | Sets one or more query string parameter values in the event's 98 | `queryStringParameters` property. The following 99 | sample code demonstrates how to set one or more query string parameter values: 100 | 101 | ```js 102 | const lambdaEventMock = require( '.' ); 103 | 104 | let myMock = lambdaEventMock.apiGateway() 105 | .queryStringParameters( { 106 | 107 | expanded: 'true', 108 | page: '1' 109 | }) 110 | .queryStringParameter( 'show', '45' ) 111 | .build(); 112 | 113 | /* 114 | 115 | myMock.headers will equal: 116 | { 117 | "expanded": "true", 118 | "page", "1", 119 | "show", "45" 120 | } 121 | 122 | */ 123 | ``` 124 | 125 | ## `stageVariable( name, value )` 126 | 127 | Sets an individual value in the event's `stageVariables` property. 128 | 129 | ## `stageVariables( variables )` 130 | 131 | Sets one or more stage variables in the event's `stageVariables` property. The 132 | syntax of this method is similar to that of `queryStringParameters()`. 133 | -------------------------------------------------------------------------------- /lib/dynamodb.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const RecordEventMock = require( './record' ); 4 | 5 | const significantDigits = require( '@extra-number/significant-digits' ); 6 | 7 | const constants = require( './constants' ); 8 | 9 | 10 | function calculateLength( type, value ) { 11 | 12 | let length = 0; 13 | 14 | switch( type ) { 15 | 16 | case 'N': 17 | length = significantDigits( Number( value ) ); 18 | break; 19 | 20 | case 'BOOL': 21 | length = 1; 22 | break; 23 | 24 | case 'B': 25 | length = Buffer.from( value, 'base64' ).length; 26 | break; 27 | 28 | //case 'S': 29 | default: 30 | return value.toString( 'UTF-8' ).length; 31 | } 32 | 33 | return length; 34 | } 35 | 36 | function calculateSetLength( type, list ) { 37 | 38 | let length = 0; 39 | 40 | for( let item of list ) { 41 | 42 | length+= calculateLength( type, item ); 43 | } 44 | 45 | return length; 46 | } 47 | 48 | function countCollection( collection ) { 49 | 50 | let totalLength = 0; 51 | 52 | for( let item in collection ) { 53 | 54 | let itemData = collection[ item ]; 55 | 56 | let length = item.length; 57 | 58 | if( itemData.SS ) { 59 | 60 | length+= calculateSetLength( 'S', itemData.SS ); 61 | } 62 | else if( itemData.NS ) { 63 | 64 | length+= calculateSetLength( 'N', itemData.NS ); 65 | } 66 | else if( itemData.BS ) { 67 | 68 | length+= calculateLength( 'B', itemData.BS ); 69 | } 70 | else { 71 | 72 | let type = Object.keys( itemData )[0]; 73 | 74 | length+= calculateLength( type, itemData[ type ] ); 75 | } 76 | 77 | totalLength+= length; 78 | } 79 | 80 | return totalLength; 81 | } 82 | 83 | class DynamoDBEventMock extends RecordEventMock { 84 | 85 | constructor() { 86 | 87 | super( 'dynamodb' ); 88 | 89 | this._nextEventID = 1; 90 | } 91 | 92 | keys( keys ) { 93 | 94 | return this.putObjectValue( 'Keys', keys ); 95 | } 96 | 97 | newImage( image ) { 98 | 99 | return this.putObjectValue( 'NewImage', image ); 100 | } 101 | 102 | oldImage( image ) { 103 | 104 | return this.putObjectValue( 'OldImage', image ); 105 | } 106 | 107 | eventName( name ) { 108 | 109 | return this.recordValue( 'eventName', name ); 110 | } 111 | 112 | _updateRecord( record ) { 113 | 114 | let obj = record.dynamodb; 115 | 116 | // calculate SizeBytes 117 | let length = countCollection( obj.Keys ); 118 | 119 | if( obj.NewImage ) { 120 | 121 | length+= countCollection( obj.NewImage ); 122 | } 123 | 124 | if( obj.OldImage ) { 125 | 126 | length+= countCollection( obj.OldImage ); 127 | } 128 | 129 | obj.SizeBytes = length; 130 | 131 | // set StreamViewType 132 | if( obj.NewImage && obj.OldImage ) { 133 | 134 | obj.StreamViewType = constants.NEW_AND_OLD_IMAGES; 135 | } 136 | else if( obj.NewImage ) { 137 | 138 | obj.StreamViewType = constants.NEW_IMAGE; 139 | } 140 | else if( obj.OldImage ) { 141 | 142 | obj.StreamViewType = constants.OLD_IMAGE; 143 | } 144 | else { 145 | 146 | obj.StreamViewType = constants.KEYS_ONLY; 147 | } 148 | } 149 | 150 | _createRecord() { 151 | 152 | let record = super._createRecord(); 153 | 154 | record.eventID = `${this._nextEventID++}`; 155 | 156 | return record; 157 | } 158 | } 159 | 160 | module.exports = DynamoDBEventMock; 161 | -------------------------------------------------------------------------------- /test/lib/s3.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const S3EventMock = require( '../../lib/s3' ); 10 | 11 | describe( 'lib/s3', function() { 12 | 13 | describe( 'S3EventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new S3EventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 's3' ); 22 | }); 23 | 24 | it( 'normal operation', function() { 25 | 26 | let event = new S3EventMock() 27 | .bucket( 'bucket-one' ) 28 | .object( 'my-key', { size: 456} ) 29 | .configurationId( '1234' ) 30 | .build(); 31 | 32 | expect( event.Records ).to.be.an( 'Array' ); 33 | expect( event.Records.length ).to.equal( 1 ); 34 | expect( event.Records[0].s3 ).to.exist; 35 | expect( event.Records[0].s3.configurationId ).to.equal( '1234' ); 36 | expect( event.Records[0].s3.object.key ).to.equal( 'my-key'); 37 | expect( event.Records[0].s3.object.size ).to.equal( 456 ); 38 | expect( event.Records[0].s3.object.eTag ).to.exist; 39 | expect( event.Records[0].s3.object.sequencer ).to.exist; 40 | expect( event.Records[0].s3.bucket.name ).to.equal( 'bucket-one' ); 41 | 42 | expect( eventIdentifier.identify( event ).type ).to.equal( 's3' ); 43 | }); 44 | 45 | it( 'multiple records', function() { 46 | 47 | let event = new S3EventMock() 48 | .bucket( 'bucket-one' ) 49 | .object( 'my-key', { size: 456} ) 50 | .configurationId( '1234' ) 51 | .next() 52 | .bucket( 'bucket-two' ) 53 | .object( 'my-other-key' ) 54 | .configurationId( '6789' ) 55 | .eventName( 's3:ObjectRemoved:Delete' ) 56 | .build(); 57 | 58 | expect( event.Records ).to.be.an( 'Array' ); 59 | expect( event.Records.length ).to.equal( 2 ); 60 | 61 | expect( event.Records[0].s3 ).to.exist; 62 | expect( event.Records[0].s3.configurationId ).to.equal( '1234' ); 63 | expect( event.Records[0].s3.object.key ).to.equal( 'my-key'); 64 | expect( event.Records[0].s3.object.size ).to.equal( 456 ); 65 | expect( event.Records[0].s3.object.eTag ).to.exist; 66 | expect( event.Records[0].s3.object.sequencer ).to.exist; 67 | expect( event.Records[0].s3.bucket.name ).to.equal( 'bucket-one' ); 68 | 69 | expect( event.Records[1].s3 ).to.exist; 70 | expect( event.Records[1].s3.configurationId ).to.equal( '6789' ); 71 | expect( event.Records[1].s3.object.key ).to.equal( 'my-other-key'); 72 | expect( event.Records[1].s3.object.size ).to.equal( 1024 ); 73 | expect( event.Records[1].s3.object.eTag ).to.exist; 74 | expect( event.Records[1].s3.object.sequencer ).to.exist; 75 | expect( event.Records[1].s3.bucket.name ).to.equal( 'bucket-two' ); 76 | expect( event.Records[1].s3.eventName ).to.equal( 's3:ObjectRemoved:Delete' ); 77 | expect( eventIdentifier.identify( event ).type ).to.equal( 's3' ); 78 | }); 79 | }); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /docs/cloudfront.md: -------------------------------------------------------------------------------- 1 | # `CloudFront` 2 | 3 | The `cloudfront` mock is used to simulate [CloudFront](https://aws.amazon.com/cloudfront/) 4 | events. To create a CloudFront event, use the `cloudfront()` builder: 5 | 6 | ```js 7 | const lambdaEventMock = require( 'lambda-event-mock' ); 8 | 9 | let myMock = lambdaEventMock.cloudfront() 10 | .distributionDomainName( 'd123.cloudfront.net' ) 11 | .distributionId( 'EDFDVBD6EXAMPLE' ) 12 | .eventType( 'viewer-request' ) 13 | .requestId( 'MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==' ) 14 | .body( { 15 | action: 'read-only', 16 | data: 'eyJ1c2VybmFtZSI6IkxhbWJkYUBFZGdlIiwiY29tbWVudCI6IlRoaXMgaXMgcmVxdWVzdCBib2R5In0=', 17 | encoding: 'base64', 18 | inputTruncated: false 19 | }) 20 | .clientIp( '2001:0db8:85a3:0:0:8a2e:0370:7334' ) 21 | .querystring( 'size=large' ) 22 | .uri( '/picture.jpg' ) 23 | .method( 'GET' ) 24 | .header( 'host', 'Host', 'd111111abcdef8.cloudfront.net' ) 25 | .header( 'user-agent', 'User-Agent', 'curl/7.51.0' ) 26 | .build(); 27 | 28 | /* myMock will be: 29 | 30 | { 31 | "Records": [ 32 | { 33 | "cf": { 34 | "config": { 35 | "distributionId": "EDFDVBD6EXAMPLE", 36 | "distributionDomainName": "d123.cloudfront.net", 37 | "eventType": "viewer-request", 38 | "requestId": "MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE==" 39 | }, 40 | "request": { 41 | "clientIp": "2001:0db8:85a3:0:0:8a2e:0370:7334", 42 | "method": "GET", 43 | "uri": "/picture.jpg", 44 | "headers": { 45 | "host": [ 46 | { 47 | "key": "Host", 48 | "value": "d111111abcdef8.cloudfront.net" 49 | } 50 | ], 51 | "user-agent": [ 52 | { 53 | "key": "User-Agent", 54 | "value": "curl/7.51.0" 55 | } 56 | ] 57 | }, 58 | "body": { 59 | "action": "read-only", 60 | "data": "eyJ1c2VybmFtZSI6IkxhbWJkYUBFZGdlIiwiY29tbWVudCI6IlRoaXMgaXMgcmVxdWVzdCBib2R5In0=", 61 | "encoding": "base64", 62 | "inputTruncated": false 63 | }, 64 | "querystring": "size=large" 65 | } 66 | } 67 | } 68 | ] 69 | } 70 | 71 | */ 72 | ``` 73 | 74 | ## `distributionDomainName( name )` 75 | Sets the `config.distributionDomainName` property in the current record 76 | 77 | ## `distributionId( id )` 78 | Sets the `config.distributionId` property in the current record 79 | 80 | ## `eventType( type )` 81 | Sets the `config.eventType` property in the current record 82 | 83 | ## `requestId( id )` 84 | Sets the `config.requestId` property in the current record 85 | 86 | ## `clientIp( ip )` 87 | Sets the `request.clientIp` property in the current record 88 | 89 | ## `method( m )` 90 | Sets the `request.method` property in the current record 91 | 92 | ## `uri( u )` 93 | Sets the `request.uri` property in the current record 94 | 95 | ## `body( b )` 96 | Sets the `request.body` property in the current record 97 | 98 | ## `querystring( str )` 99 | Sets the `request.querystring` property in the current record 100 | 101 | ## `origin( obj )` 102 | Sets the `request.origin` property in the current record 103 | 104 | ## `header( name, key, value )` 105 | Adds a header object to the `request.headers` property in the current record 106 | 107 | ## `next()` 108 | Advances to the next record. Use this method to add multiple records to the event. 109 | -------------------------------------------------------------------------------- /test/lib/record.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const proxyquire = require( 'proxyquire' ).noCallThru(); 8 | 9 | const sinon = require( 'sinon' ); 10 | 11 | describe( 'lib/record', function() { 12 | 13 | let RecordEventMock; 14 | 15 | let templates; 16 | 17 | beforeEach( function() { 18 | 19 | templates = { 20 | 21 | myService: { 22 | 23 | render: sinon.stub().returns( { Records: [] } ) 24 | }, 25 | 26 | myService_record: { 27 | 28 | render: sinon.stub().returns( { one: 1, myService: {} } ) 29 | } 30 | }; 31 | 32 | RecordEventMock = proxyquire( '../../lib/record', { 33 | 34 | './templates': templates 35 | }); 36 | }); 37 | 38 | describe( 'RecordEventMock', function() { 39 | 40 | describe( 'constructor', function() { 41 | 42 | it( 'normal operation', function() { 43 | 44 | let instance = new RecordEventMock( 'myService' ); 45 | 46 | expect( templates.myService.render.calledOnce ).to.be.true; 47 | expect( templates.myService.render.firstCall.args ).to.eql( [] ); 48 | 49 | expect( templates.myService_record.render.called ).to.be.false; 50 | 51 | expect( instance._event ).to.eql( { Records: [] } ); 52 | }); 53 | 54 | it( 'different template name than service name', function() { 55 | 56 | let instance = new RecordEventMock( 'myService', 'myService' ); 57 | 58 | expect( templates.myService.render.calledOnce ).to.be.true; 59 | expect( templates.myService.render.firstCall.args ).to.eql( [] ); 60 | 61 | expect( templates.myService_record.render.called ).to.be.false; 62 | 63 | expect( instance._event ).to.eql( { Records: [] } ); 64 | }); 65 | }); 66 | 67 | describe( '.next', function() { 68 | 69 | it( 'normal operation', function() { 70 | 71 | let instance = new RecordEventMock( 'myService' ); 72 | 73 | expect( instance._event ).to.eql( { Records: [] } ); 74 | 75 | // will add another record 76 | let returnValue = instance.next(); 77 | expect( returnValue ).to.equal( instance ); 78 | 79 | expect( instance._event ).to.eql( { Records: [ { one: 1, myService: {} } ] } ); 80 | }); 81 | }); 82 | 83 | describe( '.currentRecord', function() { 84 | 85 | it( 'normal operation', function() { 86 | 87 | let instance = new RecordEventMock( 'myService' ); 88 | 89 | expect( instance.currentRecord ).to.equal( instance._event.Records[0] ); 90 | 91 | instance.next(); 92 | expect( instance.currentRecord ).to.equal( instance._event.Records[1] ); 93 | }); 94 | }); 95 | 96 | describe( '.recordValue', function() { 97 | 98 | it( 'normal operation', function() { 99 | 100 | let instance = new RecordEventMock( 'myService' ); 101 | 102 | let returnValue = instance.recordValue( 'id', '1234' ); 103 | 104 | expect( returnValue ).to.equal( instance ); 105 | expect( instance.currentRecord.id ).to.equal( '1234' ); 106 | 107 | instance.next(); 108 | instance.recordValue( 'id', '2345' ); 109 | expect( instance.currentRecord.id ).to.equal( '2345' ); 110 | }); 111 | }); 112 | 113 | describe( '.objectValue', function() { 114 | 115 | it( 'normal operation', function() { 116 | 117 | let instance = new RecordEventMock( 'myService' ); 118 | 119 | expect( instance.objectValue ).to.eql( {} ); 120 | }); 121 | }); 122 | 123 | describe( '.putObjectValue', function() { 124 | 125 | it( 'normal operation', function() { 126 | 127 | let instance = new RecordEventMock( 'myService' ); 128 | 129 | let returnValue = instance.putObjectValue( 'something', 1234 ); 130 | expect( returnValue ).to.equal( instance ); 131 | expect( instance.objectValue ).to.eql( { something: 1234 } ); 132 | }); 133 | }); 134 | 135 | describe( '.assignObjectValue', function() { 136 | 137 | it( 'normal operation', function() { 138 | 139 | let instance = new RecordEventMock( 'myService' ); 140 | 141 | let returnValue = instance.assignObjectValue( 'something', { id: 1234 } ); 142 | expect( returnValue ).to.equal( instance ); 143 | expect( instance.objectValue ).to.eql( { something: { id: 1234 } } ); 144 | 145 | instance.assignObjectValue( 'something', { name: 'fred' } ); 146 | expect( instance.objectValue ).to.eql( { something: { id: 1234, name: 'fred' } } ); 147 | }); 148 | }); 149 | }); 150 | }); 151 | -------------------------------------------------------------------------------- /test/lib/templater.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const cloneDeep = require( 'clone-deep' ); 8 | 9 | const Templater = require( '../../lib/templater' ); 10 | 11 | describe( 'lib/templater', function() { 12 | 13 | describe( 'Templater', function() { 14 | 15 | describe( 'constructor', function() { 16 | 17 | it( 'normal operation', function() { 18 | 19 | let template = { }; 20 | 21 | let instance = new Templater( template ); 22 | 23 | expect( instance.template ).to.equal( template ); 24 | expect( instance.replacements ).to.be.empty; 25 | }); 26 | }); 27 | 28 | describe( '.transform', function() { 29 | 30 | it( 'normal value', function() { 31 | 32 | let instance = new Templater( {} ); 33 | 34 | expect( instance.replacements ).to.be.empty; 35 | 36 | let returnValue = instance.transform( 'UTC', ' '' ); 48 | 49 | expect( returnValue ).to.equal( instance ); 50 | }); 51 | }); 52 | 53 | describe( '.render', function() { 54 | 55 | it( 'simple object', function() { 56 | 57 | let count = 100; 58 | 59 | let template = { 60 | 61 | time: '{{UTC}}', 62 | name: 'my name', 63 | special_name: '{{SPECIAL-NAME}}', 64 | longDate: '{{ISODATE:milliseconds}}', 65 | stillLongDate: '{{ISODATE:milliseconds=true}}', 66 | shortDate: '{{ISODATE:milliseconds=false,otherThing=true}}', 67 | tick: '{{TICKER:offset=50}}', 68 | happy: '{{HAPPY:yesterday = no, today=good,,,}}' 69 | }; 70 | 71 | let original = cloneDeep( template ); 72 | 73 | let result = new Templater( template ) 74 | .transform( 'UTC', 'Today!' ) 75 | .transform( 'SPECIAL-NAME', (options) => 'special name!' ) 76 | .transform( 'ISODATE', (options) => 'iso-' + options.milliseconds ) 77 | .transform( 'TICKER', (options) => { count--; return count - (options.offset || 0); } ) 78 | .transform( 'HAPPY', (options) => options.today ) 79 | .render(); 80 | 81 | expect( result ).to.eql( { 82 | 83 | time: 'Today!', 84 | name: 'my name', 85 | special_name: 'special name!', 86 | longDate: 'iso-true', 87 | stillLongDate: 'iso-true', 88 | shortDate: 'iso-false', 89 | tick: 49, 90 | happy: 'good' 91 | }); 92 | 93 | expect( template ).to.eql( original ); 94 | }); 95 | 96 | it( 'no transformation', function() { 97 | 98 | let template = { 99 | 100 | time: '{{UTC}}', 101 | name: 'my name' 102 | }; 103 | 104 | let original = cloneDeep( template ); 105 | 106 | let result = new Templater( template ) 107 | .render(); 108 | 109 | expect( result ).to.eql( { 110 | 111 | time: '{{UTC}}', 112 | name: 'my name', 113 | }); 114 | 115 | expect( template ).to.eql( original ); 116 | }); 117 | 118 | it( 'nested objects and arrays', function() { 119 | 120 | let template = { 121 | 122 | Records: [ 123 | 124 | { 125 | time: '{{UTC}}', 126 | name: 'my name', 127 | special_name: '{{SPECIAL-NAME}}', 128 | ids: [ '{{COUNT}}', '{{COUNT}}', '{{COUNT}}' ], 129 | other_names: [ 'other1', 'other2' ] 130 | } 131 | ] 132 | }; 133 | 134 | let count = 1; 135 | 136 | let result = new Templater( template ) 137 | .transform( 'UTC', 'Today!' ) 138 | .transform( 'SPECIAL-NAME', (key) => 'special name!' ) 139 | .transform( 'COUNT', () => `${count++}` ) 140 | .render(); 141 | 142 | expect( result ).to.eql( { 143 | 144 | Records: [ 145 | 146 | { 147 | time: 'Today!', 148 | name: 'my name', 149 | special_name: 'special name!', 150 | ids: [ '1', '2', '3' ], 151 | other_names: [ 'other1', 'other2' ] 152 | } 153 | ] 154 | }); 155 | }); 156 | }); 157 | }); 158 | }); 159 | -------------------------------------------------------------------------------- /test/lib/cloudfront.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const CloudfrontEventMock = require( '../../lib/cloudfront' ); 10 | 11 | const utils = require( '../../lib/utils' ); 12 | 13 | describe( 'lib/api', function() { 14 | 15 | describe( 'CloudfrontEventMock', function() { 16 | 17 | // simplet tests 18 | [ 19 | [ 'distributionId', 'MyId', 'config' ], 20 | [ 'distributionDomainName', 'MyDistName', 'config' ], 21 | [ 'eventType', 'MyEventType', 'config' ], 22 | [ 'requestId', 'MyRequestId', 'config' ], 23 | 24 | [ 'body', { data: 'whatever' }, 'request'], 25 | [ 'clientIp', '2.3.4.5', 'request'], 26 | [ 'method', '4.5.6.7', 'request' ], 27 | [ 'uri', 'DELETE', 'request' ], 28 | [ 'querystring', 'MyQueryString', 'request' ], 29 | [ 'origin', { whatever: 'ok' }, 'request' ] 30 | 31 | ].forEach( function( testParams ) { 32 | 33 | const method = testParams[0]; 34 | const data = testParams[1]; 35 | const targetObj = testParams[2]; 36 | 37 | describe( `.${method}`, function() { 38 | 39 | it( 'normal operation', function() { 40 | 41 | let instance = new CloudfrontEventMock(); 42 | 43 | let returnValue = instance[method]( data ); 44 | 45 | expect( returnValue ).to.equal( instance ); 46 | 47 | if( utils.isObject( data ) ) { 48 | 49 | // value should be cloned 50 | expect( instance.objectValue[targetObj][method] ).to.eql( data ); 51 | expect( instance.objectValue[targetObj][method] ).to.not.equal( data ); 52 | } 53 | else { 54 | 55 | expect( instance.objectValue[targetObj][method] ).to.equal( data ); 56 | } 57 | }); 58 | }); 59 | }); 60 | 61 | describe( '.header', function() { 62 | 63 | it( 'normal operation', function() { 64 | 65 | let instance = new CloudfrontEventMock(); 66 | 67 | let returnValue = instance.header( 'host', 'Host1', '1.2.3.4' ); 68 | expect( returnValue ).to.equal( instance ); 69 | 70 | expect( instance.objectValue.request.headers.host ).to.eql( [ 71 | { key: 'Host1', value: '1.2.3.4' } ]); 72 | 73 | instance.header( 'host', 'Host2', '1.2.3.5' ); 74 | expect( instance.objectValue.request.headers.host ).to.eql( [ 75 | { key: 'Host1', value: '1.2.3.4' }, 76 | { key: 'Host2', value: '1.2.3.5' } ]); 77 | 78 | instance.header( 'other', 'other1', '' ); 79 | expect( instance.objectValue.request.headers ).to.eql( { 80 | 81 | host:[ 82 | { key: 'Host1', value: '1.2.3.4' }, 83 | { key: 'Host2', value: '1.2.3.5' } 84 | ], 85 | other:[ 86 | { key: 'other1', value: '' } 87 | ] 88 | }); 89 | }); 90 | }); 91 | 92 | describe( '.build', function() { 93 | 94 | it( 'default values', function() { 95 | 96 | let event = new CloudfrontEventMock().build(); 97 | 98 | expect( eventIdentifier.identify( event ).type ).to.equal( 'cloudfront' ); 99 | }); 100 | 101 | it( 'default values', function() { 102 | 103 | let event = new CloudfrontEventMock() 104 | .distributionId( '1234' ) 105 | .clientIp( '2000::1' ) 106 | .header( 'host', 'Host','d111111abcdef8.cloudfront.net' ) 107 | .header( 'host', 'Host2','d111111abcdef8.cloudfront2.net' ) 108 | .header( 'user-agent', 'User-Agent', 'curl/7.51.0' ) 109 | .method( 'PUT' ) 110 | .uri( 'uri-here' ) 111 | .build(); 112 | 113 | expect( event.Records.length ).to.equal( 1 ); 114 | expect( event.Records[0].cf.config.distributionId ).to.equal( '1234' ); 115 | expect( event.Records[0].cf.request.clientIp ).to.equal( '2000::1' ); 116 | expect( event.Records[0].cf.request.headers ).to.eql( { 117 | "host": [ 118 | { 119 | "key": "Host", 120 | "value": "d111111abcdef8.cloudfront.net" 121 | }, 122 | { 123 | "key": "Host2", 124 | "value": "d111111abcdef8.cloudfront2.net" 125 | } 126 | ], 127 | "user-agent": [ 128 | { 129 | "key": "User-Agent", 130 | "value": "curl/7.51.0" 131 | } 132 | ]}); 133 | expect( event.Records[0].cf.request.method ).to.equal( 'PUT' ); 134 | expect( event.Records[0].cf.request.uri ).to.equal( 'uri-here' ); 135 | }); 136 | }); 137 | }); 138 | }); 139 | -------------------------------------------------------------------------------- /test/lib/sns.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const SNSEventMock = require( '../../lib/sns' ); 10 | 11 | describe( 'lib/sns', function() { 12 | 13 | describe( 'SNSEventMock', function() { 14 | 15 | describe( '.build', function() { 16 | 17 | it( 'defaults', function() { 18 | 19 | let event = new SNSEventMock().build(); 20 | 21 | expect( eventIdentifier.identify( event ).type ).to.equal( 'sns' ); 22 | }); 23 | 24 | it( 'normal operation', function() { 25 | 26 | let event = new SNSEventMock() 27 | .subject( 'my-subject' ) 28 | .signature( 'XXXX' ) 29 | .signingCert( 'TEST' ) 30 | .messageId( '1234' ) 31 | .message( 'message-here' ) 32 | .messageAttributes( { whatever: 'abc' } ) 33 | .messageAttribute( 'other', 'def' ) 34 | .topic( 'topic-arn-here' ) 35 | .type( 'Type-Here' ) 36 | .eventSubscription( 'event-arn-here' ) 37 | .build(); 38 | 39 | expect( event.Records ).to.be.an( 'Array' ); 40 | expect( event.Records.length ).to.equal( 1 ); 41 | 42 | expect( event.Records[0].EventSubscriptionArn ).to.equal( 'event-arn-here' ); 43 | 44 | expect( event.Records[0].Sns ).to.exist; 45 | expect( event.Records[0].Sns.Subject ).to.equal( 'my-subject' ); 46 | expect( event.Records[0].Sns.TopicArn ).to.equal( 'topic-arn-here' ); 47 | expect( event.Records[0].Sns.Type ).to.equal( 'Type-Here' ); 48 | expect( event.Records[0].Sns.MessageId ).to.equal( '1234' ); 49 | expect( event.Records[0].Sns.Message ).to.equal( 'message-here' ); 50 | expect( event.Records[0].Sns.MessageAttributes ).to.eql( { 51 | 52 | whatever: 'abc', 53 | other: 'def' 54 | }); 55 | expect( event.Records[0].Sns.SignatureVersion ).to.equal( '1' ); 56 | expect( event.Records[0].Sns.Signature ).to.equal( 'XXXX' ); 57 | expect( event.Records[0].Sns.SigningCertUrl ).to.equal( 'TEST' ); 58 | 59 | expect( eventIdentifier.identify( event ).type ).to.equal( 'sns' ); 60 | }); 61 | 62 | 63 | it( 'multiple records', function() { 64 | 65 | let event = new SNSEventMock() 66 | .subject( 'my-subject' ) 67 | .signature( 'XXXX' ) 68 | .signingCert( 'TEST' ) 69 | .messageId( '1234' ) 70 | .message( 'message-here' ) 71 | .messageAttributes( { whatever: 'abc' } ) 72 | .messageAttribute( 'other', 'def' ) 73 | .topic( 'topic-arn-here' ) 74 | .type( 'Type-Here' ) 75 | .eventSubscription( 'event-arn-here' ) 76 | .next() 77 | .subject( 'my-subject-2' ) 78 | .signature( 'XXXX-2' ) 79 | .signingCert( 'TEST-2' ) 80 | .messageId( '1234-2' ) 81 | .message( 'message-here-2' ) 82 | .messageAttributes( { whatever: 'abc-2' } ) 83 | .messageAttribute( 'other', 'def-2' ) 84 | .topic( 'topic-arn-here-2' ) 85 | .type( 'Type-Here-2' ) 86 | .eventSubscription( 'event-arn-here-2' ) 87 | .build(); 88 | 89 | expect( event.Records ).to.be.an( 'Array' ); 90 | expect( event.Records.length ).to.equal( 2 ); 91 | 92 | expect( event.Records[0].EventSubscriptionArn ).to.equal( 'event-arn-here' ); 93 | 94 | expect( event.Records[0].Sns ).to.exist; 95 | expect( event.Records[0].Sns.Subject ).to.equal( 'my-subject' ); 96 | expect( event.Records[0].Sns.TopicArn ).to.equal( 'topic-arn-here' ); 97 | expect( event.Records[0].Sns.Type ).to.equal( 'Type-Here' ); 98 | expect( event.Records[0].Sns.MessageId ).to.equal( '1234' ); 99 | expect( event.Records[0].Sns.Message ).to.equal( 'message-here' ); 100 | expect( event.Records[0].Sns.MessageAttributes ).to.eql( { 101 | 102 | whatever: 'abc', 103 | other: 'def' 104 | }); 105 | expect( event.Records[0].Sns.SignatureVersion ).to.equal( '1' ); 106 | expect( event.Records[0].Sns.Signature ).to.equal( 'XXXX' ); 107 | expect( event.Records[0].Sns.SigningCertUrl ).to.equal( 'TEST' ); 108 | 109 | expect( event.Records[1].EventSubscriptionArn ).to.equal( 'event-arn-here-2' ); 110 | 111 | expect( event.Records[1].Sns ).to.exist; 112 | expect( event.Records[1].Sns.Subject ).to.equal( 'my-subject-2' ); 113 | expect( event.Records[1].Sns.TopicArn ).to.equal( 'topic-arn-here-2' ); 114 | expect( event.Records[1].Sns.Type ).to.equal( 'Type-Here-2' ); 115 | expect( event.Records[1].Sns.MessageId ).to.equal( '1234-2' ); 116 | expect( event.Records[1].Sns.Message ).to.equal( 'message-here-2' ); 117 | expect( event.Records[1].Sns.MessageAttributes ).to.eql( { 118 | 119 | whatever: 'abc-2', 120 | other: 'def-2' 121 | }); 122 | expect( event.Records[1].Sns.SignatureVersion ).to.equal( '1' ); 123 | expect( event.Records[1].Sns.Signature ).to.equal( 'XXXX-2' ); 124 | expect( event.Records[1].Sns.SigningCertUrl ).to.equal( 'TEST-2' ); 125 | 126 | expect( eventIdentifier.identify( event ).type ).to.equal( 'sns' ); 127 | }); 128 | }); 129 | }); 130 | }); 131 | -------------------------------------------------------------------------------- /test/lib/apigateway.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const APIGatewayEventMock = require( '../../lib/apigateway' ); 10 | 11 | describe( 'lib/api', function() { 12 | 13 | describe( 'APIGatewayEventMock', function() { 14 | 15 | describe( 'constructor', function() { 16 | 17 | let instance = new APIGatewayEventMock(); 18 | 19 | expect( instance.method ).to.exist; 20 | expect( instance.headers ).to.exist; 21 | expect( instance.queryStringParameter ).to.exist; 22 | expect( instance.queryStringParameters ).to.exist; 23 | }); 24 | 25 | describe( '.path', function() { 26 | 27 | it( 'normal operation', function() { 28 | 29 | let instance = new APIGatewayEventMock(); 30 | 31 | let returnValue = instance.path( '/whatever' ); 32 | expect( returnValue ).to.equal( instance ); 33 | 34 | expect( instance._event.path ).to.equal( '/whatever' ); 35 | expect( instance._event.resource ).to.equal( '/whatever' ); 36 | expect( instance._event.requestContext.resourcePath ).to.equal( '/whatever' ); 37 | }); 38 | }); 39 | 40 | describe( '.body', function() { 41 | 42 | it( 'body is a string', function() { 43 | 44 | let instance = new APIGatewayEventMock(); 45 | 46 | let returnValue = instance.body( 'my-body' ); 47 | expect( returnValue ).to.equal( instance ); 48 | 49 | expect( instance._event.body ).to.equal( 'my-body' ); 50 | expect( instance._event.isBase64Encoded ).to.be.false; 51 | }); 52 | 53 | it( 'body is a buffer', function() { 54 | 55 | let instance = new APIGatewayEventMock(); 56 | 57 | let returnValue = instance.body( new Buffer( 'my-body' ) ); 58 | expect( returnValue ).to.equal( instance ); 59 | 60 | expect( instance._event.body ).to.equal( new Buffer( 'my-body' ).toString( 'base64' ) ); 61 | expect( instance._event.isBase64Encoded ).to.be.true; 62 | }); 63 | 64 | it( 'body is an object', function() { 65 | 66 | let instance = new APIGatewayEventMock(); 67 | 68 | let returnValue = instance.body( { one:1, two: 'two' } ); 69 | expect( returnValue ).to.equal( instance ); 70 | 71 | expect( instance._event.body ).to.equal( '{"one":1,"two":"two"}' ); 72 | expect( instance._event.isBase64Encoded ).to.be.false; 73 | }); 74 | 75 | it( 'body not set', function() { 76 | 77 | let instance = new APIGatewayEventMock(); 78 | 79 | let returnValue = instance.body( null ); 80 | expect( returnValue ).to.equal( instance ); 81 | 82 | expect( instance._event.body ).to.be.null; 83 | expect( instance._event.isBase64Encoded ).to.be.false; 84 | }); 85 | 86 | it( 'no parameters', function() { 87 | 88 | let instance = new APIGatewayEventMock(); 89 | 90 | let returnValue = instance.body(); 91 | expect( returnValue ).to.equal( instance ); 92 | 93 | expect( instance._event.body ).to.equal( '{}' ); 94 | expect( instance._event.isBase64Encoded ).to.be.false; 95 | }); 96 | }); 97 | 98 | describe( '.apiId', function() { 99 | 100 | it( 'normal operation', function() { 101 | 102 | let instance = new APIGatewayEventMock(); 103 | 104 | let returnValue = instance.apiId( '1234' ); 105 | expect( returnValue ).to.equal( instance ); 106 | 107 | expect( instance._event.requestContext.apiId ).to.equal( '1234' ); 108 | }); 109 | }); 110 | 111 | describe( '.base64Encoded', function() { 112 | 113 | it( 'normal operation', function() { 114 | 115 | let instance = new APIGatewayEventMock(); 116 | 117 | let returnValue = instance.base64Encoded( true ); 118 | expect( returnValue ).to.equal( instance ); 119 | 120 | expect( instance._event.isBase64Encoded ).to.be.true; 121 | 122 | instance.base64Encoded( false ); 123 | expect( instance._event.isBase64Encoded ).to.be.false; 124 | 125 | instance.base64Encoded(); 126 | expect( instance._event.isBase64Encoded ).to.be.true; 127 | }); 128 | }); 129 | 130 | describe( '.build', function() { 131 | 132 | it( 'defaults', function() { 133 | 134 | let event = new APIGatewayEventMock().build(); 135 | 136 | expect( event.resource ).to.equal( '/' ); 137 | expect( event.path ).to.equal( '/' ); 138 | expect( event.httpMethod ).to.equal( 'GET' ); 139 | expect( event.headers ).to.be.null; 140 | expect( event.queryStringParameters ).to.be.null; 141 | expect( event.pathParameters ).to.be.null; 142 | expect( event.stageVariables ).to.be.null; 143 | expect( event.requestContext ).to.exist; 144 | expect( event.requestContext.resourcePath ).to.equal( '/' ); 145 | expect( event.requestContext.apiId ).to.equal( '00aaa0a00a' ); 146 | expect( event.body ).to.be.null; 147 | expect( event.isBase64Encoded ).to.be.false; 148 | 149 | expect( eventIdentifier.identify( event ).type ).to.equal( 'apigateway' ); 150 | }); 151 | 152 | it( 'simple', function() { 153 | 154 | let event = new APIGatewayEventMock() 155 | .method( 'POST' ) 156 | .path( '/things/Friday' ) 157 | .body( { one: 1, two: 2 } ) 158 | .queryStringParameter( 'expanded', 'true' ) 159 | .stageVariable( 'DEBUG_LEVEL', 'info' ) 160 | .pathParameter( 'day', 'Friday' ) 161 | .build(); 162 | 163 | expect( event.resource ).to.equal( '/things/Friday' ); 164 | expect( event.path ).to.equal( '/things/Friday' ); 165 | expect( event.httpMethod ).to.equal( 'POST' ); 166 | expect( event.headers ).to.be.null; 167 | expect( event.queryStringParameters ).to.eql( { expanded: 'true' } ); 168 | expect( event.pathParameters ).to.eql( { day: 'Friday' } ); 169 | expect( event.stageVariables ).to.eql( { DEBUG_LEVEL: 'info' } ); 170 | expect( event.requestContext ).to.exist; 171 | expect( event.requestContext.resourcePath ).to.equal( '/things/Friday' ); 172 | expect( event.requestContext.apiId ).to.equal( '00aaa0a00a' ); 173 | expect( event.body ).to.equal( '{"one":1,"two":2}'); 174 | expect( event.isBase64Encoded ).to.be.false; 175 | 176 | expect( eventIdentifier.identify( event ).type ).to.equal( 'apigateway' ); 177 | }); 178 | 179 | it( 'buffer body', function() { 180 | 181 | let event = new APIGatewayEventMock() 182 | .method( 'POST' ) 183 | .body( new Buffer( JSON.stringify( { one: 1, two: 2 } ) ) ) 184 | .queryStringParameter( 'expanded', true ) 185 | .build(); 186 | 187 | expect( event.resource ).to.equal( '/' ); 188 | expect( event.path ).to.equal( '/' ); 189 | expect( event.httpMethod ).to.equal( 'POST' ); 190 | expect( event.headers ).to.be.null; 191 | expect( event.queryStringParameters ).to.eql( { expanded: true } ); 192 | expect( event.pathParameters ).to.be.null; 193 | expect( event.stageVariables ).to.be.null; 194 | expect( event.requestContext ).to.exist; 195 | expect( event.requestContext.resourcePath ).to.equal( '/' ); 196 | expect( event.requestContext.apiId ).to.equal( '00aaa0a00a' ); 197 | expect( event.body ).to.equal( new Buffer( '{"one":1,"two":2}' ).toString( 'base64' ) ); 198 | expect( event.isBase64Encoded ).to.be.true; 199 | 200 | expect( eventIdentifier.identify( event ).type ).to.equal( 'apigateway' ); 201 | }); 202 | }); 203 | }); 204 | }); 205 | -------------------------------------------------------------------------------- /test/lib/dynamodb.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const DynamoDBEventMock = require( '../../lib/dynamodb' ); 10 | 11 | describe( 'lib/dynamodb', function() { 12 | 13 | describe( 'DynamoDBEventMock', function() { 14 | 15 | describe( '.eventName', function() { 16 | 17 | it( 'normal operation', function() { 18 | 19 | let instance = new DynamoDBEventMock(); 20 | 21 | // default 22 | expect( instance.currentRecord.eventName ).to.equal( 'INSERT' ); 23 | 24 | let returnValue = instance.eventName( 'REMOVE' ); 25 | 26 | expect( returnValue ).to.equal( instance ); 27 | expect( instance.currentRecord.eventName ).to.equal( 'REMOVE' ); 28 | }); 29 | }); 30 | 31 | describe( '.build', function() { 32 | 33 | it( 'defaults', function() { 34 | 35 | let event = new DynamoDBEventMock().build(); 36 | 37 | expect( eventIdentifier.identify( event ).type ).to.equal( 'dynamodb' ); 38 | }); 39 | 40 | it( 'validate SizeBytes', function() { 41 | 42 | // sample date from: 43 | // https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html 44 | let event1 = new DynamoDBEventMock() 45 | .keys( { 46 | Id: { 47 | N: '101' 48 | } 49 | }) 50 | .newImage( { 51 | Message: { 52 | S: 'New item!' 53 | }, 54 | Id: { 55 | N: '101' 56 | } 57 | }) 58 | .build(); 59 | 60 | expect( event1.Records[0].dynamodb.SizeBytes ).to.equal( 26 ); 61 | expect( eventIdentifier.identify( event1 ).type ).to.equal( 'dynamodb' ); 62 | 63 | let event2 = new DynamoDBEventMock() 64 | .keys( { 65 | "Id": { 66 | "N": "101" 67 | } 68 | }) 69 | .oldImage( { 70 | "Message": { 71 | "S": "New item!" 72 | }, 73 | "Id": { 74 | "N": "101" 75 | } 76 | }) 77 | .newImage( { 78 | "Message": { 79 | "S": "This item has changed" 80 | }, 81 | "Id": { 82 | "N": "101" 83 | } 84 | }) 85 | .build(); 86 | 87 | expect( event2.Records[0].dynamodb.SizeBytes ).to.equal( 59 ); 88 | expect( eventIdentifier.identify( event2 ).type ).to.equal( 'dynamodb' ); 89 | 90 | let event3 = new DynamoDBEventMock() 91 | .keys( { 92 | Id: { 93 | N: '101' 94 | } 95 | }) 96 | .newImage( { 97 | Message: { 98 | SS: ['Item1','Item2'] 99 | }, 100 | Counts: { 101 | NS: ['1','2'] 102 | }, 103 | Data: { 104 | BS: ['dGVzdA=='] 105 | }, 106 | Nice: { 107 | BOOL: true 108 | }, 109 | Id: { 110 | N: '101' 111 | } 112 | }) 113 | .build(); 114 | 115 | expect( event3.Records[0].dynamodb.SizeBytes ).to.equal( 45 ); 116 | expect( eventIdentifier.identify( event3 ).type ).to.equal( 'dynamodb' ); 117 | }); 118 | 119 | it( 'validate StreamViewType', function() { 120 | 121 | // sample date from: 122 | // https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html 123 | let event1 = new DynamoDBEventMock() 124 | .keys( { 125 | Id: { 126 | N: '101' 127 | } 128 | }) 129 | .build(); 130 | 131 | expect( event1.Records[0].dynamodb.StreamViewType ).to.equal( 'KEYS_ONLY' ); 132 | expect( eventIdentifier.identify( event1 ).type ).to.equal( 'dynamodb' ); 133 | 134 | let event2 = new DynamoDBEventMock() 135 | .keys( { 136 | "Id": { 137 | "N": "101" 138 | } 139 | }) 140 | .oldImage( { 141 | "Message": { 142 | "S": "New item!" 143 | }, 144 | "Id": { 145 | "N": "101" 146 | } 147 | }) 148 | .build(); 149 | 150 | expect( event2.Records[0].dynamodb.StreamViewType ).to.equal( 'OLD_IMAGE' ); 151 | expect( eventIdentifier.identify( event2 ).type ).to.equal( 'dynamodb' ); 152 | 153 | let event3 = new DynamoDBEventMock() 154 | .keys( { 155 | Id: { 156 | N: '101' 157 | } 158 | }) 159 | .newImage( { 160 | Message: { 161 | S: 'New item!' 162 | }, 163 | Id: { 164 | N: '101' 165 | } 166 | }) 167 | .build(); 168 | 169 | expect( event3.Records[0].dynamodb.StreamViewType ).to.equal( 'NEW_IMAGE' ); 170 | expect( eventIdentifier.identify( event3 ).type ).to.equal( 'dynamodb' ); 171 | 172 | let event4 = new DynamoDBEventMock() 173 | .keys( { 174 | "Id": { 175 | "N": "101" 176 | } 177 | }) 178 | .oldImage( { 179 | "Message": { 180 | "S": "New item!" 181 | }, 182 | "Id": { 183 | "N": "101" 184 | } 185 | }) 186 | .newImage( { 187 | "Message": { 188 | "S": "This item has changed" 189 | }, 190 | "Id": { 191 | "N": "101" 192 | } 193 | }) 194 | .build(); 195 | 196 | expect( event4.Records[0].dynamodb.StreamViewType ).to.equal( 'NEW_AND_OLD_IMAGES' ); 197 | expect( eventIdentifier.identify( event4 ).type ).to.equal( 'dynamodb' ); 198 | }); 199 | }); 200 | }); 201 | }); 202 | -------------------------------------------------------------------------------- /test/lib/templates/index.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /*jshint expr: true*/ 4 | 5 | const expect = require( 'chai' ).expect; 6 | 7 | const eventIdentifier = require( '@vandium/event-identifier' ); 8 | 9 | const templates = require( '../../../lib/templates' ); 10 | 11 | 12 | describe( 'lib/templates/index', function() { 13 | 14 | function validateTemplate( name, verifier, type = name, source = null ) { 15 | 16 | it( 'normal operation', function() { 17 | 18 | expect( templates[name] ).to.exist; 19 | expect( templates[name].render ).to.exist; 20 | 21 | let event = templates[ name ].render(); 22 | 23 | let identity = eventIdentifier.identify( event ); 24 | 25 | expect( identity.type ).to.equal( type ); 26 | 27 | if( source ) { 28 | 29 | expect( identity.source ).to.equal( source ); 30 | } 31 | 32 | verifier( event ); 33 | }); 34 | } 35 | 36 | function validateRecordTemplate( name, verifier, type = name ) { 37 | 38 | it( 'normal operation', function() { 39 | 40 | expect( templates[name] ).to.exist; 41 | expect( templates[name].render ).to.exist; 42 | 43 | let recordTemplateName = name + '_record'; 44 | 45 | expect( templates[ recordTemplateName ] ).to.exist; 46 | expect( templates[ recordTemplateName ].render ).to.exist; 47 | 48 | let event = templates[ name ].render(); 49 | let record = templates[ recordTemplateName ].render(); 50 | 51 | if( event.Records ) { 52 | 53 | expect( event.Records ).to.be.an( 'Array' ); 54 | expect( event.Records.length ).to.equal( 0 ); 55 | 56 | event.Records.push( record ); 57 | } 58 | else { 59 | 60 | expect( event.records ).to.exist; 61 | expect( event.records ).to.be.an( 'Array' ); 62 | expect( event.records.length ).to.equal( 0 ); 63 | 64 | event.records.push( record ); 65 | } 66 | 67 | expect( eventIdentifier.identify( event ).type ).to.equal( type ); 68 | 69 | verifier( event, record ); 70 | }); 71 | } 72 | 73 | describe( 'simple type events', function() { 74 | 75 | describe( '.apigateway', function() { 76 | 77 | validateTemplate( 'apigateway', (event) => { 78 | 79 | expect( event.path ).to.exist; 80 | expect( event.httpMethod ).to.exist; 81 | expect( event.headers ).to.be.null; 82 | expect( event.queryStringParameters ).to.be.null; 83 | expect( event.pathParameters ).to.be.null; 84 | expect( event.stageVariables ).to.be.null; 85 | expect( event.requestContext ).to.exist; 86 | expect( event.body ).to.be.null; 87 | expect( event.isBase64Encoded ).to.be.false; 88 | }); 89 | }); 90 | 91 | describe( '.cloudformation', function() { 92 | 93 | validateTemplate( 'cloudformation', (event) => { 94 | 95 | expect( event.StackId ).to.exist; 96 | expect( event.ResponseURL ).to.exist; 97 | expect( event.ResourceProperties ).to.exist; 98 | expect( event.RequestType ).to.exist; 99 | expect( event.ResourceType ).to.exist; 100 | expect( event.RequestId ).to.exist; 101 | expect( event.LogicalResourceId ).to.exist; 102 | }); 103 | }); 104 | 105 | describe( '.cloudwatch-logs', function() { 106 | 107 | validateTemplate( 'cloudwatch-logs', (event) => { 108 | 109 | expect( event.awslogs ).to.exist; 110 | expect( event.awslogs.data ).to.exist; 111 | }, 'cloudwatch', 'logs'); 112 | }); 113 | 114 | describe( '.cognito', function() { 115 | 116 | validateTemplate( 'cognito', (event) => { 117 | 118 | expect( event.datasetName ).to.exist; 119 | expect( event.eventType).to.exist; 120 | expect( event.region ).to.exist; 121 | expect( event.identityId ).to.exist; 122 | expect( event.datasetRecords ).to.exist; 123 | expect( event.identityPoolId).to.exist; 124 | expect( event.version ).to.exist; 125 | }); 126 | }); 127 | 128 | describe( '.config', function() { 129 | 130 | validateTemplate( 'config', (event) => { 131 | 132 | expect( event.invokingEvent ).to.exist; 133 | expect( event.ruleParameters).to.exist; 134 | expect( event.resultToken ).to.exist; 135 | expect( event.eventLeftScope ).to.exist; 136 | expect( event.executionRoleArn ).to.exist; 137 | expect( event.configRuleArn).to.exist; 138 | expect( event.configRuleName ).to.exist; 139 | expect( event.configRuleId ).to.exist; 140 | expect( event.accountId ).to.exist; 141 | expect( event.version ).to.exist; 142 | }); 143 | }); 144 | 145 | describe( '.iot-button', function() { 146 | 147 | validateTemplate( 'iot-button', (event) => { 148 | 149 | expect( event.serialNumber ).to.exist; 150 | expect( event.clickType).to.exist; 151 | expect( event.batteryVoltage ).to.exist; 152 | }); 153 | }); 154 | 155 | describe( '.lex', function() { 156 | 157 | validateTemplate( 'lex', (event) => { 158 | 159 | expect( event.messageVersion ).to.exist; 160 | expect( event.invocationSource).to.exist; 161 | expect( event.userId ).to.exist; 162 | 163 | expect( event.sessionAttributes ).to.exist; 164 | 165 | expect( event.bot ).to.exist; 166 | expect( event.bot.name).to.exist; 167 | expect( event.bot.alias ).to.exist; 168 | expect( event.bot.version ).to.exist; 169 | 170 | expect( event.outputDialogMode ).to.exist; 171 | 172 | expect( event.currentIntent).to.exist; 173 | expect( event.currentIntent.name).to.exist; 174 | expect( event.currentIntent.slots).to.exist; 175 | expect( event.currentIntent.confirmationStatus).to.exist; 176 | }); 177 | }); 178 | 179 | describe( '.scheduled', function() { 180 | 181 | validateTemplate( 'cloudwatch', (event) => { 182 | 183 | expect( event.account ).to.exist; 184 | expect( event.region ).to.exist; 185 | expect( event.detail ).to.eql( {} ); 186 | expect( event[ 'detail-type' ] ).to.exist; 187 | expect( event.source ).to.exist; 188 | expect( event.time ).to.exist; 189 | expect( event.id ).to.exist; 190 | expect( event.resources ).to.exist; 191 | }); 192 | }); 193 | }); 194 | 195 | describe( 'record type events', function() { 196 | 197 | describe( '.cloudfront', function() { 198 | 199 | validateRecordTemplate( 'cloudfront', (event,record) => { 200 | 201 | expect( record.cf.config ).to.exist; 202 | expect( record.cf.config.distributionId ).to.exist; 203 | expect( record.cf.request ).to.exist; 204 | expect( record.cf.request.clientIp ).to.exist; 205 | expect( record.cf.request.method ).to.exist; 206 | expect( record.cf.request.uri ).to.exist; 207 | expect( record.cf.request.headers ).to.exist; 208 | }); 209 | }); 210 | 211 | describe( '.dynamodb', function() { 212 | 213 | validateRecordTemplate( 'dynamodb', (event,record) => { 214 | 215 | expect( record.eventID ).to.exist; 216 | expect( record.eventVersion ).to.exist; 217 | 218 | expect( record.dynamodb ).to.exist; 219 | expect( record.dynamodb.Keys ).to.exist; 220 | expect( record.dynamodb.StreamViewType ).to.exist; 221 | expect( record.dynamodb.SequenceNumber ).to.exist; 222 | expect( record.dynamodb.SizeBytes ).to.exist; 223 | 224 | expect( record.awsRegion ).to.exist; 225 | expect( record.eventName ).to.exist; 226 | expect( record.eventSourceARN ).to.exist; 227 | expect( record.eventSource ).to.exist; 228 | }); 229 | }); 230 | 231 | describe( '.kinesis', function() { 232 | 233 | validateRecordTemplate( 'kinesis', (event,record) => { 234 | 235 | expect( record.eventID ).to.exist; 236 | expect( record.eventVersion ).to.exist; 237 | expect( record.invokeIdentityArn ).to.exist; 238 | expect( record.eventName ).to.exist; 239 | expect( record.eventSource ).to.exist; 240 | expect( record.awsRegion ).to.exist; 241 | 242 | expect( record.kinesis ).to.exist; 243 | expect( record.kinesis.partitionKey ).to.exist; 244 | expect( record.kinesis.data ).to.exist; 245 | expect( record.kinesis.kinesisSchemaVersion ).to.exist; 246 | expect( record.kinesis.sequenceNumber ).to.exist; 247 | }); 248 | }); 249 | 250 | describe( '.kinesis-firehose', function() { 251 | 252 | validateRecordTemplate( 'kinesis-firehose', (event,record) => { 253 | 254 | expect( event.invocationId ).to.exist; 255 | expect( event.deliveryStreamArn ).to.exist; 256 | expect( event.region ).to.exist; 257 | expect( event.records ).to.exist; 258 | 259 | expect( record.data ).to.exist; 260 | expect( record.recordId ).to.exist; 261 | expect( record.approximateArrivalTimestamp ).to.exist; 262 | 263 | expect( record.kinesisRecordMetadata ).to.exist; 264 | expect( record.kinesisRecordMetadata.shardId ).to.exist; 265 | expect( record.kinesisRecordMetadata.partitionKey ).to.exist; 266 | expect( record.kinesisRecordMetadata.approximateArrivalTimestamp ).to.exist; 267 | expect( record.kinesisRecordMetadata.sequenceNumber ).to.exist; 268 | expect( record.kinesisRecordMetadata.subsequenceNumber ).to.exist; 269 | }); 270 | }); 271 | 272 | describe( '.s3', function() { 273 | 274 | validateRecordTemplate( 's3', (event,record) => { 275 | 276 | expect( record.eventVersion ).to.exist; 277 | expect( record.eventTime ).to.exist; 278 | expect( record.requestParameters ).to.exist; 279 | expect( record.s3 ).to.exist; 280 | expect( record.responseElements ).to.exist; 281 | expect( record.awsRegion ).to.exist; 282 | expect( record.responseElements ).to.exist; 283 | expect( record.eventName ).to.exist; 284 | expect( record.userIdentity ).to.exist; 285 | expect( record.eventSource ).to.exist; 286 | }); 287 | }); 288 | 289 | describe( '.ses', function() { 290 | 291 | validateRecordTemplate( 'ses', (event,record) => { 292 | 293 | expect( record.eventVersion ).to.exist; 294 | expect( record.eventSource ).to.exist; 295 | 296 | expect( record.ses ).to.exist; 297 | expect( record.ses.mail ).to.exist; 298 | expect( record.ses.receipt ).to.exist; 299 | }); 300 | }); 301 | 302 | 303 | describe( '.sns', function() { 304 | 305 | validateRecordTemplate( 'sns', (event, record) => { 306 | 307 | expect( record.EventVersion ).to.exist; 308 | expect( record.EventSubscriptionArn ).to.exist; 309 | expect( record.EventSource ).to.exist; 310 | expect( record.Sns ).to.exist; 311 | }); 312 | }); 313 | 314 | describe( '.sqs', function() { 315 | 316 | validateRecordTemplate( 'sqs', (event, record) => { 317 | 318 | expect( record.messageId ).to.exist; 319 | expect( record.receiptHandle ).to.exist; 320 | expect( record.body ).to.exist; 321 | expect( record.attributes ).to.exist; 322 | expect( record.messageAttributes ).to.exist; 323 | expect( record.md5OfBody ).to.exist; 324 | expect( record.eventSource ).to.exist; 325 | expect( record.eventSourceARN ).to.exist; 326 | expect( record.awsRegion ).to.exist; 327 | }); 328 | }); 329 | }); 330 | }); 331 | --------------------------------------------------------------------------------