From 2fd60d59d95fbac7fd8c831e8b3365cd603a8556 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Wed, 14 Aug 2024 16:39:19 +0530 Subject: [PATCH 01/17] feat: onboard smartly destination --- src/cdk/v2/destinations/smartly/config.js | 21 ++++ .../smartly/data/trackMapping.json | 69 +++++++++++ .../v2/destinations/smartly/procWorkflow.yaml | 33 +++++ .../destinations/smartly/commonConfig.ts | 30 +++++ .../destinations/smartly/processor/data.ts | 4 + .../destinations/smartly/processor/track.ts | 75 +++++++++++ .../smartly/processor/validation.ts | 116 ++++++++++++++++++ 7 files changed, 348 insertions(+) create mode 100644 src/cdk/v2/destinations/smartly/config.js create mode 100644 src/cdk/v2/destinations/smartly/data/trackMapping.json create mode 100644 src/cdk/v2/destinations/smartly/procWorkflow.yaml create mode 100644 test/integrations/destinations/smartly/commonConfig.ts create mode 100644 test/integrations/destinations/smartly/processor/data.ts create mode 100644 test/integrations/destinations/smartly/processor/track.ts create mode 100644 test/integrations/destinations/smartly/processor/validation.ts diff --git a/src/cdk/v2/destinations/smartly/config.js b/src/cdk/v2/destinations/smartly/config.js new file mode 100644 index 0000000000..5083fde5fe --- /dev/null +++ b/src/cdk/v2/destinations/smartly/config.js @@ -0,0 +1,21 @@ +const { getMappingConfig } = require('../../../../v0/util'); + +const ConfigCategories = { + TRACK: { + type: 'track', + name: 'trackMapping', + }, +}; + +const mappingConfig = getMappingConfig(ConfigCategories, __dirname); +const singleEventEndpoint = 'https://s2s.smartly.io/events'; +const batchEndpoint = 'https://s2s.smartly.io/events/batch'; + +module.exports = { + ConfigCategories, + mappingConfig, + singleEventEndpoint, + batchEndpoint, + TRACK_CONFIG: mappingConfig[ConfigCategories.TRACK.name], + MAX_BATCH_SIZE: 1000, +}; diff --git a/src/cdk/v2/destinations/smartly/data/trackMapping.json b/src/cdk/v2/destinations/smartly/data/trackMapping.json new file mode 100644 index 0000000000..0557089108 --- /dev/null +++ b/src/cdk/v2/destinations/smartly/data/trackMapping.json @@ -0,0 +1,69 @@ +[ + { + "sourceKeys": "event", + "required": true, + "destKey": "event" + }, + { + "destKey": "value", + "sourceKeys": [ + "properties.total", + "properties.value", + "properties.revenue", + { + "operation": "multiplication", + "args": [ + { + "sourceKeys": "properties.price" + }, + { + "sourceKeys": "properties.quantity", + "default": 1 + } + ] + } + ], + "metadata": { + "type": "toNumber" + }, + "required": false + }, + { + "sourceKeys": ["properties.conversions", "properties.products.length"], + "required": false, + "metadata": { + "defaultValue": "1" + }, + "destKey": "conversions" + }, + { + "sourceKeys": ["properties.adUnitId", "properties.ad_unit_id"], + "required": true, + "destKey": "ad_unit_id" + }, + { + "sourceKeys": ["properties.platform"], + "required": true, + "destKey": "platform" + }, + { + "sourceKeys": ["properties.adInteractionTime", "properties.ad_interaction_time"], + "required": true, + "destKey": "ad_interaction_time" + }, + { + "sourceKeys": ["properties.installTime"], + "required": false, + "destKey": "installTime" + }, + { + "sourceKeys": ["originalTimestamp", "timestamp"], + "required": false, + "destKey": "event_time" + }, + { + "sourceKeys": ["properties.currency"], + "required": false, + "destKey": "value_currency" + } +] diff --git a/src/cdk/v2/destinations/smartly/procWorkflow.yaml b/src/cdk/v2/destinations/smartly/procWorkflow.yaml new file mode 100644 index 0000000000..0a456aa5be --- /dev/null +++ b/src/cdk/v2/destinations/smartly/procWorkflow.yaml @@ -0,0 +1,33 @@ +bindings: + - name: EventType + path: ../../../../constants + - path: ../../bindings/jsontemplate + - name: defaultRequestConfig + path: ../../../../v0/util + - name: removeUndefinedAndNullValues + path: ../../../../v0/util + - name: constructPayload + path: ../../../../v0/util + - path: ./config + +steps: + - name: messageType + template: | + .message.type.toLowerCase(); + - name: validateInput + template: | + let messageType = $.outputs.messageType; + $.assert(messageType, "message Type is not present. Aborting"); + $.assert(messageType in {{$.EventType.([.TRACK])}}, "message type " + messageType + " is not supported"); + $.assertConfig(.destination.Config.apiToken, "API Token is not present. Aborting"); + - name: preparePayload + template: | + const payload = $.constructPayload(.message, $.TRACK_CONFIG); + $.context.payload = $.removeUndefinedAndNullValues(payload); + - name: buildResponse + template: | + const response = $.defaultRequestConfig(); + response.body.JSON.events = [$.context.payload]; + response.endpoint = $.singleEventEndpoint; + response.method = "POST"; + response diff --git a/test/integrations/destinations/smartly/commonConfig.ts b/test/integrations/destinations/smartly/commonConfig.ts new file mode 100644 index 0000000000..c33150e63b --- /dev/null +++ b/test/integrations/destinations/smartly/commonConfig.ts @@ -0,0 +1,30 @@ +export const destination = { + ID: 'random_id', + Name: 'smartly', + DestinationDefinition: { + Config: { + cdkV2Enabled: true, + }, + }, + Config: { + apiToken: 'testAuthToken', + }, +}; + +export const routerInstrumentationErrorStatTags = { + destType: 'SMARTLY', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'router', + implementation: 'cdkV2', + module: 'destination', +}; +export const processInstrumentationErrorStatTags = { + destType: 'SMARTLY', + errorCategory: 'dataValidation', + errorType: 'instrumentation', + feature: 'processor', + implementation: 'cdkV2', + module: 'destination', + destinationId: 'dummyDestId', +}; diff --git a/test/integrations/destinations/smartly/processor/data.ts b/test/integrations/destinations/smartly/processor/data.ts new file mode 100644 index 0000000000..4db0c79f78 --- /dev/null +++ b/test/integrations/destinations/smartly/processor/data.ts @@ -0,0 +1,4 @@ +import { trackTestData } from './track'; +import { validationFailures } from './validation'; + +export const data = [...trackTestData, ...validationFailures]; diff --git a/test/integrations/destinations/smartly/processor/track.ts b/test/integrations/destinations/smartly/processor/track.ts new file mode 100644 index 0000000000..8ab0d58f0a --- /dev/null +++ b/test/integrations/destinations/smartly/processor/track.ts @@ -0,0 +1,75 @@ +import { destination } from '../commonConfig'; + +export const trackTestData = [ + { + name: 'smartly', + description: 'Test 0', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + event: 'Add to cart', + properties: { + platform: 'meta', + ad_unit_id: '228287', + ad_interaction_time: '1650626278', + email: 'eventIdn01@sample.com', + }, + type: 'track', + userId: 'eventIdn01', + }, + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + output: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://s2s.smartly.io/events', + headers: {}, + params: {}, + body: { + JSON: { + events: [ + { + platform: 'meta', + ad_unit_id: '228287', + ad_interaction_time: '1650626278', + conversions: '1', + event: 'Add to cart', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + files: {}, + userId: '', + }, + statusCode: 200, + }, + ], + }, + }, + }, +]; diff --git a/test/integrations/destinations/smartly/processor/validation.ts b/test/integrations/destinations/smartly/processor/validation.ts new file mode 100644 index 0000000000..8433cac561 --- /dev/null +++ b/test/integrations/destinations/smartly/processor/validation.ts @@ -0,0 +1,116 @@ +import { processInstrumentationErrorStatTags, destination } from '../commonConfig'; + +export const validationFailures = [ + { + id: 'Smartly-validation-test-1', + name: 'smartly', + description: 'Required field anonymousId not present', + scenario: 'Framework', + successCriteria: 'Transformationn Error for anonymousId not present', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'track', + event: 'product purchased', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'john123', + properties: { + products: [{}], + ad_unit_id: '22123387', + ad_interaction_time: '1650626278', + }, + integrations: { + All: true, + }, + originalTimestamp: '2021-01-25T15:32:56.409Z', + }, + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + 'Missing required value from ["properties.platform"]: Workflow: procWorkflow, Step: preparePayload, ChildStep: undefined, OriginalError: Missing required value from ["properties.platform"]', + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + statTags: processInstrumentationErrorStatTags, + statusCode: 400, + }, + ], + }, + }, + }, + { + id: 'Smartly-test-2', + name: 'smartly', + description: 'Unsupported message type -> group', + scenario: 'Framework', + successCriteria: 'Transformationn Error for Unsupported message type', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'group', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'john67', + channel: 'mobile', + rudderId: 'b7b24f86-cccx-46d8-b2b4-ccaxxx80239c', + messageId: 'dummy_msg_id', + properties: { + platform: 'snapchat', + ad_unit_id: '2653387', + ad_interaction_time: '1650646278', + }, + anonymousId: 'anon_123', + integrations: { + All: true, + }, + }, + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + 'message type group is not supported: Workflow: procWorkflow, Step: validateInput, ChildStep: undefined, OriginalError: message type group is not supported', + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + statTags: processInstrumentationErrorStatTags, + statusCode: 400, + }, + ], + }, + }, + }, +]; From 01f4e6b708703892054fef9de0952fa40c0cf5dc Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Fri, 16 Aug 2024 00:28:05 +0530 Subject: [PATCH 02/17] chore: updated processor changes --- .../smartly/data/trackMapping.json | 14 ++- .../v2/destinations/smartly/procWorkflow.yaml | 12 +-- src/cdk/v2/destinations/smartly/utils.js | 93 +++++++++++++++++++ .../destinations/smartly/commonConfig.ts | 10 ++ .../destinations/smartly/processor/track.ts | 16 ++-- .../smartly/processor/validation.ts | 58 ++++++++++++ 6 files changed, 180 insertions(+), 23 deletions(-) create mode 100644 src/cdk/v2/destinations/smartly/utils.js diff --git a/src/cdk/v2/destinations/smartly/data/trackMapping.json b/src/cdk/v2/destinations/smartly/data/trackMapping.json index 0557089108..87d5a6538a 100644 --- a/src/cdk/v2/destinations/smartly/data/trackMapping.json +++ b/src/cdk/v2/destinations/smartly/data/trackMapping.json @@ -1,9 +1,4 @@ [ - { - "sourceKeys": "event", - "required": true, - "destKey": "event" - }, { "destKey": "value", "sourceKeys": [ @@ -49,16 +44,25 @@ { "sourceKeys": ["properties.adInteractionTime", "properties.ad_interaction_time"], "required": true, + "metadata": { + "type": "secondTimestamp" + }, "destKey": "ad_interaction_time" }, { "sourceKeys": ["properties.installTime"], "required": false, + "metadata": { + "type": "secondTimestamp" + }, "destKey": "installTime" }, { "sourceKeys": ["originalTimestamp", "timestamp"], "required": false, + "metadata": { + "type": "secondTimestamp" + }, "destKey": "event_time" }, { diff --git a/src/cdk/v2/destinations/smartly/procWorkflow.yaml b/src/cdk/v2/destinations/smartly/procWorkflow.yaml index 0a456aa5be..67ae53e6ed 100644 --- a/src/cdk/v2/destinations/smartly/procWorkflow.yaml +++ b/src/cdk/v2/destinations/smartly/procWorkflow.yaml @@ -9,7 +9,7 @@ bindings: - name: constructPayload path: ../../../../v0/util - path: ./config - + - path: ./utils steps: - name: messageType template: | @@ -22,12 +22,8 @@ steps: $.assertConfig(.destination.Config.apiToken, "API Token is not present. Aborting"); - name: preparePayload template: | - const payload = $.constructPayload(.message, $.TRACK_CONFIG); - $.context.payload = $.removeUndefinedAndNullValues(payload); + const payload = $.removeUndefinedAndNullValues($.constructPayload(.message, $.TRACK_CONFIG)); + $.context.payloadList = $.getPayloads(.message.event, .destination.Config.eventsMapping, payload) - name: buildResponse template: | - const response = $.defaultRequestConfig(); - response.body.JSON.events = [$.context.payload]; - response.endpoint = $.singleEventEndpoint; - response.method = "POST"; - response + $.buildResponseList($.context.payloadList) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js new file mode 100644 index 0000000000..2a47152e3c --- /dev/null +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -0,0 +1,93 @@ +const { BatchUtils } = require('@rudderstack/workflow-engine'); +const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const config = require('./config'); +const { + getHashFromArrayWithDuplicate, + defaultRequestConfig, + isDefinedAndNotNull, +} = require('../../../../v0/util'); + +// docs reference : https://support.smartly.io/hc/en-us/articles/4406049685788-S2S-integration-API-description#01H8HBXZF6WSKSYBW1C6NY8A88 + +/** + * This function generates an array of payload objects, each with the event property set + * to different values associated with the given event name according to eventsMapping + * @param {*} event + * @param {*} eventsMapping + * @param {*} payload + * @returns + */ +const getPayloads = (event, eventsMapping, payload) => { + if (!isDefinedAndNotNull(event) || !typeof event === 'string') { + throw new InstrumentationError('Event is not defined or is not String'); + } + const eventsMap = getHashFromArrayWithDuplicate(eventsMapping); + // eventsMap = hashmap {"prop1":["val1","val2"],"prop2":["val2"]} + const eventList = eventsMap?.[event?.toLowerCase()] || [event]; + const payloadLists = eventList.map((ev) => ({ ...payload, event: ev })); + return payloadLists; +}; + +const buildResponseList = (payloadList) => + payloadList.map((payload) => { + const response = defaultRequestConfig(); + response.body.JSON = payload; + response.endpoint = config.singleEventEndpoint; + response.method = 'POST'; + return response; + }); + +const getSuccessfulEvents = (events) => { + const sucessfulEvents = []; + events.forEach((event) => { + event.forEach((ev) => { + sucessfulEvents.push({ + output: ev.body.JSON, + destination: ev.destination, + metadata: ev.metadata, + }); + }); + }); + return sucessfulEvents; +}; + +const batchBuilder = (batch) => ({ + batchedRequest: { + body: { + JSON: { events: batch.map((event) => event.output) }, + JSON_ARRAY: {}, + XML: {}, + FORM: {}, + }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: config.batchEndpoint, + headers: { + 'Content-Type': 'application/json', + }, + params: {}, + files: {}, + }, + metadata: batch.map((event) => event.metadata), + batched: true, + statusCode: 200, + destination: batch[0].destination, +}); + +/** + * This fucntions make chunk of successful events based on MAX_BATCH_SIZE + * and then build the response for each chunk to be returned as object of an array + * @param {*} events + * @returns + */ +const batchResponseBuilder = (events) => { + const batches = BatchUtils.chunkArrayBySizeAndLength(events, { maxItems: config.MAX_BATCH_SIZE }); + const response = []; + batches.items.forEach((batch) => { + response.push(batchBuilder(batch)); + }); + return response; +}; + +module.exports = { batchResponseBuilder, getPayloads, buildResponseList, getSuccessfulEvents }; diff --git a/test/integrations/destinations/smartly/commonConfig.ts b/test/integrations/destinations/smartly/commonConfig.ts index c33150e63b..f5b0a6f4d4 100644 --- a/test/integrations/destinations/smartly/commonConfig.ts +++ b/test/integrations/destinations/smartly/commonConfig.ts @@ -8,6 +8,16 @@ export const destination = { }, Config: { apiToken: 'testAuthToken', + eventsMapping: [ + { + from: 'product list viewed', + to: 'event1', + }, + { + from: 'product list viewed', + to: 'event2', + }, + ], }, }; diff --git a/test/integrations/destinations/smartly/processor/track.ts b/test/integrations/destinations/smartly/processor/track.ts index 8ab0d58f0a..b934e71e8f 100644 --- a/test/integrations/destinations/smartly/processor/track.ts +++ b/test/integrations/destinations/smartly/processor/track.ts @@ -16,7 +16,7 @@ export const trackTestData = [ event: 'Add to cart', properties: { platform: 'meta', - ad_unit_id: '228287', + ad_unit_id: 228287, ad_interaction_time: '1650626278', email: 'eventIdn01@sample.com', }, @@ -49,15 +49,11 @@ export const trackTestData = [ params: {}, body: { JSON: { - events: [ - { - platform: 'meta', - ad_unit_id: '228287', - ad_interaction_time: '1650626278', - conversions: '1', - event: 'Add to cart', - }, - ], + platform: 'meta', + ad_unit_id: 228287, + ad_interaction_time: '1650626278', + conversions: '1', + event: 'Add to cart', }, JSON_ARRAY: {}, XML: {}, diff --git a/test/integrations/destinations/smartly/processor/validation.ts b/test/integrations/destinations/smartly/processor/validation.ts index 8433cac561..c080905549 100644 --- a/test/integrations/destinations/smartly/processor/validation.ts +++ b/test/integrations/destinations/smartly/processor/validation.ts @@ -72,6 +72,7 @@ export const validationFailures = [ destination, message: { type: 'group', + event: 'purchase', sentAt: '2021-01-25T16:12:02.048Z', userId: 'john67', channel: 'mobile', @@ -113,4 +114,61 @@ export const validationFailures = [ }, }, }, + { + id: 'Smartly-test-3', + name: 'smartly', + description: 'Event name not defined', + scenario: 'Framework', + successCriteria: 'Transformationn Error for Undefined Event', + feature: 'processor', + module: 'destination', + version: 'v0', + input: { + request: { + body: [ + { + destination, + message: { + type: 'track', + sentAt: '2021-01-25T16:12:02.048Z', + userId: 'john67', + channel: 'mobile', + rudderId: 'b7b24f86-cccx-46d8-b2b4-ccaxxx80239c', + messageId: 'dummy_msg_id', + properties: { + platform: 'snapchat', + ad_unit_id: '2653387', + ad_interaction_time: '1650646278', + }, + anonymousId: 'anon_123', + integrations: { + All: true, + }, + }, + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + }, + ], + }, + }, + output: { + response: { + status: 200, + body: [ + { + error: + 'Event is not defined or is not String: Workflow: procWorkflow, Step: preparePayload, ChildStep: undefined, OriginalError: Event is not defined or is not String', + metadata: { + destinationId: 'dummyDestId', + jobId: '1', + }, + statTags: processInstrumentationErrorStatTags, + statusCode: 400, + }, + ], + }, + }, + }, ]; From ebc63a223b35ce88adfb8cb66c51ea9dacedbd11 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Fri, 16 Aug 2024 12:11:48 +0530 Subject: [PATCH 03/17] chore: router changes added --- .../v2/destinations/smartly/rtWorkflow.yaml | 35 +++++ .../destinations/smartly/router/data.ts | 128 ++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/cdk/v2/destinations/smartly/rtWorkflow.yaml create mode 100644 test/integrations/destinations/smartly/router/data.ts diff --git a/src/cdk/v2/destinations/smartly/rtWorkflow.yaml b/src/cdk/v2/destinations/smartly/rtWorkflow.yaml new file mode 100644 index 0000000000..30dd3fdd95 --- /dev/null +++ b/src/cdk/v2/destinations/smartly/rtWorkflow.yaml @@ -0,0 +1,35 @@ +bindings: + - path: ./config + - name: handleRtTfSingleEventError + path: ../../../../v0/util/index + - path: ./utils +steps: + - name: validateInput + template: | + $.assert(Array.isArray(^) && ^.length > 0, "Invalid event array") + + - name: transform + externalWorkflow: + path: ./procWorkflow.yaml + loopOverInput: true + + - name: successfulEvents + template: | + $.outputs.transform#idx.output.({ + "output": .body.JSON.events[0], + "destination": ^[idx].destination, + "metadata": ^[idx].metadata + })[] + - name: failedEvents + template: | + $.outputs.transform#idx.error.( + $.handleRtTfSingleEventError(^[idx], .originalError ?? ., {}) + )[] + - name: batchSuccessfulEvents + description: Batches the successfulEvents + template: | + $.batchResponseBuilder($.outputs.successfulEvents); + + - name: finalPayload + template: | + [...$.outputs.failedEvents, ...$.outputs.batchSuccessfulEvents] diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts new file mode 100644 index 0000000000..ca6e871d60 --- /dev/null +++ b/test/integrations/destinations/smartly/router/data.ts @@ -0,0 +1,128 @@ +import { destination } from '../commonConfig'; + +export const data = [ + { + name: 'smartly', + id: 'Test 0 - router', + description: 'Simple Batch call for track', + scenario: 'Framework+Buisness', + successCriteria: 'All events should be transformed successfully and status code should be 200', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ + { + message: { + type: 'track', + event: 'product list viewed', + properties: { + platform: 'meta', + conversions: '1', + ad_unit_id: 221187, + ad_interaction_time: '1652826278', + }, + }, + metadata: { jobId: 1, userId: 'u1' }, + destination, + }, + { + message: { + type: 'track', + event: 'product list viewed', + properties: { + platform: 'meta', + conversions: '1', + ad_unit_id: 221187, + ad_interaction_time: '1652826278', + }, + }, + metadata: { jobId: 2, userId: 'u2' }, + destination, + }, + { + message: { + type: 'track', + event: 'purchase', + userId: 'testuserId1', + integrations: { All: true }, + properties: { + conversions: 3, + platform: 'snapchat', + ad_unit_id: 77187, + ad_interaction_time: '2752826278', + }, + }, + metadata: { jobId: 3, userId: 'u3' }, + destination, + }, + ], + destType: 'smartly', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://s2s.smartly.io/events/batch', + params: {}, + body: { + FORM: {}, + JSON: { + events: [ + { + platform: 'meta', + conversions: '1', + event: 'event1', + ad_unit_id: 221187, + ad_interaction_time: '1652826278', + }, + { + platform: 'meta', + conversions: '1', + event: 'event2', + ad_unit_id: 221187, + ad_interaction_time: '1652826278', + }, + { + conversions: 3, + event: 'purchase', + platform: 'snapchat', + ad_unit_id: 77187, + ad_interaction_time: '2752826278', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + headers: { + 'Content-Type': 'application/json', + }, + files: {}, + }, + metadata: [ + { jobId: 1, userId: 'u1' }, + { jobId: 2, userId: 'u2' }, + { jobId: 3, userId: 'u3' }, + ], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, +]; From 785fe0935e0833623e02faf3eacc0552455bbc31 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Fri, 16 Aug 2024 21:08:13 +0530 Subject: [PATCH 04/17] chore: mock test added --- .../v2/destinations/smartly/procWorkflow.yaml | 3 +- .../v2/destinations/smartly/rtWorkflow.yaml | 2 +- src/cdk/v2/destinations/smartly/utils.js | 21 +- .../destinations/smartly/mocks.ts | 5 + .../destinations/smartly/router/data.ts | 219 ++++++++++++++++-- 5 files changed, 219 insertions(+), 31 deletions(-) create mode 100644 test/integrations/destinations/smartly/mocks.ts diff --git a/src/cdk/v2/destinations/smartly/procWorkflow.yaml b/src/cdk/v2/destinations/smartly/procWorkflow.yaml index 67ae53e6ed..318c8a79b8 100644 --- a/src/cdk/v2/destinations/smartly/procWorkflow.yaml +++ b/src/cdk/v2/destinations/smartly/procWorkflow.yaml @@ -26,4 +26,5 @@ steps: $.context.payloadList = $.getPayloads(.message.event, .destination.Config.eventsMapping, payload) - name: buildResponse template: | - $.buildResponseList($.context.payloadList) + const response = $.buildResponseList($.context.payloadList) + response diff --git a/src/cdk/v2/destinations/smartly/rtWorkflow.yaml b/src/cdk/v2/destinations/smartly/rtWorkflow.yaml index 30dd3fdd95..4d3afdb6d0 100644 --- a/src/cdk/v2/destinations/smartly/rtWorkflow.yaml +++ b/src/cdk/v2/destinations/smartly/rtWorkflow.yaml @@ -16,7 +16,7 @@ steps: - name: successfulEvents template: | $.outputs.transform#idx.output.({ - "output": .body.JSON.events[0], + "output": .body.JSON, "destination": ^[idx].destination, "metadata": ^[idx].metadata })[] diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index 2a47152e3c..4f51467a97 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -23,7 +23,10 @@ const getPayloads = (event, eventsMapping, payload) => { } const eventsMap = getHashFromArrayWithDuplicate(eventsMapping); // eventsMap = hashmap {"prop1":["val1","val2"],"prop2":["val2"]} - const eventList = eventsMap?.[event?.toLowerCase()] || [event]; + const eventList = Array.isArray(eventsMap[event.toLowerCase()]) + ? eventsMap[event.toLowerCase()] + : Array.from(eventsMap[event.toLowerCase()] || [event]); + const payloadLists = eventList.map((ev) => ({ ...payload, event: ev })); return payloadLists; }; @@ -37,20 +40,6 @@ const buildResponseList = (payloadList) => return response; }); -const getSuccessfulEvents = (events) => { - const sucessfulEvents = []; - events.forEach((event) => { - event.forEach((ev) => { - sucessfulEvents.push({ - output: ev.body.JSON, - destination: ev.destination, - metadata: ev.metadata, - }); - }); - }); - return sucessfulEvents; -}; - const batchBuilder = (batch) => ({ batchedRequest: { body: { @@ -90,4 +79,4 @@ const batchResponseBuilder = (events) => { return response; }; -module.exports = { batchResponseBuilder, getPayloads, buildResponseList, getSuccessfulEvents }; +module.exports = { batchResponseBuilder, getPayloads, buildResponseList }; diff --git a/test/integrations/destinations/smartly/mocks.ts b/test/integrations/destinations/smartly/mocks.ts new file mode 100644 index 0000000000..9f498b0f67 --- /dev/null +++ b/test/integrations/destinations/smartly/mocks.ts @@ -0,0 +1,5 @@ +import config from '../../../../src/cdk/v2/destinations/smartly/config'; + +export const defaultMockFns = () => { + jest.replaceProperty(config, 'MAX_BATCH_SIZE', 2); +}; diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index ca6e871d60..93cc81804c 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -1,10 +1,11 @@ -import { destination } from '../commonConfig'; +import { destination, routerInstrumentationErrorStatTags } from '../commonConfig'; +import { defaultMockFns } from '../mocks'; export const data = [ { name: 'smartly', id: 'Test 0 - router', - description: 'Simple Batch call for track', + description: 'Track call with multiplexing and batching', scenario: 'Framework+Buisness', successCriteria: 'All events should be transformed successfully and status code should be 200', feature: 'router', @@ -20,26 +21,120 @@ export const data = [ event: 'product list viewed', properties: { platform: 'meta', - conversions: '1', + conversions: 1, ad_unit_id: 221187, ad_interaction_time: '1652826278', }, }, - metadata: { jobId: 1, userId: 'u1' }, + metadata: { jobId: 2, userId: 'u2' }, destination, }, + { + message: { + type: 'track', + event: 'add to cart', + properties: { + conversions: 3, + platform: 'snapchat', + ad_unit_id: 77187, + ad_interaction_time: '2752826278', + }, + }, + metadata: { jobId: 3, userId: 'u2' }, + destination, + }, + ], + destType: 'smartly', + }, + method: 'POST', + }, + }, + output: { + response: { + status: 200, + body: { + output: [ + { + batchedRequest: { + version: '0', + type: 'REST', + method: 'POST', + endpoint: 'https://s2s.smartly.io/events/batch', + params: {}, + body: { + FORM: {}, + JSON: { + events: [ + { + platform: 'meta', + conversions: 1, + event: 'event1', + ad_unit_id: 221187, + ad_interaction_time: '1652826278', + }, + { + platform: 'meta', + conversions: 1, + event: 'event2', + ad_unit_id: 221187, + ad_interaction_time: '1652826278', + }, + { + conversions: 3, + event: 'add to cart', + platform: 'snapchat', + ad_unit_id: 77187, + ad_interaction_time: '2752826278', + }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + headers: { + 'Content-Type': 'application/json', + }, + files: {}, + }, + metadata: [ + { jobId: 2, userId: 'u2' }, + { jobId: 2, userId: 'u2' }, + { jobId: 3, userId: 'u2' }, + ], + batched: true, + statusCode: 200, + destination, + }, + ], + }, + }, + }, + }, + { + name: 'smartly', + id: 'Test 0 - router', + description: 'Batch calls with 4 succesfull events including multiplexing and 2 failed events', + scenario: 'Framework+Buisness', + successCriteria: 'All events should be transformed successfully and status code should be 200', + feature: 'router', + module: 'destination', + version: 'v0', + input: { + request: { + body: { + input: [ { message: { type: 'track', event: 'product list viewed', properties: { platform: 'meta', - conversions: '1', + conversions: 1, ad_unit_id: 221187, ad_interaction_time: '1652826278', }, }, - metadata: { jobId: 2, userId: 'u2' }, + metadata: { jobId: 11, userId: 'u1' }, destination, }, { @@ -55,7 +150,53 @@ export const data = [ ad_interaction_time: '2752826278', }, }, - metadata: { jobId: 3, userId: 'u3' }, + metadata: { jobId: 13, userId: 'u1' }, + destination, + }, + { + message: { + type: 'track', + userId: 'testuserId1', + integrations: { All: true }, + properties: { + conversions: 3, + platform: 'snapchat', + ad_unit_id: 12387, + ad_interaction_time: '2752826278', + }, + }, + metadata: { jobId: 14, userId: 'u1' }, + destination, + }, + { + message: { + type: 'track', + event: 'random event', + userId: 'testuserId1', + integrations: { All: true }, + properties: { + conversions: 3, + ad_unit_id: 77187, + ad_interaction_time: '2752826278', + }, + }, + metadata: { jobId: 15, userId: 'u1' }, + destination, + }, + { + message: { + type: 'track', + event: 'add to cart', + userId: 'testuserId1', + integrations: { All: true }, + properties: { + conversions: 3, + platform: 'tiktok', + ad_unit_id: 789187, + ad_interaction_time: '2752826278', + }, + }, + metadata: { jobId: 16, userId: 'u1' }, destination, }, ], @@ -69,9 +210,25 @@ export const data = [ status: 200, body: { output: [ + { + batched: false, + destination, + error: 'Event is not defined or is not String', + metadata: { jobId: 14, userId: 'u1' }, + statTags: routerInstrumentationErrorStatTags, + statusCode: 400, + }, + { + batched: false, + destination, + error: 'Missing required value from ["properties.platform"]', + metadata: { jobId: 15, userId: 'u1' }, + statTags: routerInstrumentationErrorStatTags, + statusCode: 400, + }, { batchedRequest: { - version: '1', + version: '0', type: 'REST', method: 'POST', endpoint: 'https://s2s.smartly.io/events/batch', @@ -82,18 +239,47 @@ export const data = [ events: [ { platform: 'meta', - conversions: '1', + conversions: 1, event: 'event1', ad_unit_id: 221187, ad_interaction_time: '1652826278', }, { platform: 'meta', - conversions: '1', + conversions: 1, event: 'event2', ad_unit_id: 221187, ad_interaction_time: '1652826278', }, + ], + }, + JSON_ARRAY: {}, + XML: {}, + }, + headers: { + 'Content-Type': 'application/json', + }, + files: {}, + }, + metadata: [ + { jobId: 11, userId: 'u1' }, + { jobId: 11, userId: 'u1' }, + ], + batched: true, + statusCode: 200, + destination, + }, + { + batchedRequest: { + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://s2s.smartly.io/events/batch', + params: {}, + body: { + FORM: {}, + JSON: { + events: [ { conversions: 3, event: 'purchase', @@ -101,6 +287,13 @@ export const data = [ ad_unit_id: 77187, ad_interaction_time: '2752826278', }, + { + conversions: 3, + event: 'add to cart', + platform: 'tiktok', + ad_unit_id: 789187, + ad_interaction_time: '2752826278', + }, ], }, JSON_ARRAY: {}, @@ -112,9 +305,8 @@ export const data = [ files: {}, }, metadata: [ - { jobId: 1, userId: 'u1' }, - { jobId: 2, userId: 'u2' }, - { jobId: 3, userId: 'u3' }, + { jobId: 13, userId: 'u1' }, + { jobId: 16, userId: 'u1' }, ], batched: true, statusCode: 200, @@ -124,5 +316,6 @@ export const data = [ }, }, }, + mockFns: defaultMockFns, }, ]; From 307990554eec1cca63420c24fe0872ac113ce32b Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Fri, 16 Aug 2024 22:23:21 +0530 Subject: [PATCH 05/17] chore: batch builder func and test case updated --- src/cdk/v2/destinations/smartly/utils.js | 4 +- .../destinations/smartly/router/data.ts | 50 ++++++++++--------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index 4f51467a97..980634dab7 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -58,7 +58,9 @@ const batchBuilder = (batch) => ({ params: {}, files: {}, }, - metadata: batch.map((event) => event.metadata), + metadata: batch + .map((event) => event.metadata) + .filter((metadata, index, self) => self.findIndex((m) => m.jobId === metadata.jobId) === index), // handling jobId duplication for multiplexed events batched: true, statusCode: 200, destination: batch[0].destination, diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index 93cc81804c..975610c1a0 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -40,7 +40,7 @@ export const data = [ ad_interaction_time: '2752826278', }, }, - metadata: { jobId: 3, userId: 'u2' }, + metadata: { jobId: 3, userId: 'u3' }, destination, }, ], @@ -56,50 +56,55 @@ export const data = [ output: [ { batchedRequest: { - version: '0', - type: 'REST', - method: 'POST', - endpoint: 'https://s2s.smartly.io/events/batch', - params: {}, body: { - FORM: {}, JSON: { events: [ { - platform: 'meta', conversions: 1, - event: 'event1', ad_unit_id: 221187, + platform: 'meta', ad_interaction_time: '1652826278', + event: 'event1', }, { - platform: 'meta', conversions: 1, - event: 'event2', ad_unit_id: 221187, + platform: 'meta', ad_interaction_time: '1652826278', + event: 'event2', }, { conversions: 3, - event: 'add to cart', - platform: 'snapchat', ad_unit_id: 77187, + platform: 'snapchat', ad_interaction_time: '2752826278', + event: 'add to cart', }, ], }, JSON_ARRAY: {}, XML: {}, + FORM: {}, }, + version: '1', + type: 'REST', + method: 'POST', + endpoint: 'https://s2s.smartly.io/events/batch', headers: { 'Content-Type': 'application/json', }, + params: {}, files: {}, }, metadata: [ - { jobId: 2, userId: 'u2' }, - { jobId: 2, userId: 'u2' }, - { jobId: 3, userId: 'u2' }, + { + jobId: 2, + userId: 'u2', + }, + { + jobId: 3, + userId: 'u3', + }, ], batched: true, statusCode: 200, @@ -112,7 +117,7 @@ export const data = [ }, { name: 'smartly', - id: 'Test 0 - router', + id: 'Test 1 - router', description: 'Batch calls with 4 succesfull events including multiplexing and 2 failed events', scenario: 'Framework+Buisness', successCriteria: 'All events should be transformed successfully and status code should be 200', @@ -214,7 +219,7 @@ export const data = [ batched: false, destination, error: 'Event is not defined or is not String', - metadata: { jobId: 14, userId: 'u1' }, + metadata: [{ jobId: 14, userId: 'u1' }], statTags: routerInstrumentationErrorStatTags, statusCode: 400, }, @@ -222,13 +227,13 @@ export const data = [ batched: false, destination, error: 'Missing required value from ["properties.platform"]', - metadata: { jobId: 15, userId: 'u1' }, + metadata: [{ jobId: 15, userId: 'u1' }], statTags: routerInstrumentationErrorStatTags, statusCode: 400, }, { batchedRequest: { - version: '0', + version: '1', type: 'REST', method: 'POST', endpoint: 'https://s2s.smartly.io/events/batch', @@ -261,10 +266,7 @@ export const data = [ }, files: {}, }, - metadata: [ - { jobId: 11, userId: 'u1' }, - { jobId: 11, userId: 'u1' }, - ], + metadata: [{ jobId: 11, userId: 'u1' }], batched: true, statusCode: 200, destination, From 09d8437b980b55f8ac82b0a08f3d2e7588e24a5c Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Mon, 19 Aug 2024 11:29:37 +0530 Subject: [PATCH 06/17] chore: update for auth token --- src/cdk/v2/destinations/smartly/utils.js | 8 +++++--- test/integrations/destinations/smartly/router/data.ts | 3 +++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index 980634dab7..c317bbe642 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -18,7 +18,7 @@ const { * @returns */ const getPayloads = (event, eventsMapping, payload) => { - if (!isDefinedAndNotNull(event) || !typeof event === 'string') { + if (!isDefinedAndNotNull(event) || typeof event !== 'string') { throw new InstrumentationError('Event is not defined or is not String'); } const eventsMap = getHashFromArrayWithDuplicate(eventsMapping); @@ -40,7 +40,7 @@ const buildResponseList = (payloadList) => return response; }); -const batchBuilder = (batch) => ({ +const batchBuilder = (batch, destination) => ({ batchedRequest: { body: { JSON: { events: batch.map((event) => event.output) }, @@ -54,6 +54,7 @@ const batchBuilder = (batch) => ({ endpoint: config.batchEndpoint, headers: { 'Content-Type': 'application/json', + Authorization: `Bearer ${destination.Config.apiToken}`, }, params: {}, files: {}, @@ -73,10 +74,11 @@ const batchBuilder = (batch) => ({ * @returns */ const batchResponseBuilder = (events) => { + const { destination } = events[0]; const batches = BatchUtils.chunkArrayBySizeAndLength(events, { maxItems: config.MAX_BATCH_SIZE }); const response = []; batches.items.forEach((batch) => { - response.push(batchBuilder(batch)); + response.push(batchBuilder(batch, destination)); }); return response; }; diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index 975610c1a0..88e417fd00 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -92,6 +92,7 @@ export const data = [ endpoint: 'https://s2s.smartly.io/events/batch', headers: { 'Content-Type': 'application/json', + Authorization: `Bearer testAuthToken`, }, params: {}, files: {}, @@ -263,6 +264,7 @@ export const data = [ }, headers: { 'Content-Type': 'application/json', + Authorization: `Bearer testAuthToken`, }, files: {}, }, @@ -303,6 +305,7 @@ export const data = [ }, headers: { 'Content-Type': 'application/json', + Authorization: `Bearer testAuthToken`, }, files: {}, }, From 921fb38b58b9a3700d5b4845875f7f9c98b0a10c Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Mon, 19 Aug 2024 18:46:42 +0530 Subject: [PATCH 07/17] fix: edit after primary dev testing --- .../v2/destinations/smartly/data/trackMapping.json | 5 ++++- src/cdk/v2/destinations/smartly/procWorkflow.yaml | 2 +- src/cdk/v2/destinations/smartly/utils.js | 11 ++++++----- src/features.json | 3 ++- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/cdk/v2/destinations/smartly/data/trackMapping.json b/src/cdk/v2/destinations/smartly/data/trackMapping.json index 87d5a6538a..55ba437f12 100644 --- a/src/cdk/v2/destinations/smartly/data/trackMapping.json +++ b/src/cdk/v2/destinations/smartly/data/trackMapping.json @@ -34,7 +34,10 @@ { "sourceKeys": ["properties.adUnitId", "properties.ad_unit_id"], "required": true, - "destKey": "ad_unit_id" + "destKey": "ad_unit_id", + "metadata": { + "type": "toString" + } }, { "sourceKeys": ["properties.platform"], diff --git a/src/cdk/v2/destinations/smartly/procWorkflow.yaml b/src/cdk/v2/destinations/smartly/procWorkflow.yaml index 318c8a79b8..43c4783783 100644 --- a/src/cdk/v2/destinations/smartly/procWorkflow.yaml +++ b/src/cdk/v2/destinations/smartly/procWorkflow.yaml @@ -23,7 +23,7 @@ steps: - name: preparePayload template: | const payload = $.removeUndefinedAndNullValues($.constructPayload(.message, $.TRACK_CONFIG)); - $.context.payloadList = $.getPayloads(.message.event, .destination.Config.eventsMapping, payload) + $.context.payloadList = $.getPayloads(.message.event, .destination.Config, payload) - name: buildResponse template: | const response = $.buildResponseList($.context.payloadList) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index c317bbe642..b2d6fd3f87 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -17,17 +17,17 @@ const { * @param {*} payload * @returns */ -const getPayloads = (event, eventsMapping, payload) => { +const getPayloads = (event, Config, payload) => { if (!isDefinedAndNotNull(event) || typeof event !== 'string') { throw new InstrumentationError('Event is not defined or is not String'); } - const eventsMap = getHashFromArrayWithDuplicate(eventsMapping); + const eventsMap = getHashFromArrayWithDuplicate(Config.eventsMapping); // eventsMap = hashmap {"prop1":["val1","val2"],"prop2":["val2"]} const eventList = Array.isArray(eventsMap[event.toLowerCase()]) ? eventsMap[event.toLowerCase()] : Array.from(eventsMap[event.toLowerCase()] || [event]); - const payloadLists = eventList.map((ev) => ({ ...payload, event: ev })); + const payloadLists = eventList.map((ev) => ({ ...payload, event_name: ev })); return payloadLists; }; @@ -35,7 +35,7 @@ const buildResponseList = (payloadList) => payloadList.map((payload) => { const response = defaultRequestConfig(); response.body.JSON = payload; - response.endpoint = config.singleEventEndpoint; + response.endpoint = config.batchEndpoint; response.method = 'POST'; return response; }); @@ -78,7 +78,8 @@ const batchResponseBuilder = (events) => { const batches = BatchUtils.chunkArrayBySizeAndLength(events, { maxItems: config.MAX_BATCH_SIZE }); const response = []; batches.items.forEach((batch) => { - response.push(batchBuilder(batch, destination)); + const batchedResponse = batchBuilder(batch, destination); + response.push(batchedResponse); }); return response; }; diff --git a/src/features.json b/src/features.json index 94e36a2416..8b3b0c4006 100644 --- a/src/features.json +++ b/src/features.json @@ -76,7 +76,8 @@ "WUNDERKIND": true, "CLICKSEND": true, "ZOHO": true, - "CORDIAL": true + "CORDIAL": true, + "SMARTLY": true }, "regulations": [ "BRAZE", From 2cdc522a16230e683c17fa910e3a1037866c2565 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Tue, 20 Aug 2024 14:08:41 +0530 Subject: [PATCH 08/17] fix: test --- .../v2/destinations/smartly/procWorkflow.yaml | 3 +- src/cdk/v2/destinations/smartly/utils.js | 35 +++++++- src/cdk/v2/destinations/smartly/utils.test.js | 66 +++++++++++++++ .../destinations/smartly/processor/data.ts | 7 +- .../destinations/smartly/processor/track.ts | 16 ++-- .../smartly/processor/validation.ts | 10 +-- .../destinations/smartly/router/data.ts | 82 +++++++++---------- 7 files changed, 163 insertions(+), 56 deletions(-) create mode 100644 src/cdk/v2/destinations/smartly/utils.test.js diff --git a/src/cdk/v2/destinations/smartly/procWorkflow.yaml b/src/cdk/v2/destinations/smartly/procWorkflow.yaml index 43c4783783..56f360d6c2 100644 --- a/src/cdk/v2/destinations/smartly/procWorkflow.yaml +++ b/src/cdk/v2/destinations/smartly/procWorkflow.yaml @@ -23,7 +23,8 @@ steps: - name: preparePayload template: | const payload = $.removeUndefinedAndNullValues($.constructPayload(.message, $.TRACK_CONFIG)); - $.context.payloadList = $.getPayloads(.message.event, .destination.Config, payload) + $.verifyAdInteractionTime(payload.ad_interaction_time); + $.context.payloadList = $.getPayloads(.message.event_name, .destination.Config, payload) - name: buildResponse template: | const response = $.buildResponseList($.context.payloadList) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index b2d6fd3f87..6b4b3ce6d5 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -1,5 +1,6 @@ const { BatchUtils } = require('@rudderstack/workflow-engine'); const { InstrumentationError } = require('@rudderstack/integrations-lib'); +const moment = require('moment'); const config = require('./config'); const { getHashFromArrayWithDuplicate, @@ -31,6 +32,38 @@ const getPayloads = (event, Config, payload) => { return payloadLists; }; +const verifyAdInteractionTime = (adInteractionTime) => { + if (isDefinedAndNotNull(adInteractionTime)) { + let adInteractionTimeMoment; + + // Handle both UNIX timestamps and UTC date strings + if (typeof adInteractionTime === 'number') { + adInteractionTimeMoment = moment.unix(adInteractionTime); // Parse as UNIX timestamp + } else { + adInteractionTimeMoment = moment.utc(adInteractionTime); // Parse as UTC date string + } + + const currentMoment = moment.utc(); // Current time in UTC + + // Calculate the time difference in days + const diffDaysPast = currentMoment.diff(adInteractionTimeMoment, 'days'); + const diffDaysFuture = adInteractionTimeMoment.diff(currentMoment, 'days'); + + // Define the day range: 3 years (1095 days) in the past and 1 year (365 days) in the future + const maxDaysPast = 3 * 365 + 1; // 1095 days + 1 day for a leap year + const maxDaysFuture = 1 * 365 + 1; // 365 days + 1 day for a leap year + + // Check if adInteractionTime is within the allowed range + const isWithinAllowedRange = diffDaysPast <= maxDaysPast && diffDaysFuture <= maxDaysFuture; + + if (!isWithinAllowedRange) { + throw new InstrumentationError( + 'ad_interaction_time must be within one year in the future and three years in the past.', + ); + } + } +}; + const buildResponseList = (payloadList) => payloadList.map((payload) => { const response = defaultRequestConfig(); @@ -84,4 +117,4 @@ const batchResponseBuilder = (events) => { return response; }; -module.exports = { batchResponseBuilder, getPayloads, buildResponseList }; +module.exports = { batchResponseBuilder, getPayloads, buildResponseList, verifyAdInteractionTime }; diff --git a/src/cdk/v2/destinations/smartly/utils.test.js b/src/cdk/v2/destinations/smartly/utils.test.js new file mode 100644 index 0000000000..a3c0071eda --- /dev/null +++ b/src/cdk/v2/destinations/smartly/utils.test.js @@ -0,0 +1,66 @@ +const moment = require('moment'); +const { InstrumentationError } = require('@rudderstack/workflow-engine'); +const { verifyAdInteractionTime } = require('./utils'); + +describe('verifyAdInteractionTime', () => { + it('should pass when adInteractionTime is 2 years in the past (UNIX timestamp)', () => { + // 2 years ago from now + const adInteractionTime = moment().subtract(2, 'years').unix(); + expect(() => verifyAdInteractionTime(adInteractionTime)).not.toThrow(); + }); + + it('should pass when adInteractionTime is 10 months in the future (UNIX timestamp)', () => { + // 10 months in the future from now + const adInteractionTime = moment().add(10, 'months').unix(); + expect(() => verifyAdInteractionTime(adInteractionTime)).not.toThrow(); + }); + + it('should fail when adInteractionTime is 4 years in the past (UNIX timestamp)', () => { + // 4 years ago from now + const adInteractionTime = moment().subtract(4, 'years').unix(); + expect(() => verifyAdInteractionTime(adInteractionTime)).toThrow( + 'ad_interaction_time must be within one year in the future and three years in the past.', + ); + }); + + it('should fail when adInteractionTime is 2 years in the future (UNIX timestamp)', () => { + // 2 years in the future from now + const adInteractionTime = moment().add(2, 'years').unix(); + expect(() => verifyAdInteractionTime(adInteractionTime)).toThrow( + 'ad_interaction_time must be within one year in the future and three years in the past.', + ); + }); + + it('should pass when adInteractionTime is exactly 3 years in the past (UTC date string)', () => { + // Exactly 3 years ago from now + const adInteractionTime = moment.utc().subtract(3, 'years').toISOString(); + expect(() => verifyAdInteractionTime(adInteractionTime)).not.toThrow(); + }); + + it('should pass when adInteractionTime is exactly 1 year in the future (UTC date string)', () => { + // Exactly 1 year in the future from now + const adInteractionTime = moment.utc().add(1, 'year').toISOString(); + expect(() => verifyAdInteractionTime(adInteractionTime)).not.toThrow(); + }); + + it('should fail when adInteractionTime is 4 years in the past (UTC date string)', () => { + // 4 years ago from now + const adInteractionTime = moment.utc().subtract(4, 'years').toISOString(); + expect(() => verifyAdInteractionTime(adInteractionTime)).toThrow( + 'ad_interaction_time must be within one year in the future and three years in the past.', + ); + }); + + it('should fail when adInteractionTime is 2 years in the future (UTC date string)', () => { + // 2 years in the future from now + const adInteractionTime = moment.utc().add(2, 'years').toISOString(); + expect(() => verifyAdInteractionTime(adInteractionTime)).toThrow( + 'ad_interaction_time must be within one year in the future and three years in the past.', + ); + }); + + it('should not throw an error if adInteractionTime is null or undefined', () => { + expect(() => verifyAdInteractionTime(null)).not.toThrow(); + expect(() => verifyAdInteractionTime(undefined)).not.toThrow(); + }); +}); diff --git a/test/integrations/destinations/smartly/processor/data.ts b/test/integrations/destinations/smartly/processor/data.ts index 4db0c79f78..a94f6b220f 100644 --- a/test/integrations/destinations/smartly/processor/data.ts +++ b/test/integrations/destinations/smartly/processor/data.ts @@ -1,4 +1,9 @@ import { trackTestData } from './track'; import { validationFailures } from './validation'; -export const data = [...trackTestData, ...validationFailures]; +export const mockFns = (_) => { + // @ts-ignore + jest.useFakeTimers().setSystemTime(new Date('2024-02-01')); +}; + +export const data = [...trackTestData, ...validationFailures].map((d) => ({ ...d, mockFns })); diff --git a/test/integrations/destinations/smartly/processor/track.ts b/test/integrations/destinations/smartly/processor/track.ts index b934e71e8f..08b3f41b0e 100644 --- a/test/integrations/destinations/smartly/processor/track.ts +++ b/test/integrations/destinations/smartly/processor/track.ts @@ -1,3 +1,5 @@ +const moment = require('moment'); +import { verifyAdInteractionTime } from '../../../../../src/cdk/v2/destinations/smartly/utils'; import { destination } from '../commonConfig'; export const trackTestData = [ @@ -13,11 +15,11 @@ export const trackTestData = [ { destination, message: { - event: 'Add to cart', + event_name: 'Add to cart', properties: { platform: 'meta', - ad_unit_id: 228287, - ad_interaction_time: '1650626278', + ad_unit_id: '228287', + ad_interaction_time: '1612137600', email: 'eventIdn01@sample.com', }, type: 'track', @@ -44,16 +46,16 @@ export const trackTestData = [ version: '1', type: 'REST', method: 'POST', - endpoint: 'https://s2s.smartly.io/events', + endpoint: 'https://s2s.smartly.io/events/batch', headers: {}, params: {}, body: { JSON: { platform: 'meta', - ad_unit_id: 228287, - ad_interaction_time: '1650626278', + ad_unit_id: '228287', + ad_interaction_time: '1612137600', conversions: '1', - event: 'Add to cart', + event_name: 'Add to cart', }, JSON_ARRAY: {}, XML: {}, diff --git a/test/integrations/destinations/smartly/processor/validation.ts b/test/integrations/destinations/smartly/processor/validation.ts index c080905549..d0a657b011 100644 --- a/test/integrations/destinations/smartly/processor/validation.ts +++ b/test/integrations/destinations/smartly/processor/validation.ts @@ -17,13 +17,13 @@ export const validationFailures = [ destination, message: { type: 'track', - event: 'product purchased', + event_name: 'product purchased', sentAt: '2021-01-25T16:12:02.048Z', userId: 'john123', properties: { products: [{}], ad_unit_id: '22123387', - ad_interaction_time: '1650626278', + ad_interaction_time: '1690867200', }, integrations: { All: true, @@ -72,7 +72,7 @@ export const validationFailures = [ destination, message: { type: 'group', - event: 'purchase', + event_name: 'purchase', sentAt: '2021-01-25T16:12:02.048Z', userId: 'john67', channel: 'mobile', @@ -81,7 +81,7 @@ export const validationFailures = [ properties: { platform: 'snapchat', ad_unit_id: '2653387', - ad_interaction_time: '1650646278', + ad_interaction_time: '1690867200', }, anonymousId: 'anon_123', integrations: { @@ -138,7 +138,7 @@ export const validationFailures = [ properties: { platform: 'snapchat', ad_unit_id: '2653387', - ad_interaction_time: '1650646278', + ad_interaction_time: '1675094400', }, anonymousId: 'anon_123', integrations: { diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index 88e417fd00..ff500eab4c 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -18,12 +18,12 @@ export const data = [ { message: { type: 'track', - event: 'product list viewed', + event_name: 'product list viewed', properties: { platform: 'meta', conversions: 1, - ad_unit_id: 221187, - ad_interaction_time: '1652826278', + ad_unit_id: "221187", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 2, userId: 'u2' }, @@ -32,12 +32,12 @@ export const data = [ { message: { type: 'track', - event: 'add to cart', + event_name: 'add to cart', properties: { conversions: 3, platform: 'snapchat', - ad_unit_id: 77187, - ad_interaction_time: '2752826278', + ad_unit_id: "77187", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 3, userId: 'u3' }, @@ -61,24 +61,24 @@ export const data = [ events: [ { conversions: 1, - ad_unit_id: 221187, + ad_unit_id: "221187", platform: 'meta', - ad_interaction_time: '1652826278', - event: 'event1', + ad_interaction_time: '1690867200', + event_name: 'event1', }, { conversions: 1, - ad_unit_id: 221187, + ad_unit_id: "221187", platform: 'meta', - ad_interaction_time: '1652826278', - event: 'event2', + ad_interaction_time: '1690867200', + event_name: 'event2', }, { conversions: 3, - ad_unit_id: 77187, + ad_unit_id: "77187", platform: 'snapchat', - ad_interaction_time: '2752826278', - event: 'add to cart', + ad_interaction_time: '1690867200', + event_name: 'add to cart', }, ], }, @@ -132,12 +132,12 @@ export const data = [ { message: { type: 'track', - event: 'product list viewed', + event_name: 'product list viewed', properties: { platform: 'meta', conversions: 1, - ad_unit_id: 221187, - ad_interaction_time: '1652826278', + ad_unit_id: "221187", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 11, userId: 'u1' }, @@ -146,14 +146,14 @@ export const data = [ { message: { type: 'track', - event: 'purchase', + event_name: 'purchase', userId: 'testuserId1', integrations: { All: true }, properties: { conversions: 3, platform: 'snapchat', - ad_unit_id: 77187, - ad_interaction_time: '2752826278', + ad_unit_id: "77187", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 13, userId: 'u1' }, @@ -167,8 +167,8 @@ export const data = [ properties: { conversions: 3, platform: 'snapchat', - ad_unit_id: 12387, - ad_interaction_time: '2752826278', + ad_unit_id: "12387", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 14, userId: 'u1' }, @@ -177,13 +177,13 @@ export const data = [ { message: { type: 'track', - event: 'random event', + event_name: 'random event', userId: 'testuserId1', integrations: { All: true }, properties: { conversions: 3, - ad_unit_id: 77187, - ad_interaction_time: '2752826278', + ad_unit_id: "77187", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 15, userId: 'u1' }, @@ -192,14 +192,14 @@ export const data = [ { message: { type: 'track', - event: 'add to cart', + event_name: 'add to cart', userId: 'testuserId1', integrations: { All: true }, properties: { conversions: 3, platform: 'tiktok', - ad_unit_id: 789187, - ad_interaction_time: '2752826278', + ad_unit_id: "789187", + ad_interaction_time: '1690867200', }, }, metadata: { jobId: 16, userId: 'u1' }, @@ -246,16 +246,16 @@ export const data = [ { platform: 'meta', conversions: 1, - event: 'event1', - ad_unit_id: 221187, - ad_interaction_time: '1652826278', + event_name: 'event1', + ad_unit_id: "221187", + ad_interaction_time: '1690867200', }, { platform: 'meta', conversions: 1, - event: 'event2', - ad_unit_id: 221187, - ad_interaction_time: '1652826278', + event_name: 'event2', + ad_unit_id: "221187", + ad_interaction_time: '1690867200', }, ], }, @@ -286,17 +286,17 @@ export const data = [ events: [ { conversions: 3, - event: 'purchase', + event_name: 'purchase', platform: 'snapchat', - ad_unit_id: 77187, - ad_interaction_time: '2752826278', + ad_unit_id: "77187", + ad_interaction_time: '1690867200', }, { conversions: 3, - event: 'add to cart', + event_name: 'add to cart', platform: 'tiktok', - ad_unit_id: 789187, - ad_interaction_time: '2752826278', + ad_unit_id: "789187", + ad_interaction_time: '1690867200', }, ], }, From c0cb3216fda23912e6a2b0413b999e850c1249a7 Mon Sep 17 00:00:00 2001 From: shrouti1507 Date: Tue, 20 Aug 2024 15:52:37 +0530 Subject: [PATCH 09/17] fix: editing test caes --- .../destinations/smartly/processor/track.ts | 6 +- .../smartly/processor/validation.ts | 2 +- .../destinations/smartly/router/data.ts | 56 +++++++++---------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/test/integrations/destinations/smartly/processor/track.ts b/test/integrations/destinations/smartly/processor/track.ts index 08b3f41b0e..9331b0631d 100644 --- a/test/integrations/destinations/smartly/processor/track.ts +++ b/test/integrations/destinations/smartly/processor/track.ts @@ -1,5 +1,3 @@ -const moment = require('moment'); -import { verifyAdInteractionTime } from '../../../../../src/cdk/v2/destinations/smartly/utils'; import { destination } from '../commonConfig'; export const trackTestData = [ @@ -19,7 +17,7 @@ export const trackTestData = [ properties: { platform: 'meta', ad_unit_id: '228287', - ad_interaction_time: '1612137600', + ad_interaction_time: 1612137600, email: 'eventIdn01@sample.com', }, type: 'track', @@ -53,7 +51,7 @@ export const trackTestData = [ JSON: { platform: 'meta', ad_unit_id: '228287', - ad_interaction_time: '1612137600', + ad_interaction_time: 1612137600, conversions: '1', event_name: 'Add to cart', }, diff --git a/test/integrations/destinations/smartly/processor/validation.ts b/test/integrations/destinations/smartly/processor/validation.ts index d0a657b011..bd18d15b1c 100644 --- a/test/integrations/destinations/smartly/processor/validation.ts +++ b/test/integrations/destinations/smartly/processor/validation.ts @@ -138,7 +138,7 @@ export const validationFailures = [ properties: { platform: 'snapchat', ad_unit_id: '2653387', - ad_interaction_time: '1675094400', + ad_interaction_time: 1675094400, }, anonymousId: 'anon_123', integrations: { diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index ff500eab4c..8f904378c3 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -22,8 +22,8 @@ export const data = [ properties: { platform: 'meta', conversions: 1, - ad_unit_id: "221187", - ad_interaction_time: '1690867200', + ad_unit_id: '221187', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 2, userId: 'u2' }, @@ -36,8 +36,8 @@ export const data = [ properties: { conversions: 3, platform: 'snapchat', - ad_unit_id: "77187", - ad_interaction_time: '1690867200', + ad_unit_id: '77187', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 3, userId: 'u3' }, @@ -61,23 +61,23 @@ export const data = [ events: [ { conversions: 1, - ad_unit_id: "221187", + ad_unit_id: '221187', platform: 'meta', - ad_interaction_time: '1690867200', + ad_interaction_time: 1690867200, event_name: 'event1', }, { conversions: 1, - ad_unit_id: "221187", + ad_unit_id: '221187', platform: 'meta', - ad_interaction_time: '1690867200', + ad_interaction_time: 1690867200, event_name: 'event2', }, { conversions: 3, - ad_unit_id: "77187", + ad_unit_id: '77187', platform: 'snapchat', - ad_interaction_time: '1690867200', + ad_interaction_time: 1690867200, event_name: 'add to cart', }, ], @@ -136,8 +136,8 @@ export const data = [ properties: { platform: 'meta', conversions: 1, - ad_unit_id: "221187", - ad_interaction_time: '1690867200', + ad_unit_id: '221187', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 11, userId: 'u1' }, @@ -152,8 +152,8 @@ export const data = [ properties: { conversions: 3, platform: 'snapchat', - ad_unit_id: "77187", - ad_interaction_time: '1690867200', + ad_unit_id: '77187', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 13, userId: 'u1' }, @@ -167,8 +167,8 @@ export const data = [ properties: { conversions: 3, platform: 'snapchat', - ad_unit_id: "12387", - ad_interaction_time: '1690867200', + ad_unit_id: '12387', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 14, userId: 'u1' }, @@ -182,8 +182,8 @@ export const data = [ integrations: { All: true }, properties: { conversions: 3, - ad_unit_id: "77187", - ad_interaction_time: '1690867200', + ad_unit_id: '77187', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 15, userId: 'u1' }, @@ -198,8 +198,8 @@ export const data = [ properties: { conversions: 3, platform: 'tiktok', - ad_unit_id: "789187", - ad_interaction_time: '1690867200', + ad_unit_id: '789187', + ad_interaction_time: 1690867200, }, }, metadata: { jobId: 16, userId: 'u1' }, @@ -247,15 +247,15 @@ export const data = [ platform: 'meta', conversions: 1, event_name: 'event1', - ad_unit_id: "221187", - ad_interaction_time: '1690867200', + ad_unit_id: '221187', + ad_interaction_time: 1690867200, }, { platform: 'meta', conversions: 1, event_name: 'event2', - ad_unit_id: "221187", - ad_interaction_time: '1690867200', + ad_unit_id: '221187', + ad_interaction_time: 1690867200, }, ], }, @@ -288,15 +288,15 @@ export const data = [ conversions: 3, event_name: 'purchase', platform: 'snapchat', - ad_unit_id: "77187", - ad_interaction_time: '1690867200', + ad_unit_id: '77187', + ad_interaction_time: 1690867200, }, { conversions: 3, event_name: 'add to cart', platform: 'tiktok', - ad_unit_id: "789187", - ad_interaction_time: '1690867200', + ad_unit_id: '789187', + ad_interaction_time: 1690867200, }, ], }, From ecab59f4802249d1b04dbbc8de1f7d4619b70f8d Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Tue, 20 Aug 2024 18:07:10 +0530 Subject: [PATCH 10/17] fix: smartly test cases --- src/cdk/v2/destinations/smartly/utils.js | 4 ++++ test/integrations/destinations/smartly/mocks.ts | 1 + test/integrations/destinations/smartly/router/data.ts | 3 +++ 3 files changed, 8 insertions(+) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index 6b4b3ce6d5..43ff59c7e7 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -107,8 +107,12 @@ const batchBuilder = (batch, destination) => ({ * @returns */ const batchResponseBuilder = (events) => { + if (events.length === 0) { + return []; + } const { destination } = events[0]; const batches = BatchUtils.chunkArrayBySizeAndLength(events, { maxItems: config.MAX_BATCH_SIZE }); + const response = []; batches.items.forEach((batch) => { const batchedResponse = batchBuilder(batch, destination); diff --git a/test/integrations/destinations/smartly/mocks.ts b/test/integrations/destinations/smartly/mocks.ts index 9f498b0f67..78773d8853 100644 --- a/test/integrations/destinations/smartly/mocks.ts +++ b/test/integrations/destinations/smartly/mocks.ts @@ -1,5 +1,6 @@ import config from '../../../../src/cdk/v2/destinations/smartly/config'; export const defaultMockFns = () => { + jest.useFakeTimers().setSystemTime(new Date('2024-02-01')); jest.replaceProperty(config, 'MAX_BATCH_SIZE', 2); }; diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index 8f904378c3..7cd6dbd482 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -115,6 +115,9 @@ export const data = [ }, }, }, + mockFns: () => { + jest.useFakeTimers().setSystemTime(new Date('2024-02-01')); + }, }, { name: 'smartly', From 5b659a08c872fe4a7545f9062536d0b2d679b3e3 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Wed, 21 Aug 2024 10:59:54 +0530 Subject: [PATCH 11/17] chore: updated test cases and function --- .../v2/destinations/smartly/procWorkflow.yaml | 2 +- src/cdk/v2/destinations/smartly/utils.js | 30 +++++-------------- src/cdk/v2/destinations/smartly/utils.test.js | 9 +----- .../destinations/smartly/processor/track.ts | 6 ++-- .../smartly/processor/validation.ts | 2 +- .../destinations/smartly/router/data.ts | 12 ++++---- 6 files changed, 19 insertions(+), 42 deletions(-) diff --git a/src/cdk/v2/destinations/smartly/procWorkflow.yaml b/src/cdk/v2/destinations/smartly/procWorkflow.yaml index 56f360d6c2..b69df0dd09 100644 --- a/src/cdk/v2/destinations/smartly/procWorkflow.yaml +++ b/src/cdk/v2/destinations/smartly/procWorkflow.yaml @@ -24,7 +24,7 @@ steps: template: | const payload = $.removeUndefinedAndNullValues($.constructPayload(.message, $.TRACK_CONFIG)); $.verifyAdInteractionTime(payload.ad_interaction_time); - $.context.payloadList = $.getPayloads(.message.event_name, .destination.Config, payload) + $.context.payloadList = $.getPayloads(.message.event, .destination.Config, payload) - name: buildResponse template: | const response = $.buildResponseList($.context.payloadList) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index 43ff59c7e7..74101563d6 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -32,31 +32,15 @@ const getPayloads = (event, Config, payload) => { return payloadLists; }; +// ad_interaction_time must be within one year in the future and three years in the past from the current date +// Example : "1735680000" const verifyAdInteractionTime = (adInteractionTime) => { if (isDefinedAndNotNull(adInteractionTime)) { - let adInteractionTimeMoment; - - // Handle both UNIX timestamps and UTC date strings - if (typeof adInteractionTime === 'number') { - adInteractionTimeMoment = moment.unix(adInteractionTime); // Parse as UNIX timestamp - } else { - adInteractionTimeMoment = moment.utc(adInteractionTime); // Parse as UTC date string - } - - const currentMoment = moment.utc(); // Current time in UTC - - // Calculate the time difference in days - const diffDaysPast = currentMoment.diff(adInteractionTimeMoment, 'days'); - const diffDaysFuture = adInteractionTimeMoment.diff(currentMoment, 'days'); - - // Define the day range: 3 years (1095 days) in the past and 1 year (365 days) in the future - const maxDaysPast = 3 * 365 + 1; // 1095 days + 1 day for a leap year - const maxDaysFuture = 1 * 365 + 1; // 365 days + 1 day for a leap year - - // Check if adInteractionTime is within the allowed range - const isWithinAllowedRange = diffDaysPast <= maxDaysPast && diffDaysFuture <= maxDaysFuture; - - if (!isWithinAllowedRange) { + const now = moment(); + const threeYearAgo = now.clone().subtract(3, 'year'); + const oneYearFromNow = now.clone().add(1, 'year'); + const inputMoment = moment(adInteractionTime * 1000); // Convert to milliseconds + if (!inputMoment.isAfter(threeYearAgo) || !inputMoment.isBefore(oneYearFromNow)) { throw new InstrumentationError( 'ad_interaction_time must be within one year in the future and three years in the past.', ); diff --git a/src/cdk/v2/destinations/smartly/utils.test.js b/src/cdk/v2/destinations/smartly/utils.test.js index a3c0071eda..0ad73f5369 100644 --- a/src/cdk/v2/destinations/smartly/utils.test.js +++ b/src/cdk/v2/destinations/smartly/utils.test.js @@ -1,5 +1,4 @@ const moment = require('moment'); -const { InstrumentationError } = require('@rudderstack/workflow-engine'); const { verifyAdInteractionTime } = require('./utils'); describe('verifyAdInteractionTime', () => { @@ -31,16 +30,10 @@ describe('verifyAdInteractionTime', () => { ); }); - it('should pass when adInteractionTime is exactly 3 years in the past (UTC date string)', () => { - // Exactly 3 years ago from now - const adInteractionTime = moment.utc().subtract(3, 'years').toISOString(); - expect(() => verifyAdInteractionTime(adInteractionTime)).not.toThrow(); - }); - it('should pass when adInteractionTime is exactly 1 year in the future (UTC date string)', () => { // Exactly 1 year in the future from now const adInteractionTime = moment.utc().add(1, 'year').toISOString(); - expect(() => verifyAdInteractionTime(adInteractionTime)).not.toThrow(); + expect(() => verifyAdInteractionTime(adInteractionTime)).toThrow(); }); it('should fail when adInteractionTime is 4 years in the past (UTC date string)', () => { diff --git a/test/integrations/destinations/smartly/processor/track.ts b/test/integrations/destinations/smartly/processor/track.ts index 9331b0631d..5d15d3f968 100644 --- a/test/integrations/destinations/smartly/processor/track.ts +++ b/test/integrations/destinations/smartly/processor/track.ts @@ -13,11 +13,11 @@ export const trackTestData = [ { destination, message: { - event_name: 'Add to cart', + event: 'Add to cart', properties: { platform: 'meta', ad_unit_id: '228287', - ad_interaction_time: 1612137600, + ad_interaction_time: 1735680000, email: 'eventIdn01@sample.com', }, type: 'track', @@ -51,7 +51,7 @@ export const trackTestData = [ JSON: { platform: 'meta', ad_unit_id: '228287', - ad_interaction_time: 1612137600, + ad_interaction_time: 1735680000, conversions: '1', event_name: 'Add to cart', }, diff --git a/test/integrations/destinations/smartly/processor/validation.ts b/test/integrations/destinations/smartly/processor/validation.ts index bd18d15b1c..996afc34b3 100644 --- a/test/integrations/destinations/smartly/processor/validation.ts +++ b/test/integrations/destinations/smartly/processor/validation.ts @@ -17,7 +17,7 @@ export const validationFailures = [ destination, message: { type: 'track', - event_name: 'product purchased', + event: 'product purchased', sentAt: '2021-01-25T16:12:02.048Z', userId: 'john123', properties: { diff --git a/test/integrations/destinations/smartly/router/data.ts b/test/integrations/destinations/smartly/router/data.ts index 7cd6dbd482..7c2d74e6f0 100644 --- a/test/integrations/destinations/smartly/router/data.ts +++ b/test/integrations/destinations/smartly/router/data.ts @@ -18,7 +18,7 @@ export const data = [ { message: { type: 'track', - event_name: 'product list viewed', + event: 'product list viewed', properties: { platform: 'meta', conversions: 1, @@ -32,7 +32,7 @@ export const data = [ { message: { type: 'track', - event_name: 'add to cart', + event: 'add to cart', properties: { conversions: 3, platform: 'snapchat', @@ -135,7 +135,7 @@ export const data = [ { message: { type: 'track', - event_name: 'product list viewed', + event: 'product list viewed', properties: { platform: 'meta', conversions: 1, @@ -149,7 +149,7 @@ export const data = [ { message: { type: 'track', - event_name: 'purchase', + event: 'purchase', userId: 'testuserId1', integrations: { All: true }, properties: { @@ -180,7 +180,7 @@ export const data = [ { message: { type: 'track', - event_name: 'random event', + event: 'random event', userId: 'testuserId1', integrations: { All: true }, properties: { @@ -195,7 +195,7 @@ export const data = [ { message: { type: 'track', - event_name: 'add to cart', + event: 'add to cart', userId: 'testuserId1', integrations: { All: true }, properties: { From 18cad1eb54f7bfcbd44649694932457660b30aac Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Wed, 21 Aug 2024 13:34:43 +0530 Subject: [PATCH 12/17] chore: ignore eslint of yaml files --- .eslintignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.eslintignore b/.eslintignore index ce54730f4b..b0e219b2eb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -21,3 +21,5 @@ src/v0/destinations/personalize/scripts/ test/integrations/destinations/testTypes.d.ts *.config*.js scripts/skipPrepareScript.js +*.yaml +*.yml From 6dd4de8e22bb568ec68477313759cdd7ab184203 Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Wed, 21 Aug 2024 13:39:12 +0530 Subject: [PATCH 13/17] chore: add .eslintignore to .prettierignore --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index 99747b29bb..e9ac2b4adf 100644 --- a/.prettierignore +++ b/.prettierignore @@ -8,3 +8,4 @@ test/**/*.js src/util/lodash-es-core.js src/util/url-search-params.min.js dist +.eslintignore From c9dd9fd7586e98b16ebb2468061a95558e63cbe9 Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Wed, 21 Aug 2024 13:45:09 +0530 Subject: [PATCH 14/17] chore: ignore eslint of yaml files --- .eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 556470697d..144b90e348 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -19,7 +19,8 @@ "parserOptions": { "ecmaVersion": 12, "sourceType": "module", - "project": "./tsconfig.json" + "project": "./tsconfig.json", + "extraFileExtensions": [".yaml"] }, "rules": { "unicorn/filename-case": [ From 6cc4d4185730854fff365d3ca69351077eb3caa0 Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Wed, 21 Aug 2024 13:47:50 +0530 Subject: [PATCH 15/17] chore: update .prettierignore --- .prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.prettierignore b/.prettierignore index e9ac2b4adf..ac5f1fc409 100644 --- a/.prettierignore +++ b/.prettierignore @@ -9,3 +9,4 @@ src/util/lodash-es-core.js src/util/url-search-params.min.js dist .eslintignore +.prettierignore From 7f0a9604a5384318b0cb200cc55bed1a26faf3b1 Mon Sep 17 00:00:00 2001 From: Dilip Kola Date: Wed, 21 Aug 2024 13:52:08 +0530 Subject: [PATCH 16/17] chore: update .eslintignore --- .eslintignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.eslintignore b/.eslintignore index b0e219b2eb..b1bbed4416 100644 --- a/.eslintignore +++ b/.eslintignore @@ -23,3 +23,6 @@ test/integrations/destinations/testTypes.d.ts scripts/skipPrepareScript.js *.yaml *.yml +.eslintignore +.prettierignore +*.json \ No newline at end of file From 115003b525ce6180e26380687b9460f273e958f3 Mon Sep 17 00:00:00 2001 From: Aanshi Lahoti Date: Wed, 21 Aug 2024 14:01:48 +0530 Subject: [PATCH 17/17] chore: updated enpoint for processor --- src/cdk/v2/destinations/smartly/utils.js | 2 +- test/integrations/destinations/smartly/processor/track.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cdk/v2/destinations/smartly/utils.js b/src/cdk/v2/destinations/smartly/utils.js index 74101563d6..7d53ed0d27 100644 --- a/src/cdk/v2/destinations/smartly/utils.js +++ b/src/cdk/v2/destinations/smartly/utils.js @@ -52,7 +52,7 @@ const buildResponseList = (payloadList) => payloadList.map((payload) => { const response = defaultRequestConfig(); response.body.JSON = payload; - response.endpoint = config.batchEndpoint; + response.endpoint = config.singleEventEndpoint; response.method = 'POST'; return response; }); diff --git a/test/integrations/destinations/smartly/processor/track.ts b/test/integrations/destinations/smartly/processor/track.ts index 5d15d3f968..944327fce3 100644 --- a/test/integrations/destinations/smartly/processor/track.ts +++ b/test/integrations/destinations/smartly/processor/track.ts @@ -44,7 +44,7 @@ export const trackTestData = [ version: '1', type: 'REST', method: 'POST', - endpoint: 'https://s2s.smartly.io/events/batch', + endpoint: 'https://s2s.smartly.io/events', headers: {}, params: {}, body: {