Skip to content

Commit

Permalink
bidWatch Analytics Adapter : limit bandwidth usage + refactory (#8774)
Browse files Browse the repository at this point in the history
* bidWatch Analytics Adapter : code refactory

* Update bidwatchAnalyticsAdapter_spec.js

* Update bidwatchAnalyticsAdapter_spec.js
  • Loading branch information
matthieularere-msq authored Aug 22, 2022
1 parent 7e5548e commit 0b71a33
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 71 deletions.
171 changes: 112 additions & 59 deletions modules/bidwatchAnalyticsAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const {
BID_WON,
BID_RESPONSE,
BID_REQUESTED,
BID_TIMEOUT,
}
} = CONSTANTS;

Expand All @@ -20,93 +21,142 @@ let allEvents = {}
let auctionEnd = {}
let initOptions = {}
let endpoint = 'https://default'
let objectToSearchForBidderCode = ['bidderRequests', 'bidsReceived', 'noBids']
let requestsAttributes = ['adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'params', 'userId', 'labelAny', 'bids'];

function getAdapterNameForAlias(aliasName) {
return adapterManager.aliasRegistry[aliasName] || aliasName;
}

function cleanArgObject(arg, removead) {
if (typeof arg['bidderCode'] == 'string') { arg['originalBidder'] = getAdapterNameForAlias(arg['bidderCode']); }
if (typeof arg['creativeId'] == 'number') {
arg['creativeId'] = arg['creativeId'].toString();
}
if (removead && typeof arg['ad'] != 'undefined') {
arg['ad'] = 'emptied';
}
if (typeof arg['gdprConsent'] != 'undefined' && typeof arg['gdprConsent']['vendorData'] != 'undefined') {
arg['gdprConsent']['vendorData'] = 'emptied';
function filterAttributes(arg, removead) {
let response = {};
if (typeof arg == 'object') {
if (typeof arg['bidderCode'] == 'string') {
response['originalBidder'] = getAdapterNameForAlias(arg['bidderCode']);
} else if (typeof arg['bidder'] == 'string') {
response['originalBidder'] = getAdapterNameForAlias(arg['bidder']);
}
if (!removead && typeof arg['ad'] != 'undefined') {
response['ad'] = arg['ad'];
}
if (typeof arg['gdprConsent'] != 'undefined') {
response['gdprConsent'] = {};
if (typeof arg['gdprConsent']['consentString'] != 'undefined') { response['gdprConsent']['consentString'] = arg['gdprConsent']['consentString']; }
}
requestsAttributes.forEach((attr) => {
if (typeof arg[attr] != 'undefined') { response[attr] = arg[attr]; }
});
if (typeof response['creativeId'] == 'number') { response['creativeId'] = response['creativeId'].toString(); }
}
return arg;
return response;
}

function cleanArgs(arg, removead) {
Object.keys(arg).forEach(key => {
arg[key] = cleanArgObject(arg[key], removead);
function cleanAuctionEnd(args) {
let response = {};
let filteredObj;
let objects = ['bidderRequests', 'bidsReceived', 'noBids'];
objects.forEach((attr) => {
if (Array.isArray(args[attr])) {
response[attr] = [];
args[attr].forEach((obj) => {
filteredObj = filterAttributes(obj, true);
if (typeof obj['bids'] == 'object') {
filteredObj['bids'] = [];
obj['bids'].forEach((bid) => {
filteredObj['bids'].push(filterAttributes(bid, true));
});
}
response[attr].push(filteredObj);
});
}
});
return arg
return response;
}

function cleanCreatives(args) {
return filterAttributes(args, false);
}

function checkBidderCode(args, removead) {
if (typeof args == 'object') {
for (let i = 0; i < objectToSearchForBidderCode.length; i++) {
if (typeof args[objectToSearchForBidderCode[i]] == 'object') { args[objectToSearchForBidderCode[i]] = cleanArgs(args[objectToSearchForBidderCode[i]], removead) }
function enhanceMediaType(arg) {
saveEvents['bidRequested'].forEach((bidRequested) => {
if (bidRequested['auctionId'] == arg['auctionId'] && Array.isArray(bidRequested['bids'])) {
bidRequested['bids'].forEach((bid) => {
if (bid['transactionId'] == arg['transactionId'] && bid['bidId'] == arg['requestId']) { arg['mediaTypes'] = bid['mediaTypes']; }
});
}
}
if (typeof args['bidderCode'] == 'string') { args['originalBidder'] = getAdapterNameForAlias(args['bidderCode']); } else if (typeof args['bidder'] == 'string') { args['originalBidder'] = getAdapterNameForAlias(args['bidder']); }
if (typeof args['creativeId'] == 'number') { args['creativeId'] = args['creativeId'].toString(); }
});
return arg;
}

return args
function addBidResponse(args) {
let eventType = BID_RESPONSE;
let argsCleaned = cleanCreatives(JSON.parse(JSON.stringify(args))); ;
if (allEvents[eventType] == undefined) { allEvents[eventType] = [] }
allEvents[eventType].push(argsCleaned);
}

function addEvent(eventType, args) {
let argsCleaned;
if (eventType && args) {
if (allEvents[eventType] == undefined) { allEvents[eventType] = [] }
if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] }
argsCleaned = checkBidderCode(JSON.parse(JSON.stringify(args)), false);
allEvents[eventType].push(argsCleaned);
saveEvents[eventType].push(argsCleaned);
argsCleaned = checkBidderCode(JSON.parse(JSON.stringify(args)), true);
if (['auctionend', 'bidtimeout'].includes(eventType.toLowerCase())) {
if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] }
auctionEnd[eventType].push(argsCleaned);
}
}
function addBidRequested(args) {
let eventType = BID_REQUESTED;
let argsCleaned = filterAttributes(args, true);
if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] }
saveEvents[eventType].push(argsCleaned);
}

function addTimeout(args) {
let eventType = BID_TIMEOUT;
if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] }
saveEvents[eventType].push(args);
let argsCleaned = [];
let argsDereferenced = JSON.parse(JSON.stringify(args));
argsDereferenced.forEach((attr) => {
argsCleaned.push(filterAttributes(JSON.parse(JSON.stringify(attr)), false));
});
if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] }
auctionEnd[eventType].push(argsCleaned);
}

function addAuctionEnd(args) {
let eventType = AUCTION_END;
if (saveEvents[eventType] == undefined) { saveEvents[eventType] = [] }
saveEvents[eventType].push(args);
let argsCleaned = cleanAuctionEnd(JSON.parse(JSON.stringify(args)));
if (auctionEnd[eventType] == undefined) { auctionEnd[eventType] = [] }
auctionEnd[eventType].push(argsCleaned);
}

function handleBidWon(args) {
args = cleanArgObject(JSON.parse(JSON.stringify(args)), true);
args = enhanceMediaType(filterAttributes(JSON.parse(JSON.stringify(args)), true));
let increment = args['cpm'];
if (typeof saveEvents['auctionEnd'] == 'object') {
for (let i = 0; i < saveEvents['auctionEnd'].length; i++) {
let tmpAuction = saveEvents['auctionEnd'][i];
if (tmpAuction['auctionId'] == args['auctionId'] && typeof tmpAuction['bidsReceived'] == 'object') {
for (let j = 0; j < tmpAuction['bidsReceived'].length; j++) {
let tmpBid = tmpAuction['bidsReceived'][j];
if (tmpBid['transactionId'] == args['transactionId'] && tmpBid['adId'] != args['adId']) {
if (args['cpm'] < tmpBid['cpm']) {
saveEvents['auctionEnd'].forEach((auction) => {
if (auction['auctionId'] == args['auctionId'] && typeof auction['bidsReceived'] == 'object') {
auction['bidsReceived'].forEach((bid) => {
if (bid['transactionId'] == args['transactionId'] && bid['adId'] != args['adId']) {
if (args['cpm'] < bid['cpm']) {
increment = 0;
} else if (increment > args['cpm'] - tmpBid['cpm']) {
increment = args['cpm'] - tmpBid['cpm'];
} else if (increment > args['cpm'] - bid['cpm']) {
increment = args['cpm'] - bid['cpm'];
}
}
}
});
}
}
});
}
args['cpmIncrement'] = increment;
if (typeof saveEvents.bidRequested == 'object' && saveEvents.bidRequested.length > 0 && saveEvents.bidRequested[0].gdprConsent) { args.gdpr = saveEvents.bidRequested[0].gdprConsent; }
ajax(endpoint + '.bidwatch.io/analytics/bid_won', null, JSON.stringify(args), {method: 'POST', withCredentials: true});
}

function handleAuctionEnd() {
ajax(endpoint + '.bidwatch.io/analytics/auctions', null, JSON.stringify(auctionEnd), {method: 'POST', withCredentials: true});
auctionEnd = {}
if (typeof allEvents['bidResponse'] != 'undefined') {
for (let i = 0; i < allEvents['bidResponse'].length; i++) { ajax(endpoint + '.bidwatch.io/analytics/creatives', null, JSON.stringify(allEvents['bidResponse'][i]), {method: 'POST', withCredentials: true}); }
}
allEvents = {}
ajax(endpoint + '.bidwatch.io/analytics/auctions', function (data) {
let list = JSON.parse(data);
if (Array.isArray(list) && typeof allEvents['bidResponse'] != 'undefined') {
allEvents['bidResponse'].forEach((bidResponse) => {
if (list.includes(bidResponse['originalBidder'] + '_' + bidResponse['creativeId'])) { ajax(endpoint + '.bidwatch.io/analytics/creatives', null, JSON.stringify(bidResponse), {method: 'POST', withCredentials: true}); }
});
}
allEvents = {};
}, JSON.stringify(auctionEnd), {method: 'POST', withCredentials: true});
auctionEnd = {};
}

let bidwatchAnalytics = Object.assign(adapter({url, analyticsType}), {
Expand All @@ -116,17 +166,20 @@ let bidwatchAnalytics = Object.assign(adapter({url, analyticsType}), {
}) {
switch (eventType) {
case AUCTION_END:
addEvent(eventType, args);
addAuctionEnd(args);
handleAuctionEnd();
break;
case BID_WON:
handleBidWon(args);
break;
case BID_RESPONSE:
addEvent(eventType, args);
addBidResponse(args);
break;
case BID_REQUESTED:
addEvent(eventType, args);
addBidRequested(args);
break;
case BID_TIMEOUT:
addTimeout(args);
break;
}
}});
Expand Down
40 changes: 28 additions & 12 deletions test/spec/modules/bidwatchAnalyticsAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,15 @@ describe('BidWatch Analytics', function () {
describe('main test flow', function () {
beforeEach(function () {
sinon.stub(events, 'getEvents').returns([]);
sinon.spy(bidwatchAnalytics, 'track');
});

afterEach(function () {
events.getEvents.restore();
bidwatchAnalytics.disableAnalytics();
bidwatchAnalytics.track.restore();
});

it('should catch events of interest', function () {
sinon.spy(bidwatchAnalytics, 'track');

it('test auctionEnd', function () {
adapterManager.registerAnalyticsAdapter({
code: 'bidwatch',
adapter: bidwatchAnalytics
Expand All @@ -280,25 +280,41 @@ describe('BidWatch Analytics', function () {
domain: 'test'
}
});

events.emit(constants.EVENTS.BID_REQUESTED, auctionEnd['bidderRequests'][0]);
events.emit(constants.EVENTS.BID_RESPONSE, auctionEnd['bidsReceived'][0]);
events.emit(constants.EVENTS.BID_TIMEOUT, bidTimeout);
events.emit(constants.EVENTS.AUCTION_END, auctionEnd);
expect(server.requests.length).to.equal(1);
let message = JSON.parse(server.requests[0].requestBody);
expect(message).to.have.property('auctionEnd').exist;
expect(message.auctionEnd).to.have.lengthOf(1);
expect(message.auctionEnd[0]).to.have.property('bidsReceived').and.to.have.lengthOf(1);
expect(message.auctionEnd[0].bidsReceived[0]).to.have.property('ad');
expect(message.auctionEnd[0].bidsReceived[0].ad).to.equal('emptied');
expect(message.auctionEnd[0].bidsReceived[0]).not.to.have.property('ad');
expect(message.auctionEnd[0]).to.have.property('bidderRequests').and.to.have.lengthOf(1);
expect(message.auctionEnd[0].bidderRequests[0]).to.have.property('gdprConsent');
expect(message.auctionEnd[0].bidderRequests[0].gdprConsent).to.have.property('vendorData');
expect(message.auctionEnd[0].bidderRequests[0].gdprConsent.vendorData).to.equal('emptied');
expect(message.auctionEnd[0].bidderRequests[0].gdprConsent).not.to.have.property('vendorData');
sinon.assert.callCount(bidwatchAnalytics.track, 4);
});

it('test bidWon', function() {
adapterManager.registerAnalyticsAdapter({
code: 'bidwatch',
adapter: bidwatchAnalytics
});

adapterManager.enableAnalytics({
provider: 'bidwatch',
options: {
domain: 'test'
}
});
events.emit(constants.EVENTS.BID_WON, bidWon);
expect(server.requests.length).to.equal(2);
message = JSON.parse(server.requests[1].requestBody);
expect(message).to.have.property('ad').and.to.equal('emptied');
expect(server.requests.length).to.equal(1);
let message = JSON.parse(server.requests[0].requestBody);
expect(message).not.to.have.property('ad');
expect(message).to.have.property('cpmIncrement').and.to.equal(27.4276);
sinon.assert.callCount(bidwatchAnalytics.track, 3);
sinon.assert.callCount(bidwatchAnalytics.track, 1);
});
});
});

0 comments on commit 0b71a33

Please sign in to comment.