Skip to content

Commit

Permalink
fix: track batch handled
Browse files Browse the repository at this point in the history
  • Loading branch information
shrouti1507 committed May 2, 2024
1 parent f3fe891 commit 0610d38
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 77 deletions.
29 changes: 26 additions & 3 deletions src/cdk/v2/destinations/emarsys/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,17 +294,23 @@ const createGroupBatches = (events) => {
key_id: keyId,
external_ids: chunk,
},
metadata: group.map((g) => g.metadata), // assuming metadata is needed per original event grouping
metadata: group.map((g) => g.metadata),
}));
});
};

const createTrackBatches = (events) => ({
endpoint: events[0].message.endPoint,
payload: events[0].message.body.JSON.destinationPayload,
metadata: events[0].metadata,
});
const formatIdentifyPayloadsWithEndpoint = (combinedPayloads, endpointUrl = '') =>
combinedPayloads.map((payload) => ({
endpoint: endpointUrl,
payload,
}));

const buildBatchedRequest = (batches, method, constants) =>
const buildBatchedRequest = (batches, method, constants, batchedStatus = true) =>
batches.map((batch) => ({
batchedRequest: {
body: {
Expand All @@ -322,7 +328,7 @@ const buildBatchedRequest = (batches, method, constants) =>
files: {},
},
metadata: batch.metadata,
batched: true,
batched: batchedStatus,
statusCode: 200,
destination: constants.destination,
}));
Expand All @@ -338,6 +344,10 @@ const batchResponseBuilder = (successfulEvents) => {
method: 'POST',
batches: [],
},
track: {
method: 'POST',
batches: [],
},
};
let batchesOfIdentifyEvents;
if (successfulEvents.length === 0) {
Expand Down Expand Up @@ -366,6 +376,9 @@ const batchResponseBuilder = (successfulEvents) => {
case EVENT_TYPE.GROUP:
groupedSuccessfulPayload.group.batches = createGroupBatches(eachEventGroup);
break;
case EVENT_TYPE.TRACK:
groupedSuccessfulPayload.track.batches = createTrackBatches(eachEventGroup);
break;
default:
break;
}
Expand All @@ -391,6 +404,16 @@ const batchResponseBuilder = (successfulEvents) => {
finaloutput.push(...groupBatches);
}

if (groupedSuccessfulPayload.track) {
const trackBatches = buildBatchedRequest(
groupedSuccessfulPayload.track.batches,
groupedSuccessfulPayload.track.method,
constants,
false,
);
finaloutput.push(...trackBatches);
}

return finaloutput;
};
module.exports = {
Expand Down
81 changes: 79 additions & 2 deletions src/cdk/v2/destinations/emarsys/utils.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const lodash = require('lodash');
const { EVENT_TYPE } = require('rudder-transformer-cdk/build/constants');
const {
buildIdentifyPayload,
Expand All @@ -8,7 +7,9 @@ const {
findRudderPropertyByEmersysProperty,
createGroupBatches,
} = require('./utils');
const utils = require('./utils');
const {
checkIfEventIsAbortableAndExtractErrorMessage,
} = require('../../../../v1/destinations/emarsys/networkHandler');
const crypto = require('crypto');
const { InstrumentationError } = require('@rudderstack/integrations-lib');

Expand Down Expand Up @@ -409,3 +410,79 @@ describe('findRudderPropertyByEmersysProperty', () => {
expect(result).toBeNull();
});
});

describe('checkIfEventIsAbortableAndExtractErrorMessage', () => {
// Returns {isAbortable: false, errorMsg: ''} if event is neither a string nor an object with keyId.
it('should return {isAbortable: false, errorMsg: ""} when event is neither a string nor an object with keyId', () => {
const event = 123;
const destinationResponse = {
data: {
errors: {
errorKey: {
errorCode: 'errorMessage',
},
},
},
};
const keyId = 'keyId';

const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse, keyId);

expect(result).toEqual({ isAbortable: false, errorMsg: '' });
});

// Returns {isAbortable: false, errorMsg: ''} if errors object is empty.
it('should return {isAbortable: false, errorMsg: ""} when errors object is empty', () => {
const event = 'event';
const destinationResponse = {
data: {
errors: {},
},
};
const keyId = 'keyId';

const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse, keyId);

expect(result).toEqual({ isAbortable: false, errorMsg: '' });
});

// Returns {isAbortable: true, errorMsg} if event is a string and has a corresponding error in the errors object.
it('should return {isAbortable: true, errorMsg} when event is a string and has a corresponding error in the errors object', () => {
const event = 'event';
const destinationResponse = {
data: {
errors: {
event: {
errorCode: 'errorMessage',
},
},
},
};
const keyId = 'keyId';

const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse, keyId);

expect(result).toEqual({ isAbortable: true, errorMsg: '{"errorCode":"errorMessage"}' });
});

// Returns {isAbortable: true, errorMsg} if event is an object with keyId and has a corresponding error in the errors object.
it('should return {isAbortable: true, errorMsg} when event is an object with keyId and has a corresponding error in the errors object', () => {
const event = {
keyId: 'event',
};
const destinationResponse = {
data: {
errors: {
event: {
errorCode: 'errorMessage',
},
},
},
};
const keyId = 'keyId';

const result = checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse, keyId);

expect(result).toEqual({ isAbortable: true, errorMsg: '{"errorCode":"errorMessage"}' });
});
});
2 changes: 1 addition & 1 deletion src/constants/destinationCanonicalNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ const DestCanonicalNames = {
],
koala: ['Koala', 'koala', 'KOALA'],
bloomreach: ['Bloomreach', 'bloomreach', 'BLOOMREACH'],
emersys: ['EMERSYS', 'Emersys', 'emersys'],
emersys: ['EMARSYS', 'Emarsys', 'emarsys'],
};

module.exports = { DestHandlerMap, DestCanonicalNames };
80 changes: 20 additions & 60 deletions src/v1/destinations/emarsys/networkHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,28 @@ const {
} = require('../../../adapters/utils/networkUtils');
const tags = require('../../../v0/util/tags');

function checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse) {
// Extract the errors from the destination response
function checkIfEventIsAbortableAndExtractErrorMessage(event, destinationResponse, keyId) {
const { errors } = destinationResponse.data;
const { key_id } = event; // Assuming the 'key_id' is constant as before

// Find the first abortable case
const result = event.find((item) => {
if (typeof item === 'string') {
return errors[item]; // Check if the string is a key in errors
}
if (typeof item === 'object' && item[key_id]) {
return errors[item[key_id]]; // Check if the object's value under key_id is a key in errors
}
return false; // Continue if no condition is met
});
// Determine if event is a string or an object, then fetch the corresponding key or value
let errorKey;
if (typeof event === 'string') {
errorKey = event;
} else if (typeof event === 'object' && event[keyId]) {
errorKey = event[keyId];
} else {
return { isAbortable: false, errorMsg: '' }; // Early return if neither condition is met or if keyId is missing in the object
}

if (result) {
if (typeof result === 'string') {
// Handle case where result is a string key found in errors
return {
isAbortable: true,
errorMsg: errors[result][Object.keys(errors[result])[0]],
};
}
if (typeof result === 'object') {
// Handle case where result is an object found in errors
const keyValue = result[key_id];
return {
isAbortable: true,
errorMsg: errors[keyValue][Object.keys(errors[keyValue])[0]],
};
}
// Check if this key has a corresponding error in the errors object
if (errors[errorKey]) {
// const errorCode = Object.keys(errors[errorKey])[0]; // Assume there is at least one error code
const errorMsg = JSON.stringify(errors[errorKey]);
return { isAbortable: true, errorMsg };
}

// If no match or abortable condition is found
return {
isAbortable: false,
errorMsg: '',
};
// Return false and an empty error message if no error is found
return { isAbortable: false, errorMsg: '' };
}

const responseHandler = (responseParams) => {
Expand All @@ -64,30 +47,6 @@ const responseHandler = (responseParams) => {
metadata,
error: errorMessage,
}));
// if the status is 422, we need to parse the error message and construct the response array
// if (status === 422) {
// const destPartialStatus = constructPartialStatus(response?.message);
// // if the error message is not in the expected format, we will abort all of the events
// if (!destPartialStatus || lodash.isEmpty(destPartialStatus)) {
// throw new TransformerProxyError(
// `EMARSYS: Error transformer proxy v1 during EMARSYS response transformation. Error parsing error message`,
// status,
// {
// [tags.TAG_NAMES.ERROR_TYPE]: getDynamicErrorType(status),
// },
// destinationResponse,
// getAuthErrCategoryFromStCode(status),
// responseWithIndividualEvents,
// );
// }
// responseWithIndividualEvents = [...createResponseArray(rudderJobMetadata, destPartialStatus)];
// return {
// status,
// message,
// destinationResponse,
// response: responseWithIndividualEvents,
// };
// }
throw new TransformerProxyError(
`EMARSYS: Error transformer proxy v1 during EMARSYS response transformation. ${errorMessage}`,
status,
Expand All @@ -103,7 +62,7 @@ const responseHandler = (responseParams) => {
if (isHttpStatusSuccess(status)) {
// check for Partial Event failures and Successes
// eslint-disable-next-line @typescript-eslint/naming-convention
const { contacts, external_ids } = destinationRequest.body.JSON;
const { contacts, external_ids, key_id } = destinationRequest.body.JSON;
const finalData = contacts || external_ids;
finalData.forEach((event, idx) => {
const proxyOutput = {
Expand All @@ -115,6 +74,7 @@ const responseHandler = (responseParams) => {
const { isAbortable, errorMsg } = checkIfEventIsAbortableAndExtractErrorMessage(
event,
destinationResponse,
key_id,
);
if (isAbortable) {
proxyOutput.statusCode = 400;
Expand Down Expand Up @@ -152,4 +112,4 @@ function networkHandler() {
this.responseHandler = responseHandler;
}

module.exports = { networkHandler };
module.exports = { networkHandler, checkIfEventIsAbortableAndExtractErrorMessage };
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ const commonDestination = {
Name: 'sample-destination',
DestinationDefinition: {
ID: '123',
Name: 'emersys',
DisplayName: 'Emersys',
Name: 'emarsys',
DisplayName: 'Emarsys',
Config: {
cdkV2Enabled: true,
},
Expand All @@ -42,8 +42,8 @@ const commonDestination = {

export const data = [
{
id: 'emersys-track-test-1',
name: 'emersys',
id: 'emarsys-track-test-1',
name: 'emarsys',
description: 'Track call : custom event calls with simple user properties and traits',
scenario: 'Business',
successCriteria:
Expand Down Expand Up @@ -202,7 +202,7 @@ export const data = [
destination: commonDestination,
},
],
destType: 'emersys',
destType: 'emarsys',
},
method: 'POST',
},
Expand All @@ -229,8 +229,8 @@ export const data = [
Name: 'sample-destination',
DestinationDefinition: {
ID: '123',
Name: 'emersys',
DisplayName: 'emersys',
Name: 'emarsys',
DisplayName: 'emarsys',
Config: {
cdkV2Enabled: true,
},
Expand All @@ -243,9 +243,9 @@ export const data = [
batched: false,
statusCode: 400,
error:
'[emersys Conversion API] no matching user id found. Please provide at least one of the following: email, emersysFirstPartyAdsTrackingUUID, acxiomId, oracleMoatId',
'[emarsys Conversion API] no matching user id found. Please provide at least one of the following: email, emersysFirstPartyAdsTrackingUUID, acxiomId, oracleMoatId',
statTags: {
destType: 'emersys',
destType: 'emarsys',
errorCategory: 'dataValidation',
errorType: 'instrumentation',
feature: 'router',
Expand Down Expand Up @@ -355,12 +355,12 @@ export const data = [
version: '1',
type: 'REST',
method: 'POST',
endpoint: 'https://api.emersys.com/rest/conversionEvents',
endpoint: 'https://api.emarsys.com/rest/conversionEvents',
headers: {
'Content-Type': 'application/json',
'X-RestLi-Method': 'BATCH_CREATE',
'X-Restli-Protocol-Version': '2.0.0',
'emersys-Version': '202402',
'emarsys-Version': '202402',
Authorization: 'Bearer dummyToken',
},
params: {},
Expand Down

0 comments on commit 0610d38

Please sign in to comment.