Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: algolia add validation for currency fields #3329

Merged
merged 3 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/cdk/v2/destinations/algolia/procWorkflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ steps:
const objectIDs = ~r products.objectId;
$.context.payload.objectIDs = Array.isArray(objectIDs) ? objectIDs[:20]:$.context.payload.objectIDs;
$.context.payload.objectData = $.outputs.prepareObjectDataBlock
$.validatePayload($.context.payload)

- name: validateDestPayload
template: |
Expand Down
19 changes: 19 additions & 0 deletions src/v0/destinations/algolia/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,28 @@ const clickPayloadValidator = (payload) => {
return updatedPayload;
};

// ref : https://www.algolia.com/doc/rest-api/insights/#method-param-objectdata-2:~:text=currency-,%23,currency%20as%20ISO%2D4217%20currency%20code%2C%20such%20as%20USD%20or%20EUR.,-ObjectData
function validatePayload(payload) {
if (payload.objectData && Array.isArray(payload.objectData)) {
const hasRelevantFields = payload.objectData.some(
(obj) =>
obj.hasOwnProperty('price') ||
obj.hasOwnProperty('quantity') ||
obj.hasOwnProperty('discount'),
);

if (hasRelevantFields && !payload.currency) {
throw new InstrumentationError(
'Currency missing when objectData fields has price informations.',
);
}
}
}

module.exports = {
genericpayloadValidator,
createObjectArray,
eventTypeMapping,
clickPayloadValidator,
validatePayload,
};
58 changes: 58 additions & 0 deletions src/v0/destinations/algolia/util.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const { InstrumentationError } = require('@rudderstack/integrations-lib');
const { validatePayload } = require('./util');

describe('validatePayload', () => {
// When payload is valid and contains relevant fields and currency
it('should validate payload when it is valid and contains relevant fields and currency', () => {
const payload = {
objectData: [
{ price: 10, quantity: 2, discount: 0.1 },
{ price: 20, quantity: 1, discount: 0 },
],
currency: 'USD',
};

expect(() => validatePayload(payload)).not.toThrow();
});

// When payload contains objects with missing relevant fields
it('should throw an error when payload contains objects with missing relevant fields', () => {
const payload = {
objectData: [
{ price: 10, quantity: 2 },
{ price: 20, discount: 0 },
],
};

expect(() => validatePayload(payload)).toThrow(InstrumentationError);
});

// When payload is valid and contains relevant fields but no currency
it('should throw an InstrumentationError when currency is missing', () => {
const payload = {
objectData: [
{ price: 10, quantity: 2, discount: 0.1 },
{ price: 20, quantity: 1, discount: 0 },
],
};

expect(() => validatePayload(payload)).toThrow(InstrumentationError);
});

// When payload is valid but does not contain relevant fields
it('should not throw an error when payload does not contain relevant fields', () => {
const payload = {
objectData: [{ position: 'Product A' }, { position: 'Product B' }],
currency: 'USD',
};

expect(() => validatePayload(payload)).not.toThrow();
});

// When payload is empty
it('should not throw an error when payload is empty', () => {
const payload = {};

expect(() => validatePayload(payload)).not.toThrow();
});
});
142 changes: 142 additions & 0 deletions test/integrations/destinations/algolia/processor/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1688,6 +1688,7 @@ export const data = [
properties: {
index: 'products',
eventSubtype: 'addToCart',
currency: 'USD',
products: [
{
objectId: 'ecommerce-sample-data-919',
Expand Down Expand Up @@ -1751,6 +1752,7 @@ export const data = [
events: [
{
index: 'products',
currency: 'USD',
queryID: '43b15df305339e827f0ac0bdc5ebcaa7',
objectIDs: ['ecommerce-sample-data-919', '9780439784542'],
userToken: 'testuserId1',
Expand All @@ -1760,11 +1762,13 @@ export const data = [
objectData: [
{
quantity: 2,
price: '10',
queryID: '123',
discount: '10',
},
{
quantity: 3,
price: '30',
queryID: '123',
discount: '10',
},
Expand Down Expand Up @@ -1858,6 +1862,7 @@ export const data = [
userId: 'testuserId1',
properties: {
index: 'products',
currency: 'USD',
eventSubtype: 'purchase',
products: [
{
Expand Down Expand Up @@ -1922,6 +1927,7 @@ export const data = [
events: [
{
index: 'products',
currency: 'USD',
queryID: '43b15df305339e827f0ac0bdc5ebcaa7',
objectIDs: ['ecommerce-sample-data-919', '9780439784542'],
userToken: 'testuserId1',
Expand All @@ -1933,11 +1939,13 @@ export const data = [
quantity: 2,
queryID: '123',
discount: '10',
price: '10',
},
{
quantity: 3,
queryID: '123',
discount: '10',
price: '30',
},
],
},
Expand Down Expand Up @@ -2287,4 +2295,138 @@ export const data = [
},
},
},
{
name: 'algolia',
description: 'When price information is present in objectData, currency is mandatory',
feature: 'processor',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
message: {
channel: 'web',
context: {
app: {
build: '1.0.0',
name: 'RudderLabs JavaScript SDK',
namespace: 'com.rudderlabs.javascript',
version: '1.0.0',
},
traits: {
email: '[email protected]',
firstName: 'test',
lastName: 'one',
},
library: {
name: 'RudderLabs JavaScript SDK',
version: '1.0.0',
},
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36',
locale: 'en-US',
ip: '0.0.0.0',
os: {
name: '',
version: '',
},
screen: {
density: 2,
},
page: {
path: '/destinations/ometria',
referrer: '',
search: '',
title: '',
url: 'https://docs.rudderstack.com/destinations/ometria',
category: 'destination',
initial_referrer: 'https://docs.rudderstack.com',
initial_referring_domain: 'docs.rudderstack.com',
},
},
type: 'track',
messageId: '84e26acc-56a5-4835-8233-591137fca468',
session_id: '3049dc4c-5a95-4ccd-a3e7-d74a7e411f22',
originalTimestamp: '2019-10-14T09:03:17.562Z',
anonymousId: '123456',
event: 'product list viewed',
userId: 'testuserId1',
properties: {
index: 'products',
products: [
{
objectId: 'ecommerce-sample-data-919',
position: 7,
quantity: '2',
price: 10,
},
{
objectId: '9780439784542',
position: 8,
quantity: '3',
price: 30,
},
],
queryId: '43b15df305339e827f0ac0bdc5ebcaa7',
},
integrations: {
All: true,
},
sentAt: '2019-10-14T09:03:22.563Z',
},
metadata: {
destinationId: 'destId',
workspaceId: 'wspId',
},
destination: {
DestinationDefinition: {
Config: {
cdkV2Enabled: true,
excludeKeys: [],
includeKeys: [],
},
},
Config: {
apiKey: 'dummyApiKey',
applicationId: 'O2YARRI15I',
eventTypeSettings: [
{
from: 'product list viewed',
to: 'conversion',
},
],
},
},
},
],
},
},
output: {
response: {
status: 200,
body: [
{
error:
'Currency missing when objectData fields has price informations.: Workflow: procWorkflow, Step: populateProductsData, ChildStep: populateForClickEvent, OriginalError: Currency missing when objectData fields has price informations.',
statTags: {
destType: 'ALGOLIA',
errorCategory: 'dataValidation',
errorType: 'instrumentation',
feature: 'processor',
implementation: 'cdkV2',
module: 'destination',
destinationId: 'destId',
workspaceId: 'wspId',
},
statusCode: 400,
metadata: {
destinationId: 'destId',
workspaceId: 'wspId',
},
},
],
},
},
},
];
Loading