From d5daa05f37bfcc7bf9b170f8bda5fd44254f2c64 Mon Sep 17 00:00:00 2001 From: idettman Date: Fri, 22 May 2020 00:29:21 -0700 Subject: [PATCH 01/15] event updates --- modules/prebidServerBidAdapter/index.js | 96 ++++++++++-- modules/rubiconAnalyticsAdapter.js | 2 +- modules/rubiconBidAdapter.js | 3 + src/adapterManager.js | 4 +- .../modules/prebidServerBidAdapter_spec.js | 140 +++++++++++++++++- test/spec/modules/rubiconBidAdapter_spec.js | 1 + 6 files changed, 232 insertions(+), 14 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 9476b7a76a3..86fdfb2e719 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -366,10 +366,48 @@ let nativeEventTrackerMethodMap = { */ let bidIdMap = {}; let nativeAssetCache = {}; // store processed native params to preserve + +/** + * map wurl to auction id and adId for use in the BID_WON event + */ +`const wurlMap = {}; + +/** + * @param {string} auctionId + * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() + * @param {string} wurl events.winurl passed from prebidServer as wurl + */ +function addWurl(auctionId, adId, wurl) { + if (![auctionId, adId].some(utils.isEmptyStr)) { + wurlMap[`${auctionId}${adId}`] = wurl; + } +} + +/** + * @param {string} auctionId + * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() + */ +function removeWurl(auctionId, adId) { + if (![auctionId, adId].some(utils.isEmptyStr)) { + wurlMap[`${auctionId}${adId}`] = undefined; + } +} +/** + * @param {string} auctionId + * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() + * @return {(string|undefined)} events.winurl which was passed as wurl + */ +function getWurl(auctionId, adId) { + if (![auctionId, adId].some(utils.isEmptyStr)) { + return wurlMap[`${auctionId}${adId}`]; + } +} + const OPEN_RTB_PROTOCOL = { buildRequest(s2sBidRequest, bidRequests, adUnits) { let imps = []; let aliases = {}; + const firstBidRequest = bidRequests[0]; // transform ad unit into array of OpenRTB impression objects adUnits.forEach(adUnit => { @@ -515,14 +553,14 @@ const OPEN_RTB_PROTOCOL = { * @type {(string|undefined)} */ const pbAdSlot = utils.deepAccess(adUnit, 'fpd.context.pbAdSlot'); - if (typeof pbAdSlot === 'string' && pbAdSlot) { + if (!utils.isEmptyStr(pbAdSlot)) { utils.deepSetValue(imp, 'ext.context.data.adslot', pbAdSlot); } Object.assign(imp, mediaTypes); // if storedAuctionResponse has been set, pass SRID - const storedAuctionResponseBid = find(bidRequests[0].bids, bid => (bid.adUnitCode === adUnit.code && bid.storedAuctionResponse)); + const storedAuctionResponseBid = find(firstBidRequest.bids, bid => (bid.adUnitCode === adUnit.code && bid.storedAuctionResponse)); if (storedAuctionResponseBid) { utils.deepSetValue(imp, 'ext.prebid.storedauctionresponse.id', storedAuctionResponseBid.storedAuctionResponse.toString()); } @@ -544,6 +582,8 @@ const OPEN_RTB_PROTOCOL = { test: getConfig('debug') ? 1 : 0, ext: { prebid: { + // set ext.prebid.auctiontimestamp with the auction timestamp. Data type is long integer. + auctiontimestamp: firstBidRequest.auctionStart, targeting: { // includewinners is always true for openrtb includewinners: true, @@ -571,9 +611,9 @@ const OPEN_RTB_PROTOCOL = { request.cur = [adServerCur[0]]; } - _appendSiteAppDevice(request, bidRequests[0].refererInfo.referer); + _appendSiteAppDevice(request, firstBidRequest.refererInfo.referer); - const digiTrust = _getDigiTrustQueryParams(bidRequests && bidRequests[0]); + const digiTrust = _getDigiTrustQueryParams(firstBidRequest); if (digiTrust) { utils.deepSetValue(request, 'user.ext.digitrust', digiTrust); } @@ -596,19 +636,19 @@ const OPEN_RTB_PROTOCOL = { } if (bidRequests) { - if (bidRequests[0].gdprConsent) { + if (firstBidRequest.gdprConsent) { // note - gdprApplies & consentString may be undefined in certain use-cases for consentManagement module let gdprApplies; - if (typeof bidRequests[0].gdprConsent.gdprApplies === 'boolean') { - gdprApplies = bidRequests[0].gdprConsent.gdprApplies ? 1 : 0; + if (typeof firstBidRequest.gdprConsent.gdprApplies === 'boolean') { + gdprApplies = firstBidRequest.gdprConsent.gdprApplies ? 1 : 0; } utils.deepSetValue(request, 'regs.ext.gdpr', gdprApplies); - utils.deepSetValue(request, 'user.ext.consent', bidRequests[0].gdprConsent.consentString); + utils.deepSetValue(request, 'user.ext.consent', firstBidRequest.gdprConsent.consentString); } // US Privacy (CCPA) support - if (bidRequests[0].uspConsent) { - utils.deepSetValue(request, 'regs.ext.us_privacy', bidRequests[0].uspConsent); + if (firstBidRequest.uspConsent) { + utils.deepSetValue(request, 'regs.ext.us_privacy', firstBidRequest.uspConsent); } } @@ -658,10 +698,26 @@ const OPEN_RTB_PROTOCOL = { bidRequest.serverResponseTimeMs = serverResponseTimeMs; } - const extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); + // Look for seatbid[].bid[].ext.prebid.bidid and place it in the bidResponse object for use in analytics adapters as 'pbsBidId' + const bidId = utils.deepAccess(bid, 'ext.prebid.bidid'); + if (!utils.isEmptyStr(bidId)) { + bidObject.pbsBidId = bidId; + } + + // store wurl by auctionId and adId so it can be access from the BID_WON event handler + if (!utils.isEmptyStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { + addWurl(bidRequest.auctionId, bidObject.adId, utils.deepAccess(bid, 'ext.prebid.event.win')); + } + + let extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); // If ext.prebid.targeting exists, add it as a property value named 'adserverTargeting' if (extPrebidTargeting && typeof extPrebidTargeting === 'object') { + // If wurl exists, remove hb_winurl and hb_bidid targeting attributes + if (!utils.isEmptyStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { + extPrebidTargeting = utils.getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting) + .filter(i => (i.indexOf('hb_winurl') === -1 && i.indexOf('hb_bidid') === -1))); + } bidObject.adserverTargeting = extPrebidTargeting; } @@ -773,6 +829,21 @@ const OPEN_RTB_PROTOCOL = { } }; +/** + * BID_WON event to request the wurl + * @param {Bid} bid the winning bid object + */ +function bidWonHandler(bid) { + const wurl = getWurl(bid.auctionId, bid.adId); + if (!utils.isEmptyStr(wurl)) { + utils.logMessage(`Invoking image pixel for wurl on BID_WIN: "${wurl}"`); + utils.triggerPixel(wurl); + + // remove from wurl cache, since the wurl url was called + removeWurl(bid.auctionId, bid.adId); + } +} + /** * Bidder adapter for Prebid Server */ @@ -856,6 +927,9 @@ export function PrebidServer() { doClientSideSyncs(requestedBidders); } + // Listen for bid won to call wurl + events.on(EVENTS.BID_WON, bidWonHandler); + return Object.assign(this, { callBids: baseAdapter.callBids, setBidderCode: baseAdapter.setBidderCode, diff --git a/modules/rubiconAnalyticsAdapter.js b/modules/rubiconAnalyticsAdapter.js index 28c11ef8264..8117662ad81 100644 --- a/modules/rubiconAnalyticsAdapter.js +++ b/modules/rubiconAnalyticsAdapter.js @@ -87,7 +87,7 @@ function sendMessage(auctionId, bidWonId) { function formatBid(bid) { return utils.pick(bid, [ 'bidder', - 'bidId', bidId => utils.deepAccess(bid, 'bidResponse.seatBidId') || bidId, + 'bidId', bidId => utils.deepAccess(bid, 'bidResponse.pbsBidId') || utils.deepAccess(bid, 'bidResponse.seatBidId') || bidId, 'status', 'error', 'source', (source, bid) => { diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 3c17f609a37..f09bc51e2c5 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -339,6 +339,9 @@ export const spec = { utils.deepSetValue(data.imp[0], 'ext.prebid.storedauctionresponse.id', bidRequest.storedAuctionResponse.toString()); } + // set ext.prebid.auctiontimestamp using auction time + utils.deepSetValue(data.imp[0], 'ext.prebid.auctiontimestamp', bidderRequest.auctionStart); + return { method: 'POST', url: VIDEO_ENDPOINT, diff --git a/src/adapterManager.js b/src/adapterManager.js index 2108bb7a4f6..14f158f9f3c 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -69,7 +69,9 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, labels, src}) 'fpd', 'mediaType', 'renderer', - 'storedAuctionResponse' + 'storedAuctionResponse', + 'seatBidId', + 'pbsBidId' ])); let { diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 4744bef0ee3..fb545793504 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -261,7 +261,12 @@ const RESPONSE_OPENRTB = { 'w': 300, 'h': 250, 'ext': { - 'prebid': { 'type': 'banner' }, + 'prebid': { + 'type': 'banner', + 'event': { + 'win': 'http://wurl.org?id=333' + } + }, 'bidder': { 'appnexus': { 'brand_id': 1, @@ -304,6 +309,7 @@ const RESPONSE_OPENRTB_VIDEO = { ext: { prebid: { type: 'video', + bidid: '654321' }, bidder: { appnexus: { @@ -955,6 +961,7 @@ describe('S2S Adapter', function () { aliases: { brealtime: 'appnexus' }, + auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true @@ -989,6 +996,7 @@ describe('S2S Adapter', function () { aliases: { [alias]: 'appnexus' }, + auctiontimestamp: 1510852447530, targeting: { includebidderkeys: false, includewinners: true @@ -1240,6 +1248,7 @@ describe('S2S Adapter', function () { expect(requestBid).to.haveOwnProperty('ext'); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.equal({ + auctiontimestamp: 1510852447530, foo: 'bar', targeting: { includewinners: true, @@ -1271,6 +1280,7 @@ describe('S2S Adapter', function () { expect(requestBid).to.haveOwnProperty('ext'); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.equal({ + auctiontimestamp: 1510852447530, targeting: { includewinners: false, includebidderkeys: true @@ -1304,6 +1314,7 @@ describe('S2S Adapter', function () { expect(requestBid).to.haveOwnProperty('ext'); expect(requestBid.ext).to.haveOwnProperty('prebid'); expect(requestBid.ext.prebid).to.deep.equal({ + auctiontimestamp: 1510852447530, cache: { vastxml: 'vastxml-set-though-extPrebid.cache.vastXml' }, @@ -1768,6 +1779,80 @@ describe('S2S Adapter', function () { expect(response).to.have.property('vastUrl', 'https://prebid-cache.net/cache?uuid=a5ad3993'); }); + it('handles response cache from ext.prebid.targeting with wurl', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param' + }); + config.setConfig({ s2sConfig }); + const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); + cacheResponse.seatbid.forEach(item => { + item.bid[0].ext.prebid.event = { + win: 'https://wurl.com?a=1&b=2' + }; + item.bid[0].ext.prebid.targeting = { + hb_uuid: 'a5ad3993', + hb_cache_host: 'prebid-cache.net', + hb_cache_path: '/cache' + } + }); + server.respondWith(JSON.stringify(cacheResponse)); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.respond(); + + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + expect(response).to.have.property('pbsBidId', '654321'); + }); + + it('handles response cache from ext.prebid.targeting with wurl and removes invalid targeting', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param' + }); + config.setConfig({ s2sConfig }); + const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); + cacheResponse.seatbid.forEach(item => { + item.bid[0].ext.prebid.event = { + win: 'https://wurl.com?a=1&b=2' + }; + item.bid[0].ext.prebid.targeting = { + hb_uuid: 'a5ad3993', + hb_cache_host: 'prebid-cache.net', + hb_cache_path: '/cache', + hb_winurl: 'https://hbwinurl.com?a=1&b=2', + hb_bidid: '1234567890', + } + }); + server.respondWith(JSON.stringify(cacheResponse)); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.respond(); + + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + + expect(response.adserverTargeting).to.deep.equal({ + hb_uuid: 'a5ad3993', + hb_cache_host: 'prebid-cache.net', + hb_cache_path: '/cache' + }); + }); + + it('add request property pbsBidId with ext.prebid.bidid value', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebidserverurl/openrtb2/auction?querystring=param' + }); + config.setConfig({ s2sConfig }); + const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); + + server.respondWith(JSON.stringify(cacheResponse)); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.respond(); + + sinon.assert.calledOnce(addBidResponse); + const response = addBidResponse.firstCall.args[1]; + + expect(response).to.have.property('pbsBidId', '654321'); + }); + it('handles OpenRTB native responses', function () { sinon.stub(utils, 'getBidRequest').returns({ adUnitCode: 'div-gpt-ad-1460505748561-0', @@ -1796,6 +1881,59 @@ describe('S2S Adapter', function () { }); }); + describe('bid won events', function () { + let server; + let logWarnSpy; + let getUniqueIdentifierStrStub; + + beforeEach(function () { + server = sinon.fakeServer.create(); + sinon.stub(utils, 'triggerPixel'); + sinon.stub(utils, 'insertUserSyncIframe'); + sinon.stub(utils, 'logError'); + logWarnSpy = sinon.spy(utils, 'logWarn'); + getUniqueIdentifierStrStub = sinon.stub(utils, 'getUniqueIdentifierStr').callsFake(() => '101010101010'); + }); + + afterEach(function () { + server.restore(); + utils.triggerPixel.restore(); + utils.insertUserSyncIframe.restore(); + utils.logError.restore(); + logWarnSpy.restore(); + getUniqueIdentifierStrStub.restore(); + }); + + it('should call triggerPixel on bid won event when wurl is defined', function () { + const s2sConfig = Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }); + config.setConfig({ s2sConfig }); + + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); + clonedResponse.seatbid[0].bid[0].ext.prebid.event = { + win: 'https://wurl.org' + }; + server.respondWith(JSON.stringify(clonedResponse)); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.respond(); + + events.emit(CONSTANTS.EVENTS.BID_WON, { + auctionId: '173afb6d132ba3', + adId: '101010101010' + }); + + sinon.assert.calledOnce(addBidResponse); + + const response = addBidResponse.firstCall.args[1]; + expect(response).to.have.property('bidderCode', 'appnexus'); + expect(response).to.have.property('requestId', '123'); + + expect(utils.triggerPixel.called).to.be.true; + expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org'); + }); + }) + describe('s2sConfig', function () { let logErrorSpy; diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 99928b41d7b..11ed17df5f8 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -1461,6 +1461,7 @@ describe('the rubicon adapter', function () { expect(post.site.content.language).to.equal('en'); expect(imp.ext.rubicon.video.skip).to.equal(1); expect(imp.ext.rubicon.video.skipafter).to.equal(15); + expect(imp.ext.prebid.auctiontimestamp).to.equal(1472239426000); expect(post.user.ext.consent).to.equal('BOJ/P2HOJ/P2HABABMAAAAAZ+A=='); expect(post.user.ext.eids[0].source).to.equal('liveintent.com'); expect(post.user.ext.eids[0].uids[0].id).to.equal('0000-1111-2222-3333'); From 6919a265e8ab9a1c8b8f3b04f0a2d41cdf6e1e35 Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 09:33:27 -0700 Subject: [PATCH 02/15] removed char --- modules/prebidServerBidAdapter/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 86fdfb2e719..25d37f2c93e 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -370,7 +370,7 @@ let nativeAssetCache = {}; // store processed native params to preserve /** * map wurl to auction id and adId for use in the BID_WON event */ -`const wurlMap = {}; +const wurlMap = {}; /** * @param {string} auctionId From ac93962746f87deb55c3b132a2acd9e112554619 Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 09:54:58 -0700 Subject: [PATCH 03/15] add comment regarding removal of hb_wiurl and hb_bidid --- modules/prebidServerBidAdapter/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 25d37f2c93e..0345d37eb9a 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -712,6 +712,8 @@ const OPEN_RTB_PROTOCOL = { let extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); // If ext.prebid.targeting exists, add it as a property value named 'adserverTargeting' + // The removal of hb_winurl and hb_bidid targeting values is temporary + // once we get through the transition, this block will be removed. if (extPrebidTargeting && typeof extPrebidTargeting === 'object') { // If wurl exists, remove hb_winurl and hb_bidid targeting attributes if (!utils.isEmptyStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { From 4d2670c99a78d17cf2255538759d9c1c3abe60d6 Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 13:09:01 -0700 Subject: [PATCH 04/15] optimized tests --- .../modules/prebidServerBidAdapter_spec.js | 173 +++++++++--------- 1 file changed, 90 insertions(+), 83 deletions(-) diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index fb545793504..06b6189837c 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -438,6 +438,7 @@ describe('S2S Adapter', function () { done = sinon.spy(); beforeEach(function () { + config.resetConfig(); adapter = new Adapter(); BID_REQUESTS = [ { @@ -487,16 +488,15 @@ describe('S2S Adapter', function () { done.resetHistory(); }); + after(function () { + config.resetConfig(); + }); + describe('request function', function () { beforeEach(function () { - config.resetConfig(); resetSyncedStatus(); }); - afterEach(function () { - config.resetConfig(); - }); - it('should not add outstrean without renderer', function () { let ortb2Config = utils.deepClone(CONFIG); ortb2Config.endpoint = 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction'; @@ -515,7 +515,6 @@ describe('S2S Adapter', function () { describe('gdpr tests', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -614,7 +613,6 @@ describe('S2S Adapter', function () { describe('us_privacy (ccpa) consent data', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -659,7 +657,6 @@ describe('S2S Adapter', function () { describe('gdpr and us_privacy (ccpa) consent data', function () { afterEach(function () { - config.resetConfig(); $$PREBID_GLOBAL$$.requestBids.removeAll(); }); @@ -1470,67 +1467,52 @@ describe('S2S Adapter', function () { }); describe('response handler', function () { - let server; - let logWarnSpy; - beforeEach(function () { - server = sinon.fakeServer.create(); sinon.stub(utils, 'triggerPixel'); sinon.stub(utils, 'insertUserSyncIframe'); sinon.stub(utils, 'logError'); sinon.stub(events, 'emit'); - logWarnSpy = sinon.spy(utils, 'logWarn'); }); afterEach(function () { - server.restore(); utils.triggerPixel.restore(); utils.insertUserSyncIframe.restore(); utils.logError.restore(); events.emit.restore(); - logWarnSpy.restore(); }); // TODO: test dependent on pbjs_api_spec. Needs to be isolated it('does not call addBidResponse and calls done when ad unit not set', function () { - server.respondWith(JSON.stringify(RESPONSE_NO_BID_NO_UNIT)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_BID_NO_UNIT)); sinon.assert.notCalled(addBidResponse); sinon.assert.calledOnce(done); }); it('does not call addBidResponse and calls done when server requests cookie sync', function () { - server.respondWith(JSON.stringify(RESPONSE_NO_COOKIE)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_COOKIE)); sinon.assert.notCalled(addBidResponse); sinon.assert.calledOnce(done); }); it('does not call addBidResponse and calls done when ad unit is set', function () { - server.respondWith(JSON.stringify(RESPONSE_NO_BID_UNIT_SET)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_BID_UNIT_SET)); sinon.assert.notCalled(addBidResponse); sinon.assert.calledOnce(done); }); it('registers successful bids and calls done when there are less bids than requests', function () { - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(addBidResponse); sinon.assert.calledOnce(done); @@ -1544,11 +1526,9 @@ describe('S2S Adapter', function () { }); it('should have dealId in bidObject', function () { - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); const response = addBidResponse.firstCall.args[1]; expect(response).to.have.property('dealId', 'test-dealid'); }); @@ -1564,9 +1544,8 @@ describe('S2S Adapter', function () { cacheResponse.seatbid.forEach(item => { item.bid[0].ext.prebid.targeting = targetingTestData }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1578,9 +1557,8 @@ describe('S2S Adapter', function () { }); it('should set the bidResponse currency to whats in the PBS response', function() { - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(addBidResponse); const pbjsResponse = addBidResponse.firstCall.args[1]; expect(pbjsResponse).to.have.property('currency', 'EUR'); @@ -1589,9 +1567,8 @@ describe('S2S Adapter', function () { it('should set the default bidResponse currency when not specified in OpenRTB', function() { let modifiedResponse = utils.deepClone(RESPONSE_OPENRTB); modifiedResponse.cur = ''; - server.respondWith(JSON.stringify(modifiedResponse)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(modifiedResponse)); sinon.assert.calledOnce(addBidResponse); const pbjsResponse = addBidResponse.firstCall.args[1]; expect(pbjsResponse).to.have.property('currency', 'USD'); @@ -1608,11 +1585,9 @@ describe('S2S Adapter', function () { item.bid[0].ext.prebid.targeting = targetingTestData }); - server.respondWith(JSON.stringify(cacheResponse)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; expect(response).to.have.property('adserverTargeting').that.deep.equals({ 'foo': 'bar' }); @@ -1624,11 +1599,9 @@ describe('S2S Adapter', function () { }; sinon.stub(adapterManager, 'getBidAdapter').callsFake(() => rubiconAdapter); - server.respondWith(JSON.stringify(RESPONSE_NO_PBS_COOKIE)); - config.setConfig({ s2sConfig: CONFIG }); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_NO_PBS_COOKIE)); sinon.assert.calledOnce(rubiconAdapter.registerSyncs); @@ -1646,9 +1619,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(rubiconAdapter.registerSyncs); @@ -1661,9 +1633,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB)); sinon.assert.calledOnce(events.emit); const event = events.emit.firstCall.args; @@ -1686,9 +1657,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB_VIDEO)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB_VIDEO)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1714,9 +1684,9 @@ describe('S2S Adapter', function () { } } }); - server.respondWith(JSON.stringify(cacheResponse)); + adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1740,9 +1710,8 @@ describe('S2S Adapter', function () { cacheResponse.seatbid.forEach(item => { item.bid[0].ext.prebid.targeting = targetingTestData }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1767,9 +1736,8 @@ describe('S2S Adapter', function () { hb_cache_path: '/cache' } }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1795,9 +1763,8 @@ describe('S2S Adapter', function () { hb_cache_path: '/cache' } }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1822,9 +1789,8 @@ describe('S2S Adapter', function () { hb_bidid: '1234567890', } }); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1843,9 +1809,8 @@ describe('S2S Adapter', function () { config.setConfig({ s2sConfig }); const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); - server.respondWith(JSON.stringify(cacheResponse)); adapter.callBids(VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(cacheResponse)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1864,9 +1829,8 @@ describe('S2S Adapter', function () { }); config.setConfig({ s2sConfig }); - server.respondWith(JSON.stringify(RESPONSE_OPENRTB_NATIVE)); adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(RESPONSE_OPENRTB_NATIVE)); sinon.assert.calledOnce(addBidResponse); const response = addBidResponse.firstCall.args[1]; @@ -1882,55 +1846,90 @@ describe('S2S Adapter', function () { }); describe('bid won events', function () { - let server; - let logWarnSpy; - let getUniqueIdentifierStrStub; + let uniqueIdCount = 0; + + const staticUniqueIds = ['1000', '1001', '1002', '1003', '1004', '1005']; beforeEach(function () { - server = sinon.fakeServer.create(); sinon.stub(utils, 'triggerPixel'); sinon.stub(utils, 'insertUserSyncIframe'); sinon.stub(utils, 'logError'); - logWarnSpy = sinon.spy(utils, 'logWarn'); - getUniqueIdentifierStrStub = sinon.stub(utils, 'getUniqueIdentifierStr').callsFake(() => '101010101010'); + sinon.stub(utils, 'getUniqueIdentifierStr').callsFake(() => { + uniqueIdCount++; + return staticUniqueIds[uniqueIdCount - 1]; + }); + + config.setConfig({ + s2sConfig: Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }) + }); }); afterEach(function () { - server.restore(); utils.triggerPixel.restore(); utils.insertUserSyncIframe.restore(); utils.logError.restore(); - logWarnSpy.restore(); - getUniqueIdentifierStrStub.restore(); + utils.getUniqueIdentifierStr.restore(); + uniqueIdCount = 0; }); - it('should call triggerPixel on bid won event when wurl is defined', function () { - const s2sConfig = Object.assign({}, CONFIG, { - endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + it('should call triggerPixel if wurl is defined', function () { + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); + clonedResponse.seatbid[0].bid[0].ext.prebid.event = { + win: 'https://wurl.org' + }; + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); + + events.emit(CONSTANTS.EVENTS.BID_WON, { + auctionId: '173afb6d132ba3', + adId: '1000' }); - config.setConfig({ s2sConfig }); + sinon.assert.calledOnce(addBidResponse); + + expect(utils.triggerPixel.called).to.be.true; + expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org'); + }); + + it('should not call triggerPixel if the wurl cache does not contain the winning', function () { const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); clonedResponse.seatbid[0].bid[0].ext.prebid.event = { win: 'https://wurl.org' }; - server.respondWith(JSON.stringify(clonedResponse)); + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); - server.respond(); + server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); events.emit(CONSTANTS.EVENTS.BID_WON, { auctionId: '173afb6d132ba3', - adId: '101010101010' + adId: 'missingAdId' }); - sinon.assert.calledOnce(addBidResponse); + sinon.assert.calledOnce(addBidResponse) - const response = addBidResponse.firstCall.args[1]; - expect(response).to.have.property('bidderCode', 'appnexus'); - expect(response).to.have.property('requestId', '123'); + expect(utils.triggerPixel.called).to.be.true; + expect(utils.triggerPixel.getCall(0).args[0]).to.not.exist; + }); + + it('should not call triggerPixel if wurl is undefined', function () { + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); + clonedResponse.seatbid[0].bid[0].ext.prebid.event = undefined; + + adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); + + events.emit(CONSTANTS.EVENTS.BID_WON, { + auctionId: '173afb6d132ba3', + adId: '1000' + }); + + sinon.assert.calledOnce(addBidResponse) expect(utils.triggerPixel.called).to.be.true; - expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org'); + expect(utils.triggerPixel.getCall(0).args[0]).to.not.exist; }); }) @@ -2039,6 +2038,14 @@ describe('S2S Adapter', function () { }); it('should return proper defaults', function () { + const options = { + accountId: 'abc', + bidders: ['rubicon'], + defaultVendor: 'rubicon', + timeout: 750 + }; + + config.setConfig({ s2sConfig: options }); expect(config.getConfig('s2sConfig')).to.deep.equal({ 'accountId': 'abc', 'adapter': 'prebidServer', From d7ff87e317cdcfb788142f24838b346a8ce1d75d Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 13:44:42 -0700 Subject: [PATCH 05/15] fix for str validation --- modules/prebidServerBidAdapter/index.js | 14 +++++++------- test/spec/modules/prebidServerBidAdapter_spec.js | 9 ++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 0345d37eb9a..752f1ca6c16 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -378,7 +378,7 @@ const wurlMap = {}; * @param {string} wurl events.winurl passed from prebidServer as wurl */ function addWurl(auctionId, adId, wurl) { - if (![auctionId, adId].some(utils.isEmptyStr)) { + if ([auctionId, adId].every(utils.isStr)) { wurlMap[`${auctionId}${adId}`] = wurl; } } @@ -388,7 +388,7 @@ function addWurl(auctionId, adId, wurl) { * @param {string} adId generated value set to bidObject.adId by bidderFactory Bid() */ function removeWurl(auctionId, adId) { - if (![auctionId, adId].some(utils.isEmptyStr)) { + if ([auctionId, adId].every(utils.isStr)) { wurlMap[`${auctionId}${adId}`] = undefined; } } @@ -398,7 +398,7 @@ function removeWurl(auctionId, adId) { * @return {(string|undefined)} events.winurl which was passed as wurl */ function getWurl(auctionId, adId) { - if (![auctionId, adId].some(utils.isEmptyStr)) { + if ([auctionId, adId].every(utils.isStr)) { return wurlMap[`${auctionId}${adId}`]; } } @@ -700,12 +700,12 @@ const OPEN_RTB_PROTOCOL = { // Look for seatbid[].bid[].ext.prebid.bidid and place it in the bidResponse object for use in analytics adapters as 'pbsBidId' const bidId = utils.deepAccess(bid, 'ext.prebid.bidid'); - if (!utils.isEmptyStr(bidId)) { + if (utils.isStr(bidId)) { bidObject.pbsBidId = bidId; } // store wurl by auctionId and adId so it can be access from the BID_WON event handler - if (!utils.isEmptyStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { + if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { addWurl(bidRequest.auctionId, bidObject.adId, utils.deepAccess(bid, 'ext.prebid.event.win')); } @@ -714,7 +714,7 @@ const OPEN_RTB_PROTOCOL = { // If ext.prebid.targeting exists, add it as a property value named 'adserverTargeting' // The removal of hb_winurl and hb_bidid targeting values is temporary // once we get through the transition, this block will be removed. - if (extPrebidTargeting && typeof extPrebidTargeting === 'object') { + if (utils.isPlainObject(extPrebidTargeting)) { // If wurl exists, remove hb_winurl and hb_bidid targeting attributes if (!utils.isEmptyStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { extPrebidTargeting = utils.getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting) @@ -837,7 +837,7 @@ const OPEN_RTB_PROTOCOL = { */ function bidWonHandler(bid) { const wurl = getWurl(bid.auctionId, bid.adId); - if (!utils.isEmptyStr(wurl)) { + if (utils.isStr(wurl)) { utils.logMessage(`Invoking image pixel for wurl on BID_WIN: "${wurl}"`); utils.triggerPixel(wurl); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 06b6189837c..ddfdfb0c6a9 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1848,7 +1848,7 @@ describe('S2S Adapter', function () { describe('bid won events', function () { let uniqueIdCount = 0; - const staticUniqueIds = ['1000', '1001', '1002', '1003', '1004', '1005']; + const staticUniqueIds = ['1000', '1001', '1002', '1003']; beforeEach(function () { sinon.stub(utils, 'triggerPixel'); @@ -1889,7 +1889,6 @@ describe('S2S Adapter', function () { }); sinon.assert.calledOnce(addBidResponse); - expect(utils.triggerPixel.called).to.be.true; expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org'); }); @@ -1909,9 +1908,7 @@ describe('S2S Adapter', function () { }); sinon.assert.calledOnce(addBidResponse) - - expect(utils.triggerPixel.called).to.be.true; - expect(utils.triggerPixel.getCall(0).args[0]).to.not.exist; + expect(utils.triggerPixel.called).to.be.false; }); it('should not call triggerPixel if wurl is undefined', function () { @@ -1927,9 +1924,7 @@ describe('S2S Adapter', function () { }); sinon.assert.calledOnce(addBidResponse) - expect(utils.triggerPixel.called).to.be.true; - expect(utils.triggerPixel.getCall(0).args[0]).to.not.exist; }); }) From 205fefbf4435a2f4abe0dedf78cd8653f7e0eb3b Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 14:47:50 -0700 Subject: [PATCH 06/15] add test helper method to reset wurl map --- modules/prebidServerBidAdapter/index.js | 9 ++++ .../modules/prebidServerBidAdapter_spec.js | 47 ++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 752f1ca6c16..0477ea0be67 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -403,6 +403,15 @@ function getWurl(auctionId, adId) { } } +/** + * remove all wurl wurl items + */ +export function resetWurlMap() { + Object.keys(bidIdMap).forEach(function (key) { + wurlMap[key] = undefined; + }) +} + const OPEN_RTB_PROTOCOL = { buildRequest(s2sBidRequest, bidRequests, adUnits) { let imps = []; diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index ddfdfb0c6a9..556a9f9e33c 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { PrebidServer as Adapter, resetSyncedStatus } from 'modules/prebidServerBidAdapter/index.js'; +import { PrebidServer as Adapter, resetSyncedStatus, resetWurlMap } from 'modules/prebidServerBidAdapter/index.js'; import adapterManager from 'src/adapterManager.js'; import * as utils from 'src/utils.js'; import { ajax } from 'src/ajax.js'; @@ -1847,34 +1847,43 @@ describe('S2S Adapter', function () { describe('bid won events', function () { let uniqueIdCount = 0; - + let triggerPixelStub; const staticUniqueIds = ['1000', '1001', '1002', '1003']; + before(function () { + triggerPixelStub = sinon.stub(utils, 'triggerPixel'); + }); + beforeEach(function () { - sinon.stub(utils, 'triggerPixel'); + resetWurlMap(); sinon.stub(utils, 'insertUserSyncIframe'); sinon.stub(utils, 'logError'); sinon.stub(utils, 'getUniqueIdentifierStr').callsFake(() => { uniqueIdCount++; return staticUniqueIds[uniqueIdCount - 1]; }); - - config.setConfig({ - s2sConfig: Object.assign({}, CONFIG, { - endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' - }) - }); + triggerPixelStub.resetHistory(); }); afterEach(function () { - utils.triggerPixel.restore(); + utils.triggerPixel.resetHistory(); utils.insertUserSyncIframe.restore(); utils.logError.restore(); utils.getUniqueIdentifierStr.restore(); uniqueIdCount = 0; }); + after(function () { + triggerPixelStub.restore(); + }) + it('should call triggerPixel if wurl is defined', function () { + config.setConfig({ + s2sConfig: Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }) + }); + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); clonedResponse.seatbid[0].bid[0].ext.prebid.event = { win: 'https://wurl.org' @@ -1894,6 +1903,12 @@ describe('S2S Adapter', function () { }); it('should not call triggerPixel if the wurl cache does not contain the winning', function () { + config.setConfig({ + s2sConfig: Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }) + }); + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); clonedResponse.seatbid[0].bid[0].ext.prebid.event = { win: 'https://wurl.org' @@ -1912,19 +1927,25 @@ describe('S2S Adapter', function () { }); it('should not call triggerPixel if wurl is undefined', function () { + config.setConfig({ + s2sConfig: Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }) + }); + const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); - clonedResponse.seatbid[0].bid[0].ext.prebid.event = undefined; + clonedResponse.seatbid[0].bid[0].ext.prebid.event = {}; adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); events.emit(CONSTANTS.EVENTS.BID_WON, { auctionId: '173afb6d132ba3', - adId: '1000' + adId: '1060' }); sinon.assert.calledOnce(addBidResponse) - expect(utils.triggerPixel.called).to.be.true; + expect(utils.triggerPixel.called).to.be.false; }); }) From d782e3da545a6aabe4bc4de3ffe31f19689718f5 Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 16:37:41 -0700 Subject: [PATCH 07/15] update resetWurlMap --- modules/prebidServerBidAdapter/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 0477ea0be67..5e17e5bdccd 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -404,12 +404,12 @@ function getWurl(auctionId, adId) { } /** - * remove all wurl wurl items + * remove all cached wurls */ export function resetWurlMap() { - Object.keys(bidIdMap).forEach(function (key) { + Object.keys(wurlMap).forEach(key => { wurlMap[key] = undefined; - }) + }); } const OPEN_RTB_PROTOCOL = { From b2f0c350290a382d6d25ccbf6bb3b0a8b60f5ad4 Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 17:00:36 -0700 Subject: [PATCH 08/15] update test description --- test/spec/modules/prebidServerBidAdapter_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 556a9f9e33c..35115981769 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1902,7 +1902,7 @@ describe('S2S Adapter', function () { expect(utils.triggerPixel.getCall(0).args[0]).to.include('https://wurl.org'); }); - it('should not call triggerPixel if the wurl cache does not contain the winning', function () { + it('should not call triggerPixel if the wurl cache does not contain the winning bid', function () { config.setConfig({ s2sConfig: Object.assign({}, CONFIG, { endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' From dc52d9597334cde43aef362e0db742ab6d9dd2a9 Mon Sep 17 00:00:00 2001 From: idettman Date: Wed, 27 May 2020 17:10:19 -0700 Subject: [PATCH 09/15] optimized calls to setConfig in tests --- .../modules/prebidServerBidAdapter_spec.js | 26 +++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 35115981769..849fdb7958d 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1863,6 +1863,12 @@ describe('S2S Adapter', function () { return staticUniqueIds[uniqueIdCount - 1]; }); triggerPixelStub.resetHistory(); + + config.setConfig({ + s2sConfig: Object.assign({}, CONFIG, { + endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' + }) + }); }); afterEach(function () { @@ -1875,15 +1881,9 @@ describe('S2S Adapter', function () { after(function () { triggerPixelStub.restore(); - }) + }); it('should call triggerPixel if wurl is defined', function () { - config.setConfig({ - s2sConfig: Object.assign({}, CONFIG, { - endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' - }) - }); - const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); clonedResponse.seatbid[0].bid[0].ext.prebid.event = { win: 'https://wurl.org' @@ -1903,12 +1903,6 @@ describe('S2S Adapter', function () { }); it('should not call triggerPixel if the wurl cache does not contain the winning bid', function () { - config.setConfig({ - s2sConfig: Object.assign({}, CONFIG, { - endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' - }) - }); - const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); clonedResponse.seatbid[0].bid[0].ext.prebid.event = { win: 'https://wurl.org' @@ -1927,12 +1921,6 @@ describe('S2S Adapter', function () { }); it('should not call triggerPixel if wurl is undefined', function () { - config.setConfig({ - s2sConfig: Object.assign({}, CONFIG, { - endpoint: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' - }) - }); - const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); clonedResponse.seatbid[0].bid[0].ext.prebid.event = {}; From 2422e1da49a4f6a83d4ab92e724ab53abd78d0d4 Mon Sep 17 00:00:00 2001 From: idettman Date: Thu, 28 May 2020 23:28:12 -0700 Subject: [PATCH 10/15] add timestamp to videoCache cached bid --- modules/prebidServerBidAdapter/index.js | 2 +- src/auction.js | 2 +- src/videoCache.js | 12 ++- test/spec/videoCache_spec.js | 99 +++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 5 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 5e17e5bdccd..678e47c08de 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -713,7 +713,7 @@ const OPEN_RTB_PROTOCOL = { bidObject.pbsBidId = bidId; } - // store wurl by auctionId and adId so it can be access from the BID_WON event handler + // store wurl by auctionId and adId so it can be accessed from the BID_WON event handler if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { addWurl(bidRequest.auctionId, bidObject.adId, utils.deepAccess(bid, 'ext.prebid.event.win')); } diff --git a/src/auction.js b/src/auction.js index 6166e59bbf0..b82b4752479 100644 --- a/src/auction.js +++ b/src/auction.js @@ -483,7 +483,7 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon afterBidAdded(); } } - }); + }, bidderRequest); }, 'callPrebidCache'); // Postprocess the bids so that all the universal properties exist, no matter which bidder they came from. diff --git a/src/videoCache.js b/src/videoCache.js index 46bf74ee553..3838b1bc0d5 100644 --- a/src/videoCache.js +++ b/src/videoCache.js @@ -10,7 +10,8 @@ */ import { ajax } from './ajax.js'; -import { config } from '../src/config.js'; +import * as utils from './utils.js'; +import { config } from './config.js'; /** * @typedef {object} CacheableUrlBid @@ -70,6 +71,10 @@ function toStorageRequest(bid) { if (config.getConfig('cache.vasttrack')) { payload.bidder = bid.bidder; payload.bidid = bid.requestId; + // function has a thisArg set to bidderRequest for accessing the auctionStart + if (utils.isPlainObject(this) && this.hasOwnProperty('auctionStart')) { + payload.timestamp = this.auctionStart; + } } if (typeof bid.customCacheKey === 'string' && bid.customCacheKey !== '') { @@ -126,11 +131,12 @@ function shimStorageCallback(done) { * * @param {CacheableBid[]} bids A list of bid objects which should be cached. * @param {videoCacheStoreCallback} [done] An optional callback which should be executed after + * @param {BidderRequest} [bidderRequest] * the data has been stored in the cache. */ -export function store(bids, done) { +export function store(bids, done, bidderRequest) { const requestData = { - puts: bids.map(toStorageRequest) + puts: bids.map(toStorageRequest, bidderRequest) }; ajax(config.getConfig('cache.url'), shimStorageCallback(done), JSON.stringify(requestData), { diff --git a/test/spec/videoCache_spec.js b/test/spec/videoCache_spec.js index 7d706947416..6bb214af8a0 100644 --- a/test/spec/videoCache_spec.js +++ b/test/spec/videoCache_spec.js @@ -5,6 +5,50 @@ import { server } from 'test/mocks/xhr.js'; const should = chai.should(); +function getMockBid(bidder, auctionId, bidderRequestId) { + return { + 'bidder': bidder, + 'params': { + 'placementId': '10433394', + 'member': 123, + 'keywords': { + 'foo': ['bar', 'baz'], + 'fizz': ['buzz'] + } + }, + 'bid_id': '12345abc', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'mediaTypes': { + 'banner': { + 'sizes': [[300, 250]] + } + }, + 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', + 'sizes': [300, 250], + 'bidId': '123', + 'bidderRequestId': bidderRequestId, + 'auctionId': auctionId, + 'storedAuctionResponse': 11111 + }; +} + +function getMockBidRequest(bidder = 'appnexus', auctionId = '173afb6d132ba3', bidderRequestId = '3d1063078dfcc8') { + return { + 'bidderCode': bidder, + 'auctionId': auctionId, + 'bidderRequestId': bidderRequestId, + 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', + 'bids': [getMockBid(bidder, auctionId, bidderRequestId)], + 'auctionStart': 1510852447530, + 'timeout': 5000, + 'src': 's2s', + 'doneCbCallCount': 0, + 'refererInfo': { + 'referer': 'http://mytestpage.com' + } + } +} + describe('The video cache', function () { function assertError(callbackSpy) { callbackSpy.calledOnce.should.equal(true); @@ -192,6 +236,61 @@ describe('The video cache', function () { JSON.parse(request.requestBody).should.deep.equal(payload); }); + it('should include additional params in request payload should config.cache.vasttrack be true and bidderRequest argument was defined', () => { + config.setConfig({ + cache: { + url: 'https://prebid.adnxs.com/pbc/v1/cache', + vasttrack: true + } + }); + + const customKey1 = 'vasttrack_123'; + const customKey2 = 'vasttrack_abc'; + const vastXml1 = 'testvast1'; + const vastXml2 = 'testvast2'; + + const bids = [{ + vastXml: vastXml1, + ttl: 25, + customCacheKey: customKey1, + requestId: '12345abc', + bidder: 'appnexus' + }, { + vastXml: vastXml2, + ttl: 25, + customCacheKey: customKey2, + requestId: 'cba54321', + bidder: 'rubicon' + }]; + + store(bids, function () { }, getMockBidRequest()); + const request = server.requests[0]; + request.method.should.equal('POST'); + request.url.should.equal('https://prebid.adnxs.com/pbc/v1/cache'); + request.requestHeaders['Content-Type'].should.equal('text/plain;charset=utf-8'); + let payload = { + puts: [{ + type: 'xml', + value: vastXml1, + ttlseconds: 25, + key: customKey1, + bidid: '12345abc', + bidder: 'appnexus', + timestamp: 1510852447530 + }, { + type: 'xml', + value: vastXml2, + ttlseconds: 25, + key: customKey2, + bidid: 'cba54321', + bidder: 'rubicon', + timestamp: 1510852447530 + }] + }; + + JSON.parse(request.requestBody).should.deep.equal(payload); + }); + function assertRequestMade(bid, expectedValue) { store([bid], function () { }); From 69f37ebf3de574e0b9fe50789b38989a3fbb1728 Mon Sep 17 00:00:00 2001 From: idettman Date: Thu, 28 May 2020 23:49:33 -0700 Subject: [PATCH 11/15] revert unintended change to adapterManager.js --- src/adapterManager.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/adapterManager.js b/src/adapterManager.js index 14f158f9f3c..2108bb7a4f6 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -69,9 +69,7 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, labels, src}) 'fpd', 'mediaType', 'renderer', - 'storedAuctionResponse', - 'seatBidId', - 'pbsBidId' + 'storedAuctionResponse' ])); let { From b2ecb74e66ae792cb03dfc46d379d9d8e8acabda Mon Sep 17 00:00:00 2001 From: idettman Date: Thu, 28 May 2020 23:52:31 -0700 Subject: [PATCH 12/15] update imports ordering for cleaner diff --- src/videoCache.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/videoCache.js b/src/videoCache.js index 3838b1bc0d5..9f1fd7e4117 100644 --- a/src/videoCache.js +++ b/src/videoCache.js @@ -10,8 +10,8 @@ */ import { ajax } from './ajax.js'; -import * as utils from './utils.js'; import { config } from './config.js'; +import * as utils from './utils.js'; /** * @typedef {object} CacheableUrlBid From d7fdd68f3faa64c7aafc9d82fffeb80acd6d9808 Mon Sep 17 00:00:00 2001 From: idettman Date: Fri, 29 May 2020 00:24:08 -0700 Subject: [PATCH 13/15] update string validation to use isStr --- modules/prebidServerBidAdapter/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 678e47c08de..6b127f5cea8 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -562,7 +562,7 @@ const OPEN_RTB_PROTOCOL = { * @type {(string|undefined)} */ const pbAdSlot = utils.deepAccess(adUnit, 'fpd.context.pbAdSlot'); - if (!utils.isEmptyStr(pbAdSlot)) { + if (typeof pbAdSlot === 'string' && pbAdSlot) { utils.deepSetValue(imp, 'ext.context.data.adslot', pbAdSlot); } @@ -725,7 +725,7 @@ const OPEN_RTB_PROTOCOL = { // once we get through the transition, this block will be removed. if (utils.isPlainObject(extPrebidTargeting)) { // If wurl exists, remove hb_winurl and hb_bidid targeting attributes - if (!utils.isEmptyStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { + if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { extPrebidTargeting = utils.getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting) .filter(i => (i.indexOf('hb_winurl') === -1 && i.indexOf('hb_bidid') === -1))); } From 666e07fa9914a0c2e9180506d7128b8669fd724b Mon Sep 17 00:00:00 2001 From: idettman Date: Mon, 1 Jun 2020 10:25:38 -0700 Subject: [PATCH 14/15] fix rename event to plural form --- modules/prebidServerBidAdapter/index.js | 6 +++--- test/spec/modules/prebidServerBidAdapter_spec.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 6b127f5cea8..4a56dead9a3 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -714,8 +714,8 @@ const OPEN_RTB_PROTOCOL = { } // store wurl by auctionId and adId so it can be accessed from the BID_WON event handler - if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { - addWurl(bidRequest.auctionId, bidObject.adId, utils.deepAccess(bid, 'ext.prebid.event.win')); + if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.events.win'))) { + addWurl(bidRequest.auctionId, bidObject.adId, utils.deepAccess(bid, 'ext.prebid.events.win')); } let extPrebidTargeting = utils.deepAccess(bid, 'ext.prebid.targeting'); @@ -725,7 +725,7 @@ const OPEN_RTB_PROTOCOL = { // once we get through the transition, this block will be removed. if (utils.isPlainObject(extPrebidTargeting)) { // If wurl exists, remove hb_winurl and hb_bidid targeting attributes - if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.event.win'))) { + if (utils.isStr(utils.deepAccess(bid, 'ext.prebid.events.win'))) { extPrebidTargeting = utils.getDefinedParams(extPrebidTargeting, Object.keys(extPrebidTargeting) .filter(i => (i.indexOf('hb_winurl') === -1 && i.indexOf('hb_bidid') === -1))); } diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 849fdb7958d..6cdd5daeaf6 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1778,7 +1778,7 @@ describe('S2S Adapter', function () { config.setConfig({ s2sConfig }); const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); cacheResponse.seatbid.forEach(item => { - item.bid[0].ext.prebid.event = { + item.bid[0].ext.prebid.events = { win: 'https://wurl.com?a=1&b=2' }; item.bid[0].ext.prebid.targeting = { @@ -1885,7 +1885,7 @@ describe('S2S Adapter', function () { it('should call triggerPixel if wurl is defined', function () { const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); - clonedResponse.seatbid[0].bid[0].ext.prebid.event = { + clonedResponse.seatbid[0].bid[0].ext.prebid.events = { win: 'https://wurl.org' }; @@ -1904,7 +1904,7 @@ describe('S2S Adapter', function () { it('should not call triggerPixel if the wurl cache does not contain the winning bid', function () { const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); - clonedResponse.seatbid[0].bid[0].ext.prebid.event = { + clonedResponse.seatbid[0].bid[0].ext.prebid.events = { win: 'https://wurl.org' }; @@ -1922,7 +1922,7 @@ describe('S2S Adapter', function () { it('should not call triggerPixel if wurl is undefined', function () { const clonedResponse = utils.deepClone(RESPONSE_OPENRTB); - clonedResponse.seatbid[0].bid[0].ext.prebid.event = {}; + clonedResponse.seatbid[0].bid[0].ext.prebid.events = {}; adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax); server.requests[0].respond(200, {}, JSON.stringify(clonedResponse)); From 7e0ac1c44cd7148ae97c28122317fe3b12b06ade Mon Sep 17 00:00:00 2001 From: idettman Date: Mon, 1 Jun 2020 10:27:50 -0700 Subject: [PATCH 15/15] update event to events in tests --- modules/prebidServerBidAdapter/index.js | 6 ++---- test/spec/modules/prebidServerBidAdapter_spec.js | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index 4a56dead9a3..5794dc86f3a 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -370,7 +370,7 @@ let nativeAssetCache = {}; // store processed native params to preserve /** * map wurl to auction id and adId for use in the BID_WON event */ -const wurlMap = {}; +let wurlMap = {}; /** * @param {string} auctionId @@ -407,9 +407,7 @@ function getWurl(auctionId, adId) { * remove all cached wurls */ export function resetWurlMap() { - Object.keys(wurlMap).forEach(key => { - wurlMap[key] = undefined; - }); + wurlMap = {}; } const OPEN_RTB_PROTOCOL = { diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index 6cdd5daeaf6..f66c87582f5 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -1754,7 +1754,7 @@ describe('S2S Adapter', function () { config.setConfig({ s2sConfig }); const cacheResponse = utils.deepClone(RESPONSE_OPENRTB_VIDEO); cacheResponse.seatbid.forEach(item => { - item.bid[0].ext.prebid.event = { + item.bid[0].ext.prebid.events = { win: 'https://wurl.com?a=1&b=2' }; item.bid[0].ext.prebid.targeting = {