From 75535f56fdf4b308f9b2c41b9025166bb0600b40 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Sun, 14 Mar 2021 19:11:02 -0700 Subject: [PATCH 01/13] add get, update, delete for stickers --- services/registrations/handler.js | 4 +- services/stickers/handler.js | 97 +++++++++++++++++++- services/stickers/serverless.yml | 57 ++++++++++-- services/stickers/test/stickerDelete.js | 80 +++++++++++++++++ services/stickers/test/stickerGet.js | 81 +++++++++++++++++ services/stickers/test/stickerUpdate.js | 114 ++++++++++++++++++++++++ 6 files changed, 425 insertions(+), 8 deletions(-) create mode 100644 services/stickers/test/stickerDelete.js create mode 100644 services/stickers/test/stickerGet.js create mode 100644 services/stickers/test/stickerUpdate.js diff --git a/services/registrations/handler.js b/services/registrations/handler.js index 13a1f2b9..e94a53b1 100644 --- a/services/registrations/handler.js +++ b/services/registrations/handler.js @@ -267,8 +267,8 @@ export const get = async (event, ctx, callback) => { const queryString = event.queryStringParameters; if(!queryString || (!queryString.eventID && !queryString.year && !queryString.email)) throw helpers.missingIdQueryResponse('eventID/year/user '); - - const email = queryString.email + + const email = queryString.email; if((queryString.eventID && !queryString.year) || (!queryString.eventID && queryString.year)) { throw helpers.missingIdQueryResponse('eventID or year (must have both or neither)'); diff --git a/services/stickers/handler.js b/services/stickers/handler.js index e2ec0145..9060e81d 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -44,7 +44,8 @@ export const create = async(event, ctx, callback) => { const item = { id: data.id, name: data.name, - url: data.url + url: data.url, + description: data.description }; const res = await db.create(item, STICKERS_TABLE); @@ -66,3 +67,97 @@ export const create = async(event, ctx, callback) => { } }; +export const get = async(event, ctx, callback) => { + + try { + + if (!event.pathParameters || !event.pathParameters.id) throw helpers.missingIdQueryResponse('id'); + const id = event.pathParameters.id; + + const sticker = await db.getOne(id, STICKERS_TABLE); + if(isEmpty(sticker)) throw helpers.notFoundResponse('sticker', id); + + const response = helpers.createResponse(200, sticker); + callback(null, response); + return null; + + } + catch(err) { + + console.error(err); + callback(null, err); + return null; + + } + +}; + +export const update = async (event, ctx, callback) => { + + try { + + const data = JSON.parse(event.body); + + if(!event.pathParameters || !event.pathParameters.id) throw helpers.missingIdQueryResponse('id'); + const id = event.pathParameters.id; + + // check request body + helpers.checkPayloadProps(data, { + name: { required: true, type: 'string' }, + url: { required: true, type: 'string' } + }); + + const existingSticker = await db.getOne(id, STICKERS_TABLE); + if(isEmpty(existingSticker)) throw helpers.notFoundResponse('sticker', id); + + + const res = await db.updateDB(id, data, STICKERS_TABLE); + const response = helpers.createResponse(200, { + message: `Updated sticker with id ${id}!`, + response: res + }); + + callback(null, response); + return null; + + } + catch(err) { + + console.error(err); + callback(null, err); + return null; + + } + +}; + +export const del = async (event, ctx, callback) => { + + try { + + // check if id was given + if(!event.pathParameters || !event.pathParameters.id) throw helpers.missingIdQueryResponse('prize'); + const id = event.pathParameters.id; + + // check that the id exists + const existingSticker = await db.getOne(id, STICKERS_TABLE); + if(isEmpty(existingSticker)) throw helpers.notFoundResponse('Sticker', id); + + // do the magic + const res = await db.deleteOne(id, STICKERS_TABLE); + const response = helpers.createResponse(200, { + message: 'Sticker deleted!', + response: res + }); + + callback(null, response); + return null; + + } catch(err) { + + callback(null, err); + return null; + + } + +}; diff --git a/services/stickers/serverless.yml b/services/stickers/serverless.yml index d2200aa4..226ece72 100644 --- a/services/stickers/serverless.yml +++ b/services/stickers/serverless.yml @@ -27,6 +27,8 @@ provider: - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem + - dynamodb:UpdateItem + - dynamodb:DeleteItem Resource: - "arn:aws:dynamodb:us-west-2:432714361962:table/biztechStickers${self:provider.environment.ENVIRONMENT}" @@ -46,13 +48,58 @@ functions: type: COGNITO_USER_POOLS arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp stickerCreate: - handler: handler.create + handler: handler.create + events: + - http: + path: stickers/ + method: post + cors: true + authorizer: + name: ${self:service}-authorizer + type: COGNITO_USER_POOLS + arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp + stickerGet: + handler: handler.get + events: + - http: + path: stickers/{id} + method: get + request: + parameters: + path: + id: true + cors: true + authorizer: + name: ${self:service}-authorizer + type: COGNITO_USER_POOLS + arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp + stickerUpdate: + handler: handler.update + events: + - http: + path: stickers/{id} + method: patch + request: + parameters: + path: + id: true + cors: true + authorizer: + name: ${self:service}-authorizer + type: COGNITO_USER_POOLS + arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp + stickerDelete: + handler: handler.del events: - http: - path: stickers/ - method: post - cors: true - authorizer: + path: stickers/{id} + method: delete + request: + parameters: + path: + id: true + cors: true + authorizer: name: ${self:service}-authorizer type: COGNITO_USER_POOLS arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp \ No newline at end of file diff --git a/services/stickers/test/stickerDelete.js b/services/stickers/test/stickerDelete.js new file mode 100644 index 00000000..dec17a71 --- /dev/null +++ b/services/stickers/test/stickerDelete.js @@ -0,0 +1,80 @@ +'use strict'; +import AWSMock from 'aws-sdk-mock'; + +// tests for stickerDelete +// Generated by serverless-mocha-plugin + +import mochaPlugin from 'serverless-mocha-plugin'; +const expect = mochaPlugin.chai.expect; +let wrapped = mochaPlugin.getWrapper('stickerDelete', '/handler.js', 'del'); + +const stickerPayload = { + id: 'sticker001', + name: 'i am a sticker', + url: 'https://www.google.ca' +}; + +describe('stickerDelete', () => { + + let existingStickers = ['sticker001']; + + before(() => { + + AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { + + let returnValue = null; + if(existingStickers.includes(params.Key.id)) returnValue = { + ...stickerPayload, + id: params.Key.id + }; + callback(null, { Item: returnValue }); + + }); + + + AWSMock.mock('DynamoDB.DocumentClient', 'delete', (params, callback) => { + + if(params.Key.id && existingStickers.includes(params.Key.id)) { + + callback(null, 'successfully deleted item in database'); + + } + else callback('item not found in database'); + + }); + + }); + + after(() => { + + AWSMock.restore('DynamoDB.DocumentClient'); + + }); + + it('return 400 for trying to delete a sticker with no id', async () => { + + + const response = await wrapped.run({ pathParameters: {} }); + expect(response.statusCode).to.be.equal(400); + + }); + + it('return 404 for trying to delete a sticker that doesn\'t exist', async () => { + + const unknownId = 'nonExistantSticker'; + + const response = await wrapped.run({ pathParameters: { id: unknownId } }); + expect(response.statusCode).to.be.equal(404); + + }); + + it('return 200 for successfully deleting a sticker', async () => { + + const validId = existingStickers[0]; + + const response = await wrapped.run({ pathParameters: { id: validId } }); + expect(response.statusCode).to.be.equal(200); + + }); + +}); diff --git a/services/stickers/test/stickerGet.js b/services/stickers/test/stickerGet.js new file mode 100644 index 00000000..2d125f98 --- /dev/null +++ b/services/stickers/test/stickerGet.js @@ -0,0 +1,81 @@ +'use strict'; +import AWSMock from 'aws-sdk-mock'; + +// tests for stickerGet +// Generated by serverless-mocha-plugin + +import mochaPlugin from 'serverless-mocha-plugin'; +const expect = mochaPlugin.chai.expect; +let wrapped = mochaPlugin.getWrapper('stickerGet', '/handler.js', 'get'); + +const stickerPayload = { + id: 'sticker001', + name: 'i am a sticker', + url: 'https://www.google.ca' +}; + +describe('stickerGet', () => { + + before(() => { + + AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { + + if (params.Key.id === stickerPayload.id) { + + callback(null, { Item: stickerPayload }); + + } else { + + callback(null, { Item: null }); + + } + + }); + + }); + + after(() => { + + AWSMock.restore('DynamoDB.DocumentClient'); + + }); + + it ('should return 400 if id is missing from path parameters', async () => { + + const response = await wrapped.run({ + pathParameters: {} + }); + expect(response).to.not.be.empty; + expect(response.statusCode).to.equal(400); + + }); + + it('return 200 response for getting sticker that exists', async() => { + + const response = await wrapped.run({ + pathParameters: { + id: stickerPayload.id + } + }); + expect(response.statusCode).to.be.equal(200); + + const sticker = JSON.parse(response.body); + expect(sticker).to.have.property('id'); + expect(sticker).to.have.property('name'); + expect(sticker).to.have.property('url'); + + }); + + it ('should return 404 for trying to get a sticker that does not exist', async () => { + + const response = await wrapped.run({ + pathParameters: { + id: 'nonExistantSticker' + } + }); + expect(response).to.not.be.empty; + expect(response.statusCode).to.equal(404); + + }); + +}); diff --git a/services/stickers/test/stickerUpdate.js b/services/stickers/test/stickerUpdate.js new file mode 100644 index 00000000..05eabc30 --- /dev/null +++ b/services/stickers/test/stickerUpdate.js @@ -0,0 +1,114 @@ +'use strict'; +import AWSMock from 'aws-sdk-mock'; + +// tests for stickerUpdate +// Generated by serverless-mocha-plugin + +import mochaPlugin from 'serverless-mocha-plugin'; +const expect = mochaPlugin.chai.expect; +let wrapped = mochaPlugin.getWrapper('stickerUpdate', '/handler.js', 'update'); + +const updateId = 'sticker001'; +const updatePayload = { + name: 'i am a sticker', + url: 'https://www.google.ca' +}; + +describe('prizeUpdate', () => { + + let existingStickers = [updateId]; + + before(() => { + + AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { + + let returnValue = null; + if(existingStickers.includes(params.Key.id)) returnValue = { + ...updatePayload, + id: params.Key.id + }; + callback(null, { Item: returnValue }); + + }); + + AWSMock.mock('DynamoDB.DocumentClient', 'update', (params, callback) => { + + if(params.Key.id && existingStickers.includes(params.Key.id)) { + + callback(null, 'successfully updated item in database'); + + } + else callback('item not found in database'); + + }); + + }); + + after(() => { + + AWSMock.restore('DynamoDB.DocumentClient'); + + }); + + it('return 400 for trying to update a sticker with no id', async () => { + + const response = await wrapped.run({ + body: JSON.stringify(updatePayload) + }); + expect(response.statusCode).to.be.equal(400); + + }); + + it('return 404 for trying to update a sticker that doesn\'t exist', async () => { + + const unknownId = 'unknownid'; + + const response = await wrapped.run({ + pathParameters: { id: unknownId }, + body: JSON.stringify(updatePayload) + }); + expect(response.statusCode).to.be.equal(404); + + }); + + it('return 406 for trying to update a sticker with invalid name', async () => { + + const invalidPayload = { + ...updatePayload, + name: 123456789 + }; + + const response = await wrapped.run({ + pathParameters: { id: updateId }, + body: JSON.stringify(invalidPayload) + }); + expect(response.statusCode).to.be.equal(406); + + }); + + it('return 406 for trying to update a sticker with invalid url', async () => { + + const invalidPayload = { + ...updatePayload, + url: 123456789 + }; + + const response = await wrapped.run({ + pathParameters: { id: updateId }, + body: JSON.stringify(invalidPayload) + }); + expect(response.statusCode).to.be.equal(406); + + }); + + it('return 200 for successfully updating a sticker', async () => { + + const response = await wrapped.run({ + pathParameters: { id: updateId }, + body: JSON.stringify(updatePayload) + }); + expect(response.statusCode).to.be.equal(200); + + }); + +}); From 6e73b4b38af768fb7b21d36bf183fe8546090077 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Tue, 16 Mar 2021 23:51:22 -0700 Subject: [PATCH 02/13] create integration test for stickers --- constants/test.js | 3 + services/stickers/handler.js | 2 +- .../stickers/test_integration/stickers.js | 175 ++++++++++++++++++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 services/stickers/test_integration/stickers.js diff --git a/constants/test.js b/constants/test.js index 8a7bc39d..b71e623d 100644 --- a/constants/test.js +++ b/constants/test.js @@ -13,6 +13,9 @@ export const INTEGRATION_TEST_NON_EXISTANT_YEAR = 1234; export const INTEGRATION_TEST_PRIZE_ID = '__INTEGRATION_TEST_PRIZE_POST'; export const INTEGRATION_TEST_PERSISTENT_PRIZE_ID = '__INTEGRATION_TEST_PRIZE'; export const INTEGRATION_TEST_NON_EXISTANT_PRIZE_ID = 'someRandomPrizeThatDoesNotExist123'; +export const INTEGRATION_TEST_STICKER_ID = '__INTEGRATION_TEST_STICKER_POST'; +export const INTEGRATION_TEST_PERSISTENT_STICKER_ID = '__INTEGRATION_TEST_STICKER'; +export const INTEGRATION_TEST_NON_EXISTANT_STICKER_ID = 'someRandomStickerThatDoesNotExist123'; export const INTEGRATION_TEST_PERSISTENT_REGISTRATION_PARAMETERS = { eventId: INTEGRATION_TEST_PERSISTENT_EVENT_ID_2, // has capacity of "1" diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 9060e81d..89c0e193 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -39,7 +39,7 @@ export const create = async(event, ctx, callback) => { }); const existingSticker = await db.getOne(data.id, STICKERS_TABLE); - if (!isEmpty(existingSticker)) throw helpers.duplicateResponse('sticker id', data); + if (!isEmpty(existingSticker)) throw helpers.duplicateResponse('id', data); const item = { id: data.id, diff --git a/services/stickers/test_integration/stickers.js b/services/stickers/test_integration/stickers.js new file mode 100644 index 00000000..aeb0fd8a --- /dev/null +++ b/services/stickers/test_integration/stickers.js @@ -0,0 +1,175 @@ +'use strict'; +import chai from 'chai'; +const expect = chai.expect; + +import helpers from '../../../lib/testHelpers'; +import { + INTEGRATION_TEST_STICKER_ID, + INTEGRATION_TEST_NON_EXISTANT_STICKER_ID +} from '../../../constants/test'; + +const SERVICE = 'stickers'; + +describe('stickers integration', function () { + + this.timeout(3000); + + const defaultPayload = { + pathParameters: { + id: INTEGRATION_TEST_STICKER_ID, + } + }; + + describe('stickers/{id} GET setup', function () { + + it('stickers/{id} GET doesn\'t exist returns 404', async () => { + + return helpers.invokeLambda(SERVICE, 'stickerGet', JSON.stringify(defaultPayload)) + .then(([statusCode]) => { + + expect(statusCode).to.equal(404); + + }); + + }); + + }); + + describe('stickers/ POST tests', function () { + + let stickerPayload = { + body: JSON.stringify({ + id: INTEGRATION_TEST_STICKER_ID, + name: 'Integration Sticker', + url: 'http://google.ca' + }) + }; + + it('stickers/ POST returns 201 on success', async () => { + + await helpers.invokeLambda(SERVICE, 'stickerCreate', JSON.stringify(stickerPayload)) + .then(([statusCode]) => { + + expect(statusCode).to.equal(201); + + }); + + }); + + it('stickers/ POST returns 409 when sticker id already exists', async () => { + + return helpers.invokeLambda(SERVICE, 'stickerCreate', JSON.stringify(stickerPayload)) + .then(([statusCode, body]) => { + + expect(statusCode).to.equal(409); + expect(body.message).to.equal('A database entry with the same \'id\' already exists!'); + + }); + + }); + + }); + + describe('stickers/{id} PATCH and GET tests', function () { + + const stickerPayload = { + name: 'Updated Sticker', + url: 'http://google.com' + }; + + it('stickers/{id} PATCH returns 404 when event not found', async () => { + + const payload = { + pathParameters: { + id: INTEGRATION_TEST_NON_EXISTANT_STICKER_ID + }, + body: JSON.stringify(stickerPayload) + }; + + return helpers.invokeLambda(SERVICE, 'stickerUpdate', JSON.stringify(payload)) + .then(([statusCode]) => { + + expect(statusCode).to.equal(404); + + }); + + }); + + it('stickers/{id} PATCH returns 200 on update success', async () => { + + const payload = { + pathParameters: { + id: INTEGRATION_TEST_STICKER_ID + }, + body: JSON.stringify(stickerPayload) + }; + await helpers.invokeLambda(SERVICE, 'stickerUpdate', JSON.stringify(payload)) + .then(([statusCode]) => { + + expect(statusCode).to.equal(200); + + }); + + }); + + it('stickers/{id} GET returns 200 and check PATCH success', async () => { + + return helpers.invokeLambda(SERVICE, 'stickerGet', JSON.stringify(defaultPayload)) + .then(([statusCode, body]) => { + + expect(statusCode).to.equal(200); + + // Check that update succeeded + expect(body.name).to.equal(stickerPayload.name); + expect(body.url).to.equal(stickerPayload.url); + + }); + + }); + + it('stickers/ GET returns 200 on success', async () => { + + return helpers.invokeLambda(SERVICE, 'stickerGetAll', '').then(([statusCode]) => { + + expect(statusCode).to.equal(200); + + }); + + }); + + }); + + describe('stickers/{id} DELETE tests', function () { + + it('stickers/{id} DELETE returns 404 when event not found', async () => { + + const payload = { + pathParameters: { + id: INTEGRATION_TEST_NON_EXISTANT_STICKER_ID + } + }; + + return helpers.invokeLambda(SERVICE, 'stickerDelete', JSON.stringify(payload)) + .then(([statusCode]) => { + + expect(statusCode).to.equal(404); + + }); + + }); + + it('stickers/{id} DELETE returns 200 on update success', async () => { + + await helpers.invokeLambda(SERVICE, 'stickerDelete', JSON.stringify(defaultPayload)) + .then(([statusCode]) => { + + expect(statusCode).to.equal(200); + + }); + + }); + + }); + + +}); From c898154e6f0734af1e04c9e31fb5c7bf1a49a4d0 Mon Sep 17 00:00:00 2001 From: huangsamantha Date: Sat, 20 Mar 2021 12:20:00 -0700 Subject: [PATCH 03/13] Set up image upload, DNW --- lib/s3ImageUpload.js | 68 +++++++++++++++++++++++++ package-lock.json | 86 ++++++++++++++++++++++++++++++-- package.json | 1 + services/stickers/handler.js | 16 +++++- services/stickers/serverless.yml | 11 +++- 5 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 lib/s3ImageUpload.js diff --git a/lib/s3ImageUpload.js b/lib/s3ImageUpload.js new file mode 100644 index 00000000..733d1be2 --- /dev/null +++ b/lib/s3ImageUpload.js @@ -0,0 +1,68 @@ +import * as fileType from 'file-type'; +import { v4 as uuid } from 'uuid'; +import * as AWS from 'aws-sdk'; +import helpers from "./handlerHelpers"; + +const s3 = new AWS.S3(); + +const allowedMimes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg']; + +exports.imageUpload = async (body) => { + try { + const body = JSON.parse(body); + + if (!body || !body.image || !body.mime) { + return helpers.createResponse(400, { + message: 'incorrect body on request' + }); + } + + if (!allowedMimes.includes(body.mime)) { + return helpers.createResponse(400, { + message: 'mime is not allowed' + }); + } + + let imageData = body.image; + if (body.image.substr(0, 7) === 'base64,') { + imageData = body.image.substr(7, body.image.length); + } + + const buffer = Buffer.from(imageData, 'base64'); + const fileInfo = await fileType.fromBuffer(buffer); + const detectedExt = fileInfo.ext; + const detectedMime = fileInfo.mime; + + if (detectedMime !== body.mime) { + return helpers.createResponse(400, { + message: 'mime types don\'t match' + }); + } + + const name = uuid(); + const key = `${name}.${detectedExt}`; + + console.log(`writing image to bucket called ${key}`); + + await s3 + .putObject({ + Body: buffer, + Key: key, + ContentType: body.mime, + Bucket: process.env.stickerImagesBucket, + ACL: 'public-read', + }) + .promise(); + + const url = `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/${key}`; + return helpers.createResponse(200, { + imageURL: url + }); + } catch (error) { + console.log('error', error); + + return helpers.createResponse(400, { + message: error.message || 'Failed to upload image' + }); + } +}; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ec5d4440..467b7973 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2368,6 +2368,11 @@ "request-promise-native": "^1.0.8" } }, + "@tokenizer/token": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.1.1.tgz", + "integrity": "sha512-XO6INPbZCxdprl+9qa/AAbFFOMzzwqYxpjPgLICrMD6C2FCw6qfJOPcBk6JqqPLSaZ/Qx87qn4rpPmPMwaAK6w==" + }, "@types/babel__core": { "version": "7.1.12", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", @@ -2414,6 +2419,11 @@ "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==" + }, "@types/events": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", @@ -2517,6 +2527,15 @@ "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", "dev": true }, + "@types/readable-stream": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-2.3.9.tgz", + "integrity": "sha512-sqsgQqFT7HmQz/V5jH1O0fvQQnXAJO46Gg9LRO/JPfjmVmGUlcx831TZZO3Y3HtWhIkzf3kTsNT0Z0kzIhIvZw==", + "requires": { + "@types/node": "*", + "safe-buffer": "*" + } + }, "@types/stack-utils": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", @@ -6487,6 +6506,13 @@ "file-type": "^5.2.0", "is-stream": "^1.1.0", "tar-stream": "^1.5.2" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } } }, "decompress-tarbz2": { @@ -6516,6 +6542,13 @@ "decompress-tar": "^4.1.1", "file-type": "^5.2.0", "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + } } }, "decompress-unzip": { @@ -8212,9 +8245,15 @@ "integrity": "sha512-r70c72ln2YHzQINNfxDp02hAhbGkt1HffZ+Du8oetWDLjDtFja/Lm10lUaSh9e+wD+7VDvPee0b0C9SAy8pWZg==" }, "file-type": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", - "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=" + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.3.0.tgz", + "integrity": "sha512-ZA0hV64611vJT42ltw0T9IDwHApQuxRdrmQZWTeDmeAUtZBBVSQW3nSQqhhW1cAgpXgqcJvm410BYHXJQ9AymA==", + "requires": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.0.3", + "token-types": "^2.0.0", + "typedarray-to-buffer": "^3.1.5" + } }, "file-uri-to-path": { "version": "1.0.0", @@ -14286,6 +14325,11 @@ "sha.js": "^2.4.8" } }, + "peek-readable": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-3.1.3.tgz", + "integrity": "sha512-mpAcysyRJxmICBcBa5IXH7SZPvWkcghm6Fk8RekoS3v+BpbSzlZzuWbMx+GXrlUwESi9qHar4nVEZNMKylIHvg==" + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -15069,6 +15113,15 @@ "util-deprecate": "^1.0.1" } }, + "readable-web-to-node-stream": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.1.tgz", + "integrity": "sha512-4zDC6CvjUyusN7V0QLsXVB7pJCD9+vtrM9bYDRv6uBQ+SKfx36rp5AFNPRgh9auKRul/a1iFZJYXcCbwRL+SaA==", + "requires": { + "@types/readable-stream": "^2.3.9", + "readable-stream": "^3.6.0" + } + }, "readdir-glob": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz", @@ -17714,6 +17767,16 @@ "escape-string-regexp": "^1.0.2" } }, + "strtok3": { + "version": "6.0.8", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.0.8.tgz", + "integrity": "sha512-QLgv+oiXwXgCgp2PdPPa+Jpp4D9imK9e/0BsyfeFMr6QL6wMVqoVn9+OXQ9I7MZbmUzN6lmitTJ09uwS2OmGcw==", + "requires": { + "@tokenizer/token": "^0.1.1", + "@types/debug": "^4.1.5", + "peek-readable": "^3.1.3" + } + }, "stylus-lookup": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/stylus-lookup/-/stylus-lookup-3.0.2.tgz", @@ -18309,6 +18372,22 @@ "is-number": "^7.0.0" } }, + "token-types": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-2.1.1.tgz", + "integrity": "sha512-wnQcqlreS6VjthyHO3Y/kpK/emflxDBNhlNUPfh7wE39KnuDdOituXomIbyI79vBtF0Ninpkh72mcuRHo+RG3Q==", + "requires": { + "@tokenizer/token": "^0.1.1", + "ieee754": "^1.2.1" + }, + "dependencies": { + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + } + } + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -18571,7 +18650,6 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, "requires": { "is-typedarray": "^1.0.0" } diff --git a/package.json b/package.json index 854f695f..368cf57e 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "type": "module", "dependencies": { + "file-type": "^16.3.0", "serverless": "^1.67.2" }, "scripts": { diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 89c0e193..88a53389 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -2,6 +2,7 @@ import helpers from '../../lib/handlerHelpers'; import db from '../../lib/db'; import { isEmpty } from '../../lib/utils'; import { STICKERS_TABLE } from '../../constants/tables'; +import imageUpload from '../../lib/s3ImageUpload'; export const getAll = async(event, ctx, callback) => { @@ -32,19 +33,30 @@ export const create = async(event, ctx, callback) => { const data = JSON.parse(event.body); + console.log("HELLO"); + helpers.checkPayloadProps(data, { id: { required: true, type: 'string' }, name: { required: true, type: 'string' }, - url: { required: true, type: 'string' } + image: { required: true, type: 'string' }, + mime: { required: true, type: 'string' } }); const existingSticker = await db.getOne(data.id, STICKERS_TABLE); if (!isEmpty(existingSticker)) throw helpers.duplicateResponse('id', data); + const s3Upload = await imageUpload.imageUpload(event.body); + + console.log("STICKER ATTEMPTED UPLOAD"); + + if (s3Upload.statusCode !== 200) { + throw s3Upload; + } + const item = { id: data.id, name: data.name, - url: data.url, + url: s3Upload.imageURL, description: data.description }; const res = await db.create(item, STICKERS_TABLE); diff --git a/services/stickers/serverless.yml b/services/stickers/serverless.yml index 226ece72..61651e08 100644 --- a/services/stickers/serverless.yml +++ b/services/stickers/serverless.yml @@ -16,6 +16,7 @@ provider: cfLogs: true environment: ENVIRONMENT: ${file(../../config.${self:provider.stage}.json):ENVIRONMENT} + stickerImagesBucket: ${self:custom.stickerImagesBucket} apiGateway: restApiId: !ImportValue ${self:provider.stage}-ExtApiGatewayRestApiId @@ -29,11 +30,17 @@ provider: - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem + - s3:GetItem + - s3:PutItem + - s3:UpdateItem + - s3:DeleteItem Resource: - "arn:aws:dynamodb:us-west-2:432714361962:table/biztechStickers${self:provider.environment.ENVIRONMENT}" + # TODO: dynamically determine prod vs. staging bucket + - "arn:aws:s3:::biztech-images-staging" - -custom: ${file(../../serverless.common.yml):custom} +custom: + ${file(../../serverless.common.yml):custom} functions: stickerGetAll: From a2bf73b6c4f60250f0570af2e7643e47ae1bfe4d Mon Sep 17 00:00:00 2001 From: huangsamantha Date: Thu, 25 Mar 2021 20:18:03 -0700 Subject: [PATCH 04/13] IT WORKS!! Able to upload image, check comments for TODO --- lib/s3ImageUpload.js | 134 +++++++++++++++++-------------- services/stickers/handler.js | 7 +- services/stickers/serverless.yml | 10 +-- 3 files changed, 83 insertions(+), 68 deletions(-) diff --git a/lib/s3ImageUpload.js b/lib/s3ImageUpload.js index 733d1be2..25ef9b75 100644 --- a/lib/s3ImageUpload.js +++ b/lib/s3ImageUpload.js @@ -1,68 +1,84 @@ import * as fileType from 'file-type'; import { v4 as uuid } from 'uuid'; import * as AWS from 'aws-sdk'; -import helpers from "./handlerHelpers"; +import helpers from './handlerHelpers'; const s3 = new AWS.S3(); const allowedMimes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg']; -exports.imageUpload = async (body) => { - try { - const body = JSON.parse(body); - - if (!body || !body.image || !body.mime) { - return helpers.createResponse(400, { - message: 'incorrect body on request' - }); - } - - if (!allowedMimes.includes(body.mime)) { - return helpers.createResponse(400, { - message: 'mime is not allowed' - }); - } - - let imageData = body.image; - if (body.image.substr(0, 7) === 'base64,') { - imageData = body.image.substr(7, body.image.length); - } - - const buffer = Buffer.from(imageData, 'base64'); - const fileInfo = await fileType.fromBuffer(buffer); - const detectedExt = fileInfo.ext; - const detectedMime = fileInfo.mime; - - if (detectedMime !== body.mime) { - return helpers.createResponse(400, { - message: 'mime types don\'t match' - }); - } - - const name = uuid(); - const key = `${name}.${detectedExt}`; - - console.log(`writing image to bucket called ${key}`); - - await s3 - .putObject({ - Body: buffer, - Key: key, - ContentType: body.mime, - Bucket: process.env.stickerImagesBucket, - ACL: 'public-read', - }) - .promise(); - - const url = `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/${key}`; - return helpers.createResponse(200, { - imageURL: url - }); - } catch (error) { - console.log('error', error); - - return helpers.createResponse(400, { - message: error.message || 'Failed to upload image' - }); +const imageUpload = async (body) => { + + try { + console.log("INSIDE IMAGE UPLOAD"); + + if (!body || !body.image || !body.mime) { + + return helpers.createResponse(400, { + message: 'incorrect body on request' + }); + + } + + if (!allowedMimes.includes(body.mime)) { + + return helpers.createResponse(400, { + message: 'mime is not allowed' + }); + } -}; \ No newline at end of file + + let imageData = body.image; + if (body.image.substr(0, 7) === 'base64,') { + + imageData = body.image.substr(7, body.image.length); + + } + + const buffer = Buffer.from(imageData, 'base64'); + const fileInfo = await fileType.fromBuffer(buffer); + const detectedExt = fileInfo.ext; + const detectedMime = fileInfo.mime; + + if (detectedMime !== body.mime) { + + return helpers.createResponse(400, { + message: 'mime types don\'t match' + }); + + } + + const id = body.id; + const key = "stickers/" + id + "." + detectedExt; + + console.log(`writing image to bucket called ${key}`); + console.log(process.env.stickerImagesBucket); + + await s3 + .putObject({ + Body: buffer, + Key: key, + ContentType: body.mime, + Bucket: process.env.stickerImagesBucket, + ACL: 'public-read', + }) + .promise(); + + const url = `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/${key}`; + return helpers.createResponse(200, { + imageURL: url + }); + + } catch (error) { + + console.log('error', error); + + return helpers.createResponse(400, { + message: error.message || 'Failed to upload image' + }); + + } + +}; + +export default imageUpload; diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 88a53389..2adb595d 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -33,7 +33,7 @@ export const create = async(event, ctx, callback) => { const data = JSON.parse(event.body); - console.log("HELLO"); + console.log('HELLO'); helpers.checkPayloadProps(data, { id: { required: true, type: 'string' }, @@ -45,11 +45,12 @@ export const create = async(event, ctx, callback) => { const existingSticker = await db.getOne(data.id, STICKERS_TABLE); if (!isEmpty(existingSticker)) throw helpers.duplicateResponse('id', data); - const s3Upload = await imageUpload.imageUpload(event.body); + const s3Upload = await imageUpload(data); - console.log("STICKER ATTEMPTED UPLOAD"); + console.log('STICKER ATTEMPTED UPLOAD'); if (s3Upload.statusCode !== 200) { + throw s3Upload; } diff --git a/services/stickers/serverless.yml b/services/stickers/serverless.yml index 61651e08..9b431f35 100644 --- a/services/stickers/serverless.yml +++ b/services/stickers/serverless.yml @@ -16,7 +16,7 @@ provider: cfLogs: true environment: ENVIRONMENT: ${file(../../config.${self:provider.stage}.json):ENVIRONMENT} - stickerImagesBucket: ${self:custom.stickerImagesBucket} + stickerImagesBucket: biztech-images-staging apiGateway: restApiId: !ImportValue ${self:provider.stage}-ExtApiGatewayRestApiId @@ -30,14 +30,12 @@ provider: - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem - - s3:GetItem - - s3:PutItem - - s3:UpdateItem - - s3:DeleteItem + - s3:PutObject + - s3:PutObjectAcl Resource: - "arn:aws:dynamodb:us-west-2:432714361962:table/biztechStickers${self:provider.environment.ENVIRONMENT}" # TODO: dynamically determine prod vs. staging bucket - - "arn:aws:s3:::biztech-images-staging" + - "arn:aws:s3:::biztech-images-staging/*" custom: ${file(../../serverless.common.yml):custom} From ae59e6a3adf9e9113904c5f29eae67d3acec9500 Mon Sep 17 00:00:00 2001 From: huangsamantha Date: Fri, 9 Apr 2021 16:30:29 -0700 Subject: [PATCH 05/13] fix create, do upload --- lib/{s3ImageUpload.js => s3.js} | 4 +--- services/stickers/handler.js | 33 ++++++++++++++++++++++++++------ services/stickers/serverless.yml | 3 ++- 3 files changed, 30 insertions(+), 10 deletions(-) rename lib/{s3ImageUpload.js => s3.js} (93%) diff --git a/lib/s3ImageUpload.js b/lib/s3.js similarity index 93% rename from lib/s3ImageUpload.js rename to lib/s3.js index 25ef9b75..ba8bcee7 100644 --- a/lib/s3ImageUpload.js +++ b/lib/s3.js @@ -1,5 +1,4 @@ import * as fileType from 'file-type'; -import { v4 as uuid } from 'uuid'; import * as AWS from 'aws-sdk'; import helpers from './handlerHelpers'; @@ -10,7 +9,6 @@ const allowedMimes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg']; const imageUpload = async (body) => { try { - console.log("INSIDE IMAGE UPLOAD"); if (!body || !body.image || !body.mime) { @@ -49,7 +47,7 @@ const imageUpload = async (body) => { } const id = body.id; - const key = "stickers/" + id + "." + detectedExt; + const key = 'stickers/' + id + '.' + detectedExt; console.log(`writing image to bucket called ${key}`); console.log(process.env.stickerImagesBucket); diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 2adb595d..5395dc53 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -2,7 +2,7 @@ import helpers from '../../lib/handlerHelpers'; import db from '../../lib/db'; import { isEmpty } from '../../lib/utils'; import { STICKERS_TABLE } from '../../constants/tables'; -import imageUpload from '../../lib/s3ImageUpload'; +import { imageUpload } from '../../lib/s3'; export const getAll = async(event, ctx, callback) => { @@ -47,17 +47,19 @@ export const create = async(event, ctx, callback) => { const s3Upload = await imageUpload(data); - console.log('STICKER ATTEMPTED UPLOAD'); - if (s3Upload.statusCode !== 200) { throw s3Upload; + } + const uploadBody = JSON.parse(s3Upload.body); + console.log(uploadBody.imageURL); + const item = { id: data.id, name: data.name, - url: s3Upload.imageURL, + imageURL: uploadBody.imageURL, description: data.description }; const res = await db.create(item, STICKERS_TABLE); @@ -116,15 +118,34 @@ export const update = async (event, ctx, callback) => { // check request body helpers.checkPayloadProps(data, { + id: { required: true, type: 'string' }, name: { required: true, type: 'string' }, - url: { required: true, type: 'string' } + image: { required: true, type: 'string' }, + mime: { required: true, type: 'string' } }); const existingSticker = await db.getOne(id, STICKERS_TABLE); if(isEmpty(existingSticker)) throw helpers.notFoundResponse('sticker', id); + const s3Upload = await imageUpload(data); + + if (s3Upload.statusCode !== 200) { + + throw s3Upload; + + } + + const uploadBody = JSON.parse(s3Upload.body); + console.log(uploadBody.imageURL); + + const item = { + id: data.id, + name: data.name, + imageURL: uploadBody.imageURL, + description: data.description + }; - const res = await db.updateDB(id, data, STICKERS_TABLE); + const res = await db.updateDB(id, item, STICKERS_TABLE); const response = helpers.createResponse(200, { message: `Updated sticker with id ${id}!`, response: res diff --git a/services/stickers/serverless.yml b/services/stickers/serverless.yml index 9b431f35..5a058f33 100644 --- a/services/stickers/serverless.yml +++ b/services/stickers/serverless.yml @@ -17,7 +17,8 @@ provider: environment: ENVIRONMENT: ${file(../../config.${self:provider.stage}.json):ENVIRONMENT} stickerImagesBucket: biztech-images-staging - + region: ${file(../../serverless.common.yml):provider.region} + apiGateway: restApiId: !ImportValue ${self:provider.stage}-ExtApiGatewayRestApiId restApiRootResourceId: !ImportValue ${self:provider.stage}-ExtApiGatewayRestApiRootResourceId From dbf1c5e6019003b4ecfaeccec819a5f1a709403e Mon Sep 17 00:00:00 2001 From: huangsamantha Date: Fri, 9 Apr 2021 16:34:01 -0700 Subject: [PATCH 06/13] remove console logs --- lib/s3.js | 7 +------ services/stickers/handler.js | 4 ---- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/lib/s3.js b/lib/s3.js index ba8bcee7..1c62010e 100644 --- a/lib/s3.js +++ b/lib/s3.js @@ -6,7 +6,7 @@ const s3 = new AWS.S3(); const allowedMimes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg']; -const imageUpload = async (body) => { +export const imageUpload = async (body) => { try { @@ -49,9 +49,6 @@ const imageUpload = async (body) => { const id = body.id; const key = 'stickers/' + id + '.' + detectedExt; - console.log(`writing image to bucket called ${key}`); - console.log(process.env.stickerImagesBucket); - await s3 .putObject({ Body: buffer, @@ -78,5 +75,3 @@ const imageUpload = async (body) => { } }; - -export default imageUpload; diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 5395dc53..f55002c4 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -33,8 +33,6 @@ export const create = async(event, ctx, callback) => { const data = JSON.parse(event.body); - console.log('HELLO'); - helpers.checkPayloadProps(data, { id: { required: true, type: 'string' }, name: { required: true, type: 'string' }, @@ -54,7 +52,6 @@ export const create = async(event, ctx, callback) => { } const uploadBody = JSON.parse(s3Upload.body); - console.log(uploadBody.imageURL); const item = { id: data.id, @@ -136,7 +133,6 @@ export const update = async (event, ctx, callback) => { } const uploadBody = JSON.parse(s3Upload.body); - console.log(uploadBody.imageURL); const item = { id: data.id, From fa8cfcb4898e08f90db71026812834c242ef8fc6 Mon Sep 17 00:00:00 2001 From: huangsamantha Date: Fri, 9 Apr 2021 16:39:49 -0700 Subject: [PATCH 07/13] dynamically choose bucket --- config.dev.json | 3 ++- config.prod.json | 3 ++- config.staging.json | 3 ++- services/stickers/serverless.yml | 3 +-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/config.dev.json b/config.dev.json index e751f7f4..34ec5c1d 100644 --- a/config.dev.json +++ b/config.dev.json @@ -1,4 +1,5 @@ { "ENVIRONMENT": "", - "REQUIRE_API_KEY": false + "REQUIRE_API_KEY": false, + "BUCKET": "staging" } \ No newline at end of file diff --git a/config.prod.json b/config.prod.json index 7b328972..9220b600 100644 --- a/config.prod.json +++ b/config.prod.json @@ -1,4 +1,5 @@ { "ENVIRONMENT": "PROD", - "REQUIRE_API_KEY": true + "REQUIRE_API_KEY": true, + "BUCKET": "prod" } \ No newline at end of file diff --git a/config.staging.json b/config.staging.json index b3fcbf13..167f4b07 100644 --- a/config.staging.json +++ b/config.staging.json @@ -1,4 +1,5 @@ { "ENVIRONMENT": "", - "REQUIRE_API_KEY": true + "REQUIRE_API_KEY": true, + "BUCKET": "staging" } \ No newline at end of file diff --git a/services/stickers/serverless.yml b/services/stickers/serverless.yml index 5a058f33..413cdb51 100644 --- a/services/stickers/serverless.yml +++ b/services/stickers/serverless.yml @@ -35,8 +35,7 @@ provider: - s3:PutObjectAcl Resource: - "arn:aws:dynamodb:us-west-2:432714361962:table/biztechStickers${self:provider.environment.ENVIRONMENT}" - # TODO: dynamically determine prod vs. staging bucket - - "arn:aws:s3:::biztech-images-staging/*" + - "arn:aws:s3:::biztech-images-${file(../../config.${self:provider.stage}.json):BUCKET}/*" custom: ${file(../../serverless.common.yml):custom} From c0d4a43810c0d0a63501bf4526b2025b96c76303 Mon Sep 17 00:00:00 2001 From: huangsamantha Date: Fri, 9 Apr 2021 17:00:43 -0700 Subject: [PATCH 08/13] delete done! --- lib/s3.js | 31 ++++++++++++++++++++++++++++++- services/stickers/handler.js | 11 +++++++++-- services/stickers/serverless.yml | 12 +++++++----- 3 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/s3.js b/lib/s3.js index 1c62010e..3e416408 100644 --- a/lib/s3.js +++ b/lib/s3.js @@ -61,7 +61,8 @@ export const imageUpload = async (body) => { const url = `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/${key}`; return helpers.createResponse(200, { - imageURL: url + imageURL: url, + s3ObjectKey: key }); } catch (error) { @@ -75,3 +76,31 @@ export const imageUpload = async (body) => { } }; + +export const deleteObject = async (body) => { + + try { + + const id = body.id; + const key = body.key; + + await s3 + .deleteObject({ + Key: key, + Bucket: process.env.stickerImagesBucket + }) + .promise(); + + return helpers.createResponse(200, {message: "Success"}); + + } catch (error) { + + console.log('error', error); + + return helpers.createResponse(400, { + message: error.message || 'Failed to upload image' + }); + + } + +} diff --git a/services/stickers/handler.js b/services/stickers/handler.js index f55002c4..85c4cbe9 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -2,7 +2,7 @@ import helpers from '../../lib/handlerHelpers'; import db from '../../lib/db'; import { isEmpty } from '../../lib/utils'; import { STICKERS_TABLE } from '../../constants/tables'; -import { imageUpload } from '../../lib/s3'; +import { imageUpload, deleteObject } from '../../lib/s3'; export const getAll = async(event, ctx, callback) => { @@ -57,7 +57,8 @@ export const create = async(event, ctx, callback) => { id: data.id, name: data.name, imageURL: uploadBody.imageURL, - description: data.description + description: data.description, + key: uploadBody.s3ObjectKey }; const res = await db.create(item, STICKERS_TABLE); @@ -173,6 +174,12 @@ export const del = async (event, ctx, callback) => { const existingSticker = await db.getOne(id, STICKERS_TABLE); if(isEmpty(existingSticker)) throw helpers.notFoundResponse('Sticker', id); + const s3Delete = await deleteObject(existingSticker); + + if (s3Delete.statusCode !== 200) { + throw s3Delete; + } + // do the magic const res = await db.deleteOne(id, STICKERS_TABLE); const response = helpers.createResponse(200, { diff --git a/services/stickers/serverless.yml b/services/stickers/serverless.yml index 413cdb51..56bb5808 100644 --- a/services/stickers/serverless.yml +++ b/services/stickers/serverless.yml @@ -33,6 +33,8 @@ provider: - dynamodb:DeleteItem - s3:PutObject - s3:PutObjectAcl + - s3:DeleteObject + - s3:DeleteObjectAcl Resource: - "arn:aws:dynamodb:us-west-2:432714361962:table/biztechStickers${self:provider.environment.ENVIRONMENT}" - "arn:aws:s3:::biztech-images-${file(../../config.${self:provider.stage}.json):BUCKET}/*" @@ -41,7 +43,7 @@ custom: ${file(../../serverless.common.yml):custom} functions: - stickerGetAll: + stickersGetAll: handler: handler.getAll events: - http: @@ -52,7 +54,7 @@ functions: name: ${self:service}-authorizer type: COGNITO_USER_POOLS arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp - stickerCreate: + stickersCreate: handler: handler.create events: - http: @@ -63,7 +65,7 @@ functions: name: ${self:service}-authorizer type: COGNITO_USER_POOLS arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp - stickerGet: + stickersGet: handler: handler.get events: - http: @@ -78,7 +80,7 @@ functions: name: ${self:service}-authorizer type: COGNITO_USER_POOLS arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp - stickerUpdate: + stickersUpdate: handler: handler.update events: - http: @@ -93,7 +95,7 @@ functions: name: ${self:service}-authorizer type: COGNITO_USER_POOLS arn: arn:aws:cognito-idp:us-west-2:432714361962:userpool/us-west-2_w0R176hhp - stickerDelete: + stickersDelete: handler: handler.del events: - http: From 09660d679ccdd704978e6bcc79f08e09f64f4c95 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Mon, 28 Jun 2021 21:27:34 -0700 Subject: [PATCH 09/13] fix copy paste typos --- services/stickers/handler.js | 2 +- services/stickers/test/stickerUpdate.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 85c4cbe9..b3be4d49 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -167,7 +167,7 @@ export const del = async (event, ctx, callback) => { try { // check if id was given - if(!event.pathParameters || !event.pathParameters.id) throw helpers.missingIdQueryResponse('prize'); + if(!event.pathParameters || !event.pathParameters.id) throw helpers.missingIdQueryResponse('Sticker'); const id = event.pathParameters.id; // check that the id exists diff --git a/services/stickers/test/stickerUpdate.js b/services/stickers/test/stickerUpdate.js index 05eabc30..815cfb1a 100644 --- a/services/stickers/test/stickerUpdate.js +++ b/services/stickers/test/stickerUpdate.js @@ -14,7 +14,7 @@ const updatePayload = { url: 'https://www.google.ca' }; -describe('prizeUpdate', () => { +describe('stickerUpdate', () => { let existingStickers = [updateId]; From 622d005a1fba682102baea43ae97caa0e8504ae7 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Mon, 28 Jun 2021 21:28:22 -0700 Subject: [PATCH 10/13] lint fixes --- lib/s3.js | 14 +++++++------- services/stickers/handler.js | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/s3.js b/lib/s3.js index 3e416408..e6dab392 100644 --- a/lib/s3.js +++ b/lib/s3.js @@ -85,13 +85,13 @@ export const deleteObject = async (body) => { const key = body.key; await s3 - .deleteObject({ - Key: key, - Bucket: process.env.stickerImagesBucket - }) - .promise(); + .deleteObject({ + Key: key, + Bucket: process.env.stickerImagesBucket + }) + .promise(); - return helpers.createResponse(200, {message: "Success"}); + return helpers.createResponse(200, { message: 'Success' }); } catch (error) { @@ -103,4 +103,4 @@ export const deleteObject = async (body) => { } -} +}; diff --git a/services/stickers/handler.js b/services/stickers/handler.js index b3be4d49..d48f9cbd 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -177,7 +177,9 @@ export const del = async (event, ctx, callback) => { const s3Delete = await deleteObject(existingSticker); if (s3Delete.statusCode !== 200) { + throw s3Delete; + } // do the magic From a4de2887996f94e9d7f33a63bf77449f49684613 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Mon, 5 Jul 2021 18:03:12 -0700 Subject: [PATCH 11/13] modifying tests to accoubnt for s3, mock NOT WORKING --- lib/s3.js | 19 ++++++--- services/stickers/handler.js | 10 ++--- services/stickers/test/stickerCreate.js | 56 ++++++++++--------------- services/stickers/test/stickerDelete.js | 9 +--- services/stickers/test/stickerGet.js | 16 +++---- services/stickers/test/stickerGetAll.js | 7 ++-- services/stickers/test/stickerUpdate.js | 11 ++--- services/stickers/test/stickers.json | 3 +- services/stickers/test/testData.js | 32 ++++++++++++++ 9 files changed, 92 insertions(+), 71 deletions(-) create mode 100644 services/stickers/test/testData.js diff --git a/lib/s3.js b/lib/s3.js index e6dab392..97498824 100644 --- a/lib/s3.js +++ b/lib/s3.js @@ -2,11 +2,13 @@ import * as fileType from 'file-type'; import * as AWS from 'aws-sdk'; import helpers from './handlerHelpers'; -const s3 = new AWS.S3(); const allowedMimes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg']; -export const imageUpload = async (body) => { + + + +const imageUpload = async (body) => { try { @@ -41,7 +43,7 @@ export const imageUpload = async (body) => { if (detectedMime !== body.mime) { return helpers.createResponse(400, { - message: 'mime types don\'t match' + message: `mime types don't match: ${detectedMime} vs ${body.mime}` }); } @@ -49,6 +51,7 @@ export const imageUpload = async (body) => { const id = body.id; const key = 'stickers/' + id + '.' + detectedExt; + const s3 = new AWS.S3(); await s3 .putObject({ Body: buffer, @@ -77,13 +80,14 @@ export const imageUpload = async (body) => { }; -export const deleteObject = async (body) => { +const deleteObject = async (body) => { try { - const id = body.id; const key = body.key; + const s3 = new AWS.S3(); + await s3 .deleteObject({ Key: key, @@ -104,3 +108,8 @@ export const deleteObject = async (body) => { } }; + +export default { + imageUpload, + deleteObject +}; diff --git a/services/stickers/handler.js b/services/stickers/handler.js index d48f9cbd..1785d836 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -2,8 +2,8 @@ import helpers from '../../lib/handlerHelpers'; import db from '../../lib/db'; import { isEmpty } from '../../lib/utils'; import { STICKERS_TABLE } from '../../constants/tables'; -import { imageUpload, deleteObject } from '../../lib/s3'; - +import s3Helpers from '../../lib/s3'; +// import { imageUpload, deleteObject } from '../../lib/s3; export const getAll = async(event, ctx, callback) => { try { @@ -43,7 +43,7 @@ export const create = async(event, ctx, callback) => { const existingSticker = await db.getOne(data.id, STICKERS_TABLE); if (!isEmpty(existingSticker)) throw helpers.duplicateResponse('id', data); - const s3Upload = await imageUpload(data); + const s3Upload = await s3Helpers.imageUpload(data); if (s3Upload.statusCode !== 200) { @@ -125,7 +125,7 @@ export const update = async (event, ctx, callback) => { const existingSticker = await db.getOne(id, STICKERS_TABLE); if(isEmpty(existingSticker)) throw helpers.notFoundResponse('sticker', id); - const s3Upload = await imageUpload(data); + const s3Upload = await s3Helpers.imageUpload(data); if (s3Upload.statusCode !== 200) { @@ -174,7 +174,7 @@ export const del = async (event, ctx, callback) => { const existingSticker = await db.getOne(id, STICKERS_TABLE); if(isEmpty(existingSticker)) throw helpers.notFoundResponse('Sticker', id); - const s3Delete = await deleteObject(existingSticker); + const s3Delete = await s3Helpers.deleteObject(existingSticker); if (s3Delete.statusCode !== 200) { diff --git a/services/stickers/test/stickerCreate.js b/services/stickers/test/stickerCreate.js index 36cea8ae..7ee43de4 100644 --- a/services/stickers/test/stickerCreate.js +++ b/services/stickers/test/stickerCreate.js @@ -5,26 +5,28 @@ import AWSMock from 'aws-sdk-mock'; // Generated by serverless-mocha-plugin import mochaPlugin from 'serverless-mocha-plugin'; +import { stickerItem, stickerPayload } from './testData'; const expect = mochaPlugin.chai.expect; let wrapped = mochaPlugin.getWrapper('stickerCreate', '/handler.js', 'create'); -const stickerPayload = { - 'id': 'sticker001', - 'name': 'BluePrint Sticker', - 'url': 'http://google.ca' -}; - describe('stickerCreate', () => { let createdStickerIds = []; before(() => { + AWSMock.mock('S3', 'putObject', (params, callback) => { + + console.log('Running mock s3 put'); + callback(null, 'Successfully put sticker into S3 bucket'); + + }); + AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { let returnValue = null; if (createdStickerIds.includes(params.Key.id)) returnValue = { - ...stickerPayload, + ...stickerItem, id: params.Key.id }; callback(null, { Item: returnValue }); @@ -43,47 +45,31 @@ describe('stickerCreate', () => { }); + }); after(() => { AWSMock.restore('DynamoDB.DocumentClient'); + AWSMock.restore('S3'); }); - it('return 406 for trying to create a sticker with no id', async() => { - - const invalidPayload = { - ...stickerPayload - }; - delete invalidPayload.id; - - const response = await wrapped.run({ body: JSON.stringify(invalidPayload) }); - expect(response.statusCode).to.be.equal(406); - - }); - - it('return 406 for trying to create a sticker with no name', async() => { + it('return 406 for trying to create a sticker with missing required fields in payload', async() => { - const invalidPayload = { - ...stickerPayload - }; - delete invalidPayload.name; + const requiredFields = ['id', 'name', 'image', 'mime']; + for (let field of requiredFields) { - const response = await wrapped.run({ body: JSON.stringify(invalidPayload) }); - expect(response.statusCode).to.be.equal(406); - - }); + const invalidPayload = { + ...stickerPayload + }; + delete invalidPayload[field]; - it('return 406 for trying to create a sticker with no url', async() => { - const invalidPayload = { - ...stickerPayload - }; - delete invalidPayload.url; + const response = await wrapped.run({ body: JSON.stringify(invalidPayload) }); + expect(response.statusCode).to.be.equal(406); - const response = await wrapped.run({ body: JSON.stringify(invalidPayload) }); - expect(response.statusCode).to.be.equal(406); + } }); diff --git a/services/stickers/test/stickerDelete.js b/services/stickers/test/stickerDelete.js index dec17a71..ddf6adeb 100644 --- a/services/stickers/test/stickerDelete.js +++ b/services/stickers/test/stickerDelete.js @@ -5,15 +5,10 @@ import AWSMock from 'aws-sdk-mock'; // Generated by serverless-mocha-plugin import mochaPlugin from 'serverless-mocha-plugin'; +import { stickerItem } from './testData'; const expect = mochaPlugin.chai.expect; let wrapped = mochaPlugin.getWrapper('stickerDelete', '/handler.js', 'del'); -const stickerPayload = { - id: 'sticker001', - name: 'i am a sticker', - url: 'https://www.google.ca' -}; - describe('stickerDelete', () => { let existingStickers = ['sticker001']; @@ -24,7 +19,7 @@ describe('stickerDelete', () => { let returnValue = null; if(existingStickers.includes(params.Key.id)) returnValue = { - ...stickerPayload, + ...stickerItem, id: params.Key.id }; callback(null, { Item: returnValue }); diff --git a/services/stickers/test/stickerGet.js b/services/stickers/test/stickerGet.js index 2d125f98..89848935 100644 --- a/services/stickers/test/stickerGet.js +++ b/services/stickers/test/stickerGet.js @@ -5,24 +5,19 @@ import AWSMock from 'aws-sdk-mock'; // Generated by serverless-mocha-plugin import mochaPlugin from 'serverless-mocha-plugin'; +import { stickerItem } from './testData'; const expect = mochaPlugin.chai.expect; let wrapped = mochaPlugin.getWrapper('stickerGet', '/handler.js', 'get'); -const stickerPayload = { - id: 'sticker001', - name: 'i am a sticker', - url: 'https://www.google.ca' -}; - describe('stickerGet', () => { before(() => { AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { - if (params.Key.id === stickerPayload.id) { + if (params.Key.id === stickerItem.id) { - callback(null, { Item: stickerPayload }); + callback(null, { Item: stickerItem }); } else { @@ -54,7 +49,7 @@ describe('stickerGet', () => { const response = await wrapped.run({ pathParameters: { - id: stickerPayload.id + id: stickerItem.id } }); expect(response.statusCode).to.be.equal(200); @@ -62,7 +57,8 @@ describe('stickerGet', () => { const sticker = JSON.parse(response.body); expect(sticker).to.have.property('id'); expect(sticker).to.have.property('name'); - expect(sticker).to.have.property('url'); + expect(sticker).to.have.property('imageURL'); + expect(sticker).to.have.property('key'); }); diff --git a/services/stickers/test/stickerGetAll.js b/services/stickers/test/stickerGetAll.js index bbddab3c..5421dd71 100644 --- a/services/stickers/test/stickerGetAll.js +++ b/services/stickers/test/stickerGetAll.js @@ -8,7 +8,7 @@ import mochaPlugin from 'serverless-mocha-plugin'; const expect = mochaPlugin.chai.expect; let wrapped = mochaPlugin.getWrapper('stickerGetAll', '/handler.js', 'getAll'); -import getStickersResponse from './stickers.json'; +import { stickerItemList } from './testData'; describe('stickerGetAll', () => { @@ -16,7 +16,7 @@ describe('stickerGetAll', () => { AWSMock.mock('DynamoDB.DocumentClient', 'scan', (params, callback) => { - callback(null, getStickersResponse); + callback(null, { Items: stickerItemList }); }); @@ -39,7 +39,8 @@ describe('stickerGetAll', () => { const event = body[0]; expect(event).to.have.property('id'); expect(event).to.have.property('name'); - expect(event).to.have.property('url'); + expect(event).to.have.property('imageURL'); + expect(event).to.have.property('key'); }); diff --git a/services/stickers/test/stickerUpdate.js b/services/stickers/test/stickerUpdate.js index 815cfb1a..049599da 100644 --- a/services/stickers/test/stickerUpdate.js +++ b/services/stickers/test/stickerUpdate.js @@ -5,13 +5,14 @@ import AWSMock from 'aws-sdk-mock'; // Generated by serverless-mocha-plugin import mochaPlugin from 'serverless-mocha-plugin'; +import { stickerPayload, stickerItem } from './testData'; const expect = mochaPlugin.chai.expect; let wrapped = mochaPlugin.getWrapper('stickerUpdate', '/handler.js', 'update'); -const updateId = 'sticker001'; +const updateId = stickerItem.id; const updatePayload = { + ...stickerPayload, name: 'i am a sticker', - url: 'https://www.google.ca' }; describe('stickerUpdate', () => { @@ -24,7 +25,7 @@ describe('stickerUpdate', () => { let returnValue = null; if(existingStickers.includes(params.Key.id)) returnValue = { - ...updatePayload, + ...stickerItem, id: params.Key.id }; callback(null, { Item: returnValue }); @@ -86,11 +87,11 @@ describe('stickerUpdate', () => { }); - it('return 406 for trying to update a sticker with invalid url', async () => { + it('return 406 for trying to update a sticker with invalid name', async () => { const invalidPayload = { ...updatePayload, - url: 123456789 + name: 123456789 }; const response = await wrapped.run({ diff --git a/services/stickers/test/stickers.json b/services/stickers/test/stickers.json index 3d72e490..3c24768f 100644 --- a/services/stickers/test/stickers.json +++ b/services/stickers/test/stickers.json @@ -1,5 +1,6 @@ { - "Items": [{ + "Items": [ + { "id": "sticker001", "name": "BluePrint Sticker", "url": "http://google.ca" diff --git a/services/stickers/test/testData.js b/services/stickers/test/testData.js new file mode 100644 index 00000000..b69ec738 --- /dev/null +++ b/services/stickers/test/testData.js @@ -0,0 +1,32 @@ +export const stickerPayload = { + id: 'sticker001', + name: 'BluePrint Sticker', + image: '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', + mime: 'image/jpeg', +}; + +export const stickerItemList = [ + { + id: 'sticker001', + name: 'BluePrint Sticker 1', + description: 'this is a sticker 1', + imageURL: `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/stickers/sticker001.jpeg`, + key: 'stickers/sticker001.jpeg', + }, + { + id: 'sticker002', + name: 'BluePrint Sticker 2', + description: 'this is a sticker 2', + imageURL: `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/stickers/sticker002.jpeg`, + key: 'stickers/sticker002.jpeg', + }, + { + id: 'sticker003', + name: 'BluePrint Sticker 3', + description: 'this is a sticker 3', + imageURL: `https://${process.env.stickerImagesBucket}.s3-${process.env.region}.amazonaws.com/stickers/sticker003.jpeg`, + key: 'stickers/sticker003.jpeg', + }, +]; + +export const stickerItem = stickerItemList[0]; From 5b959b0932c863ec8e8c5e4dd4e47bc5424cefb6 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Tue, 6 Jul 2021 22:51:19 -0700 Subject: [PATCH 12/13] s3 mock works for stickerCreate, but looks ugly --- services/stickers/test/stickerCreate.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/services/stickers/test/stickerCreate.js b/services/stickers/test/stickerCreate.js index 7ee43de4..34711de8 100644 --- a/services/stickers/test/stickerCreate.js +++ b/services/stickers/test/stickerCreate.js @@ -1,5 +1,9 @@ 'use strict'; import AWSMock from 'aws-sdk-mock'; +import AWS from 'aws-sdk'; +AWSMock.setSDKInstance(AWS); +AWSMock.mock('S3', 'putObject', { Body: 'mock response' }); + // tests for stickerCreate // Generated by serverless-mocha-plugin @@ -15,20 +19,17 @@ describe('stickerCreate', () => { before(() => { - AWSMock.mock('S3', 'putObject', (params, callback) => { - - console.log('Running mock s3 put'); - callback(null, 'Successfully put sticker into S3 bucket'); - - }); - AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { let returnValue = null; - if (createdStickerIds.includes(params.Key.id)) returnValue = { - ...stickerItem, - id: params.Key.id - }; + if (createdStickerIds.includes(params.Key.id)) { + + returnValue = { + ...stickerItem, + id: params.Key.id + }; + + } callback(null, { Item: returnValue }); }); @@ -45,7 +46,6 @@ describe('stickerCreate', () => { }); - }); after(() => { From 245a3ca460b99f823d6a0326cf6a9dcb920cfc99 Mon Sep 17 00:00:00 2001 From: Patrick Zhang Date: Mon, 19 Jul 2021 18:44:43 -0700 Subject: [PATCH 13/13] clean up s3 mock unit tests, integration tests --- lib/s3.js | 4 -- services/stickers/handler.js | 15 +++-- services/stickers/test/stickerDelete.js | 6 ++ services/stickers/test/stickerUpdate.js | 6 ++ .../test_integration/integrationTestData.js | 10 ++++ .../stickers/test_integration/stickers.js | 56 ++++++++++--------- 6 files changed, 61 insertions(+), 36 deletions(-) create mode 100644 services/stickers/test_integration/integrationTestData.js diff --git a/lib/s3.js b/lib/s3.js index 97498824..e4379029 100644 --- a/lib/s3.js +++ b/lib/s3.js @@ -2,12 +2,8 @@ import * as fileType from 'file-type'; import * as AWS from 'aws-sdk'; import helpers from './handlerHelpers'; - const allowedMimes = ['image/jpeg', 'image/png', 'image/jpg', 'image/svg']; - - - const imageUpload = async (body) => { try { diff --git a/services/stickers/handler.js b/services/stickers/handler.js index 1785d836..de8b4a87 100644 --- a/services/stickers/handler.js +++ b/services/stickers/handler.js @@ -54,12 +54,14 @@ export const create = async(event, ctx, callback) => { const uploadBody = JSON.parse(s3Upload.body); const item = { - id: data.id, - name: data.name, + ...data, imageURL: uploadBody.imageURL, - description: data.description, key: uploadBody.s3ObjectKey }; + + delete item.image; + delete item.mime; + const res = await db.create(item, STICKERS_TABLE); const response = helpers.createResponse(201, { @@ -136,12 +138,13 @@ export const update = async (event, ctx, callback) => { const uploadBody = JSON.parse(s3Upload.body); const item = { - id: data.id, - name: data.name, + ...data, imageURL: uploadBody.imageURL, - description: data.description }; + delete item.image; + delete item.mime; + const res = await db.updateDB(id, item, STICKERS_TABLE); const response = helpers.createResponse(200, { message: `Updated sticker with id ${id}!`, diff --git a/services/stickers/test/stickerDelete.js b/services/stickers/test/stickerDelete.js index ddf6adeb..da83b5ef 100644 --- a/services/stickers/test/stickerDelete.js +++ b/services/stickers/test/stickerDelete.js @@ -1,5 +1,7 @@ 'use strict'; import AWSMock from 'aws-sdk-mock'; +import AWS from 'aws-sdk'; + // tests for stickerDelete // Generated by serverless-mocha-plugin @@ -15,6 +17,9 @@ describe('stickerDelete', () => { before(() => { + AWSMock.setSDKInstance(AWS); + AWSMock.mock('S3', 'deleteObject', { Body: 'mock response' }); + AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { let returnValue = null; @@ -43,6 +48,7 @@ describe('stickerDelete', () => { after(() => { AWSMock.restore('DynamoDB.DocumentClient'); + AWSMock.restore('S3'); }); diff --git a/services/stickers/test/stickerUpdate.js b/services/stickers/test/stickerUpdate.js index 049599da..d58d5e36 100644 --- a/services/stickers/test/stickerUpdate.js +++ b/services/stickers/test/stickerUpdate.js @@ -1,5 +1,7 @@ 'use strict'; import AWSMock from 'aws-sdk-mock'; +import AWS from 'aws-sdk'; + // tests for stickerUpdate // Generated by serverless-mocha-plugin @@ -21,6 +23,9 @@ describe('stickerUpdate', () => { before(() => { + AWSMock.setSDKInstance(AWS); + AWSMock.mock('S3', 'putObject', { Body: 'mock response' }); + AWSMock.mock('DynamoDB.DocumentClient', 'get', (params, callback) => { let returnValue = null; @@ -48,6 +53,7 @@ describe('stickerUpdate', () => { after(() => { AWSMock.restore('DynamoDB.DocumentClient'); + AWSMock.restore('S3'); }); diff --git a/services/stickers/test_integration/integrationTestData.js b/services/stickers/test_integration/integrationTestData.js new file mode 100644 index 00000000..4eeb464a --- /dev/null +++ b/services/stickers/test_integration/integrationTestData.js @@ -0,0 +1,10 @@ +import { + INTEGRATION_TEST_STICKER_ID, +} from '../../../constants/test'; + +export const stickerPayloadBody = { + id: INTEGRATION_TEST_STICKER_ID, + name: 'Integration Sticker', + image: '/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHCBUVFRgSFRIVFRgYFRwVGBQYERgUEhUVGBQZGhgUFhgcIS4nHB4rHxgaKz0nKy8xNTU1HCU+QD00Py40NTEBDAwMEA8QHxISHzQrJSs2NDQ2NDExNDE2MTQ0NTQ0PTQ0NDQ0NDQ0NTQ0MTQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NP/AABEIAOEA4QMBIgACEQEDEQH/xAAcAAEAAQUBAQAAAAAAAAAAAAAAAgMEBQYHAQj/xABEEAACAQICBgYGCAMHBQEAAAABAgADEQQSBQYhMUFREyJhcYGRBzJykqGxIyRCUmJzssEUotEWQ2OCwuHwM1NUk9IV/8QAGQEBAAMBAQAAAAAAAAAAAAAAAAMEBQIB/8QAJREAAwACAQMEAwEBAAAAAAAAAAECAxEEEiExMjNBcSJRYRSB/9oADAMBAAIRAxEAPwDs0REAREQBERAEREAREQDyIJmOxGmaCetWS/IHOfELcz1JvweOkvJkYmBqa0UBuDt3KAP5iJQbW1OFJ/EqP6ztYrfwRvNC+TZYmsjW1eNFvBlMrJrVRO9Kg/yqfk0PFf6CzQ/k2CeTGUNPYdt1UD2gU+LACZFHBFwQRzBuPOcOWvKO1SfhlSIieHQiIgCIiAIiIAiIgCIiAIiIAiIgCIiAeRIu4AJJAAFySbADneatpXWfelDuNUjZ/lU7+8+RnUxVPSOLuYW2bBjcfTpDM7gchvY9wG0zXMbrWxuKShR95treCjYPEmazWrsxLMxZjvYm5PjKZaXY4yXq7lG+VT7T2LvFY56nruzdhPV90bB5S2zyF4vLKlLwVnTfknnnl5G8XnujnZK8Z5G8XjR6T6SVqGJZTdXZTzVivnbfLa8XnjlM9VNGyYLWequxwKg5+q3mNh8vGbHgNM0q2xWs33G6reHPwvOc3nq1JXvjTXjsWI5NT57nV4mkaL1kdLLUvUT7394vj9rx29s3DC4laih0YMDxHyPI9kp3jqH3L2PLNrsXEREjJBERAEREAREQBERAEREA8lDF4lKal3IAG8/05mSxFdUUuxAUC5J4Cc903pdq73N1VfVXl+JvxH4fOXFidv8AhDmzLGv6VdM6aaubbVpjcl9rci3M9m4fGYhmkC08vNKIULSMu8jt7ZKJG8XnZySiRvF4BKJG8XgEokbxeASiRvF4BKJG8XgEw0vtHaRek2ZD7Sn1WHd+8x14DTmpVLTOppy9o6dorSSV1zLsI2Mp9ZT28xyMv5y7AY1qTB1NmHkw4qw4idD0VpBayB12Hcy32q3EH+vGZubC4e14NLBmVrT8l/ERISwIiIAiIgCIiAeTyezAa06T6KnkU2d7gHiq/abv4Dv7J7KdPSObpTLbMFrPpjpW6NT1FPDc7Dee0Dh58prjNPHeeXmtjxqJ0jIyW7rbJXi8jeLyQjJXi8jeLwCV4vI3i8AleLyN4vAJXi8jeLwCV4vI3i8AleLyN4vAJXi8jeLwCQaZPQ+k2ouHG0HY6/eX+o3j/eYq89V7Tm4VLTO4ty9o65Rqq6hlIKsAQRuIMqTTtTtJ2Jw7HYbsnYd7L47/ADm4zJyQ4rTNbHaudo9iInBIIiIAiIgEDs2zmGndIGtVd79W+VOxRu89/jN21rxnR0GANmfqDx9Y+6DOau+2XeJHmijy78Sj288vI3i8vFAleSpqzMqKLszBVHMk2AlO89wePFCvSrN6quC3GykEE27Ab+E8ttS2jqEnSTN1w2pK5R0lZs1tuQKF/mBJ79k13TuimwrhWbMrglWta9rXDDgRcefl0XD6RpuodXUhhcEG4I5gjfNF180zTqPTw6MGZWLuQb5biyqe03JtwsOcoYc2R3psvZsMKNpGCvF5BWnt5oGeSvF5G8XgErxeRvF4BK8XkbxeASvF5G8XgErxeRvF4BK8XkbxeAXWFrsrBlNmUhlPIg3E6no/FCrTSou5lvbkdxHgbicjVpvGo+NuHok7uuvcdjDzsfEypy42ur9FziXp9P7NviImeaIiIgCInkA0TXvFXqJT4IuY+0x/ovxmolpldZq+bEVW/Fl9wBf2mGvNfBPTjSMfkV1W2TvF5C8XkxCTvKbYY1GVFGZnIVVuBdibAXOye3lbRL2xWHH+On6hOMj1LZ3jW6SKX9iMeLhaNRQTchcRTUHvAfbINoCthcvTUyma+Xro18tr+qxtvE7OGmi+kl7HD9pqfKnKGHK3kSaRfzYkobTfY1vC0WqMtNFzM2xVuBcgE7yQNwMyf9msZ/4zf+yl/wDcx+rtW2Mw/a5HmjTreaTZ89RWkkQ4OPOSdts5DiaLU3NJ1KupAK3DG7AEDqk3uCN3OZXCas4pxm6MIDuzkKfd2keIm8U9FUlrviiLu4UAncgVQvV7Tbf4d9wdIU75c4v3GRVy612RLPDnb2zQ8RqnikFwiP2K928mAvME4KkqylWBsVYFWB5EHdOwq4O0G/bMLrJoNcQhZQBWUdRt17fYY8Qfh539x8t71R5k4i1uTnF4zSkr8CLEbCDsII3gzMataH/iahvspJYuRsLE7kB4X4ngO8S7VzM9TKUxVV0otsBo+tXNqVNmtsLbAg72Oy/ZvmWGp+Ktf6Lu6Q37vVt8Zv8ARpqihEUKqiwVRYAdglDE6Rp0/XqKveQB5mZ9cu2/xRfniSl+TOYaS0fVw5tVplL7m2FG7mGy/Zvl4mruLYBhh2IIBB6SntBFwfXm/wBZaOJptTazoy2I424MDwI4ES9QWAUbgAPIT18uteFsf4535ejlOP0bWoZemplM18t3Rr2tf1SeYlpebN6SKlmw455z+iaqGlzDbuFTKeeFFOUVLzNas4vJXptfYWyHufqj42PhMFeVsM5BuN4Nx3jaJ1knqlo4x100mdnnso4eoGRXG5lDeYvK0xjbEREASD7jJyjiTZWPZAOP6QqZndubs3mxMs7ypiG2yjebkLsYVvuyV4vI3i860ckrypos/WsP+en6xKN5PRZ+tYf89P1iR5fQyXF60djDTRfSWduG76vypzdw00T0lnbhu+p8qcy8HuI1M/tswGgW+uYf8wfpM69mnHtAn65h/wAwfIzruaScv1/8IuJ6H9mpekbTT0KSU6RyvVYqH4oigF2HbtUDvJ4Tk50cxPSEsX35yxL355t950X0lrd8Mfw1PnTmsgC0m4+GanbIuRmqa0jbPRppyo4fC1mLugDI5N2ZCbWY8Sptt4hhym/Zpy3UGmf41iNwoPf30tOnZpUzSptpFvDTqE2cv1vpCli6gGwOFqAe2Ot/MGm86nYYU8JT5uOlY8y+1fJco8JonpFqfW9nDDoPHPUP7zomhHBw9Ejd0KW9xZNmpvFKIcMpZWyvpTGClSeq25EZzzsqkm3bsnCcb0mKdq1ZizMSQt+qinciDgB8eO2dj1wUtgsQB/2yfAEE/AGcuwygLPeLjVbbPOVkc6SLzUHFvhsUlEMejqkqUv1VfKWV1HA7LHnfsE7HmnHtBL9dw/5n+lp13NI+TCitIk41Op2zQ/SUfpMP7NT5pNaUzY/SSfpMP7NT5pNZUy7xfbRR5XuMneVaDbZQvJ0TtlhrsV15Ou6vVM2GpH/DA8hb9pk5hdUmvhqfcf1GZqYd+p/Ztx6UexETw7Et8Z6jeyZcSjiRdWHZAOJVXuAeYvKV56p6gH3SUPejFT8pSvN2O8pmHkWqaL7RWCOIrJRU5c1yzWvlQC7Nb/m0idFoavYRVy/w6t+Jrs57b8PC051q1pFaOKRnICurU8xNgC1ipPioHjOpLWUi9x5zP5eS1ek9IvcXHDnbW2aFrboVcMyVKdxTc5cpJJRgL2BO9SAd+60wuij9aw/56frE2L0g6UQrToKwLF85AO5ArAE95bZ3Ga1oTbisOP8AGQ+Rv+0mx1TwN1/SO5mc6U/w7CGmi+ko7cN31PlTm7Xmi+kltuG76nypylg9xFzP7bMDoE/XMP8AmD9JnXM05BoE/W8P+YP0mdbvJeZ619EXD9D+zDa26EbFU1yW6SmxZATYMCLMt+B2AjtHbeaH/wDmYgNk/hq2bdbonPxta3be06FjtNU6NanRd1U1QxS+zMUK3W+6/WFhx2zJJigRsf4zjFyKxzrR3l485HvejB6o6BbDK9SpbpalrqDfIgvZbjeSTc27OUz7vYXlF8Qq7Sw89s0DW/XBXDYbDNmLXV6im6op2FVYb2O643d+6P8ALJW/lkn44518I1/T2N/iMTVqg3XNkQ8CiAKCOw2J8Z0DULSQqYZKZPWpfRkdi+p/Jl8jObYalZbSpo3Sj4Sr0qDMp2Ol7Z14WPBhwPfzl3Ng3jSXwUsObWRt/J2qooYFWF1YFWB3FSLEeU51j9UsRSYinTNZL9R1ILgcFdSb37Rs+U2jQ2tGHxKgpUGa21DsqL7Sbx37u2ZU4xBtz/OVMeS8T7FvJjjKu5q2qurFRKoxOIUIUByU7gvmYFS7W2CwJsO3habnmmpY3W+kcRSwlJs7vUVGKG4Rb9Ysw2XsN3nNpvOcl1VdVHeOJiemTRfSQfpMP7NT5pNZBmxekdvpMOPw1Pmk1oGaXF9tGZyvcZUvKtA7ZbXlxhzxlh+CuvJ1TUxr4VD7XwdhM/Nd1E24Gi33kD+91v3mxTDv1M3IWpQiexOToSFQXB7pOeQDhmKTJWxVL7mIcgfhds4/VLUmZjXbD9DpJjay4ikrX5ul1P8AKF85hqmwzZ49dUIx+RPTbLfFUswlOnj8WgyJiKgUbALhrDkCwJEubzwgTq8U35OIy1HgtaFNrl3Ysx2lmJZieZJm16laLepiFxGUinSzHMRZWcqVVVPG2YnZut2zzUXI1d0dEfqBlzorZSrAErcbPWE6KW4bgNwAsB3CVM+ZSnjlFzBi6mslMlec69IOKDYilTH2EZj2Z2A+STb9NaZpYZDUdwLbABtZm4Ko4tOU1MU9eq9d9hdr24Ko2Ko7gBIeLDd7/RNyrSjX7MloI/W8P+YP0mdavORaCP1zD/mD9JnWrzrmetfRzw/Q/s556VaOd8MPw1PnTmp0MbiqYypiKgHAFswHdmvabn6Rz18P7NT5pNWAEmwYZvGtkOfLU5Hos8RWxNXZVr1HHFS1kPeosDKuGwgWXAAnt5ZjDMeCtWWq8kxPaeFNV1poMzOQqjYLk9p3SneZvUqlnxQc+rTRnvwzHqKP5ifCe5aUw2eYp6rSNY0loZ6bZaiPTYHZmUrt5qdx7xLVsMxFmqORyLsR5EzvRe4sbMOTAMPjKC4OgDmGGoBvvCigPnaZv+iX5Rof56XhnPPR/q0xrLi3QqlMEoSLZ3KlQVHFQCTfde3bbpmaRd+JP7ATX9ZdZqeGQ7Q7sOogPWY/svM/MyCm7rsixKUT3ZqevGMD4sIDcU0CnsZzmI90pMUDLOi7OzVHN3di7HmSbnwlzebGCemUjIz11W2VLxi6uSi7jflIHtEWHxIkFlXoelr4XCjbnrKzD8CHM3wB8p7lrphsYp6rSO06v4bo8NSp7slNV91QP2mTlOktlA7JUmGbQiIgCIiAc39L2jiaNPFKOtRqAk225XIB/myfGaOXDqtQbmF/9p3DTWBWvRek4uroynuYWnA8CrUalTCVNjI7KO8HbbsIsR3y/wAPJr8Sjy43+RXvF4cWMjeaRnE9H6TfDVemRA5yMmUtlFmIN72P3RLnFa8Yx9iKidvWc/EgfCWDLeRFMSvfGmq6mWI5FRPSi2fpKr9JWdnbmx2DsUblHYJe01sIE9vJYxqFpEV27fc8Fd6brUQ2dDmUkXANuUqNrVjr/wDUT/1iUzI5BOMmCbe2d481QtInidJ18RkNZg2S+WyhbZrX/SJ6DIASV5JEKFpEd26e2SvF5G8XnRySvLeo7oc6OyMPtKxU92zeJWvPDPKlUtM9mnL2iph9bcdT2Z0f2ksfNCJd/wBvcX/26fm//wBTGlBPOjEqviSyyuXSK+J1qx1TZ0ioPwJ1vNyfhMdSw7Mxd2Z2O9mYsx7ydpl4EEkDJI48ycXnqiSC09vI3nqyfRAV8OtzeZz0aYT+Ix1TFEXSkmRDwzPxH+UH35rGlcT0dPKD1nFu5eJnXfR1oT+FwiKws7/SPzzOB1T3AKPCUOXk0ukvcSO/UbbERM00RERAEREA8nIfSxoIo646mLbQlS3A/Yf/AE+7OvSy0pgEr03pOoZWUqQeIIsRO8dua2cXKpaZwehWFVM43jYw5H+kpmUtK6OqYDEtSa5XejHdUpk7D3jce0cjLlrModDcH4dhmzitUjIy43LKV4vPJG8mIid4vIXi8AneLyF4vAJ3i8heLwCd4vIXi8AneLyF4vAJ3i8heLwCd4vIXi8AneV0sql22AC8hRTidgHGWGJqtXdKFJS2ZgqKPtMeJ5D5C5keS1KO8cOmZrUrRLY/GCow+jpEOw4Eg9RPMXPcec7xTWwAmA1M1fXB4daYsW9Z2tbO5HWbu4DsAmxTFy311s2McdM6PYiJGSCIiAIiIAiIgGqa66sJjKRGxai3ZHt6rW3Hmp4j9wJxFTUw9RqVRCrKbOh+YPyPGfS9ppWvGpqYtc6WSqo6r22Eb8r23r8r7OINjBm6Hp+CDLi61teTlxCsM6G4+I7DLcy0dKuHqNTdSjr6yncRwI5g8xL+lWSpu6rfd/pzmtGRNGXkxtMheLw6ESF5KRk7xeQvF56Cd4vIXi8AneLyF4vAJ3i8heLwCd4vIXk0QmeA8EuKdP7TbAN5kWKoLue4cTMZisWzkKAbEgKi7SSTsFhvMju0juMbZV0hjs3UW+W9tg2seAt+06f6ONTzRH8TXX6VxsU/3Sn7PtHj5c722oOoxQrisSvX3oh2in2nm/y7509EAFhMrPn6uy8Gphw9K2/JICexEqlgREQBERAEREAREQBPCJ7EA1fWrVKjjEsy2ceo67HQ9h4jsOycY09q9iMG1qi5kvZayg5DyDfdPYfAmfR0tcZgUqKVdQQRYggEEciOMlx5nH0RZMSs+c6GkWGxusP5h48ZdIyP6rWPI7DN41j9GakmphW6M7+jNzSPdxT4jsnPdJ6KxGGNq1F0H37ZqZ7nGzwO2aOPkTXhlHJx2vguXoESkVPKWlHGONz3HI7R8ZcrpD7yA9xtLKyFZ4z2LyYxlM71YeAMl09LmfdM660c9DKV4lXp6X3j7pnhxVMcGPhHWh0sgBKiUSeEpNpAfZTxJ/aUKuOc/ayjkNk8eRHSgv2RV2uwHZx8pb1tI22ILfiO/wABLXCYepWbJSpvUb8Klre0dw7yZvGgPRrUqEPiXyrv6NDtPYz8O4ecrZORM+WWMeBvwjS9H4KtiX6OkjO32m+ygPF24D/gnXNTdRKeGtVqWqVfvEdVb8EHDv3ns3TaNEaEo4dAlNFUDgBbbzPM9pmVEz8uer7fBex4VPf5IooAsJOIkBMIiIAiIgCIiAIiIAiIgCIiAIiIB4RLXEYFHBBUbezZLuIBo+lvR1hat2VOjY/apnIe/L6p8RNTx3ovqL/0sRccqlPb7yn9p2OLSSctz4Zw8c15RwLEaiY9L2RH9mpYn3gJYtqtjxvwjeD0z8nn0TkHISJor90SRcq0RvjwfO66r487sI/voPm0uqGpOOf+6VPbqL/ozTv3QL90T3oxyEPlWFxoOMYL0ZYh7dJWROYRC58zb5TZ9F+jLDJZnDVT+Nur7q2B8bzoYESOs115Z3OKZ8Ix2B0RSpKFSmqgblVQqjwEyCqBukokZIIiIAiIgCIiAIiIAiIgCIiAIiIAiIgCIiAIiIAiIgCIiAIiIAnk9iAIiIAiIgCIiAIiIAiIgCIiAf/Z', + mime: 'image/jpeg', +}; diff --git a/services/stickers/test_integration/stickers.js b/services/stickers/test_integration/stickers.js index aeb0fd8a..5a4c75cb 100644 --- a/services/stickers/test_integration/stickers.js +++ b/services/stickers/test_integration/stickers.js @@ -3,6 +3,7 @@ import chai from 'chai'; const expect = chai.expect; import helpers from '../../../lib/testHelpers'; +import { stickerPayloadBody } from './integrationTestData'; import { INTEGRATION_TEST_STICKER_ID, INTEGRATION_TEST_NON_EXISTANT_STICKER_ID @@ -24,7 +25,7 @@ describe('stickers integration', function () { it('stickers/{id} GET doesn\'t exist returns 404', async () => { - return helpers.invokeLambda(SERVICE, 'stickerGet', JSON.stringify(defaultPayload)) + return helpers.invokeLambda(SERVICE, 'stickersGet', JSON.stringify(defaultPayload)) .then(([statusCode]) => { expect(statusCode).to.equal(404); @@ -37,17 +38,13 @@ describe('stickers integration', function () { describe('stickers/ POST tests', function () { - let stickerPayload = { - body: JSON.stringify({ - id: INTEGRATION_TEST_STICKER_ID, - name: 'Integration Sticker', - url: 'http://google.ca' - }) + const payload = { + body: JSON.stringify(stickerPayloadBody) }; it('stickers/ POST returns 201 on success', async () => { - await helpers.invokeLambda(SERVICE, 'stickerCreate', JSON.stringify(stickerPayload)) + await helpers.invokeLambda(SERVICE, 'stickersCreate', JSON.stringify(payload)) .then(([statusCode]) => { expect(statusCode).to.equal(201); @@ -58,7 +55,7 @@ describe('stickers integration', function () { it('stickers/ POST returns 409 when sticker id already exists', async () => { - return helpers.invokeLambda(SERVICE, 'stickerCreate', JSON.stringify(stickerPayload)) + return helpers.invokeLambda(SERVICE, 'stickersCreate', JSON.stringify(payload)) .then(([statusCode, body]) => { expect(statusCode).to.equal(409); @@ -72,21 +69,21 @@ describe('stickers integration', function () { describe('stickers/{id} PATCH and GET tests', function () { - const stickerPayload = { - name: 'Updated Sticker', - url: 'http://google.com' - }; + const newStickerName = `${stickerPayloadBody}-updatedName`; - it('stickers/{id} PATCH returns 404 when event not found', async () => { + it('stickers/{id} PATCH returns 404 when sticker not found', async () => { const payload = { pathParameters: { id: INTEGRATION_TEST_NON_EXISTANT_STICKER_ID }, - body: JSON.stringify(stickerPayload) + body: JSON.stringify({ + ...stickerPayloadBody, + id: INTEGRATION_TEST_NON_EXISTANT_STICKER_ID, + }) }; - return helpers.invokeLambda(SERVICE, 'stickerUpdate', JSON.stringify(payload)) + return helpers.invokeLambda(SERVICE, 'stickersUpdate', JSON.stringify(payload)) .then(([statusCode]) => { expect(statusCode).to.equal(404); @@ -101,9 +98,13 @@ describe('stickers integration', function () { pathParameters: { id: INTEGRATION_TEST_STICKER_ID }, - body: JSON.stringify(stickerPayload) + body: JSON.stringify({ + ...stickerPayloadBody, + name: newStickerName, + id: INTEGRATION_TEST_STICKER_ID, + }) }; - await helpers.invokeLambda(SERVICE, 'stickerUpdate', JSON.stringify(payload)) + await helpers.invokeLambda(SERVICE, 'stickersUpdate', JSON.stringify(payload)) .then(([statusCode]) => { expect(statusCode).to.equal(200); @@ -114,14 +115,17 @@ describe('stickers integration', function () { it('stickers/{id} GET returns 200 and check PATCH success', async () => { - return helpers.invokeLambda(SERVICE, 'stickerGet', JSON.stringify(defaultPayload)) + return helpers.invokeLambda(SERVICE, 'stickersGet', JSON.stringify(defaultPayload)) .then(([statusCode, body]) => { expect(statusCode).to.equal(200); // Check that update succeeded - expect(body.name).to.equal(stickerPayload.name); - expect(body.url).to.equal(stickerPayload.url); + expect(body.name).to.equal(newStickerName); + expect(body).to.have.property('id'); + expect(body).to.have.property('name'); + expect(body).to.have.property('imageURL'); + expect(body).to.have.property('key'); }); @@ -129,7 +133,7 @@ describe('stickers integration', function () { it('stickers/ GET returns 200 on success', async () => { - return helpers.invokeLambda(SERVICE, 'stickerGetAll', '').then(([statusCode]) => { + return helpers.invokeLambda(SERVICE, 'stickersGetAll', '').then(([statusCode]) => { expect(statusCode).to.equal(200); @@ -141,7 +145,7 @@ describe('stickers integration', function () { describe('stickers/{id} DELETE tests', function () { - it('stickers/{id} DELETE returns 404 when event not found', async () => { + it('stickers/{id} DELETE returns 404 when sticker not found', async () => { const payload = { pathParameters: { @@ -149,7 +153,7 @@ describe('stickers integration', function () { } }; - return helpers.invokeLambda(SERVICE, 'stickerDelete', JSON.stringify(payload)) + return helpers.invokeLambda(SERVICE, 'stickersDelete', JSON.stringify(payload)) .then(([statusCode]) => { expect(statusCode).to.equal(404); @@ -158,9 +162,9 @@ describe('stickers integration', function () { }); - it('stickers/{id} DELETE returns 200 on update success', async () => { + it('stickers/{id} DELETE returns 200 on delete success', async () => { - await helpers.invokeLambda(SERVICE, 'stickerDelete', JSON.stringify(defaultPayload)) + await helpers.invokeLambda(SERVICE, 'stickersDelete', JSON.stringify(defaultPayload)) .then(([statusCode]) => { expect(statusCode).to.equal(200);