Skip to content

Commit

Permalink
fix: handling invalid timestamp for adjust source (#3866)
Browse files Browse the repository at this point in the history
* fix: handling invalid timestamp for adjust source

* fix: small change in logic

* fix: unnecessary line removal

* fix: unnecessary line removal

* fix: review comment addressed

* fix: review comment addressed

* chore: add edge testcase
- update error messages

* fix: testcase error message

---------

Co-authored-by: Sai Sankeerth <[email protected]>
  • Loading branch information
shrouti1507 and Sai Sankeerth authored Nov 18, 2024
1 parent f3ff409 commit d57f48e
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 2 deletions.
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
27 changes: 27 additions & 0 deletions src/v0/sources/adjust/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { TransformationError } = require('@rudderstack/integrations-lib');

const convertToISODate = (rawTimestamp) => {
if (typeof rawTimestamp !== 'number' && typeof rawTimestamp !== 'string') {
throw new TransformationError(
`Invalid timestamp type: expected number or string, received ${typeof rawTimestamp}`,
);
}

const createdAt = Number(rawTimestamp);

if (Number.isNaN(createdAt)) {
throw new TransformationError(`Failed to parse timestamp: "${rawTimestamp}"`);
}

const date = new Date(createdAt * 1000);

if (Number.isNaN(date.getTime())) {
throw new TransformationError(`Failed to create valid date for timestamp "${rawTimestamp}"`);
}

return date.toISOString();
};

module.exports = {
convertToISODate,
};
37 changes: 37 additions & 0 deletions src/v0/sources/adjust/utils.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
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);
});

it('should throw error for timestamp that results in invalid date when multiplied', () => {
const hugeTimestamp = 999999999999999; // This will become invalid when multiplied by 1000
expect(() => convertToISODate(hugeTimestamp)).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: 'Failed to parse timestamp: "test"',
statTags: {
destinationId: 'Non determinable',
errorCategory: 'transformation',
implementation: 'native',
module: 'source',
workspaceId: 'Non determinable',
},
statusCode: 400,
},
],
},
},
mockFns: () => {
defaultMockFns();
},
},
];

0 comments on commit d57f48e

Please sign in to comment.