From 4ae7e1b92364f116fd1f3829582e8bf921526858 Mon Sep 17 00:00:00 2001 From: Robert Ray Martinez III Date: Tue, 2 Nov 2021 01:23:25 -0700 Subject: [PATCH] Prebid Server Bid Adapter: auctionId to $.id UUID to $.source.tid + mergeDeep extPrebid (#7585) * sourceTid * revert unique to tid cuz easier * deep merge extprebid * add tests for changes * .length duh * test was incorrect * no longer let this val be tid as it is not representitive * fix test --- modules/prebidServerBidAdapter/index.js | 6 ++--- src/adapterManager.js | 22 +++++++++++------- .../modules/prebidServerBidAdapter_spec.js | 21 +++++++++++++++-- test/spec/unit/core/adapterManager_spec.js | 23 +++++++++++++++---- 4 files changed, 55 insertions(+), 17 deletions(-) diff --git a/modules/prebidServerBidAdapter/index.js b/modules/prebidServerBidAdapter/index.js index e82fdfd02a9..b5cd0232187 100644 --- a/modules/prebidServerBidAdapter/index.js +++ b/modules/prebidServerBidAdapter/index.js @@ -731,7 +731,7 @@ const OPEN_RTB_PROTOCOL = { return; } const request = { - id: s2sBidRequest.tid, + id: firstBidRequest.auctionId, source: {tid: s2sBidRequest.tid}, tmax: s2sConfig.timeout, imp: imps, @@ -751,7 +751,7 @@ const OPEN_RTB_PROTOCOL = { } }; - // Sets pbjs version, can be overwritten below if channel exists in s2sConfig.extPrebid + // This is no longer overwritten unless name and version explicitly overwritten by extPrebid (mergeDeep) request.ext.prebid = Object.assign(request.ext.prebid, {channel: {name: 'pbjs', version: $$PREBID_GLOBAL$$.version}}) // set debug flag if in debug mode @@ -761,7 +761,7 @@ const OPEN_RTB_PROTOCOL = { // s2sConfig video.ext.prebid is passed through openrtb to PBS if (s2sConfig.extPrebid && typeof s2sConfig.extPrebid === 'object') { - request.ext.prebid = Object.assign(request.ext.prebid, s2sConfig.extPrebid); + request.ext.prebid = mergeDeep(request.ext.prebid, s2sConfig.extPrebid); } /** diff --git a/src/adapterManager.js b/src/adapterManager.js index 3ee0dff81ad..9a041543cf8 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -262,14 +262,16 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a } let adUnitsS2SCopy = getAdUnitCopyForPrebidServer(adUnits, s2sConfig); - let tid = generateUUID(); + + // uniquePbsTid is so we know which server to send which bids to during the callBids function + let uniquePbsTid = generateUUID(); adaptersServerSide.forEach(bidderCode => { const bidderRequestId = getUniqueIdentifierStr(); const bidderRequest = { bidderCode, auctionId, bidderRequestId, - tid, + uniquePbsTid, bids: hookedGetBids({bidderCode, auctionId, bidderRequestId, 'adUnits': deepClone(adUnitsS2SCopy), labels, src: CONSTANTS.S2S.SRC}), auctionStart: auctionStart, timeout: s2sConfig.timeout, @@ -350,7 +352,7 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request serverBidRequests.forEach(serverBidRequest => { var index = -1; for (var i = 0; i < uniqueServerBidRequests.length; ++i) { - if (serverBidRequest.tid === uniqueServerBidRequests[i].tid) { + if (serverBidRequest.uniquePbsTid === uniqueServerBidRequests[i].uniquePbsTid) { index = i; break; } @@ -360,7 +362,10 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request } }); - let counter = 0 + let counter = 0; + + // $.source.tid MUST be a unique UUID and also THE SAME between all PBS Requests for a given Auction + const sourceTid = generateUUID(); _s2sConfigs.forEach((s2sConfig) => { if (s2sConfig && uniqueServerBidRequests[counter] && includes(s2sConfig.bidders, uniqueServerBidRequests[counter].bidderCode)) { // s2s should get the same client side timeout as other client side requests. @@ -370,13 +375,13 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request } : undefined); let adaptersServerSide = s2sConfig.bidders; const s2sAdapter = _bidderRegistry[s2sConfig.adapter]; - let tid = uniqueServerBidRequests[counter].tid; + let uniquePbsTid = uniqueServerBidRequests[counter].uniquePbsTid; let adUnitsS2SCopy = uniqueServerBidRequests[counter].adUnitsS2SCopy; - let uniqueServerRequests = serverBidRequests.filter(serverBidRequest => serverBidRequest.tid === tid) + let uniqueServerRequests = serverBidRequests.filter(serverBidRequest => serverBidRequest.uniquePbsTid === uniquePbsTid); if (s2sAdapter) { - let s2sBidRequest = {tid, 'ad_units': adUnitsS2SCopy, s2sConfig}; + let s2sBidRequest = {tid: sourceTid, 'ad_units': adUnitsS2SCopy, s2sConfig}; if (s2sBidRequest.ad_units.length) { let doneCbs = uniqueServerRequests.map(bidRequest => { bidRequest.start = timestamp(); @@ -391,7 +396,8 @@ adapterManager.callBids = (adUnits, bidRequests, addBidResponse, doneCb, request // fire BID_REQUESTED event for each s2s bidRequest uniqueServerRequests.forEach(bidRequest => { - events.emit(CONSTANTS.EVENTS.BID_REQUESTED, bidRequest); + // add the new sourceTid + events.emit(CONSTANTS.EVENTS.BID_REQUESTED, {...bidRequest, tid: sourceTid}); }); // make bid requests diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js index a06d4dbcd68..be07e1dcc93 100644 --- a/test/spec/modules/prebidServerBidAdapter_spec.js +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -507,6 +507,17 @@ describe('S2S Adapter', function () { resetSyncedStatus(); }); + it('should set id to auction ID and source.tid to tid', function () { + config.setConfig({ s2sConfig: CONFIG }); + + adapter.callBids(OUTSTREAM_VIDEO_REQUEST, BID_REQUESTS, addBidResponse, done, ajax); + + const requestBid = JSON.parse(server.requests[0].requestBody); + expect(requestBid.id).to.equal('173afb6d132ba3'); + expect(requestBid.source).to.be.an('object'); + expect(requestBid.source.tid).to.equal('437fbbf5-33f5-487a-8e16-a7112903cfe5'); + }); + it('should block request if config did not define p1Consent URL in endpoint object config', function() { let badConfig = utils.deepClone(CONFIG); badConfig.endpoint = { noP1Consent: 'https://prebid.adnxs.com/pbs/v1/openrtb2/auction' }; @@ -1705,7 +1716,7 @@ describe('S2S Adapter', function () { expect(parsedRequestBody.ext.prebid.channel).to.deep.equal({name: 'pbjs', version: 'v$prebid.version$'}); }); - it('does not set pbjs version in request if channel does exist in s2sConfig', () => { + it('extPrebid is now mergedDeep -> should include default channel as well', () => { const s2sBidRequest = utils.deepClone(REQUEST); const bidRequests = utils.deepClone(BID_REQUESTS); @@ -1714,7 +1725,13 @@ describe('S2S Adapter', function () { adapter.callBids(s2sBidRequest, bidRequests, addBidResponse, done, ajax); const parsedRequestBody = JSON.parse(server.requests[0].requestBody); - expect(parsedRequestBody.ext.prebid.channel).to.deep.equal({test: 1}); + + // extPrebid is now deep merged with + expect(parsedRequestBody.ext.prebid.channel).to.deep.equal({ + name: 'pbjs', + test: 1, + version: 'v$prebid.version$' + }); }); it('passes first party data in request', () => { diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 30aa30c52e9..5b37f64688f 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -162,7 +162,7 @@ describe('adapterManager tests', function () { 'bidderCode': 'appnexus', 'auctionId': '1863e370099523', 'bidderRequestId': '2946b569352ef2', - 'tid': '34566b569352ef2', + 'uniquePbsTid': '34566b569352ef2', 'bids': [ { 'bidder': 'appnexus', @@ -479,7 +479,7 @@ describe('adapterManager tests', function () { 'bidderCode': 'appnexus', 'auctionId': '1863e370099523', 'bidderRequestId': '2946b569352ef2', - 'tid': '34566b569352ef2', + 'uniquePbsTid': '34566b569352ef2', 'timeout': 1000, 'src': 's2s', 'adUnitsS2SCopy': [ @@ -708,7 +708,7 @@ describe('adapterManager tests', function () { 'bidderCode': 'appnexus', 'auctionId': '1863e370099523', 'bidderRequestId': '2946b569352ef2', - 'tid': '34566b569352ef2', + 'uniquePbsTid': '34566b569352ef2', 'timeout': 1000, 'src': 's2s', 'adUnitsS2SCopy': [ @@ -844,7 +844,7 @@ describe('adapterManager tests', function () { 'bidderCode': 'pubmatic', 'auctionId': '1863e370099523', 'bidderRequestId': '2946b569352ef2', - 'tid': '2342342342lfi23', + 'uniquePbsTid': '2342342342lfi23', 'timeout': 1000, 'src': 's2s', 'adUnitsS2SCopy': [ @@ -1041,6 +1041,21 @@ describe('adapterManager tests', function () { sinon.assert.calledTwice(prebidServerAdapterMock.callBids); }); + it('should have one tid for ALL s2s bidRequests', function () { + let adUnits = utils.deepClone(getAdUnits()).map(adUnit => { + adUnit.bids = adUnit.bids.filter(bid => includes(['appnexus', 'pubmatic'], bid.bidder)); + return adUnit; + }) + let bidRequests = adapterManager.makeBidRequests(adUnits, 1111, 2222, 1000); + adapterManager.callBids(adUnits, bidRequests, () => {}, () => {}); + sinon.assert.calledTwice(prebidServerAdapterMock.callBids); + const firstBid = prebidServerAdapterMock.callBids.firstCall.args[0]; + const secondBid = prebidServerAdapterMock.callBids.secondCall.args[0]; + + // TIDS should be the same + expect(firstBid.tid).to.equal(secondBid.tid); + }); + it('should fire for simultaneous s2s and client requests', function () { adapterManager.bidderRegistry['adequant'] = adequantAdapterMock; let adUnits = utils.deepClone(getAdUnits()).map(adUnit => {