@@ -1211,3 +1211,177 @@ describe('LinkedinConversions.onMappingSave - performHook', () => {
12111211 } )
12121212 } )
12131213} )
1214+
1215+ describe ( 'LinkedinConversions.multistatus' , ( ) => {
1216+ const staleTimestamp = new Date ( Date . now ( ) - 100 * 24 * 60 * 60 * 1000 ) . toISOString ( )
1217+
1218+ const staleEvent = createTestEvent ( {
1219+ messageId : 'stale-event-id' ,
1220+ event : 'Funding Application Submitted' ,
1221+ type : 'track' ,
1222+ timestamp : staleTimestamp ,
1223+ context :
{ traits :
{ email :
'[email protected] ' } } , 1224+ properties : { }
1225+ } )
1226+
1227+ const batchMapping = {
1228+ email : { '@path' : '$.context.traits.email' } ,
1229+ conversionHappenedAt : { '@path' : '$.timestamp' } ,
1230+ onMappingSave : {
1231+ inputs : { } ,
1232+ outputs : { id : payload . conversionId }
1233+ } ,
1234+ enable_batching : true ,
1235+ batch_size : 5000
1236+ }
1237+
1238+ it ( 'should mark stale event as PAYLOAD_VALIDATION_FAILED and still send valid events' , async ( ) => {
1239+ nock ( `${ BASE_URL } /conversionEvents` )
1240+ . post ( '' , {
1241+ elements : [
1242+ {
1243+ conversion : `urn:lla:llaPartnerConversion:${ payload . conversionId } ` ,
1244+ conversionHappenedAt : currentTimestamp ,
1245+ user : {
1246+ userIds : [
1247+ { idType : 'SHA256_EMAIL' , idValue : '584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777' }
1248+ ]
1249+ }
1250+ }
1251+ ]
1252+ } )
1253+ . reply ( 201 )
1254+
1255+ const response = await testDestination . executeBatch ( 'streamConversion' , {
1256+ events : [ event , staleEvent ] ,
1257+ settings,
1258+ mapping : batchMapping
1259+ } )
1260+
1261+ // valid event succeeds
1262+ expect ( response [ 0 ] ) . toMatchObject ( { status : 201 } )
1263+ // stale event fails with PAYLOAD_VALIDATION_FAILED
1264+ expect ( response [ 1 ] ) . toMatchObject ( {
1265+ status : 400 ,
1266+ errortype : 'PAYLOAD_VALIDATION_FAILED' ,
1267+ errormessage : 'Timestamp should be within the past 90 days.' ,
1268+ errorreporter : 'INTEGRATIONS'
1269+ } )
1270+ } )
1271+
1272+ it ( 'should not make an API call when all events in the batch are invalid' , async ( ) => {
1273+ const staleEvent2 = createTestEvent ( {
1274+ messageId : 'stale-event-id-2' ,
1275+ event : 'Funding Application Submitted' ,
1276+ type : 'track' ,
1277+ timestamp : staleTimestamp ,
1278+ context :
{ traits :
{ email :
'[email protected] ' } } , 1279+ properties : { }
1280+ } )
1281+
1282+ const scope = nock ( `${ BASE_URL } /conversionEvents` ) . post ( '' ) . reply ( 201 )
1283+
1284+ const response = await testDestination . executeBatch ( 'streamConversion' , {
1285+ events : [ staleEvent , staleEvent2 ] ,
1286+ settings,
1287+ mapping : batchMapping
1288+ } )
1289+
1290+ expect ( scope . isDone ( ) ) . toBe ( false )
1291+ expect ( response [ 0 ] ) . toMatchObject ( { status : 400 , errortype : 'PAYLOAD_VALIDATION_FAILED' } )
1292+ expect ( response [ 1 ] ) . toMatchObject ( { status : 400 , errortype : 'PAYLOAD_VALIDATION_FAILED' } )
1293+ } )
1294+
1295+ it ( 'should mark event as PAYLOAD_VALIDATION_FAILED when user ID is missing' , async ( ) => {
1296+ const noUserIdEvent = createTestEvent ( {
1297+ messageId : 'no-user-id-event' ,
1298+ event : 'Funding Application Submitted' ,
1299+ type : 'track' ,
1300+ timestamp : currentTimestamp . toString ( ) ,
1301+ context : { traits : { } } ,
1302+ properties : { }
1303+ } )
1304+
1305+ nock ( `${ BASE_URL } /conversionEvents` )
1306+ . post ( '' , {
1307+ elements : [
1308+ {
1309+ conversion : `urn:lla:llaPartnerConversion:${ payload . conversionId } ` ,
1310+ conversionHappenedAt : currentTimestamp ,
1311+ user : {
1312+ userIds : [
1313+ { idType : 'SHA256_EMAIL' , idValue : '584c4423c421df49955759498a71495aba49b8780eb9387dff333b6f0982c777' }
1314+ ]
1315+ }
1316+ }
1317+ ]
1318+ } )
1319+ . reply ( 201 )
1320+
1321+ const response = await testDestination . executeBatch ( 'streamConversion' , {
1322+ events : [ event , noUserIdEvent ] ,
1323+ settings,
1324+ mapping : batchMapping
1325+ } )
1326+
1327+ expect ( response [ 0 ] ) . toMatchObject ( { status : 201 } )
1328+ expect ( response [ 1 ] ) . toMatchObject ( {
1329+ status : 400 ,
1330+ errortype : 'PAYLOAD_VALIDATION_FAILED' ,
1331+ errormessage : 'One of email or LinkedIn UUID or Axciom ID or Oracle ID is required.' ,
1332+ errorreporter : 'INTEGRATIONS'
1333+ } )
1334+ } )
1335+
1336+ it ( 'should correctly map responses to original batch indices' , async ( ) => {
1337+ nock ( `${ BASE_URL } /conversionEvents` ) . post ( '' ) . reply ( 201 )
1338+
1339+ const response = await testDestination . executeBatch ( 'streamConversion' , {
1340+ events : [ staleEvent , event , staleEvent ] ,
1341+ settings,
1342+ mapping : batchMapping
1343+ } )
1344+
1345+ expect ( response [ 0 ] ) . toMatchObject ( { status : 400 , errortype : 'PAYLOAD_VALIDATION_FAILED' } )
1346+ expect ( response [ 1 ] ) . toMatchObject ( { status : 201 } )
1347+ expect ( response [ 2 ] ) . toMatchObject ( { status : 400 , errortype : 'PAYLOAD_VALIDATION_FAILED' } )
1348+ } )
1349+
1350+ it ( 'should throw InvalidAuthenticationError when LinkedIn returns 401' , async ( ) => {
1351+ nock ( `${ BASE_URL } /conversionEvents` ) . post ( '' ) . reply ( 401 , { message : 'Unauthorized' } )
1352+
1353+ await expect (
1354+ testDestination . executeBatch ( 'streamConversion' , {
1355+ events : [ event ] ,
1356+ settings,
1357+ mapping : batchMapping
1358+ } )
1359+ ) . rejects . toThrow ( 'LinkedIn OAuth token is expired or invalid. Please re-authenticate.' )
1360+ } )
1361+
1362+ it ( 'should mark all valid events as failed when LinkedIn returns 429' , async ( ) => {
1363+ nock ( `${ BASE_URL } /conversionEvents` ) . post ( '' ) . reply ( 429 , { message : 'Too Many Requests' } )
1364+
1365+ const response = await testDestination . executeBatch ( 'streamConversion' , {
1366+ events : [ event , secondEvent ] ,
1367+ settings,
1368+ mapping : batchMapping
1369+ } )
1370+
1371+ expect ( response [ 0 ] ) . toMatchObject ( { status : 429 } )
1372+ expect ( response [ 1 ] ) . toMatchObject ( { status : 429 } )
1373+ } )
1374+
1375+ it ( 'should mark all valid events as failed when LinkedIn returns 500' , async ( ) => {
1376+ nock ( `${ BASE_URL } /conversionEvents` ) . post ( '' ) . reply ( 500 , { message : 'Internal Server Error' } )
1377+
1378+ const response = await testDestination . executeBatch ( 'streamConversion' , {
1379+ events : [ event , secondEvent ] ,
1380+ settings,
1381+ mapping : batchMapping
1382+ } )
1383+
1384+ expect ( response [ 0 ] ) . toMatchObject ( { status : 500 } )
1385+ expect ( response [ 1 ] ) . toMatchObject ( { status : 500 } )
1386+ } )
1387+ } )
0 commit comments