Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

aws-sdk-v3-upgrade - bff #6

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions template-bff-service/.babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"@babel/preset-env",
{
"targets": {
"node": "16"
"node": "20"
}
}
]
Expand All @@ -22,7 +22,7 @@
"@babel/preset-env",
{
"targets": {
"node": "16"
"node": "20"
},
"modules": "umd"
}
Expand Down
21,493 changes: 12,505 additions & 8,988 deletions template-bff-service/package-lock.json

Large diffs are not rendered by default.

62 changes: 38 additions & 24 deletions template-bff-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"test:int:ci": "eval \"$(assume-role) npm run test:int\"",
"test:sls": "sls package --verbose -r us-west-2 -s np",
"test:sls:ci": "eval \"$(assume-role) npm run test:sls\"",
"start": "sls offline --port 3001 --apiKey test-int-api-key-123456 -r us-west-2 -s np",
"start": "sls offline --httpPort 3001 --lambdaPort 3002 -r us-west-2 -s np",
"dp:np:w": "sls deploy --verbose -r us-west-2 -s np --force",
"dp:np:e": "sls deploy --verbose -r us-east-1 -s np --force",
"dp:prd:w": "sls deploy --verbose -r us-west-2 -s prd --force",
Expand All @@ -27,14 +27,16 @@
"command": "nyc mocha --recursive \"./test/unit/**/*.test.js\"",
"env": {
"NODE_ENV": "test",
"AES": "false",
"AWS_REGION": "us-west-2",
"KMS_REGIONS": "us-east-1,us-west-2"
}
},
"test:int": {
"command": "npm start -- --exec \"mocha --timeout 20000 --require @babel/register --recursive ./test/helper.js \"./test/int/**/*.test.js\"\"",
"command": "start-test --expect 404 http://localhost:3002 'mocha --timeout 20000 --require @babel/register --recursive ./test/helper.js \"./test/int/**/*.test.js\"'",
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

serverless-offline no longer supports the --exec arg

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • the lambda endpoint of 3002 returns a 404 when start-test sends a ping request
  • since there is no ping function defined
  • but that is good enough to know that serverless-offline is up

"env": {
"NODE_ENV": "test",
"AES": "false",
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turn AES off in the serverless-offline http and lambda processes

"AWS_REGION": "us-west-2",
"KMS_REGIONS": "us-east-1,us-west-2",
"DEBUG": "tbd*"
Expand All @@ -50,54 +52,66 @@
}
},
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/core": "^7.17.10",
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-transform-runtime": "^7.17.10",
"@babel/preset-env": "^7.17.7",
"@babel/register": "^7.17.7",
"@aws-sdk/client-dynamodb": "^3.450.0",
"@aws-sdk/client-eventbridge": "^3.450.0",
"@aws-sdk/client-kms": "^3.450.0",
"@aws-sdk/client-lambda": "^3.450.0",
"@aws-sdk/client-s3": "^3.450.0",
"@aws-sdk/client-secrets-manager": "^3.450.0",
"@aws-sdk/client-sns": "^3.450.0",
"@aws-sdk/client-sqs": "^3.450.0",
"@aws-sdk/lib-dynamodb": "^3.450.0",
"@aws-sdk/s3-request-presigner": "^3.450.0",
"@aws-sdk/util-dynamodb": "^3.450.0",
"@babel/cli": "^7.23.0",
"@babel/core": "^7.23.0",
"@babel/eslint-parser": "^7.23.3",
"@babel/plugin-transform-runtime": "^7.23.3",
"@babel/preset-env": "^7.23.3",
"@babel/register": "^7.23.3",
"aws-assume-role-cicd": "^1.0.4",
"aws-sdk": "^2.1133.0",
jgilbert01 marked this conversation as resolved.
Show resolved Hide resolved
"aws-sdk-mock": "^5.7.0",
"babel-loader": "^8.2.5",
"aws-sdk-client-mock": "^3.0.0",
"babel-loader": "^9.1.3",
"babel-plugin-istanbul": "^6.1.1",
"baton-vcr-replay-for-aws-sdk": "^1.0.1",
"baton-vcr-serverless-plugin": "^1.0.0",
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these no longer work with the newer versions of serverless-offline

jgilbert01 marked this conversation as resolved.
Show resolved Hide resolved
"better-npm-run": "^0.1.1",
"chai": "^4.3.6",
"eslint": "^8.15.0",
"eslint": "^8.53.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-formatter-pretty": "^4.1.0",
"eslint-plugin-import": "^2.26.0",
"husky": "^8.0.1",
"lint-staged": "^12.4.1",
"lint-staged": "^15.1.0",
"mocha": "^10.0.0",
"nock": "^13.2.4",
"nyc": "^15.1.0",
"serverless": "^3.0.0",
"serverless": "^3.36.0",
jgilbert01 marked this conversation as resolved.
Show resolved Hide resolved
"serverless-aws-describe-plugin": "^1.0.0",
"serverless-kinesis-esm-plugin": "^1.0.1",
"serverless-offline": "^5.0.0",
"serverless-offline": "^13.3.3",
"serverless-webpack": "^5.7.1",
"sinon": "^14.0.0",
"sinon-chai": "^3.5.0",
"start-server-and-test": "^2.0.3",
"supertest": "^6.2.3",
"webpack": "^4.46.0",
"webpack-node-externals": "^2.5.2"
"webpack": "^5.89.0",
"webpack-node-externals": "^3.0.0"
},
"dependencies": {
"@babel/runtime": "^7.17.9",
"aws-kms-ee": "^0.14.0",
"aws-lambda-stream": "^0.49.0",
"@babel/runtime": "^7.23.2",
"@smithy/node-http-handler": "^2.1.9",
"@smithy/util-retry": "^2.1.1",
"@smithy/util-stream": "^2.1.1",
"aws-kms-ee": "^1.0.0",
"aws-lambda-stream": "^1.0.0",
"bluebird": "^3.7.2",
"debug": "^4.1.0",
"debug": "^4.3.4",
"highland": "^2.13.5",
"isomorphic-fetch": "^3.0.0",
"lambda-api": "^0.11.2",
"lodash": "^4.17.21",
"memory-cache": "^0.2.0",
"moment": "^2.29.4",
"node-fetch": "^2.6.1",
"uuid": "^3.3.3"
"uuid": "^9.0.1"
}
}
2 changes: 1 addition & 1 deletion template-bff-service/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ provider:
deploymentRole: ${file(serverless/cfn.yml):deploymentRole}
role: ${file(serverless/iam.yml):role}
stackTags: ${file(serverless/tags.yml)}
runtime: nodejs16.x
runtime: nodejs20.x
logRetentionInDays: ${param:logRetentionInDays}
environment: ${file(serverless/config.yml):environment}
endpointType: REGIONAL
Expand Down
35 changes: 23 additions & 12 deletions template-bff-service/src/connectors/dynamodb.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */
import { config, DynamoDB } from 'aws-sdk';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import {
DynamoDBDocumentClient,
QueryCommand,
UpdateCommand,
} from '@aws-sdk/lib-dynamodb';
import { NodeHttpHandler } from '@smithy/node-http-handler';
import Promise from 'bluebird';
import _ from 'highland';
import { updateExpression } from 'aws-lambda-stream';

config.setPromisesDependency(Promise);

class Connector {
constructor(
debug,
Expand All @@ -14,12 +18,13 @@ class Connector {
) {
this.debug = (msg) => debug('%j', msg);
this.tableName = tableName || /* istanbul ignore next */ 'undefined';
this.db = new DynamoDB.DocumentClient({
httpOptions: {
timeout,
},
this.db = DynamoDBDocumentClient.from(new DynamoDBClient({
requestHandler: new NodeHttpHandler({
requestTimeout: timeout,
connectionTimeout: timeout,
}),
logger: { log: /* istanbul ignore next */ (msg) => debug('%s', msg.replace(/\n/g, '\r')) },
});
}));
}

update(Key, inputParams) {
Expand All @@ -29,7 +34,7 @@ class Connector {
...updateExpression(inputParams),
};

return this.db.update(params).promise()
return this._executeCommand(new UpdateCommand(params))
.tap(this.debug)
.tapCatch(this.debug);
}
Expand All @@ -54,7 +59,7 @@ class Connector {
ConsistentRead: !IndexName,
};

return this.db.query(params).promise()
return this._executeCommand(new QueryCommand(params))
.tap(this.debug)
.tapCatch(this.debug)
.then((data) => data.Items);
Expand Down Expand Up @@ -92,7 +97,7 @@ class Connector {

return _((push, next) => {
params.ExclusiveStartKey = cursor;
return this.db.query(params).promise()
return this._executeCommand(new QueryCommand(params))
.tap(this.debug)
.tapCatch(this.debug)
.then((data) => {
Expand Down Expand Up @@ -158,7 +163,7 @@ class Connector {

return _((push, next) => {
params.ExclusiveStartKey = cursor;
return this.db.query(params).promise()
return this._executeCommand(new QueryCommand(params))
.tap(this.debug)
.tapCatch(this.debug)
.then((data) => {
Expand Down Expand Up @@ -187,6 +192,12 @@ class Connector {
.map((data) => ({ data }))
.toPromise(Promise);
}

_executeCommand(command) {
return Promise.resolve(this.db.send(command))
.tap(this.debug)
.tapCatch(this.debug);
}
}

export default Connector;
6 changes: 3 additions & 3 deletions template-bff-service/src/listener/index.js

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should update this to not import from root index file. Since this test is still importing from the root index file, you'll have to add all the other aws-sdk dependencies like cloudwatch, etc.

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class Handler {
this.options = options;
}

handle(event, includeErrors = true) {
handle(event, includeErrors = !process.env.IS_OFFLINE) {
return initialize(PIPELINES, this.options)
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

automatically turn off fault handling for integration tests

.assemble(
fromSqsEvent(event)
Expand All @@ -42,13 +42,13 @@ export class Handler {
}
}

export const handle = async (event, context, int = {}) => {
export const handle = async (event, context) => {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this argument can no longer be passed by the int tests

debug('event: %j', event);
debug('context: %j', context);

// const options = await getSecrets(OPTIONS);

return new Handler({ ...OPTIONS, ...int })
return new Handler(OPTIONS)
.handle(event)
.through(toPromise);
};
11 changes: 4 additions & 7 deletions template-bff-service/test/int/listener/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,14 @@ import 'mocha';
import { expect } from 'chai';

import { toKinesisRecords, toSqsEventRecords } from 'aws-lambda-stream';
import lambdaTest from 'aws-lambda-stream/utils/lambda-test';

import { handle } from '../../../src/listener';
const invoke = lambdaTest({ functionName: `${process.env.npm_package_name}-dev-listener` });

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • this util works similar to supertest in the api gateway integration tests
  • it calls the serverless-offline lambda endpoint on 3002

describe('listener/index.js', () => {
before(() => {
require('baton-vcr-replay-for-aws-sdk'); // eslint-disable-line global-require
});

it('should test listener integration', async () => {
const res = await handle(EVENT, {}, { AES: false });
expect(res).to.equal('Success');
const res = await invoke(EVENT);
expect(res.Payload).toEqual('Success');
});
});

Expand Down
17 changes: 17 additions & 0 deletions template-bff-service/test/int/mocks.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
// eslint-disable-next-line no-unused-vars
import * as sinon from 'sinon';
import * as utils from '../../src/utils';
import Replay from 'replay';
jgilbert01 marked this conversation as resolved.
Show resolved Hide resolved

// ==========================
// Mock dates, uuids, etc
// ==========================
sinon.stub(utils, 'now').returns(1653877763001); // TODO update when re-recording

// ==========================
// VCR - https://github.com/assaf/node-replay
// ==========================
Replay.mode = process.env.REPLAY;
console.log(`Replay mode = ${Replay.mode}`);

// typical headers
Replay.headers = [/^x-amz-target/].concat(Replay.headers.filter((header) => !header.test('authorization') && !header.test('x-')));

// monkey patch replay to avoid immediate max retries and ultimately timeout
const rproxy = require('replay/lib/proxy');
rproxy.prototype.setTimeout = () => { };
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • serverless-offline now starts the api gateway and lambda endpoints in separate processes from the serverless framework
  • but the baton vcr plugin runs in the sls process
  • so we need to include Replay in the webpack bundle so that we initialize it in the right processes

12 changes: 5 additions & 7 deletions template-bff-service/test/int/trigger/index.test.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import 'mocha';
import { expect } from 'chai';

import { handle } from '../../../src/trigger';
import lambdaTest from 'aws-lambda-stream/utils/lambda-test';

describe('trigger/index.js', () => {
before(() => {
require('baton-vcr-replay-for-aws-sdk'); // eslint-disable-line global-require
});
const invoke = lambdaTest({ functionName: `${process.env.npm_package_name}-dev-trigger` });

describe('trigger/index.js', () => {
it('should test trigger integration', async () => {
const res = await handle(EVENT, {});
expect(res).to.equal('Success');
const res = await invoke(EVENT);
expect(res.Payload).toEqual('Success');
});
});

Expand Down
28 changes: 18 additions & 10 deletions template-bff-service/test/unit/connectors/dynamodb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,27 @@ import 'mocha';
import { expect } from 'chai';
import sinon from 'sinon';
import debug from 'debug';
import AWS from 'aws-sdk-mock';
import {
DynamoDBDocumentClient,
QueryCommand,
UpdateCommand,
} from '@aws-sdk/lib-dynamodb';
import { mockClient } from 'aws-sdk-client-mock';

import Connector from '../../../src/connectors/dynamodb';

describe('connectors/dynamodb.js', () => {
let mockDdb;
beforeEach(() => {
mockDdb = mockClient(DynamoDBDocumentClient);
});
afterEach(() => {
AWS.restore('DynamoDB.DocumentClient');
mockDdb.restore();
});

it('should update', async () => {
const spy = sinon.spy((params, cb) => cb(null, {}));
AWS.mock('DynamoDB.DocumentClient', 'update', spy);
const spy = sinon.spy((_) => ({}));
mockDdb.on(UpdateCommand).callsFake(spy);

const data = await new Connector(debug('db'), 't1')
.update({
Expand Down Expand Up @@ -49,7 +58,7 @@ describe('connectors/dynamodb.js', () => {
}],
}));

AWS.mock('DynamoDB.DocumentClient', 'query', spy);
mockDdb.on(QueryCommand).callsFake(spy);

const data = await new Connector(debug('db'), 't1')
.get('00000000-0000-0000-0000-000000000000');
Expand Down Expand Up @@ -82,7 +91,7 @@ describe('connectors/dynamodb.js', () => {
}],
}));

AWS.mock('DynamoDB.DocumentClient', 'query', spy);
mockDdb.on(QueryCommand).callsFake(spy);

const data = await new Connector(debug('db'), 't1')
.query({
Expand Down Expand Up @@ -126,7 +135,7 @@ describe('connectors/dynamodb.js', () => {
}],
}));

AWS.mock('DynamoDB.DocumentClient', 'query', spy);
mockDdb.on(QueryCommand).callsFake(spy);

const data = await new Connector(debug('db'), 't1')
.query({
Expand Down Expand Up @@ -174,7 +183,7 @@ describe('connectors/dynamodb.js', () => {
}],
}));

AWS.mock('DynamoDB.DocumentClient', 'query', spy);
mockDdb.on(QueryCommand).callsFake(spy);

const data = await new Connector(debug('db'), 't1')
.query({
Expand Down Expand Up @@ -230,8 +239,7 @@ describe('connectors/dynamodb.js', () => {
];

const spy = sinon.spy((params, cb) => cb(null, responses.shift()));

AWS.mock('DynamoDB.DocumentClient', 'query', spy);
mockDdb.on(QueryCommand).callsFake(spy);

const data = await new Connector(debug('db'), 't1')
.queryAll({
Expand Down
Loading