Skip to content

Commit

Permalink
CS-1264 Improved Logging Messages for lambda functions
Browse files Browse the repository at this point in the history
CS-1264 Greatly increase logging in Lambda Functions

CS-1264 Log lambda return values
  • Loading branch information
jwelborn-sugar committed Dec 16, 2020
1 parent be01e15 commit 9fa87fd
Show file tree
Hide file tree
Showing 19 changed files with 299 additions and 82 deletions.
19 changes: 12 additions & 7 deletions __tests__/unit/handlers/add-note-to-case.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@
const app = require('../../../src/core/app');
const lambda = require('../../../src/handlers/add-note-to-case');

const ErrorMessages = require('../../../src/constants/messages/error');
const SuccessMessages = require('../../../src/constants/messages/success');

describe('Test for add-note-to-case', function() {
test.each([
[1, 'cid', 'test1', 'John Doe', { data: { records: [{ id: 1 }] } }, { data: { record: { id: 1 } } }, true],
[1, 'cid', 'test2', '', { data: { records: [{ id: 1 }] } }, { data: { record: { id: 1 } } }, true],
[1, 'cid', 'test3', 'John Doe', { data: { records: [{ id: 1 }] } }, { data: {} }, false],
[1, 'cid', 'test4', 'John Doe', { data: { records: [] } }, { data: { record: { id: 1 } } }, false],
[1, 'cid', 'test5', 'John Doe', { data: { records: [] } }, { data: {} }, false]
[1, 'cid', 'test1', 'John Doe', { data: { records: [{ id: 1 }] } }, { data: { record: { id: 1 } } }, true, SuccessMessages.LAMBDA_FUNCTION_SUCCESS],
[1, 'cid', 'test2', null, { data: { records: [{ id: 1 }] } }, { data: { record: { id: 1 } } }, true, SuccessMessages.LAMBDA_FUNCTION_SUCCESS],
[1, 'cid', 'test3', 'John Doe', { data: { records: [{ id: 1 }] } }, { data: {} }, false, ErrorMessages.ERROR_NOTE_CREATE_FAILED],
[1, 'cid', 'test4', 'John Doe', { data: { records: [] } }, { data: { record: { id: 1 } } }, false, 'Unable to match any Case records'],
[1, 'cid', 'test5', 'John Doe', { data: { records: [] } }, { data: {} }, false, 'Unable to match any Case records'],
[1, 'cid', 'test6', 'John Doe', { data: { records: [{ id: 1 }, { id: 2 }] } }, { data: {} }, false, 'Matched multiple Case records']
])(
'Verify correct response whether or not case is returned by API and note is added',
async (number, cid, noteDescription, contactName, apiResponse1, apiResponse2, matched) => {
async (number, cid, noteDescription, contactName, apiResponse1, apiResponse2, matched, body) => {
process.env = {
sugarUrl: 'https://cs-829.msqa.sugarcrm.com'
};
Expand All @@ -45,7 +49,8 @@ describe('Test for add-note-to-case', function() {

let expected = {
statusCode: matched ? 200 : 500,
caseId: matched ? 1 : ''
caseId: matched ? 1 : '',
body: body
};
expect(result).toEqual(expected);
});
Expand Down
20 changes: 13 additions & 7 deletions __tests__/unit/handlers/case-status.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
const app = require('../../../src/core/app');
const lambda = require('../../../src/handlers/case-status');

const SuccessMessages = require('../../../src/constants/messages/success');

describe('Test for case-status', function() {
test.each([
[1, 'cid', { data: { records: [{ id: 1, status: 'good' }] } }, true],
Expand All @@ -32,13 +34,17 @@ describe('Test for case-status', function() {
mockApi.mockReturnValue(apiResponse);
app.api.call = mockApi;
let result = await lambda.handler(evt);
let expected = matched ? {
statusCode: 200,
caseId: 1,
caseStatus: 'good'
} : {
statusCode: 404
};
let expected = matched
? {
statusCode: 200,
caseId: 1,
caseStatus: 'good',
body: SuccessMessages.LAMBDA_FUNCTION_SUCCESS
}
: {
statusCode: 404,
body: 'Unable to match exactly one Case record'
};
expect(result).toEqual(expected);
});
});
5 changes: 4 additions & 1 deletion __tests__/unit/handlers/create-case.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

// Import all functions from createCase.js
const lambda = require('../../../src/handlers/create-case.js');
// Defined Constants
const SuccessMessages = require('../../../src/constants/messages/success');

// Mock bean.js
jest.mock('../../../src/core/bean.js', () => () => ({
Expand Down Expand Up @@ -46,7 +48,8 @@ describe('Test for create-case', function() {
const expectedResult = {
statusCode: 200,
caseId: 1,
caseNumber: 1
caseNumber: 1,
body: SuccessMessages.LAMBDA_FUNCTION_SUCCESS
};
// Compare the result with the expected result
expect(result).toEqual(expectedResult);
Expand Down
39 changes: 39 additions & 0 deletions __tests__/unit/utils/string-utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/
const strUtils = require('../../../src/utils/string-utils.js');

describe('generateMessage', function() {
test.each([
{
template: 'Single ${} test',
filler: 'dog',
expected: 'Single dog test'
},
{
template: 'Multiples ${} ${} test',
filler: ['dog', 'cat'],
expected: 'Multiples dog cat test'
},
{
template: 'Mismatched ${} ${} ${} too few fillers',
filler: ['dog', 'cat'],
expected: 'Mismatched dog cat ${} too few fillers'
},
{
template: 'Mismatch ${} too many fillers',
filler: ['dog', 'cat'],
expected: 'Mismatch dog too many fillers'
}
])('should fill the template string as expected', (values) => {
let actual = strUtils.generateMessage(values.template, values.filler);
expect(actual).toEqual(values.expected);
});
});
10 changes: 8 additions & 2 deletions src/constants/messages/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@
* Copyright (C) SugarCRM Inc. All rights reserved.
*/

module.exports = {
module.exports = {
/**
* Error messages
*/
ERROR_MULTIPLE_CALL_RECORDS_IN_RESPONSE: 'Unable to match to exactly one Call record'
ERROR_CANNOT_CREATE_CASE: 'Unable to create Case in SugarCRM',
ERROR_NOTE_CREATE_FAILED: 'Unable to link Note to Case in SugarCRM',

TPL_CANNOT_MATCH_RECORD: 'Unable to match exactly one ${} record',
TPL_MISSING_REQUIRED_PARAMETERS: 'Missing required parameters: ${}',
TPL_MULTIPLE_RECORDS_MATCHED: 'Matched multiple ${} records',
TPL_NO_RECORDS_MATCHED: 'Unable to match any ${} records'
};
17 changes: 17 additions & 0 deletions src/constants/messages/success.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Your installation or use of this SugarCRM file is subject to the applicable
* terms available at
* http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
* If you do not agree to all of the applicable terms or do not have the
* authority to bind the entity as an authorized representative, then do not
* install or use this SugarCRM file.
*
* Copyright (C) SugarCRM Inc. All rights reserved.
*/

module.exports = {
/**
* Success messages
*/
LAMBDA_FUNCTION_SUCCESS: 'Lambda Function Completed Successfully'
};
3 changes: 3 additions & 0 deletions src/core/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
const axios = require('axios');

const { HttpStatus } = require('../constants/http-status.js');
const loggerUtils = require('../utils/logger-utils');
const { Secrets } = require('../utils/aws/secrets');

const methodToRequest = {
Expand Down Expand Up @@ -61,7 +62,9 @@ module.exports = () => {
request.params = params;
}
response = await axios(request);

if (response.data) {
loggerUtils.logSugarApiResponse(response.data);
return {
status: HttpStatus.ok,
data: response.data
Expand Down
61 changes: 42 additions & 19 deletions src/handlers/add-note-to-case.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@
*/
const app = require('../core/app.js');
/**
* Util class to log JSOn to Cloudwatch
* Util classes to write logs to Cloudwatch
*/
const loggerUtils = require('../utils/logger-utils');
const strUtils = require('../utils/string-utils');
/**
* HTTP status codes used in this function
* Defined Constants
*/
const { HttpStatus } = require('../constants/http-status');
const ErrorMessages = require('../constants/messages/error');
const SuccessMessages = require('../constants/messages/success');
/**
* Sugar Instance URL
*/
Expand All @@ -32,27 +35,44 @@ const baseUrl = process.env.sugarUrl;
* @param {Object} event
*/
const addNoteToCaseHandler = async (event) => {
loggerUtils.logContactFlowEvent(event);

let statusCode = HttpStatus.error;
let caseId = '';
let noteName = '';
let body = '';

// input from the contact flow provided by the user
const caseNumber = event.Details.Parameters.caseNumber || '';
const contactId = event.Details.Parameters.contactId || '';

if (!caseNumber || !contactId) {
return {
statusCode: HttpStatus.preconditionFailed
};
let filler = caseNumber ? '' : 'caseNumber ';
filler += contactId ? '' : 'contactId';
body = strUtils.generateMessage(ErrorMessages.TPL_MISSING_REQUIRED_PARAMETERS, filler);
return loggerUtils.logReturnValue({
statusCode: HttpStatus.preconditionFailed,
caseId: caseId,
body: body
});
}

const noteDescription = event.Details.Parameters.noteDescription;
const contactName = event.Details.Parameters.contactName;

// Use the given case number to get the relavant case id
const filterUrl = encodeURI(`${baseUrl}/rest/v11_10/Contact/${contactId}/Cases?filter[0][case_number]=${caseNumber}&fields=id`);
const idResponse = await app.api.call('read', filterUrl, null, null);
const caseBean = idResponse.data.records[0];

loggerUtils.logSugarApiResponse(idResponse);

let statusCode = HttpStatus.error;
let caseId = '';
let noteName = ''
if (idResponse.data.records.length > 1) {
body = strUtils.generateMessage(ErrorMessages.TPL_MULTIPLE_RECORDS_MATCHED, 'Case');
return loggerUtils.logReturnValue({
statusCode: statusCode,
caseId: caseId,
body: body
});
}
const caseBean = idResponse.data.records[0];

// if contact name is empty then default it to 'customer'
if (contactName === '' || contactName === undefined) {
Expand All @@ -70,26 +90,29 @@ const addNoteToCaseHandler = async (event) => {
'description': noteDescription,
'name': noteName
};

// add note to the case
const filterUrl = encodeURI(`${baseUrl}/rest/v11_10/Cases/${caseBean.id}/link/notes`);
const noteResponse = await app.api.call('create', filterUrl, null, notePayload);

loggerUtils.logSugarApiResponse(noteResponse);

const updateCaseBean = noteResponse.data.record;

// if the case was successfully updated
if (updateCaseBean && updateCaseBean.id !== '') {
statusCode = HttpStatus.ok;
caseId = updateCaseBean.id;
body = SuccessMessages.LAMBDA_FUNCTION_SUCCESS;
} else {
body = ErrorMessages.ERROR_NOTE_CREATE_FAILED;
}
} else {
body = strUtils.generateMessage(ErrorMessages.TPL_NO_RECORDS_MATCHED, 'Case');
}

return {
return loggerUtils.logReturnValue({
statusCode: statusCode,
caseId: caseId
};
caseId: caseId,
body: body
});
};

exports.handler = addNoteToCaseHandler;
16 changes: 9 additions & 7 deletions src/handlers/call-recording.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,45 @@ const app = require('../core/app.js');
/**
* Utils
*/
const callRecordingUtils = require('../utils/sugar/call-record-utils');
const loggerUtils = require('../utils/logger-utils');
const s3Utils = require('../utils/aws/s3-utils');
const callRecordingUtils = require('../utils/sugar/call-record-utils');
const stringUtils = require('../utils/string-utils.js');

/**
* Defined constants
*/
const ErrorMessages = require('../constants/messages/error');
const CallsConstants = require('../constants/sugar-modules/calls');
const ErrorMessages = require('../constants/messages/error');
const { HttpStatus } = require('../constants/http-status.js');

/**
* Function to update a call record's call recording URL when the
* Function to update a call record's call recording URL when the
* audio file is ready
*
* @param {Object} event the S3 trigger event
*/
const handler = async (event) => {
// Log S3 Event to cloudwatch for debugging
loggerUtils.logS3Event(event);

let objectKey = s3Utils.getObjectKeyFromS3Event(event);
let contactId = s3Utils.getAwsConnectContactIdFromS3Key(objectKey);
let callRecord = await callRecordingUtils.getCallRecord(contactId);

if (!callRecord) {
return {
return loggerUtils.logReturnValue({
status: HttpStatus.preconditionFailed,
body: ErrorMessages.ERROR_MULTIPLE_CALL_RECORDS_IN_RESPONSE
};
body: stringUtils.generateMessage(ErrorMessages.TPL_CANNOT_MATCH_RECORD, 'Call')
});
}

let callRecordingUrl = callRecordingUtils.buildCallRecordingUrl(contactId);

let callBean = app.data.createBean('Calls', callRecord);
callBean.set(CallsConstants.CALLS_CALL_RECORDING_URL, callRecordingUrl);

return await callBean.save();
return loggerUtils.logReturnValue(await callBean.save());
};

exports.handler = handler;
Loading

0 comments on commit 9fa87fd

Please sign in to comment.