Skip to content

Commit

Permalink
feat: onboard tune destination (#3795)
Browse files Browse the repository at this point in the history
* feat: onboard tune destination

* chore: test cases added

* chore: file name updated

* chore: import fix

* chore: updated mappings

* chore: updated transform.js

* chore: updated test cases

* chore: small fix

* chore: router test cases added

* chore: minor fix

---------

Co-authored-by: Sai Sankeerth <[email protected]>
  • Loading branch information
aanshi07 and Sai Sankeerth committed Nov 5, 2024
1 parent 276bb1b commit c665550
Show file tree
Hide file tree
Showing 4 changed files with 511 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/v0/destinations/tune/transform.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const get = require('get-value');
const { InstrumentationError } = require('@rudderstack/integrations-lib');
const {
defaultRequestConfig,
simpleProcessRouterDest,
getHashFromArray,
isDefinedAndNotNull,
isNotEmpty,
} = require('../../util');

const mapPropertiesWithNestedSupport = (msg, properties, mappings) => {
const mappedObj = {}; // Create a new object for parameters
Object.entries(mappings).forEach(([key, value]) => {
const keyStr = `${key}`;
const args = { object: properties, key: keyStr };
if (args.key.split('.').length > 1) {
// Handle nested keys
args.object = msg; // This line modifies the object property of args
}
const data = get(args.object, args.key);
if (isDefinedAndNotNull(data) && isNotEmpty(data)) {
mappedObj[value] = data; // Map to the corresponding destination key
}
});
return mappedObj; // Return the new params object
};

const responseBuilder = (message, { Config }) => {
const { tuneEvents } = Config; // Extract tuneEvents from config
const { properties, event: messageEvent } = message; // Destructure properties and event from message

// Find the relevant tune event based on the message's event name
const tuneEvent = tuneEvents.find((event) => event.eventName === messageEvent);

if (tuneEvent) {
const standardHashMap = getHashFromArray(tuneEvent.standardMapping, 'from', 'to', false);
const advSubIdHashMap = getHashFromArray(tuneEvent.advSubIdMapping, 'from', 'to', false);
const advUniqueIdHashMap = getHashFromArray(tuneEvent.advUniqueIdMapping, 'from', 'to', false);

const params = {
...mapPropertiesWithNestedSupport(message, properties, standardHashMap),
...mapPropertiesWithNestedSupport(message, properties, advSubIdHashMap),
...mapPropertiesWithNestedSupport(message, properties, advUniqueIdHashMap),
};

// Prepare the response
const response = defaultRequestConfig();
response.params = params; // Set only the mapped params
response.endpoint = tuneEvent.url; // Use the user-defined URL

return response;
}

throw new InstrumentationError('No matching tune event found for the provided event.', 400);
};

const processEvent = (message, destination) => {
// Validate message type
if (!isDefinedAndNotNull(message.type) || typeof message.type !== 'string') {
throw new InstrumentationError(
'Message Type is not present or is not a string. Aborting message.',
400,
);
}
const messageType = message.type.toLowerCase();

// Initialize response variable
let response;

// Process 'track' messages using the responseBuilder
if (messageType === 'track') {
response = responseBuilder(message, destination);
} else {
throw new InstrumentationError('Message type not supported. Only "track" is allowed.', 400);
}

return response;
};

const process = (event) => processEvent(event.message, event.destination);

const processRouterDest = async (inputs, reqMetadata) => {
const respList = await simpleProcessRouterDest(inputs, process, reqMetadata);
return respList;
};

module.exports = {
process,
processRouterDest,
};
3 changes: 3 additions & 0 deletions test/integrations/destinations/tune/processor/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { trackTestdata } from './trackTestData';

export const data = [...trackTestdata];
228 changes: 228 additions & 0 deletions test/integrations/destinations/tune/processor/trackTestData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
import { Destination } from '../../../../../src/types';
import { ProcessorTestData } from '../../../testTypes';
import {
generateMetadata,
generateSimplifiedTrackPayload,
overrideDestination,
transformResultBuilder,
} from '../../../testUtils';

const destination: Destination = {
ID: '123',
Name: 'tune',
DestinationDefinition: {
ID: '123',
Name: 'tune',
DisplayName: 'tune',
Config: {},
},
Config: {
connectionMode: {
web: 'cloud',
},
consentManagement: {},
oneTrustCookieCategories: {},
ketchConsentPurposes: {},
tuneEvents: [
{
url: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029',
eventName: 'Product added',
standardMapping: [
{ to: 'aff_id', from: 'affId' },
{ to: 'promo_code', from: 'promoCode' },
{ to: 'security_token', from: 'securityToken' },
{ to: 'status', from: 'status' },
{ to: 'transaction_id', from: 'mytransactionId' },
],
advSubIdMapping: [{ from: 'context.traits.ip', to: 'adv_sub2' }],
advUniqueIdMapping: [{ from: 'context.traits.customProperty1', to: 'adv_unique1' }],
},
],
},
Enabled: true,
WorkspaceID: '123',
Transformations: [],
};

export const trackTestdata: ProcessorTestData[] = [
{
id: 'Test 0',
name: 'tune',
description: 'Track call with standard properties mapping',
scenario: 'Business',
successCriteria:
'The response should have a status code of 200 and correctly map the properties to the specified parameters.',
feature: 'processor',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
message: generateSimplifiedTrackPayload({
type: 'track',
event: 'Product added',
properties: {
securityToken: '1123',
mytransactionId: 'test-123',
},
context: {
traits: {
customProperty1: 'customValue',
firstName: 'David',
logins: 2,
ip: '0.0.0.0',
},
},
anonymousId: 'david_bowie_anonId',
}),
metadata: generateMetadata(1),
destination,
},
],
},
},
output: {
response: {
status: 200,
body: [
{
output: transformResultBuilder({
method: 'POST',
endpoint: 'https://demo.go2cloud.org/aff_l?offer_id=45&aff_id=1029',
event: 'Product added',
headers: {},
params: {
security_token: '1123',
transaction_id: 'test-123',
adv_sub2: '0.0.0.0',
adv_unique1: 'customValue',
},
userId: '',
JSON: {},
}),
metadata: generateMetadata(1),
statusCode: 200,
},
],
},
},
},
{
id: 'Test 1',
name: 'tune',
description: 'Test case for handling a missing tune event for a given event name',
scenario: 'Business',
successCriteria:
'The response should return a 400 status code with an appropriate error message indicating no matching tune event was found.',
feature: 'processor',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
message: generateSimplifiedTrackPayload({
type: 'track',
event: 'Purchase event',
properties: {
securityToken: '1123',
mytransactionId: 'test-123',
},
context: {
traits: {
customProperty1: 'customValue',
firstName: 'David',
logins: 2,
},
},
anonymousId: 'david_bowie_anonId',
}),
metadata: generateMetadata(1),
destination,
},
],
},
},
output: {
response: {
status: 200,
body: [
{
error: 'No matching tune event found for the provided event.',
statTags: {
destType: 'TUNE',
destinationId: 'default-destinationId',
errorCategory: 'dataValidation',
errorType: 'instrumentation',
feature: 'processor',
implementation: 'native',
module: 'destination',
workspaceId: 'default-workspaceId',
},
metadata: generateMetadata(1),
statusCode: 400,
},
],
},
},
},
{
id: 'Test 2',
name: 'tune',
description: 'Incorrect message type',
scenario: 'Business',
successCriteria: 'The response should return a 400 status code due to invalid message type.',
feature: 'processor',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
message: {
type: 'abc',
event: 'Product added',
properties: {
securityToken: '1123',
mytransactionId: 'test-123',
},
context: {
traits: {
customProperty1: 'customValue',
firstName: 'David',
logins: 2,
},
},
anonymousId: 'david_bowie_anonId',
},
metadata: generateMetadata(1),
destination,
},
],
},
},
output: {
response: {
status: 200,
body: [
{
error: 'Message type not supported. Only "track" is allowed.',
statTags: {
destType: 'TUNE',
destinationId: 'default-destinationId',
errorCategory: 'dataValidation',
errorType: 'instrumentation',
feature: 'processor',
implementation: 'native',
module: 'destination',
workspaceId: 'default-workspaceId',
},
metadata: generateMetadata(1),
statusCode: 400,
},
],
},
},
},
];
Loading

0 comments on commit c665550

Please sign in to comment.