From 031fa560069330891e49edb04d513a3a127f1c8a Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 15 Aug 2017 15:43:08 +0300 Subject: [PATCH 01/20] Add trustx adapter and tests for it --- modules/trustxBidAdapter.js | 210 ++++++++++++++++++ test/spec/modules/trustxBidAdapter_spec.js | 234 +++++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 modules/trustxBidAdapter.js create mode 100644 test/spec/modules/trustxBidAdapter_spec.js diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js new file mode 100644 index 00000000000..a570e564ea4 --- /dev/null +++ b/modules/trustxBidAdapter.js @@ -0,0 +1,210 @@ +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); + +var TrustxAdapter = function TrustxAdapter() { + var bidderCode = 'trustx'; + var reqHost = '//sofia.trustx.org'; + var reqPath = '/hb?'; + var LOG_ERROR_MESS = { + noAuid: 'Bid from response has no auid parameter - ', + noAdm: 'Bid from response has no adm parameter - ', + noBid: 'Array of bid objects is empty', + noPlacementCode: 'Can\'t find placementCode for bid with auid - ', + havePCodeFor: ', placementCode is available only for the following uids - ', + emptyUids: 'Uids should be not empty', + emptySeatbid: 'Seatbid array from response has empty item', + emptyResponse: 'Response is empty', + hasEmptySeatbidArray: 'Response has empty seatbid array', + hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' + }; + + function _makeHandler(auids, placementMap, onTimeoutWorker, needToSendStat) { + var cbName = bidderCode + '_callback_wrapper_' + auids.join('_'); + $$PREBID_GLOBAL$$[cbName] = function(resp) { + delete $$PREBID_GLOBAL$$[cbName]; + _responseProcessing(resp, auids, placementMap, onTimeoutWorker, needToSendStat); + }; + return '$$PREBID_GLOBAL$$.' + cbName; + } + + function _sendRequest(auids, placementMap, onTimeoutWorker) { + var query = []; + var path = reqPath; + var needToSendStat = Math.random() < 0.1; + query.push('u=' + encodeURIComponent(location.href)); + query.push('auids=' + encodeURIComponent(auids.join(','))); + query.push('cb=' + _makeHandler(auids, placementMap, onTimeoutWorker, needToSendStat)); + query.push('pt=' + (window.globalPrebidTrustxPriceType === 'net' ? 'net' : 'gross')); + query.push('hbstat=' + (needToSendStat ? '1' : '0')); + + adloader.loadScript(reqHost + path + query.join('&')); + } + + function _makeTimeoutWorker() { + var active = true; + var handler = function() { + worker.called = true; + $$PREBID_GLOBAL$$.offEvent('bidTimeout', handler); + }; + $$PREBID_GLOBAL$$.onEvent('bidTimeout', handler); + var worker = { + startTime: new Date().getTime(), + off: function() { + if (active && !this.called) { + active = false; + $$PREBID_GLOBAL$$.offEvent('bidTimeout', handler); + } + }, + called: false + }; + return worker; + } + + function _callBids(params) { + var auids = []; + var placementMap = {}; + var hasBid; + var bid; + var bids = params.bids || []; + for (var i = 0; i < bids.length; i++) { + bid = bids[i]; + if (bid && bid.bidder === bidderCode && bid.placementCode) { + hasBid = true; + if (bid.params && bid.params.uid) { + if (!placementMap[bid.params.uid]) { + placementMap[bid.params.uid] = [bid.placementCode]; + auids.push(bid.params.uid); + } else { + placementMap[bid.params.uid].push(bid.placementCode); + } + } + } + } + + if (auids.length) { + var onTimeoutWorker = _makeTimeoutWorker(); + _sendRequest(auids, placementMap, onTimeoutWorker); + } else if (hasBid) { + utils.logError(LOG_ERROR_MESS.emptyUids); + } + } + + function tryToSendStat(startTime, timeout, auids, isTimeouted, error) { + var protocol = location.protocol === 'https:' ? 'https:' : 'http:'; + var stat = { + wrapper: 'prebid', + tt: timeout, + ct: new Date().getTime() - startTime, + st: isTimeouted ? 'to' : error ? 'err' : 'ok', + cr: 10 + }; + stat = encodeURIComponent(JSON.stringify(stat)); + auids = encodeURIComponent(auids.join(',')); + (new Image()).src = protocol + '//sofia.trustx.org/hbstat?auids=' + auids + '&stat=' + stat + '&rnd=' + Math.random(); + } + + function _getBidFromResponse(resp) { + if (!resp) { + utils.logError(LOG_ERROR_MESS.emptySeatbid); + } else if (!resp.bid) { + utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(resp)); + } else if (!resp.bid[0]) { + utils.logError(LOG_ERROR_MESS.noBid); + } + return resp && resp.bid && resp.bid[0]; + } + + function _forEachPlacement(error, bid, placementCode) { + var bidObject; + if (error) { + bidObject = bidfactory.createBid(2); + } else { + bidObject = bidfactory.createBid(1); + bidObject.cpm = bid.price; + bidObject.ad = bid.adm; + bidObject.width = bid.w; + bidObject.height = bid.h; + if (bid.dealid) { + bidObject.dealId = bid.dealid; + } + } + bidObject.bidderCode = bidderCode; + bidmanager.addBidResponse(placementCode, bidObject); + } + + function _addBidResponse(bid, auids, placementMap) { + if (!bid) return; + var errorMessage, placementCodes; + if (!bid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(bid); + else { + placementCodes = placementMap.hasOwnProperty(bid.auid) && placementMap[bid.auid]; + if (!placementCodes) { + errorMessage = LOG_ERROR_MESS.noPlacementCode + bid.auid + LOG_ERROR_MESS.havePCodeFor + auids.join(','); + } + } + + if (!errorMessage) { + if (!bid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(bid); + + var l = placementCodes.length; + while (l--) { + _forEachPlacement(errorMessage, bid, placementCodes[l]); + } + + delete placementMap[bid.auid]; + } + + if (errorMessage) { + utils.logError(errorMessage); + } + } + + function _responseProcessing(resp, auids, placementMap, onTimeoutWorker, needToSendStat) { + var errorMessage; + + if (!resp) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (resp.seatbid && !resp.seatbid.length) errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; + + if (!errorMessage) { + resp = resp.seatbid || []; + var l = resp.length; + while (l--) { + _addBidResponse(_getBidFromResponse(resp[l]), auids, placementMap); + } + } + + var n, bidObj; + for (var auid in placementMap) { + if (placementMap.hasOwnProperty(auid) && placementMap[auid]) { + n = placementMap[auid].length; + while (n--) { + bidObj = bidfactory.createBid(2); + bidObj.bidderCode = bidderCode; + bidmanager.addBidResponse(placementMap[auid][n], bidObj); + } + } + } + + onTimeoutWorker.off(); + needToSendStat && tryToSendStat( + onTimeoutWorker.startTime, + $$PREBID_GLOBAL$$.cbTimeout + $$PREBID_GLOBAL$$.timeoutBuffer, + auids, + onTimeoutWorker.called, + errorMessage + ); + + if (errorMessage) utils.logError(errorMessage); + } + + return { + callBids: _callBids + }; +}; + +adaptermanager.registerBidAdapter(new TrustxAdapter(), 'trustx'); + +module.exports = TrustxAdapter; diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js new file mode 100644 index 00000000000..e559a16d71a --- /dev/null +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -0,0 +1,234 @@ +describe('trustx adapter tests', function () { + var expect = require('chai').expect; + var assert = require('chai').assert; + var urlParse = require('url-parse'); + var querystringify = require('querystringify'); + + var adapter = require('modules/trustxBidAdapter'); + var bidmanager = require('src/bidmanager'); + var adLoader = require('src/adloader'); + var utils = require('src/utils'); + window.pbjs = window.pbjs || {}; + + if (typeof (pbjs) === 'undefined') { + var pbjs = window.pbjs; + } + let stubLoadScript; + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); + afterEach(function () { + stubLoadScript.restore(); + }); + var logErrorSpy; + beforeEach(function () { + logErrorSpy = sinon.spy(utils, 'logError'); + }); + afterEach(function () { + logErrorSpy.restore(); + }); + describe('creation of request url', function () { + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = []; + } + it('should fix parameter name', function () { + var params = { + bidderCode: 'trustx', + bids: [ + { + bidder: 'trustx', + params: { + uid: 5 + }, + placementCode: 'div-1' + }, + { + bidder: 'trustx', + params: { + uid: 6 + }, + placementCode: 'div-1' + }, + { + bidder: 'trustx', + params: {}, + placementCode: 'div-2' + }, + { + bidder: 'trustx', + params: { + uid: 6, + test: true + }, + placementCode: 'div-3' + }, + { + bidder: 'trustx', + placementCode: 'div-4' + } + ] + }; + adapter().callBids(params); + var bidUrl = stubLoadScript.getCall(0).args[0]; + sinon.assert.calledWith(stubLoadScript, bidUrl); + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + var generatedCallback = 'pbjs.trustx_callback_wrapper_5_6'; + expect(parsedBidUrl.hostname).to.equal('sofia.trustx.org'); + expect(parsedBidUrl.pathname).to.equal('/hb'); + expect(parsedBidUrlQueryString).to.have.property('auids').and.to.equal('5,6'); + expect(parsedBidUrlQueryString).to.have.property('u').and.to.equal(location.href); + expect(parsedBidUrlQueryString).to.have.property('cb').and.to.equal(generatedCallback); + }); + }); + describe('validate incoming params', function () { + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = []; + } + it('has no correct item in config', function () { + var params = { + bidderCode: 'trustx', + bids: [ + { + bidder: 'trustx', + params: {}, + placementCode: 'div-1' + }, + { + bidder: 'trustx', + placementCode: 'div-1' + } + ] + }; + adapter().callBids(params); + sinon.assert.notCalled(stubLoadScript); + expect(logErrorSpy.getCall(0).args[0]).to.equal('Uids should be not empty'); + }); + }); + describe('handling of the callback response', function () { + if (typeof (pbjs._bidsReceived) === 'undefined') { + pbjs._bidsReceived = []; + } + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = []; + } + if (typeof (pbjs._adsReceived) === 'undefined') { + pbjs._adsReceived = []; + } + var params = { + bidderCode: 'trustx', + bids: [ + { + bidder: 'trustx', + params: { + uid: 5 + }, + placementCode: '/19968336/header-bid-tag-0' + }, + { + bidder: 'trustx', + params: { + uid: 6 + }, + placementCode: '/19968336/header-bid-tag-1' + }, + { + bidder: 'trustx', + params: { + uid: 42 + }, + placementCode: '/19968336/header-bid-tag-2' + }, + { + bidder: 'trustx', + params: { + uid: 43 + }, + placementCode: '/19968336/header-bid-tag-3' + }, + { + bidder: 'trustx', + params: { + uid: 44 + }, + placementCode: '/19968336/header-bid-tag-4' + }, + { + bidder: 'trustx', + params: { + uid: 45 + }, + placementCode: '/19968336/header-bid-tag-5' + } + ] + }; + it('callback function should exist', function () { + adapter().callBids(params); + expect(pbjs['trustx_callback_wrapper_5_6_42_43_44_45']) + .to.exist.and.to.be.a('function'); + }); + it('bidmanager.addBidResponse should be called with correct arguments', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + adapter().callBids(params); + var adUnits = []; + var unit = {}; + unit.bids = params.bids; + unit.code = '/19968336/header-bid-tag'; + adUnits.push(unit); + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + pbjs.adUnits = adUnits; + var response = { + seatbid: [ + {bid: [{price: 1.15, adm: '
test content 1
', auid: 5, h: 90, w: 728}], seat: '1'}, + {bid: [{price: 0, auid: 6, h: 250, w: 300}], seat: '1'}, + {bid: [{price: 0, adm: '
test content 3
', h: 250, w: 300}], seat: '1'}, + undefined, + {bid: [], seat: '1'}, + {seat: '1'}, + {bid: [{price: 0, adm: '
test content 7
', auid: 46, h: 250, w: 300}], seat: '1'} + ] + }; + pbjs['trustx_callback_wrapper_5_6_42_43_44_45'](response); + var bidPlacementCode1 = stubAddBidResponse.getCall(1).args[0]; + var bidObject1 = stubAddBidResponse.getCall(1).args[1]; + var bidPlacementCode2 = stubAddBidResponse.getCall(0).args[0]; + var bidObject2 = stubAddBidResponse.getCall(0).args[1]; + var bidPlacementCode3 = stubAddBidResponse.getCall(2).args[0]; + var bidObject3 = stubAddBidResponse.getCall(2).args[1]; + var bidPlacementCode4 = stubAddBidResponse.getCall(3).args[0]; + var bidObject4 = stubAddBidResponse.getCall(3).args[1]; + var bidPlacementCode5 = stubAddBidResponse.getCall(4).args[0]; + var bidObject5 = stubAddBidResponse.getCall(4).args[1]; + var bidPlacementCode6 = stubAddBidResponse.getCall(5).args[0]; + var bidObject6 = stubAddBidResponse.getCall(5).args[1]; + expect(logErrorSpy.getCall(5).args[0]).to.equal('Bid from response has no adm parameter - {"price":0,"auid":6,"h":250,"w":300}'); + expect(logErrorSpy.getCall(4).args[0]).to.equal('Bid from response has no auid parameter - {"price":0,"adm":"<' + 'div>test content 3","h":250,"w":300}'); + expect(logErrorSpy.getCall(3).args[0]).to.equal('Seatbid array from response has empty item'); + expect(logErrorSpy.getCall(2).args[0]).to.equal('Array of bid objects is empty'); + expect(logErrorSpy.getCall(1).args[0]).to.equal('Seatbid from response has no array of bid objects - {"seat":"1"}'); + expect(logErrorSpy.getCall(0).args[0]).to.equal('Can\'t find placementCode for bid with auid - 46, placementCode is available only for the following uids - 5,6,42,43,44,45'); + expect(bidPlacementCode1).to.equal('/19968336/header-bid-tag-0'); + expect(bidObject1.cpm).to.equal(1.15); + expect(bidObject1.ad).to.equal('
test content 1
'); + expect(bidObject1.width).to.equal(728); + expect(bidObject1.height).to.equal(90); + expect(bidObject1.getStatusCode()).to.equal(1); + expect(bidObject1.bidderCode).to.equal('trustx'); + expect(bidPlacementCode2).to.equal('/19968336/header-bid-tag-1'); + expect(bidObject2.getStatusCode()).to.equal(2); + expect(bidPlacementCode3).to.equal('/19968336/header-bid-tag-2'); + expect(bidObject3.getStatusCode()).to.equal(2); + expect(bidPlacementCode4).to.equal('/19968336/header-bid-tag-3'); + expect(bidObject4.getStatusCode()).to.equal(2); + expect(bidPlacementCode5).to.equal('/19968336/header-bid-tag-4'); + expect(bidObject5.getStatusCode()).to.equal(2); + expect(bidPlacementCode6).to.equal('/19968336/header-bid-tag-5'); + expect(bidObject6.getStatusCode()).to.equal(2); + stubAddBidResponse.restore(); + }); + }); +}); From 319cadde088c6429e3cc5fd4c8d5873bdd0496fc Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 15 Aug 2017 16:30:23 +0300 Subject: [PATCH 02/20] update integration example --- integrationExamples/gpt/hello_world.html | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 0f5e24a301a..3732b84d534 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -22,11 +22,29 @@ // Replace this object to test a new Adapter! bids: [{ - bidder: 'appnexus', + bidder: 'trustx', params: { - placementId: '10433394' + uid: '42' } - }] + }, + { + bidder: 'trustx', + params: { + uid: '43' + } + }, + { + bidder: 'trustx', + params: { + uid: '44' + } + }, + { + bidder: 'trustx', + params: { + uid: '45' + } + }] }]; From 69ab1f4caf56069e42afc62d60068d9b4c93daf0 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Sat, 9 Sep 2017 13:26:04 +0300 Subject: [PATCH 03/20] Update trustx adapter --- integrationExamples/gpt/hello_world.html | 24 ++-------- modules/trustxBidAdapter.js | 57 +++--------------------- 2 files changed, 10 insertions(+), 71 deletions(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 3732b84d534..0f5e24a301a 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -22,29 +22,11 @@ // Replace this object to test a new Adapter! bids: [{ - bidder: 'trustx', + bidder: 'appnexus', params: { - uid: '42' + placementId: '10433394' } - }, - { - bidder: 'trustx', - params: { - uid: '43' - } - }, - { - bidder: 'trustx', - params: { - uid: '44' - } - }, - { - bidder: 'trustx', - params: { - uid: '45' - } - }] + }] }]; diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index a570e564ea4..07141f92e24 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -21,48 +21,29 @@ var TrustxAdapter = function TrustxAdapter() { hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' }; - function _makeHandler(auids, placementMap, onTimeoutWorker, needToSendStat) { + function _makeHandler(auids, placementMap) { var cbName = bidderCode + '_callback_wrapper_' + auids.join('_'); $$PREBID_GLOBAL$$[cbName] = function(resp) { delete $$PREBID_GLOBAL$$[cbName]; - _responseProcessing(resp, auids, placementMap, onTimeoutWorker, needToSendStat); + _responseProcessing(resp, auids, placementMap); }; return '$$PREBID_GLOBAL$$.' + cbName; } - function _sendRequest(auids, placementMap, onTimeoutWorker) { + function _sendRequest(auids, placementMap) { var query = []; var path = reqPath; var needToSendStat = Math.random() < 0.1; + $$PREBID_GLOBAL$$.needToSendTrustxStat = needToSendStat; query.push('u=' + encodeURIComponent(location.href)); query.push('auids=' + encodeURIComponent(auids.join(','))); - query.push('cb=' + _makeHandler(auids, placementMap, onTimeoutWorker, needToSendStat)); + query.push('cb=' + _makeHandler(auids, placementMap)); query.push('pt=' + (window.globalPrebidTrustxPriceType === 'net' ? 'net' : 'gross')); query.push('hbstat=' + (needToSendStat ? '1' : '0')); adloader.loadScript(reqHost + path + query.join('&')); } - function _makeTimeoutWorker() { - var active = true; - var handler = function() { - worker.called = true; - $$PREBID_GLOBAL$$.offEvent('bidTimeout', handler); - }; - $$PREBID_GLOBAL$$.onEvent('bidTimeout', handler); - var worker = { - startTime: new Date().getTime(), - off: function() { - if (active && !this.called) { - active = false; - $$PREBID_GLOBAL$$.offEvent('bidTimeout', handler); - } - }, - called: false - }; - return worker; - } - function _callBids(params) { var auids = []; var placementMap = {}; @@ -85,27 +66,12 @@ var TrustxAdapter = function TrustxAdapter() { } if (auids.length) { - var onTimeoutWorker = _makeTimeoutWorker(); - _sendRequest(auids, placementMap, onTimeoutWorker); + _sendRequest(auids, placementMap); } else if (hasBid) { utils.logError(LOG_ERROR_MESS.emptyUids); } } - function tryToSendStat(startTime, timeout, auids, isTimeouted, error) { - var protocol = location.protocol === 'https:' ? 'https:' : 'http:'; - var stat = { - wrapper: 'prebid', - tt: timeout, - ct: new Date().getTime() - startTime, - st: isTimeouted ? 'to' : error ? 'err' : 'ok', - cr: 10 - }; - stat = encodeURIComponent(JSON.stringify(stat)); - auids = encodeURIComponent(auids.join(',')); - (new Image()).src = protocol + '//sofia.trustx.org/hbstat?auids=' + auids + '&stat=' + stat + '&rnd=' + Math.random(); - } - function _getBidFromResponse(resp) { if (!resp) { utils.logError(LOG_ERROR_MESS.emptySeatbid); @@ -162,7 +128,7 @@ var TrustxAdapter = function TrustxAdapter() { } } - function _responseProcessing(resp, auids, placementMap, onTimeoutWorker, needToSendStat) { + function _responseProcessing(resp, auids, placementMap) { var errorMessage; if (!resp) errorMessage = LOG_ERROR_MESS.emptyResponse; @@ -188,15 +154,6 @@ var TrustxAdapter = function TrustxAdapter() { } } - onTimeoutWorker.off(); - needToSendStat && tryToSendStat( - onTimeoutWorker.startTime, - $$PREBID_GLOBAL$$.cbTimeout + $$PREBID_GLOBAL$$.timeoutBuffer, - auids, - onTimeoutWorker.called, - errorMessage - ); - if (errorMessage) utils.logError(errorMessage); } From ef500123318cb6b8cd3a2d730ee5017f799e65e3 Mon Sep 17 00:00:00 2001 From: pwyrembak Date: Tue, 19 Sep 2017 18:54:52 +0300 Subject: [PATCH 04/20] Post-review fixes of Trustx adapter --- modules/trustxBidAdapter.js | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 07141f92e24..44c00c2c0b3 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -1,14 +1,15 @@ -var utils = require('src/utils.js'); -var bidfactory = require('src/bidfactory.js'); -var bidmanager = require('src/bidmanager.js'); -var adloader = require('src/adloader'); -var adaptermanager = require('src/adaptermanager'); +const utils = require('src/utils.js'); +const bidfactory = require('src/bidfactory.js'); +const bidmanager = require('src/bidmanager.js'); +const adloader = require('src/adloader'); +const adaptermanager = require('src/adaptermanager'); +const CONSTANTS = require('src/constants.json'); var TrustxAdapter = function TrustxAdapter() { - var bidderCode = 'trustx'; - var reqHost = '//sofia.trustx.org'; - var reqPath = '/hb?'; - var LOG_ERROR_MESS = { + const bidderCode = 'trustx'; + const reqHost = '//sofia.trustx.org'; + const reqPath = '/hb?'; + const LOG_ERROR_MESS = { noAuid: 'Bid from response has no auid parameter - ', noAdm: 'Bid from response has no adm parameter - ', noBid: 'Array of bid objects is empty', @@ -33,13 +34,10 @@ var TrustxAdapter = function TrustxAdapter() { function _sendRequest(auids, placementMap) { var query = []; var path = reqPath; - var needToSendStat = Math.random() < 0.1; - $$PREBID_GLOBAL$$.needToSendTrustxStat = needToSendStat; query.push('u=' + encodeURIComponent(location.href)); query.push('auids=' + encodeURIComponent(auids.join(','))); query.push('cb=' + _makeHandler(auids, placementMap)); query.push('pt=' + (window.globalPrebidTrustxPriceType === 'net' ? 'net' : 'gross')); - query.push('hbstat=' + (needToSendStat ? '1' : '0')); adloader.loadScript(reqHost + path + query.join('&')); } @@ -86,9 +84,9 @@ var TrustxAdapter = function TrustxAdapter() { function _forEachPlacement(error, bid, placementCode) { var bidObject; if (error) { - bidObject = bidfactory.createBid(2); + bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bid); } else { - bidObject = bidfactory.createBid(1); + bidObject = bidfactory.createBid(CONSTANTS.STATUS.GOOD, bid); bidObject.cpm = bid.price; bidObject.ad = bid.adm; bidObject.width = bid.w; @@ -147,7 +145,7 @@ var TrustxAdapter = function TrustxAdapter() { if (placementMap.hasOwnProperty(auid) && placementMap[auid]) { n = placementMap[auid].length; while (n--) { - bidObj = bidfactory.createBid(2); + bidObj = bidfactory.createBid(CONSTANTS.STATUS.NO_BID); bidObj.bidderCode = bidderCode; bidmanager.addBidResponse(placementMap[auid][n], bidObj); } From 843440dd0f923e2e77c86bac1f5a8e7591f97b1c Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 10 Oct 2017 17:23:05 +0300 Subject: [PATCH 05/20] Code improvement for trustx adapter: changed default price type from gross to net --- modules/trustxBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 44c00c2c0b3..13f893a841d 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -37,7 +37,7 @@ var TrustxAdapter = function TrustxAdapter() { query.push('u=' + encodeURIComponent(location.href)); query.push('auids=' + encodeURIComponent(auids.join(','))); query.push('cb=' + _makeHandler(auids, placementMap)); - query.push('pt=' + (window.globalPrebidTrustxPriceType === 'net' ? 'net' : 'gross')); + query.push('pt=' + (window.globalPrebidTrustxPriceType === 'gross' ? 'gross' : 'net')); adloader.loadScript(reqHost + path + query.join('&')); } From aa249b58f41829111726bb9ea7d99ef37bd7b959 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 17 Oct 2017 22:08:36 +0300 Subject: [PATCH 06/20] Update TrustX adapter to support the 1.0 version --- modules/trustxBidAdapter.js | 284 ++++++------- modules/trustxBidAdapter.md | 39 ++ test/spec/modules/trustxBidAdapter_spec.js | 473 ++++++++++++--------- 3 files changed, 438 insertions(+), 358 deletions(-) create mode 100755 modules/trustxBidAdapter.md diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 13f893a841d..e7d163828c0 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -1,165 +1,147 @@ -const utils = require('src/utils.js'); -const bidfactory = require('src/bidfactory.js'); -const bidmanager = require('src/bidmanager.js'); -const adloader = require('src/adloader'); -const adaptermanager = require('src/adaptermanager'); -const CONSTANTS = require('src/constants.json'); +import * as utils from 'src/utils'; +import {registerBidder} from 'src/adapters/bidderFactory'; +const BIDDER_CODE = 'trustx'; +const ENDPOINT_URL = '//sofia.trustx.org/hb'; +const TIME_TO_LIVE = 360; +const ADAPTER_SYNC_URL = '//sofia.trustx.org/push_sync'; +const LOG_ERROR_MESS = { + noAuid: 'Bid from response has no auid parameter - ', + noAdm: 'Bid from response has no adm parameter - ', + noBid: 'Array of bid objects is empty', + noPlacementCode: 'Can\'t find in requested bids the bid with auid - ', + emptyUids: 'Uids should be not empty', + emptySeatbid: 'Seatbid array from response has empty item', + emptyResponse: 'Response is empty', + hasEmptySeatbidArray: 'Response has empty seatbid array', + hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' +}; +const bidsRequestMap = {}; +export const spec = { + code: BIDDER_CODE, + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!(bid.params.uid && bid.adUnitCode); + }, + /** + * Make a server request from the list of BidRequests. + * + * @param {BidRequest[]} validBidRequests - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + buildRequests: function(validBidRequests) { + const auids = []; + const bidsMap = {}; + const bids = validBidRequests || []; + const bidderRequestId = bids[0] && bids[0].bidderRequestId; + + bids.forEach(bid => { + if (!bidsMap[bid.params.uid]) { + bidsMap[bid.params.uid] = [bid]; + auids.push(bid.params.uid); + } else { + bidsMap[bid.params.uid].push(bid); + } + }); -var TrustxAdapter = function TrustxAdapter() { - const bidderCode = 'trustx'; - const reqHost = '//sofia.trustx.org'; - const reqPath = '/hb?'; - const LOG_ERROR_MESS = { - noAuid: 'Bid from response has no auid parameter - ', - noAdm: 'Bid from response has no adm parameter - ', - noBid: 'Array of bid objects is empty', - noPlacementCode: 'Can\'t find placementCode for bid with auid - ', - havePCodeFor: ', placementCode is available only for the following uids - ', - emptyUids: 'Uids should be not empty', - emptySeatbid: 'Seatbid array from response has empty item', - emptyResponse: 'Response is empty', - hasEmptySeatbidArray: 'Response has empty seatbid array', - hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' - }; + bidsRequestMap[bidderRequestId] = bidsMap; - function _makeHandler(auids, placementMap) { - var cbName = bidderCode + '_callback_wrapper_' + auids.join('_'); - $$PREBID_GLOBAL$$[cbName] = function(resp) { - delete $$PREBID_GLOBAL$$[cbName]; - _responseProcessing(resp, auids, placementMap); + const payload = { + u: utils.getTopWindowUrl(), + pt: window.globalPrebidTrustxPriceType === 'gross' ? 'gross' : 'net', + auids: auids.join(','), + reqid: bidderRequestId, }; - return '$$PREBID_GLOBAL$$.' + cbName; - } - - function _sendRequest(auids, placementMap) { - var query = []; - var path = reqPath; - query.push('u=' + encodeURIComponent(location.href)); - query.push('auids=' + encodeURIComponent(auids.join(','))); - query.push('cb=' + _makeHandler(auids, placementMap)); - query.push('pt=' + (window.globalPrebidTrustxPriceType === 'gross' ? 'gross' : 'net')); - - adloader.loadScript(reqHost + path + query.join('&')); - } - function _callBids(params) { - var auids = []; - var placementMap = {}; - var hasBid; - var bid; - var bids = params.bids || []; - for (var i = 0; i < bids.length; i++) { - bid = bids[i]; - if (bid && bid.bidder === bidderCode && bid.placementCode) { - hasBid = true; - if (bid.params && bid.params.uid) { - if (!placementMap[bid.params.uid]) { - placementMap[bid.params.uid] = [bid.placementCode]; - auids.push(bid.params.uid); - } else { - placementMap[bid.params.uid].push(bid.placementCode); - } - } - } + // const payloadString = JSON.stringify(payload); + return { + method: 'GET', + url: ENDPOINT_URL, + data: payload, + }; + }, + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @param {*} bidRequest + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + const bidResponses = []; + const bidsMap = bidsRequestMap[bidRequest.data.reqid]; + + let errorMessage; + + if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse; + else if (serverResponse.seatbid && !serverResponse.seatbid.length) { + errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; } - if (auids.length) { - _sendRequest(auids, placementMap); - } else if (hasBid) { - utils.logError(LOG_ERROR_MESS.emptyUids); + if (!errorMessage && serverResponse.seatbid) { + serverResponse.seatbid.forEach(respItem => { + _addBidResponse(_getBidFromResponse(respItem), bidsMap, bidResponses); + }); } - } - - function _getBidFromResponse(resp) { - if (!resp) { - utils.logError(LOG_ERROR_MESS.emptySeatbid); - } else if (!resp.bid) { - utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(resp)); - } else if (!resp.bid[0]) { - utils.logError(LOG_ERROR_MESS.noBid); + if (errorMessage) utils.logError(errorMessage); + return bidResponses; + }, + getUserSyncs: function(syncOptions) { + if (syncOptions.pixelEnabled) { + return [{ + type: 'image', + url: ADAPTER_SYNC_URL + }]; } - return resp && resp.bid && resp.bid[0]; } - - function _forEachPlacement(error, bid, placementCode) { - var bidObject; - if (error) { - bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bid); - } else { - bidObject = bidfactory.createBid(CONSTANTS.STATUS.GOOD, bid); - bidObject.cpm = bid.price; - bidObject.ad = bid.adm; - bidObject.width = bid.w; - bidObject.height = bid.h; - if (bid.dealid) { - bidObject.dealId = bid.dealid; - } - } - bidObject.bidderCode = bidderCode; - bidmanager.addBidResponse(placementCode, bidObject); +} + +function _getBidFromResponse(respItem) { + if (!respItem) { + utils.logError(LOG_ERROR_MESS.emptySeatbid); + } else if (!respItem.bid) { + utils.logError(LOG_ERROR_MESS.hasNoArrayOfBids + JSON.stringify(respItem)); + } else if (!respItem.bid[0]) { + utils.logError(LOG_ERROR_MESS.noBid); } - - function _addBidResponse(bid, auids, placementMap) { - if (!bid) return; - var errorMessage, placementCodes; - if (!bid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(bid); - else { - placementCodes = placementMap.hasOwnProperty(bid.auid) && placementMap[bid.auid]; - if (!placementCodes) { - errorMessage = LOG_ERROR_MESS.noPlacementCode + bid.auid + LOG_ERROR_MESS.havePCodeFor + auids.join(','); - } - } - - if (!errorMessage) { - if (!bid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(bid); - - var l = placementCodes.length; - while (l--) { - _forEachPlacement(errorMessage, bid, placementCodes[l]); - } - - delete placementMap[bid.auid]; - } - - if (errorMessage) { - utils.logError(errorMessage); + return respItem && respItem.bid && respItem.bid[0]; +} + +function _addBidResponse(serverBid, bidsMap, bidResponses) { + if (!serverBid) return; + let errorMessage; + if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); + if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); + else { + const awaitingBids = bidsMap[serverBid.auid]; + if (awaitingBids) { + awaitingBids.forEach(bid => { + const bidResponse = { + requestId: bid.bidId, // bid.bidderRequestId, + bidderCode: spec.code, + cpm: serverBid.price, + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.auid, // bid.bidId, + currency: 'USD', + netRevenue: window.globalPrebidTrustxPriceType !== 'gross', + ttl: TIME_TO_LIVE, + ad: serverBid.adm, + dealId: serverBid.dealid + }; + bidResponses.push(bidResponse); + }); + } else { + errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; } } - - function _responseProcessing(resp, auids, placementMap) { - var errorMessage; - - if (!resp) errorMessage = LOG_ERROR_MESS.emptyResponse; - else if (resp.seatbid && !resp.seatbid.length) errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray; - - if (!errorMessage) { - resp = resp.seatbid || []; - var l = resp.length; - while (l--) { - _addBidResponse(_getBidFromResponse(resp[l]), auids, placementMap); - } - } - - var n, bidObj; - for (var auid in placementMap) { - if (placementMap.hasOwnProperty(auid) && placementMap[auid]) { - n = placementMap[auid].length; - while (n--) { - bidObj = bidfactory.createBid(CONSTANTS.STATUS.NO_BID); - bidObj.bidderCode = bidderCode; - bidmanager.addBidResponse(placementMap[auid][n], bidObj); - } - } - } - - if (errorMessage) utils.logError(errorMessage); + if (errorMessage) { + utils.logError(errorMessage); } +} - return { - callBids: _callBids - }; -}; - -adaptermanager.registerBidAdapter(new TrustxAdapter(), 'trustx'); - -module.exports = TrustxAdapter; +registerBidder(spec); diff --git a/modules/trustxBidAdapter.md b/modules/trustxBidAdapter.md new file mode 100755 index 00000000000..7952b8845cf --- /dev/null +++ b/modules/trustxBidAdapter.md @@ -0,0 +1,39 @@ +# Overview + +Module Name: TrustX Bidder Adapter +Module Type: Bidder Adapter +Maintainer: paul@trustx.org + +# Description + +Module that connects to TrustX demand source to fetch bids. + +# Test Parameters +``` + window.globalPrebidTrustxPriceType = 'gross'; // by default is 'net' + var adUnits = [ + { + code: 'test-div', + sizes: [[300, 250]], + bids: [ + { + bidder: "trustx", + params: { + uid: '44' + } + } + ] + },{ + code: 'test-div', + sizes: [[728, 90]], + bids: [ + { + bidder: "trustx", + params: { + uid: 45 + } + } + ] + } + ]; +``` \ No newline at end of file diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 7208ebef343..16760d2e3ef 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -1,234 +1,293 @@ -describe('trustx adapter tests', function () { - var expect = require('chai').expect; - var assert = require('chai').assert; - var urlParse = require('url-parse'); - var querystringify = require('querystringify'); - - var adapter = require('modules/trustxBidAdapter'); - var bidmanager = require('src/bidmanager'); - var adLoader = require('src/adloader'); - var utils = require('src/utils'); - window.$$PREBID_GLOBAL$$ = window.$$PREBID_GLOBAL$$ || {}; - - if (typeof (pbjs) === 'undefined') { - var pbjs = window.$$PREBID_GLOBAL$$; - } - let stubLoadScript; - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - afterEach(function () { - stubLoadScript.restore(); - }); - var logErrorSpy; - beforeEach(function () { - logErrorSpy = sinon.spy(utils, 'logError'); - }); - afterEach(function () { - logErrorSpy.restore(); +import { expect } from 'chai'; +import { spec } from 'modules/trustxBidAdapter'; +import { newBidder } from 'src/adapters/bidderFactory'; + +describe('TrustXAdapter', function () { + const adapter = newBidder(spec); + + describe('inherited functions', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); }); - describe('creation of request url', function () { - if (typeof (pbjs._bidsRequested) === 'undefined') { - pbjs._bidsRequested = []; - } - it('should fix parameter name', function () { - var params = { - bidderCode: 'trustx', - bids: [ - { - bidder: 'trustx', - params: { - uid: 5 - }, - placementCode: 'div-1' - }, - { - bidder: 'trustx', - params: { - uid: 6 - }, - placementCode: 'div-1' - }, - { - bidder: 'trustx', - params: {}, - placementCode: 'div-2' - }, - { - bidder: 'trustx', - params: { - uid: 6, - test: true - }, - placementCode: 'div-3' - }, - { - bidder: 'trustx', - placementCode: 'div-4' - } - ] + + describe('isBidRequestValid', () => { + let bid = { + 'bidder': 'trustx', + 'params': { + 'uid': '44' + }, + 'adUnitCode': 'adunit-code', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }; + + it('should return true when required params found', () => { + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); + + it('should return false when required params are not passed', () => { + let bid = Object.assign({}, bid); + delete bid.params; + bid.params = { + 'uid': 0 }; - adapter().callBids(params); - var bidUrl = stubLoadScript.getCall(0).args[0]; - sinon.assert.calledWith(stubLoadScript, bidUrl); - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - var generatedCallback = '$$PREBID_GLOBAL$$.trustx_callback_wrapper_5_6'; - expect(parsedBidUrl.hostname).to.equal('sofia.trustx.org'); - expect(parsedBidUrl.pathname).to.equal('/hb'); - expect(parsedBidUrlQueryString).to.have.property('auids').and.to.equal('5,6'); - expect(parsedBidUrlQueryString).to.have.property('u').and.to.equal(location.href); - expect(parsedBidUrlQueryString).to.have.property('cb').and.to.equal(generatedCallback); + expect(spec.isBidRequestValid(bid)).to.equal(false); }); }); - describe('validate incoming params', function () { - if (typeof (pbjs._bidsRequested) === 'undefined') { - pbjs._bidsRequested = []; - } - it('has no correct item in config', function () { - var params = { - bidderCode: 'trustx', - bids: [ - { - bidder: 'trustx', - params: {}, - placementCode: 'div-1' - }, - { - bidder: 'trustx', - placementCode: 'div-1' - } - ] - }; - adapter().callBids(params); - sinon.assert.notCalled(stubLoadScript); - expect(logErrorSpy.getCall(0).args[0]).to.equal('Uids should be not empty'); + + describe('buildRequests', () => { + let bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '30b31c1838de1e', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '3150ccb55da321', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '45' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '42dbe3a7168a6a', + 'bidderRequestId': '22edbae2733bf6', + 'auctionId': '1d1a030790a475', + } + ]; + + it('should attach valid params to the tag', () => { + const request = spec.buildRequests([bidRequests[0]]); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('pt', 'net'); + expect(payload).to.have.property('auids', '43'); + expect(payload).to.have.property('reqid', '22edbae2733bf6'); + }); + + it('auids must not be duplicated', () => { + const request = spec.buildRequests(bidRequests); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('pt', 'net'); + expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('reqid', '22edbae2733bf6'); + }); + + it('pt parameter must be "gross" if window.globalPrebidTrustxPriceType === "gross"', () => { + window.globalPrebidTrustxPriceType = 'gross'; + const request = spec.buildRequests(bidRequests); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('pt', 'gross'); + expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('reqid', '22edbae2733bf6'); + delete window.globalPrebidTrustxPriceType; + }); + + it('pt parameter must be "net" or "gross"', () => { + window.globalPrebidTrustxPriceType = 'some'; + const request = spec.buildRequests(bidRequests); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('pt', 'net'); + expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('reqid', '22edbae2733bf6'); + delete window.globalPrebidTrustxPriceType; }); }); - describe('handling of the callback response', function () { - if (typeof (pbjs._bidsReceived) === 'undefined') { - pbjs._bidsReceived = []; - } - if (typeof (pbjs._bidsRequested) === 'undefined') { - pbjs._bidsRequested = []; - } - if (typeof (pbjs._adsReceived) === 'undefined') { - pbjs._adsReceived = []; - } - var params = { - bidderCode: 'trustx', - bids: [ + + describe('interpretResponse', () => { + const responses = [ + {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 43, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 44, 'h': 90, 'w': 728}], 'seat': '1'}, + {'bid': [{'price': 0, 'auid': 45, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0, 'adm': '
test content 4
', 'h': 250, 'w': 300}], 'seat': '1'}, + undefined, + {'bid': [], 'seat': '1'}, + {'seat': '1'}, + ]; + + it('should get correct bid response', () => { + const bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '659423fff799cb', + 'bidderRequestId': '5f2009617a7c0a', + 'auctionId': '1cbd2feafe5e8b', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '659423fff799cb', + 'cpm': 1.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'seatbid': [responses[0]]}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('should get correct multi bid response', () => { + const bidRequests = [ { - bidder: 'trustx', - params: { - uid: 5 + 'bidder': 'trustx', + 'params': { + 'uid': '43' }, - placementCode: '/19968336/header-bid-tag-0' + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '300bfeb0d71a5b', + 'bidderRequestId': '2c2bb1972df9a', + 'auctionId': '1fa09aee5c8c99', }, { - bidder: 'trustx', - params: { - uid: 6 + 'bidder': 'trustx', + 'params': { + 'uid': '44' }, - placementCode: '/19968336/header-bid-tag-1' + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4dff80cc4ee346', + 'bidderRequestId': '2c2bb1972df9a', + 'auctionId': '1fa09aee5c8c99', }, { - bidder: 'trustx', - params: { - uid: 42 + 'bidder': 'trustx', + 'params': { + 'uid': '43' }, - placementCode: '/19968336/header-bid-tag-2' + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '5703af74d0472a', + 'bidderRequestId': '2c2bb1972df9a', + 'auctionId': '1fa09aee5c8c99', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '300bfeb0d71a5b', + 'cpm': 1.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '5703af74d0472a', + 'cpm': 1.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, }, { - bidder: 'trustx', - params: { - uid: 43 + 'requestId': '4dff80cc4ee346', + 'cpm': 0.5, + 'creativeId': 44, + 'dealId': undefined, + 'width': 728, + 'height': 90, + 'ad': '
test content 2
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'seatbid': [responses[0], responses[1]]}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('handles wrong and nobid responses', () => { + const bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '45' }, - placementCode: '/19968336/header-bid-tag-3' + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '300bfeb0d7190gf', + 'bidderRequestId': '2c2bb1972d23af', + 'auctionId': '1fa09aee5c84d34', }, { - bidder: 'trustx', - params: { - uid: 44 + 'bidder': 'trustx', + 'params': { + 'uid': '46' }, - placementCode: '/19968336/header-bid-tag-4' + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '300bfeb0d71321', + 'bidderRequestId': '2c2bb1972d23af', + 'auctionId': '1fa09aee5c84d34', }, { - bidder: 'trustx', - params: { - uid: 45 + 'bidder': 'trustx', + 'params': { + 'uid': '50' }, - placementCode: '/19968336/header-bid-tag-5' + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '300bfeb0d7183bb', + 'bidderRequestId': '2c2bb1972d23af', + 'auctionId': '1fa09aee5c84d34', } - ] - }; - it('callback function should exist', function () { - adapter().callBids(params); - expect(pbjs['trustx_callback_wrapper_5_6_42_43_44_45']) - .to.exist.and.to.be.a('function'); - }); - it('bidmanager.addBidResponse should be called with correct arguments', function () { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - adapter().callBids(params); - var adUnits = []; - var unit = {}; - unit.bids = params.bids; - unit.code = '/19968336/header-bid-tag'; - adUnits.push(unit); - if (typeof (pbjs._bidsRequested) === 'undefined') { - pbjs._bidsRequested = [params]; - } else { - pbjs._bidsRequested.push(params); - } - pbjs.adUnits = adUnits; - var response = { - seatbid: [ - {bid: [{price: 1.15, adm: '
test content 1
', auid: 5, h: 90, w: 728}], seat: '1'}, - {bid: [{price: 0, auid: 6, h: 250, w: 300}], seat: '1'}, - {bid: [{price: 0, adm: '
test content 3
', h: 250, w: 300}], seat: '1'}, - undefined, - {bid: [], seat: '1'}, - {seat: '1'}, - {bid: [{price: 0, adm: '
test content 7
', auid: 46, h: 250, w: 300}], seat: '1'} - ] - }; - pbjs['trustx_callback_wrapper_5_6_42_43_44_45'](response); - var bidPlacementCode1 = stubAddBidResponse.getCall(1).args[0]; - var bidObject1 = stubAddBidResponse.getCall(1).args[1]; - var bidPlacementCode2 = stubAddBidResponse.getCall(0).args[0]; - var bidObject2 = stubAddBidResponse.getCall(0).args[1]; - var bidPlacementCode3 = stubAddBidResponse.getCall(2).args[0]; - var bidObject3 = stubAddBidResponse.getCall(2).args[1]; - var bidPlacementCode4 = stubAddBidResponse.getCall(3).args[0]; - var bidObject4 = stubAddBidResponse.getCall(3).args[1]; - var bidPlacementCode5 = stubAddBidResponse.getCall(4).args[0]; - var bidObject5 = stubAddBidResponse.getCall(4).args[1]; - var bidPlacementCode6 = stubAddBidResponse.getCall(5).args[0]; - var bidObject6 = stubAddBidResponse.getCall(5).args[1]; - expect(logErrorSpy.getCall(5).args[0]).to.equal('Bid from response has no adm parameter - {"price":0,"auid":6,"h":250,"w":300}'); - expect(logErrorSpy.getCall(4).args[0]).to.equal('Bid from response has no auid parameter - {"price":0,"adm":"<' + 'div>test content 3","h":250,"w":300}'); - expect(logErrorSpy.getCall(3).args[0]).to.equal('Seatbid array from response has empty item'); - expect(logErrorSpy.getCall(2).args[0]).to.equal('Array of bid objects is empty'); - expect(logErrorSpy.getCall(1).args[0]).to.equal('Seatbid from response has no array of bid objects - {"seat":"1"}'); - expect(logErrorSpy.getCall(0).args[0]).to.equal('Can\'t find placementCode for bid with auid - 46, placementCode is available only for the following uids - 5,6,42,43,44,45'); - expect(bidPlacementCode1).to.equal('/19968336/header-bid-tag-0'); - expect(bidObject1.cpm).to.equal(1.15); - expect(bidObject1.ad).to.equal('
test content 1
'); - expect(bidObject1.width).to.equal(728); - expect(bidObject1.height).to.equal(90); - expect(bidObject1.getStatusCode()).to.equal(1); - expect(bidObject1.bidderCode).to.equal('trustx'); - expect(bidPlacementCode2).to.equal('/19968336/header-bid-tag-1'); - expect(bidObject2.getStatusCode()).to.equal(2); - expect(bidPlacementCode3).to.equal('/19968336/header-bid-tag-2'); - expect(bidObject3.getStatusCode()).to.equal(2); - expect(bidPlacementCode4).to.equal('/19968336/header-bid-tag-3'); - expect(bidObject4.getStatusCode()).to.equal(2); - expect(bidPlacementCode5).to.equal('/19968336/header-bid-tag-4'); - expect(bidObject5.getStatusCode()).to.equal(2); - expect(bidPlacementCode6).to.equal('/19968336/header-bid-tag-5'); - expect(bidObject6.getStatusCode()).to.equal(2); - stubAddBidResponse.restore(); + ]; + const request = spec.buildRequests(bidRequests); + const result = spec.interpretResponse({'seatbid': responses.slice(2)}, request); + expect(result.length).to.equal(0); }); }); }); From 5f60ac34c2738c4de83d438df408758b2cea9655 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Fri, 20 Oct 2017 17:45:13 +0300 Subject: [PATCH 07/20] Make requested changes for TrustX adapter --- modules/trustxBidAdapter.js | 24 +++++++++++----------- test/spec/modules/trustxBidAdapter_spec.js | 14 +++++-------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index e7d163828c0..595a27626ee 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -15,7 +15,6 @@ const LOG_ERROR_MESS = { hasEmptySeatbidArray: 'Response has empty seatbid array', hasNoArrayOfBids: 'Seatbid from response has no array of bid objects - ' }; -const bidsRequestMap = {}; export const spec = { code: BIDDER_CODE, /** @@ -25,7 +24,7 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function(bid) { - return !!(bid.params.uid && bid.adUnitCode); + return !!bid.params.uid; }, /** * Make a server request from the list of BidRequests. @@ -37,9 +36,12 @@ export const spec = { const auids = []; const bidsMap = {}; const bids = validBidRequests || []; - const bidderRequestId = bids[0] && bids[0].bidderRequestId; + let priceType = 'net'; bids.forEach(bid => { + if (bid.params.priceType === 'gross') { + priceType = 'gross'; + } if (!bidsMap[bid.params.uid]) { bidsMap[bid.params.uid] = [bid]; auids.push(bid.params.uid); @@ -48,20 +50,17 @@ export const spec = { } }); - bidsRequestMap[bidderRequestId] = bidsMap; - const payload = { u: utils.getTopWindowUrl(), - pt: window.globalPrebidTrustxPriceType === 'gross' ? 'gross' : 'net', + pt: priceType, auids: auids.join(','), - reqid: bidderRequestId, }; - // const payloadString = JSON.stringify(payload); return { method: 'GET', url: ENDPOINT_URL, data: payload, + bidsMap: bidsMap, }; }, /** @@ -73,7 +72,8 @@ export const spec = { */ interpretResponse: function(serverResponse, bidRequest) { const bidResponses = []; - const bidsMap = bidsRequestMap[bidRequest.data.reqid]; + const bidsMap = bidRequest.bidsMap; + const priceType = bidRequest.data.pt; let errorMessage; @@ -84,7 +84,7 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, bidResponses); + _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses); }); } if (errorMessage) utils.logError(errorMessage); @@ -111,7 +111,7 @@ function _getBidFromResponse(respItem) { return respItem && respItem.bid && respItem.bid[0]; } -function _addBidResponse(serverBid, bidsMap, bidResponses) { +function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { if (!serverBid) return; let errorMessage; if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); @@ -128,7 +128,7 @@ function _addBidResponse(serverBid, bidsMap, bidResponses) { height: serverBid.h, creativeId: serverBid.auid, // bid.bidId, currency: 'USD', - netRevenue: window.globalPrebidTrustxPriceType !== 'gross', + netRevenue: priceType !== 'gross', ttl: TIME_TO_LIVE, ad: serverBid.adm, dealId: serverBid.dealid diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 16760d2e3ef..803df1615cb 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -82,7 +82,6 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43'); - expect(payload).to.have.property('reqid', '22edbae2733bf6'); }); it('auids must not be duplicated', () => { @@ -92,31 +91,28 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,45'); - expect(payload).to.have.property('reqid', '22edbae2733bf6'); }); - it('pt parameter must be "gross" if window.globalPrebidTrustxPriceType === "gross"', () => { - window.globalPrebidTrustxPriceType = 'gross'; + it('pt parameter must be "gross" if params.priceType === "gross"', () => { + bidRequests[1].params.priceType = 'gross'; const request = spec.buildRequests(bidRequests); const payload = request.data; expect(payload).to.be.an('object'); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'gross'); expect(payload).to.have.property('auids', '43,45'); - expect(payload).to.have.property('reqid', '22edbae2733bf6'); - delete window.globalPrebidTrustxPriceType; + delete bidRequests[1].params.priceType; }); it('pt parameter must be "net" or "gross"', () => { - window.globalPrebidTrustxPriceType = 'some'; + bidRequests[1].params.priceType = 'some'; const request = spec.buildRequests(bidRequests); const payload = request.data; expect(payload).to.be.an('object'); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,45'); - expect(payload).to.have.property('reqid', '22edbae2733bf6'); - delete window.globalPrebidTrustxPriceType; + delete bidRequests[1].params.priceType; }); }); From 2628673e1c4702572ae4136d5e57278205a7112f Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 24 Oct 2017 19:37:17 +0300 Subject: [PATCH 08/20] Updated markdown file for TrustX adapter --- modules/trustxBidAdapter.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/trustxBidAdapter.md b/modules/trustxBidAdapter.md index 7952b8845cf..ca407b0c5e8 100755 --- a/modules/trustxBidAdapter.md +++ b/modules/trustxBidAdapter.md @@ -10,7 +10,6 @@ Module that connects to TrustX demand source to fetch bids. # Test Parameters ``` - window.globalPrebidTrustxPriceType = 'gross'; // by default is 'net' var adUnits = [ { code: 'test-div', @@ -19,7 +18,8 @@ Module that connects to TrustX demand source to fetch bids. { bidder: "trustx", params: { - uid: '44' + uid: '44', + priceType: 'gross' // by default is 'net' } } ] @@ -30,7 +30,8 @@ Module that connects to TrustX demand source to fetch bids. { bidder: "trustx", params: { - uid: 45 + uid: 45, + priceType: 'gross' } } ] From 292b4ddcc864770d953f41ce314913aac5b8574f Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Thu, 26 Oct 2017 16:09:32 +0300 Subject: [PATCH 09/20] Fix TrustX adapter and spec file --- modules/trustxBidAdapter.js | 1 + test/spec/modules/trustxBidAdapter_spec.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 595a27626ee..f16b8b96ec8 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -71,6 +71,7 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse, bidRequest) { + serverResponse = serverResponse && serverResponse.body const bidResponses = []; const bidsMap = bidRequest.bidsMap; const priceType = bidRequest.data.pt; diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 803df1615cb..918e03674a9 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -158,7 +158,7 @@ describe('TrustXAdapter', function () { } ]; - const result = spec.interpretResponse({'seatbid': [responses[0]]}, request); + const result = spec.interpretResponse({'body': {'seatbid': [responses[0]]}}, request); expect(result).to.deep.equal(expectedResponse); }); @@ -241,7 +241,7 @@ describe('TrustXAdapter', function () { } ]; - const result = spec.interpretResponse({'seatbid': [responses[0], responses[1]]}, request); + const result = spec.interpretResponse({'body': {'seatbid': [responses[0], responses[1]]}}, request); expect(result).to.deep.equal(expectedResponse); }); @@ -282,7 +282,7 @@ describe('TrustXAdapter', function () { } ]; const request = spec.buildRequests(bidRequests); - const result = spec.interpretResponse({'seatbid': responses.slice(2)}, request); + const result = spec.interpretResponse({'body': {'seatbid': responses.slice(2)}}, request); expect(result.length).to.equal(0); }); }); From 09b581afcc0fc818c50302485ca03f09fbc5ced2 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 19 Dec 2017 23:29:53 +0300 Subject: [PATCH 10/20] Update TrustX adapter: r parameter was added to ad request as cache buster --- modules/trustxBidAdapter.js | 3 +++ test/spec/modules/trustxBidAdapter_spec.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index f16b8b96ec8..ec1f0247455 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -37,11 +37,13 @@ export const spec = { const bidsMap = {}; const bids = validBidRequests || []; let priceType = 'net'; + let reqId; bids.forEach(bid => { if (bid.params.priceType === 'gross') { priceType = 'gross'; } + reqId = bid.bidderRequestId; if (!bidsMap[bid.params.uid]) { bidsMap[bid.params.uid] = [bid]; auids.push(bid.params.uid); @@ -54,6 +56,7 @@ export const spec = { u: utils.getTopWindowUrl(), pt: priceType, auids: auids.join(','), + r: reqId }; return { diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 918e03674a9..6149545d59f 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -82,6 +82,7 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43'); + expect(payload).to.have.property('r', '22edbae2733bf6'); }); it('auids must not be duplicated', () => { @@ -91,6 +92,7 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('r', '22edbae2733bf6'); }); it('pt parameter must be "gross" if params.priceType === "gross"', () => { @@ -101,6 +103,7 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'gross'); expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('r', '22edbae2733bf6'); delete bidRequests[1].params.priceType; }); @@ -112,6 +115,7 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('r', '22edbae2733bf6'); delete bidRequests[1].params.priceType; }); }); From 73b724943b6bce613ef268aa86f157883b9e9b9b Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Thu, 17 May 2018 22:53:13 +0300 Subject: [PATCH 11/20] Add support of gdpr to Trustx Bid Adapter --- modules/trustxBidAdapter.js | 12 ++++++++++- test/spec/modules/trustxBidAdapter_spec.js | 24 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index ec1f0247455..3688aa3b976 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -30,9 +30,10 @@ export const spec = { * Make a server request from the list of BidRequests. * * @param {BidRequest[]} validBidRequests - an array of bids + * @param {bidderRequest} - bidder request object * @return ServerRequest Info describing the request to the server. */ - buildRequests: function(validBidRequests) { + buildRequests: function(validBidRequests, bidderRequest) { const auids = []; const bidsMap = {}; const bids = validBidRequests || []; @@ -59,6 +60,15 @@ export const spec = { r: reqId }; + if (bidderRequest && bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString) { + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + } + payload.gdpr_applies = + (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') + ? Number(bidderRequest.gdprConsent.gdprApplies) : 1; + } + return { method: 'GET', url: ENDPOINT_URL, diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 6149545d59f..75405850d7a 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -118,6 +118,30 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('r', '22edbae2733bf6'); delete bidRequests[1].params.priceType; }); + + it('if gdprConsent is present payload must have gdpr params', () => { + const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}}); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', 1); + }); + + it('if gdprApplies is false gdpr_applies must be 0', () => { + const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}}); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', 0); + }); + + it('if gdprApplies is undefined gdpr_applies must be 1', () => { + const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}}); + const payload = request.data; + expect(payload).to.be.an('object'); + expect(payload).to.have.property('gdpr_consent', 'AAA'); + expect(payload).to.have.property('gdpr_applies', 1); + }); }); describe('interpretResponse', () => { From 4974e55da6732500a8e37a9ad88d79b2cf6c08a8 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Mon, 6 Aug 2018 14:51:27 +0300 Subject: [PATCH 12/20] Add wtimeout to ad request params for TrustX Bid Adapter --- modules/trustxBidAdapter.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 3688aa3b976..5a55c3d8cf3 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -60,13 +60,18 @@ export const spec = { r: reqId }; - if (bidderRequest && bidderRequest.gdprConsent) { - if (bidderRequest.gdprConsent.consentString) { - payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + if (bidderRequest) { + if (bidderRequest.timeout) { + payload.wtimeout = bidderRequest.timeout; + } + if (bidderRequest.gdprConsent) { + if (bidderRequest.gdprConsent.consentString) { + payload.gdpr_consent = bidderRequest.gdprConsent.consentString; + } + payload.gdpr_applies = + (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') + ? Number(bidderRequest.gdprConsent.gdprApplies) : 1; } - payload.gdpr_applies = - (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') - ? Number(bidderRequest.gdprConsent.gdprApplies) : 1; } return { From 9175298551a2f5baf21c2e287571318af5249235 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Fri, 10 Aug 2018 17:52:56 +0300 Subject: [PATCH 13/20] TrustX Bid Adapter: remove last ampersand in the ad request --- modules/trustxBidAdapter.js | 4 +-- test/spec/modules/trustxBidAdapter_spec.js | 42 +++++++++++++--------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 5a55c3d8cf3..20e000e3379 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -77,7 +77,7 @@ export const spec = { return { method: 'GET', url: ENDPOINT_URL, - data: payload, + data: utils.parseQueryStringParameters(payload).replace(/\&$/, ''), bidsMap: bidsMap, }; }, @@ -89,7 +89,7 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse, bidRequest) { - serverResponse = serverResponse && serverResponse.body + serverResponse = serverResponse && serverResponse.body; const bidResponses = []; const bidsMap = bidRequest.bidsMap; const priceType = bidRequest.data.pt; diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 75405850d7a..2e099772593 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -39,6 +39,14 @@ describe('TrustXAdapter', function () { }); describe('buildRequests', () => { + function parseRequest(url) { + const res = {}; + url.split('&').forEach((it) => { + const couple = it.split('='); + res[couple[0]] = decodeURIComponent(couple[1]); + }); + return res; + } let bidRequests = [ { 'bidder': 'trustx', @@ -77,8 +85,8 @@ describe('TrustXAdapter', function () { it('should attach valid params to the tag', () => { const request = spec.buildRequests([bidRequests[0]]); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43'); @@ -87,8 +95,8 @@ describe('TrustXAdapter', function () { it('auids must not be duplicated', () => { const request = spec.buildRequests(bidRequests); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,45'); @@ -98,8 +106,8 @@ describe('TrustXAdapter', function () { it('pt parameter must be "gross" if params.priceType === "gross"', () => { bidRequests[1].params.priceType = 'gross'; const request = spec.buildRequests(bidRequests); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'gross'); expect(payload).to.have.property('auids', '43,45'); @@ -110,8 +118,8 @@ describe('TrustXAdapter', function () { it('pt parameter must be "net" or "gross"', () => { bidRequests[1].params.priceType = 'some'; const request = spec.buildRequests(bidRequests); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,45'); @@ -121,26 +129,26 @@ describe('TrustXAdapter', function () { it('if gdprConsent is present payload must have gdpr params', () => { const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}}); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); - expect(payload).to.have.property('gdpr_applies', 1); + expect(payload).to.have.property('gdpr_applies', '1'); }); it('if gdprApplies is false gdpr_applies must be 0', () => { const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}}); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); - expect(payload).to.have.property('gdpr_applies', 0); + expect(payload).to.have.property('gdpr_applies', '0'); }); it('if gdprApplies is undefined gdpr_applies must be 1', () => { const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}}); - const payload = request.data; - expect(payload).to.be.an('object'); + expect(request.data).to.be.an('string'); + const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); - expect(payload).to.have.property('gdpr_applies', 1); + expect(payload).to.have.property('gdpr_applies', '1'); }); }); From 83b3aaf8c2183cb740872f39711424a93c0c3c11 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Fri, 15 Feb 2019 14:25:11 +0300 Subject: [PATCH 14/20] Update TrustX Bid Adapter to support identical uids in parameters --- modules/trustxBidAdapter.js | 100 ++++++-- test/spec/modules/trustxBidAdapter_spec.js | 253 +++++++++++++++++++-- 2 files changed, 314 insertions(+), 39 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index b61a870c2a4..6a9ac3e6b4c 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -36,6 +36,8 @@ export const spec = { buildRequests: function(validBidRequests, bidderRequest) { const auids = []; const bidsMap = {}; + const slotsMapByUid = {}; + const sizeMap = {}; const bids = validBidRequests || []; let priceType = 'net'; let reqId; @@ -45,18 +47,41 @@ export const spec = { priceType = 'gross'; } reqId = bid.bidderRequestId; - if (!bidsMap[bid.params.uid]) { - bidsMap[bid.params.uid] = [bid]; - auids.push(bid.params.uid); + const {params: {uid}, adUnitCode} = bid; + auids.push(uid); + const sizesId = utils.parseSizesInput(bid.sizes); + + if (!slotsMapByUid[uid]) { + slotsMapByUid[uid] = {}; + } + const slotsMap = slotsMapByUid[uid]; + if (!slotsMap[adUnitCode]) { + slotsMap[adUnitCode] = {adUnitCode, bids: [bid], parents: []}; } else { - bidsMap[bid.params.uid].push(bid); + slotsMap[adUnitCode].bids.push(bid); } + const slot = slotsMap[adUnitCode]; + + sizesId.forEach((sizeId) => { + sizeMap[sizeId] = true; + if (!bidsMap[uid]) { + bidsMap[uid] = {}; + } + + if (!bidsMap[uid][sizeId]) { + bidsMap[uid][sizeId] = [slot]; + } else { + bidsMap[uid][sizeId].push(slot); + } + slot.parents.push({parent: bidsMap[uid], key: sizeId, uid}); + }); }); const payload = { u: utils.getTopWindowUrl(), pt: priceType, auids: auids.join(','), + sizes: utils.getKeys(sizeMap).join(','), r: reqId }; @@ -91,6 +116,7 @@ export const spec = { interpretResponse: function(serverResponse, bidRequest) { serverResponse = serverResponse && serverResponse.body; const bidResponses = []; + const remainingServerBids = []; const bidsMap = bidRequest.bidsMap; const priceType = bidRequest.data.pt; @@ -103,7 +129,12 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses); + _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses, remainingServerBids); + }); + } + if (remainingServerBids.length) { + remainingServerBids.forEach(serverBid => { + _addBidResponse(serverBid, bidsMap, priceType, bidResponses); }); } if (errorMessage) utils.logError(errorMessage); @@ -130,30 +161,57 @@ function _getBidFromResponse(respItem) { return respItem && respItem.bid && respItem.bid[0]; } -function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { +function _addBidResponse(serverBid, bidsMap, priceType, bidResponses, remainingServerBids) { if (!serverBid) return; let errorMessage; if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); else { + const ignoreSizes = !remainingServerBids; const awaitingBids = bidsMap[serverBid.auid]; if (awaitingBids) { - awaitingBids.forEach(bid => { - const bidResponse = { - requestId: bid.bidId, // bid.bidderRequestId, - bidderCode: spec.code, - cpm: serverBid.price, - width: serverBid.w, - height: serverBid.h, - creativeId: serverBid.auid, // bid.bidId, - currency: 'USD', - netRevenue: priceType !== 'gross', - ttl: TIME_TO_LIVE, - ad: serverBid.adm, - dealId: serverBid.dealid - }; - bidResponses.push(bidResponse); + let sizeId = `${serverBid.w}x${serverBid.h}`; + + if (!awaitingBids[sizeId]) { + if (ignoreSizes) { + sizeId = utils.getKeys(awaitingBids)[0]; + } else { + remainingServerBids.push(serverBid); + return; + } + } + + const slot = awaitingBids[sizeId][0]; + + const bid = slot.bids.shift(); + bidResponses.push({ + requestId: bid.bidId, // bid.bidderRequestId, + bidderCode: spec.code, + cpm: serverBid.price, + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.auid, // bid.bidId, + currency: 'USD', + netRevenue: priceType !== 'gross', + ttl: TIME_TO_LIVE, + ad: serverBid.adm, + dealId: serverBid.dealid }); + + if (!slot.bids.length) { + slot.parents.forEach(({parent, key, uid}) => { + const index = parent[key].indexOf(slot); + if (index > -1) { + parent[key].splice(index, 1); + } + if (!parent[key].length) { + delete parent[key]; + if (!utils.getKeys(parent).length) { + delete bidsMap[uid]; + } + } + }); + } } else { errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; } diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 9f2fdca6a99..355fbbfa4bb 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -65,7 +65,7 @@ describe('TrustXAdapter', function () { 'uid': '43' }, 'adUnitCode': 'adunit-code-2', - 'sizes': [[728, 90]], + 'sizes': [[728, 90], [300, 250]], 'bidId': '3150ccb55da321', 'bidderRequestId': '22edbae2733bf6', 'auctionId': '1d1a030790a475', @@ -90,16 +90,18 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43'); + expect(payload).to.have.property('sizes', '300x250,300x600'); expect(payload).to.have.property('r', '22edbae2733bf6'); }); - it('auids must not be duplicated', function () { + it('sizes must not be duplicated', function () { const request = spec.buildRequests(bidRequests); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); - expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('auids', '43,43,45'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); expect(payload).to.have.property('r', '22edbae2733bf6'); }); @@ -110,7 +112,8 @@ describe('TrustXAdapter', function () { const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'gross'); - expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('auids', '43,43,45'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); expect(payload).to.have.property('r', '22edbae2733bf6'); delete bidRequests[1].params.priceType; }); @@ -122,7 +125,8 @@ describe('TrustXAdapter', function () { const payload = parseRequest(request.data); expect(payload).to.have.property('u').that.is.a('string'); expect(payload).to.have.property('pt', 'net'); - expect(payload).to.have.property('auids', '43,45'); + expect(payload).to.have.property('auids', '43,43,45'); + expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); expect(payload).to.have.property('r', '22edbae2733bf6'); delete bidRequests[1].params.priceType; }); @@ -155,9 +159,10 @@ describe('TrustXAdapter', function () { describe('interpretResponse', function () { const responses = [ {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 43, 'h': 250, 'w': 300}], 'seat': '1'}, - {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 44, 'h': 90, 'w': 728}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 44, 'h': 600, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.15, 'adm': '
test content 3
', 'auid': 43, 'h': 90, 'w': 728}], 'seat': '1'}, {'bid': [{'price': 0, 'auid': 45, 'h': 250, 'w': 300}], 'seat': '1'}, - {'bid': [{'price': 0, 'adm': '
test content 4
', 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0, 'adm': '
test content 5
', 'h': 250, 'w': 300}], 'seat': '1'}, undefined, {'bid': [], 'seat': '1'}, {'seat': '1'}, @@ -250,26 +255,26 @@ describe('TrustXAdapter', function () { 'ttl': 360, }, { - 'requestId': '5703af74d0472a', - 'cpm': 1.15, - 'creativeId': 43, + 'requestId': '4dff80cc4ee346', + 'cpm': 0.5, + 'creativeId': 44, 'dealId': undefined, 'width': 300, - 'height': 250, - 'ad': '
test content 1
', + 'height': 600, + 'ad': '
test content 2
', 'bidderCode': 'trustx', 'currency': 'USD', 'netRevenue': true, 'ttl': 360, }, { - 'requestId': '4dff80cc4ee346', - 'cpm': 0.5, - 'creativeId': 44, + 'requestId': '5703af74d0472a', + 'cpm': 0.15, + 'creativeId': 43, 'dealId': undefined, 'width': 728, 'height': 90, - 'ad': '
test content 2
', + 'ad': '
test content 3
', 'bidderCode': 'trustx', 'currency': 'USD', 'netRevenue': true, @@ -277,7 +282,7 @@ describe('TrustXAdapter', function () { } ]; - const result = spec.interpretResponse({'body': {'seatbid': [responses[0], responses[1]]}}, request); + const result = spec.interpretResponse({'body': {'seatbid': responses.slice(0, 3)}}, request); expect(result).to.deep.equal(expectedResponse); }); @@ -318,8 +323,220 @@ describe('TrustXAdapter', function () { } ]; const request = spec.buildRequests(bidRequests); - const result = spec.interpretResponse({'body': {'seatbid': responses.slice(2)}}, request); + const result = spec.interpretResponse({'body': {'seatbid': responses.slice(3)}}, request); expect(result.length).to.equal(0); }); + + it('complicated case', function () { + const fullResponse = [ + {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 43, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 44, 'h': 600, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.15, 'adm': '
test content 3
', 'auid': 43, 'h': 90, 'w': 728}], 'seat': '1'}, + {'bid': [{'price': 0.15, 'adm': '
test content 4
', 'auid': 43, 'h': 600, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 5
', 'auid': 44, 'h': 600, 'w': 350}], 'seat': '1'}, + ]; + const bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '2164be6358b9', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '326bde7fbf69', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '44' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '4e111f1b66e4', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '26d6f897b516', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '44' + }, + 'adUnitCode': 'adunit-code-2', + 'sizes': [[728, 90]], + 'bidId': '1751cd90161', + 'bidderRequestId': '106efe3247', + 'auctionId': '32a1f276cb87cb8', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '2164be6358b9', + 'cpm': 1.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '4e111f1b66e4', + 'cpm': 0.5, + 'creativeId': 44, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'ad': '
test content 2
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '26d6f897b516', + 'cpm': 0.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 728, + 'height': 90, + 'ad': '
test content 3
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '326bde7fbf69', + 'cpm': 0.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'ad': '
test content 4
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '1751cd90161', + 'cpm': 0.5, + 'creativeId': 44, + 'dealId': undefined, + 'width': 350, + 'height': 600, + 'ad': '
test content 5
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': fullResponse}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('dublicate uids and sizes in one slot', function () { + const fullResponse = [ + {'bid': [{'price': 1.15, 'adm': '
test content 1
', 'auid': 43, 'h': 250, 'w': 300}], 'seat': '1'}, + {'bid': [{'price': 0.5, 'adm': '
test content 2
', 'auid': 43, 'h': 250, 'w': 300}], 'seat': '1'}, + ]; + const bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '5126e301f4be', + 'bidderRequestId': '171c5405a390', + 'auctionId': '35bcbc0f7e79c', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '57b2ebe70e16', + 'bidderRequestId': '171c5405a390', + 'auctionId': '35bcbc0f7e79c', + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '43' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '225fcd44b18c', + 'bidderRequestId': '171c5405a390', + 'auctionId': '35bcbc0f7e79c', + } + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '5126e301f4be', + 'cpm': 1.15, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 1
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + }, + { + 'requestId': '57b2ebe70e16', + 'cpm': 0.5, + 'creativeId': 43, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'ad': '
test content 2
', + 'bidderCode': 'trustx', + 'currency': 'USD', + 'netRevenue': true, + 'ttl': 360, + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': fullResponse}}, request); + expect(result).to.deep.equal(expectedResponse); + }); }); }); From f77c2ee787dfa3327b2398a785f5e0beaa8b491d Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Wed, 20 Feb 2019 14:50:56 +0300 Subject: [PATCH 15/20] Update TrustX Bid Adapter to ignore bids that sizes do not match the size of the request --- modules/trustxBidAdapter.js | 81 +++++++++------------- test/spec/modules/trustxBidAdapter_spec.js | 13 ---- 2 files changed, 33 insertions(+), 61 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 6a9ac3e6b4c..bd5f63e5302 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -116,7 +116,6 @@ export const spec = { interpretResponse: function(serverResponse, bidRequest) { serverResponse = serverResponse && serverResponse.body; const bidResponses = []; - const remainingServerBids = []; const bidsMap = bidRequest.bidsMap; const priceType = bidRequest.data.pt; @@ -129,12 +128,7 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses, remainingServerBids); - }); - } - if (remainingServerBids.length) { - remainingServerBids.forEach(serverBid => { - _addBidResponse(serverBid, bidsMap, priceType, bidResponses); + _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses); }); } if (errorMessage) utils.logError(errorMessage); @@ -161,56 +155,47 @@ function _getBidFromResponse(respItem) { return respItem && respItem.bid && respItem.bid[0]; } -function _addBidResponse(serverBid, bidsMap, priceType, bidResponses, remainingServerBids) { +function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { if (!serverBid) return; let errorMessage; if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); if (!serverBid.adm) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid); else { - const ignoreSizes = !remainingServerBids; const awaitingBids = bidsMap[serverBid.auid]; if (awaitingBids) { - let sizeId = `${serverBid.w}x${serverBid.h}`; - - if (!awaitingBids[sizeId]) { - if (ignoreSizes) { - sizeId = utils.getKeys(awaitingBids)[0]; - } else { - remainingServerBids.push(serverBid); - return; - } - } - - const slot = awaitingBids[sizeId][0]; - - const bid = slot.bids.shift(); - bidResponses.push({ - requestId: bid.bidId, // bid.bidderRequestId, - bidderCode: spec.code, - cpm: serverBid.price, - width: serverBid.w, - height: serverBid.h, - creativeId: serverBid.auid, // bid.bidId, - currency: 'USD', - netRevenue: priceType !== 'gross', - ttl: TIME_TO_LIVE, - ad: serverBid.adm, - dealId: serverBid.dealid - }); + const sizeId = `${serverBid.w}x${serverBid.h}`; + if (awaitingBids[sizeId]) { + const slot = awaitingBids[sizeId][0]; + + const bid = slot.bids.shift(); + bidResponses.push({ + requestId: bid.bidId, // bid.bidderRequestId, + bidderCode: spec.code, + cpm: serverBid.price, + width: serverBid.w, + height: serverBid.h, + creativeId: serverBid.auid, // bid.bidId, + currency: 'USD', + netRevenue: priceType !== 'gross', + ttl: TIME_TO_LIVE, + ad: serverBid.adm, + dealId: serverBid.dealid + }); - if (!slot.bids.length) { - slot.parents.forEach(({parent, key, uid}) => { - const index = parent[key].indexOf(slot); - if (index > -1) { - parent[key].splice(index, 1); - } - if (!parent[key].length) { - delete parent[key]; - if (!utils.getKeys(parent).length) { - delete bidsMap[uid]; + if (!slot.bids.length) { + slot.parents.forEach(({parent, key, uid}) => { + const index = parent[key].indexOf(slot); + if (index > -1) { + parent[key].splice(index, 1); } - } - }); + if (!parent[key].length) { + delete parent[key]; + if (!utils.getKeys(parent).length) { + delete bidsMap[uid]; + } + } + }); + } } } else { errorMessage = LOG_ERROR_MESS.noPlacementCode + serverBid.auid; diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 355fbbfa4bb..207d3a068ba 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -445,19 +445,6 @@ describe('TrustXAdapter', function () { 'currency': 'USD', 'netRevenue': true, 'ttl': 360, - }, - { - 'requestId': '1751cd90161', - 'cpm': 0.5, - 'creativeId': 44, - 'dealId': undefined, - 'width': 350, - 'height': 600, - 'ad': '
test content 5
', - 'bidderCode': 'trustx', - 'currency': 'USD', - 'netRevenue': true, - 'ttl': 360, } ]; From 549ea7a0b37f72e225d6f07459fb085f8e88ebdd Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Wed, 13 Mar 2019 18:43:42 +0300 Subject: [PATCH 16/20] Update TrustX Bid Adapter to support instream and outstream video --- modules/trustxBidAdapter.js | 60 +++++- modules/trustxBidAdapter.md | 13 ++ test/spec/modules/trustxBidAdapter_spec.js | 207 +++++++++++++++++++++ 3 files changed, 274 insertions(+), 6 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index bd5f63e5302..b0593e5c7d7 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -1,9 +1,14 @@ import * as utils from '../src/utils'; import {registerBidder} from '../src/adapters/bidderFactory'; +import { Renderer } from '../src/Renderer'; +import { VIDEO, BANNER } from '../src/mediaTypes'; + const BIDDER_CODE = 'trustx'; const ENDPOINT_URL = '//sofia.trustx.org/hb'; const TIME_TO_LIVE = 360; const ADAPTER_SYNC_URL = '//sofia.trustx.org/push_sync'; +const RENDERER_URL = '//cdn.adnxs.com/renderer/video/ANOutstreamVideo.js'; + const LOG_ERROR_MESS = { noAuid: 'Bid from response has no auid parameter - ', noAdm: 'Bid from response has no adm parameter - ', @@ -17,6 +22,7 @@ const LOG_ERROR_MESS = { }; export const spec = { code: BIDDER_CODE, + supportedMediaTypes: [ BANNER, VIDEO ], /** * Determines whether or not the given bid request is valid. * @@ -113,7 +119,7 @@ export const spec = { * @param {*} bidRequest * @return {Bid[]} An array of bids which were nested inside the server. */ - interpretResponse: function(serverResponse, bidRequest) { + interpretResponse: function(serverResponse, bidRequest, RendererConst = Renderer) { serverResponse = serverResponse && serverResponse.body; const bidResponses = []; const bidsMap = bidRequest.bidsMap; @@ -128,7 +134,7 @@ export const spec = { if (!errorMessage && serverResponse.seatbid) { serverResponse.seatbid.forEach(respItem => { - _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses); + _addBidResponse(_getBidFromResponse(respItem), bidsMap, priceType, bidResponses, RendererConst); }); } if (errorMessage) utils.logError(errorMessage); @@ -155,7 +161,7 @@ function _getBidFromResponse(respItem) { return respItem && respItem.bid && respItem.bid[0]; } -function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { +function _addBidResponse(serverBid, bidsMap, priceType, bidResponses, RendererConst) { if (!serverBid) return; let errorMessage; if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid); @@ -168,7 +174,7 @@ function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { const slot = awaitingBids[sizeId][0]; const bid = slot.bids.shift(); - bidResponses.push({ + const bidResponse = { requestId: bid.bidId, // bid.bidderRequestId, bidderCode: spec.code, cpm: serverBid.price, @@ -178,9 +184,26 @@ function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { currency: 'USD', netRevenue: priceType !== 'gross', ttl: TIME_TO_LIVE, - ad: serverBid.adm, dealId: serverBid.dealid - }); + }; + if (serverBid.content_type === 'video') { + bidResponse.vastXml = serverBid.adm; + bidResponse.mediaType = VIDEO; + bidResponse.adResponse = { + content: bidResponse.vastXml + }; + if (!bid.renderer && (!bid.mediaTypes || !bid.mediaTypes.video || bid.mediaTypes.video.context === 'outstream')) { + bidResponse.renderer = createRenderer(bidResponse, { + id: bid.bidId, + url: RENDERER_URL + }, RendererConst); + } + } else { + bidResponse.ad = serverBid.adm; + bidResponse.mediaType = BANNER; + } + + bidResponses.push(bidResponse); if (!slot.bids.length) { slot.parents.forEach(({parent, key, uid}) => { @@ -206,4 +229,29 @@ function _addBidResponse(serverBid, bidsMap, priceType, bidResponses) { } } +function outstreamRender (bid) { + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + targetId: bid.adUnitCode, + adResponse: bid.adResponse + }); + }); +} + +function createRenderer (bid, rendererParams, RendererConst) { + const rendererInst = RendererConst.install({ + id: rendererParams.id, + url: rendererParams.url, + loaded: false + }); + + try { + rendererInst.setRender(outstreamRender); + } catch (err) { + utils.logWarn('Prebid Error calling setRender on renderer', err); + } + + return rendererInst; +} + registerBidder(spec); diff --git a/modules/trustxBidAdapter.md b/modules/trustxBidAdapter.md index ca407b0c5e8..d6b660c6248 100755 --- a/modules/trustxBidAdapter.md +++ b/modules/trustxBidAdapter.md @@ -7,6 +7,7 @@ Maintainer: paul@trustx.org # Description Module that connects to TrustX demand source to fetch bids. +TrustX Bid Adapter supports Banner and Video (instream and outstream). # Test Parameters ``` @@ -35,6 +36,18 @@ Module that connects to TrustX demand source to fetch bids. } } ] + },{ + code: 'test-div', + sizes: [[640, 360]], + mediaTypes: { video: {} }, + bids: [ + { + bidder: "trustx", + params: { + uid: 7697 + } + } + ] } ]; ``` \ No newline at end of file diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 207d3a068ba..de0d1c8a530 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -194,6 +194,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 1
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, } @@ -251,6 +252,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 1
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, }, @@ -264,6 +266,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 2
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, }, @@ -277,6 +280,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 3
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, } @@ -404,6 +408,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 1
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, }, @@ -417,6 +422,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 2
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, }, @@ -430,6 +436,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 3
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, }, @@ -443,6 +450,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 4
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, } @@ -504,6 +512,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 1
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, }, @@ -517,6 +526,7 @@ describe('TrustXAdapter', function () { 'ad': '
test content 2
', 'bidderCode': 'trustx', 'currency': 'USD', + 'mediaType': 'banner', 'netRevenue': true, 'ttl': 360, } @@ -526,4 +536,201 @@ describe('TrustXAdapter', function () { expect(result).to.deep.equal(expectedResponse); }); }); + + it('should get correct video bid response', function () { + const bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '50' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '57dfefb80eca', + 'bidderRequestId': '20394420a762a2', + 'auctionId': '140132d07b031', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '51' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': 'e893c787c22dd', + 'bidderRequestId': '20394420a762a2', + 'auctionId': '140132d07b031', + 'mediaTypes': { + 'video': { + 'context': 'instream' + } + } + } + ]; + const response = [ + {'bid': [{'price': 1.15, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 50, content_type: 'video', w: 300, h: 600}], 'seat': '2'}, + {'bid': [{'price': 1.00, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 51, content_type: 'video'}], 'seat': '2'} + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': '57dfefb80eca', + 'cpm': 1.15, + 'creativeId': 50, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'bidderCode': 'trustx', + 'currency': 'USD', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + } + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': response}}, request); + expect(result).to.deep.equal(expectedResponse); + }); + + it('should have right renderer in the bid response', function () { + const spySetRenderer = sinon.spy(); + const stubRenderer = { + setRender: spySetRenderer + }; + const spyRendererInstall = sinon.spy(function() { return stubRenderer; }); + const stubRendererConst = { + install: spyRendererInstall + }; + const bidRequests = [ + { + 'bidder': 'trustx', + 'params': { + 'uid': '50' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': 'e6e65553fc8', + 'bidderRequestId': '1380f393215dc7', + 'auctionId': '10b8d2f3c697e3', + 'mediaTypes': { + 'video': { + 'context': 'outstream' + } + } + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '51' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': 'c8fdcb3f269f', + 'bidderRequestId': '1380f393215dc7', + 'auctionId': '10b8d2f3c697e3' + }, + { + 'bidder': 'trustx', + 'params': { + 'uid': '52' + }, + 'adUnitCode': 'adunit-code-1', + 'sizes': [[300, 250], [300, 600]], + 'bidId': '1de036c37685', + 'bidderRequestId': '1380f393215dc7', + 'auctionId': '10b8d2f3c697e3', + 'renderer': {} + } + ]; + const response = [ + {'bid': [{'price': 1.15, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 50, content_type: 'video', w: 300, h: 600}], 'seat': '2'}, + {'bid': [{'price': 1.00, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 51, content_type: 'video', w: 300, h: 250}], 'seat': '2'}, + {'bid': [{'price': 1.20, 'adm': '\n<\/Ad>\n<\/VAST>', 'auid': 52, content_type: 'video', w: 300, h: 250}], 'seat': '2'} + ]; + const request = spec.buildRequests(bidRequests); + const expectedResponse = [ + { + 'requestId': 'e6e65553fc8', + 'cpm': 1.15, + 'creativeId': 50, + 'dealId': undefined, + 'width': 300, + 'height': 600, + 'bidderCode': 'trustx', + 'currency': 'USD', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + }, + 'renderer': stubRenderer + }, + { + 'requestId': 'c8fdcb3f269f', + 'cpm': 1.00, + 'creativeId': 51, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'bidderCode': 'trustx', + 'currency': 'USD', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + }, + 'renderer': stubRenderer + }, + { + 'requestId': '1de036c37685', + 'cpm': 1.20, + 'creativeId': 52, + 'dealId': undefined, + 'width': 300, + 'height': 250, + 'bidderCode': 'trustx', + 'currency': 'USD', + 'mediaType': 'video', + 'netRevenue': true, + 'ttl': 360, + 'vastXml': '\n<\/Ad>\n<\/VAST>', + 'adResponse': { + 'content': '\n<\/Ad>\n<\/VAST>' + } + } + ]; + + const result = spec.interpretResponse({'body': {'seatbid': response}}, request, stubRendererConst); + + expect(spySetRenderer.calledTwice).to.equal(true); + expect(spySetRenderer.getCall(0).args[0]).to.be.a('function'); + expect(spySetRenderer.getCall(1).args[0]).to.be.a('function'); + + expect(spyRendererInstall.calledTwice).to.equal(true); + expect(spyRendererInstall.getCall(0).args[0]).to.deep.equal({ + id: 'e6e65553fc8', + url: '//cdn.adnxs.com/renderer/video/ANOutstreamVideo.js', + loaded: false + }); + expect(spyRendererInstall.getCall(1).args[0]).to.deep.equal({ + id: 'c8fdcb3f269f', + url: '//cdn.adnxs.com/renderer/video/ANOutstreamVideo.js', + loaded: false + }); + + expect(result).to.deep.equal(expectedResponse); + }); }); From 0bce98535e206a2cebfa45a3e92b1a7ef64b83c2 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Mon, 15 Apr 2019 18:55:10 +0300 Subject: [PATCH 17/20] Added wrapperType and wrapperVersion parameters in ad request for TrustX Bid Adapter --- modules/trustxBidAdapter.js | 4 +++- test/spec/modules/trustxBidAdapter_spec.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index b0593e5c7d7..1a501faf74b 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -88,7 +88,9 @@ export const spec = { pt: priceType, auids: auids.join(','), sizes: utils.getKeys(sizeMap).join(','), - r: reqId + r: reqId, + wrapperType: 'Prebid_js', + wrapperVersion: '$prebid.version$' }; if (bidderRequest) { diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index de0d1c8a530..a15ae94cfad 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -92,6 +92,8 @@ describe('TrustXAdapter', function () { expect(payload).to.have.property('auids', '43'); expect(payload).to.have.property('sizes', '300x250,300x600'); expect(payload).to.have.property('r', '22edbae2733bf6'); + expect(payload).to.have.property('wrapperType', 'Prebid_js'); + expect(payload).to.have.property('wrapperVersion', '$prebid.version$'); }); it('sizes must not be duplicated', function () { From c604ba04cf304d3e3a6348c75d2953c82472b467 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Fri, 5 Jul 2019 12:02:07 +0300 Subject: [PATCH 18/20] Update TrustX Bid Adapter to use refererInfo instead depricated function utils.getTopWindowUrl --- modules/trustxBidAdapter.js | 4 ++- test/spec/modules/trustxBidAdapter_spec.js | 33 ++++++++++++++-------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index 1a501faf74b..e9eb175671e 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -84,7 +84,6 @@ export const spec = { }); const payload = { - u: utils.getTopWindowUrl(), pt: priceType, auids: auids.join(','), sizes: utils.getKeys(sizeMap).join(','), @@ -94,6 +93,9 @@ export const spec = { }; if (bidderRequest) { + if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { + payload.u = encodeURIComponent(bidderRequest.refererInfo.referer); + } if (bidderRequest.timeout) { payload.wtimeout = bidderRequest.timeout; } diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index a15ae94cfad..0a4fddcb852 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -47,6 +47,14 @@ describe('TrustXAdapter', function () { }); return res; } + + const bidderRequest = { + refererInfo: { + referer: 'http://example.com' + } + }; + const encodedReferer = encodeURIComponent(bidderRequest.refererInfo.referer); + let bidRequests = [ { 'bidder': 'trustx', @@ -84,10 +92,10 @@ describe('TrustXAdapter', function () { ]; it('should attach valid params to the tag', function () { - const request = spec.buildRequests([bidRequests[0]]); + const request = spec.buildRequests([bidRequests[0]], bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('u', encodedReferer); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43'); expect(payload).to.have.property('sizes', '300x250,300x600'); @@ -97,10 +105,10 @@ describe('TrustXAdapter', function () { }); it('sizes must not be duplicated', function () { - const request = spec.buildRequests(bidRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('u', encodedReferer); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,43,45'); expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); @@ -109,10 +117,10 @@ describe('TrustXAdapter', function () { it('pt parameter must be "gross" if params.priceType === "gross"', function () { bidRequests[1].params.priceType = 'gross'; - const request = spec.buildRequests(bidRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('u', encodedReferer); expect(payload).to.have.property('pt', 'gross'); expect(payload).to.have.property('auids', '43,43,45'); expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); @@ -122,10 +130,10 @@ describe('TrustXAdapter', function () { it('pt parameter must be "net" or "gross"', function () { bidRequests[1].params.priceType = 'some'; - const request = spec.buildRequests(bidRequests); + const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u').that.is.a('string'); + expect(payload).to.have.property('u', encodedReferer); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,43,45'); expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); @@ -134,7 +142,8 @@ describe('TrustXAdapter', function () { }); it('if gdprConsent is present payload must have gdpr params', function () { - const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: true}}); + const bidderRequestWithGDPR = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: true}}, bidderRequest); + const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); @@ -142,7 +151,8 @@ describe('TrustXAdapter', function () { }); it('if gdprApplies is false gdpr_applies must be 0', function () { - const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA', gdprApplies: false}}); + const bidderRequestWithGDPR = Object.assign({gdprConsent: {consentString: 'AAA', gdprApplies: false}}, bidderRequest); + const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); @@ -150,7 +160,8 @@ describe('TrustXAdapter', function () { }); it('if gdprApplies is undefined gdpr_applies must be 1', function () { - const request = spec.buildRequests(bidRequests, {gdprConsent: {consentString: 'AAA'}}); + const bidderRequestWithGDPR = Object.assign({gdprConsent: {consentString: 'AAA'}}, bidderRequest); + const request = spec.buildRequests(bidRequests, bidderRequestWithGDPR); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); expect(payload).to.have.property('gdpr_consent', 'AAA'); From aedbb7c5b36e431fa70463d6a678cde271c5ca16 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 30 Jul 2019 13:37:21 +0300 Subject: [PATCH 19/20] HOTFIX for referrer encodind in TrustX Bid Adapter --- modules/trustxBidAdapter.js | 2 +- test/spec/modules/trustxBidAdapter_spec.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/trustxBidAdapter.js b/modules/trustxBidAdapter.js index e9eb175671e..aecb6aba8af 100644 --- a/modules/trustxBidAdapter.js +++ b/modules/trustxBidAdapter.js @@ -94,7 +94,7 @@ export const spec = { if (bidderRequest) { if (bidderRequest.refererInfo && bidderRequest.refererInfo.referer) { - payload.u = encodeURIComponent(bidderRequest.refererInfo.referer); + payload.u = bidderRequest.refererInfo.referer; } if (bidderRequest.timeout) { payload.wtimeout = bidderRequest.timeout; diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index 0a4fddcb852..b8cf2a2335d 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -50,10 +50,10 @@ describe('TrustXAdapter', function () { const bidderRequest = { refererInfo: { - referer: 'http://example.com' + referer: encodeURIComponent('http://example.com') } }; - const encodedReferer = encodeURIComponent(bidderRequest.refererInfo.referer); + const encodedReferer = bidderRequest.refererInfo.referer; let bidRequests = [ { From 9a6110d33e767c4fc507563f5cc109bc8a8b6b14 Mon Sep 17 00:00:00 2001 From: Paul Wyrembak Date: Tue, 30 Jul 2019 14:17:00 +0300 Subject: [PATCH 20/20] Fix test for TrustX Bid Adapter --- test/spec/modules/trustxBidAdapter_spec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/spec/modules/trustxBidAdapter_spec.js b/test/spec/modules/trustxBidAdapter_spec.js index b8cf2a2335d..f99831eeca1 100644 --- a/test/spec/modules/trustxBidAdapter_spec.js +++ b/test/spec/modules/trustxBidAdapter_spec.js @@ -50,10 +50,10 @@ describe('TrustXAdapter', function () { const bidderRequest = { refererInfo: { - referer: encodeURIComponent('http://example.com') + referer: 'http://example.com' } }; - const encodedReferer = bidderRequest.refererInfo.referer; + const referrer = bidderRequest.refererInfo.referer; let bidRequests = [ { @@ -95,7 +95,7 @@ describe('TrustXAdapter', function () { const request = spec.buildRequests([bidRequests[0]], bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u', encodedReferer); + expect(payload).to.have.property('u', referrer); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43'); expect(payload).to.have.property('sizes', '300x250,300x600'); @@ -108,7 +108,7 @@ describe('TrustXAdapter', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u', encodedReferer); + expect(payload).to.have.property('u', referrer); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,43,45'); expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); @@ -120,7 +120,7 @@ describe('TrustXAdapter', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u', encodedReferer); + expect(payload).to.have.property('u', referrer); expect(payload).to.have.property('pt', 'gross'); expect(payload).to.have.property('auids', '43,43,45'); expect(payload).to.have.property('sizes', '300x250,300x600,728x90'); @@ -133,7 +133,7 @@ describe('TrustXAdapter', function () { const request = spec.buildRequests(bidRequests, bidderRequest); expect(request.data).to.be.an('string'); const payload = parseRequest(request.data); - expect(payload).to.have.property('u', encodedReferer); + expect(payload).to.have.property('u', referrer); expect(payload).to.have.property('pt', 'net'); expect(payload).to.have.property('auids', '43,43,45'); expect(payload).to.have.property('sizes', '300x250,300x600,728x90');