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: handling invalid timestamp for adjust source #3866

Merged
merged 8 commits into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
4 changes: 2 additions & 2 deletions src/v0/sources/adjust/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const Message = require('../message');
const { CommonUtils } = require('../../../util/common');
const { excludedFieldList } = require('./config');
const { extractCustomFields, generateUUID } = require('../../util');
const { convertToISODate } = require('./utils');

// ref : https://help.adjust.com/en/article/global-callbacks#general-recommended-placeholders
// import mapping json using JSON.parse to preserve object key order
Expand Down Expand Up @@ -43,11 +44,10 @@ const processEvent = (inputEvent) => {
message.properties = { ...message.properties, ...customProperties };

if (formattedPayload.created_at) {
const ts = new Date(formattedPayload.created_at * 1000).toISOString();
const ts = convertToISODate(formattedPayload.created_at);
message.setProperty('originalTimestamp', ts);
message.setProperty('timestamp', ts);
}

// adjust does not has the concept of user but we need to set some random anonymousId in order to make the server accept the message
message.anonymousId = generateUUID();
return message;
Expand Down
31 changes: 31 additions & 0 deletions src/v0/sources/adjust/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const { TransformationError } = require('@rudderstack/integrations-lib');

const convertToISODate = (rawTimestamp) => {
if (typeof rawTimestamp !== 'number' && typeof rawTimestamp !== 'string') {
throw new TransformationError(
`[Adjust] Invalid timestamp "${rawTimestamp}": must be a number or numeric string.`,
);
}

const createdAt = Number(rawTimestamp);

if (Number.isNaN(createdAt)) {
throw new TransformationError(
`[Adjust] Invalid timestamp "${rawTimestamp}": cannot be converted to a valid number.`,
);
}

const date = new Date(createdAt * 1000);

if (Number.isNaN(date.getTime())) {
throw new TransformationError(

Check warning on line 21 in src/v0/sources/adjust/utils.js

View check run for this annotation

Codecov / codecov/patch

src/v0/sources/adjust/utils.js#L21

Added line #L21 was not covered by tests
`[Adjust] Invalid timestamp "${rawTimestamp}": results in an invalid date.`,
);
}

return date.toISOString();
};

module.exports = {
convertToISODate,
};
32 changes: 32 additions & 0 deletions src/v0/sources/adjust/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { convertToISODate } = require('./utils');
const { TransformationError } = require('@rudderstack/integrations-lib');

describe('convertToISODate', () => {
// Converts valid numeric timestamp to ISO date string
it('should return ISO date string when given a valid numeric timestamp', () => {
const timestamp = 1633072800; // Example timestamp for 2021-10-01T00:00:00.000Z
const result = convertToISODate(timestamp);
expect(result).toBe('2021-10-01T07:20:00.000Z');
});

// Throws error for non-numeric string input
it('should throw TransformationError when given a non-numeric string', () => {
const invalidTimestamp = 'invalid';
expect(() => convertToISODate(invalidTimestamp)).toThrow(TransformationError);
});

// Converts valid numeric string timestamp to ISO date string
it('should convert valid numeric string timestamp to ISO date string', () => {
const rawTimestamp = '1633072800'; // Corresponds to 2021-10-01T00:00:00.000Z
const result = convertToISODate(rawTimestamp);
expect(result).toBe('2021-10-01T07:20:00.000Z');
});

// Throws error for non-number and non-string input
it('should throw error for non-number and non-string input', () => {
expect(() => convertToISODate({})).toThrow(TransformationError);
expect(() => convertToISODate([])).toThrow(TransformationError);
expect(() => convertToISODate(null)).toThrow(TransformationError);
expect(() => convertToISODate(undefined)).toThrow(TransformationError);
});
});
53 changes: 53 additions & 0 deletions test/integrations/sources/adjust/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,57 @@ export const data = [
defaultMockFns();
},
},
{
name: 'adjust',
description: 'Simple track call with wrong created at',
module: 'source',
version: 'v0',
skipGo: 'FIXME',
input: {
request: {
body: [
{
id: 'adjust',
query_parameters: {
gps_adid: ['38400000-8cf0-11bd-b23e-10b96e40000d'],
adid: ['18546f6171f67e29d1cb983322ad1329'],
tracker_token: ['abc'],
custom: ['custom'],
tracker_name: ['dummy'],
created_at: ['test'],
event_name: ['Click'],
},
updated_at: '2023-02-10T12:16:07.251Z',
created_at: 'test',
},
],
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
},
pathSuffix: '',
},
output: {
response: {
status: 200,
body: [
{
error: '[Adjust] Invalid timestamp "test": cannot be converted to a valid number.',
statTags: {
destinationId: 'Non determinable',
errorCategory: 'transformation',
implementation: 'native',
module: 'source',
workspaceId: 'Non determinable',
},
statusCode: 400,
},
],
},
},
mockFns: () => {
defaultMockFns();
},
},
];
Loading