From 53517d342c8b51309584aeccb64e89a3e65533e2 Mon Sep 17 00:00:00 2001 From: Rich Snapp Date: Fri, 18 Jan 2019 11:01:21 -0700 Subject: [PATCH] Bid caching flag (#3402) * remove comment that isn't relevant anymore. tll in targeting code * bid caching option added (default on) * fix typo in config name --- src/auctionManager.js | 3 --- src/config.js | 9 ++++++++ src/prebid.js | 1 + src/targeting.js | 13 ++++++++++- test/spec/unit/core/targeting_spec.js | 31 +++++++++++++++++++++++++++ test/spec/unit/pbjs_api_spec.js | 23 ++++++++++++++++++++ 6 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/auctionManager.js b/src/auctionManager.js index 67f402118e0..15567f24a88 100644 --- a/src/auctionManager.js +++ b/src/auctionManager.js @@ -57,9 +57,6 @@ export function newAuctionManager() { }; auctionManager.getBidsReceived = function() { - // As of now, an old bid which is not used in auction 1 can be used in auction n. - // To prevent this, bid.ttl (time to live) will be added to this logic and bid pool will also be added - // As of now none of the adapters are sending back bid.ttl return _auctions.map((auction) => { if (auction.getAuctionStatus() === AUCTION_COMPLETED) { return auction.getBidsReceived(); diff --git a/src/config.js b/src/config.js index 4e8f45d6805..d9892f5a746 100644 --- a/src/config.js +++ b/src/config.js @@ -18,6 +18,7 @@ const DEFAULT_BIDDER_TIMEOUT = 3000; const DEFAULT_PUBLISHER_DOMAIN = window.location.origin; const DEFAULT_ENABLE_SEND_ALL_BIDS = true; const DEFAULT_DISABLE_AJAX_TIMEOUT = false; +const DEFAULT_BID_CACHE = true; const DEFAULT_TIMEOUTBUFFER = 400; @@ -133,6 +134,14 @@ export function newConfig() { this._sendAllBids = val; }, + _useBidCache: DEFAULT_BID_CACHE, + get useBidCache() { + return this._useBidCache; + }, + set useBidCache(val) { + this._useBidCache = val; + }, + _bidderSequence: DEFAULT_BIDDER_SEQUENCE, get bidderSequence() { return this._bidderSequence; diff --git a/src/prebid.js b/src/prebid.js index a6b6e90b883..b87eace95f1 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -396,6 +396,7 @@ $$PREBID_GLOBAL$$.requestBids = createHook('asyncSeries', function ({ bidsBackHa } const auction = auctionManager.createAuction({adUnits, adUnitCodes, callback: bidsBackHandler, cbTimeout, labels}); + adUnitCodes.forEach(code => targeting.setLatestAuctionForAdUnit(code, auction.getAuctionId())); auction.callBids(); return auction; }); diff --git a/src/targeting.js b/src/targeting.js index 23b0ce630a1..e9d85c07e7d 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -53,6 +53,11 @@ export function getHighestCpmBidsFromBidPool(bidsReceived, highestCpmCallback) { export function newTargeting(auctionManager) { let targeting = {}; + let latestAuctionForAdUnit = {}; + + targeting.setLatestAuctionForAdUnit = function(adUnitCode, auctionId) { + latestAuctionForAdUnit[adUnitCode] = auctionId; + }; targeting.resetPresetTargeting = function(adUnitCode) { if (isGptPubadsDefined()) { @@ -191,7 +196,13 @@ export function newTargeting(auctionManager) { } function getBidsReceived() { - const bidsReceived = auctionManager.getBidsReceived() + let bidsReceived = auctionManager.getBidsReceived(); + + if (!config.getConfig('useBidCache')) { + bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId) + } + + bidsReceived = bidsReceived .filter(bid => bid.mediaType !== 'banner' || sizeSupported([bid.width, bid.height])) .filter(filters.isUnusedBid) .filter(filters.isBidNotExpired) diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index be5e1a93c2f..c7e1ad9e2e7 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -100,15 +100,22 @@ const bid3 = { describe('targeting tests', function () { let sandbox; let enableSendAllBids = false; + let useBidCache; beforeEach(function() { sandbox = sinon.sandbox.create(); + useBidCache = true; + // enableSendAllBids = false; + let origGetConfig = config.getConfig; sandbox.stub(config, 'getConfig').callsFake(function (key) { if (key === 'enableSendAllBids') { return enableSendAllBids; } + if (key === 'useBidCache') { + return useBidCache; + } return origGetConfig.apply(config, arguments); }); }); @@ -222,6 +229,30 @@ describe('targeting tests', function () { expect(bids[1].adId).to.equal('adid-2'); }); + it('should honor useBidCache', function() { + useBidCache = true; + + auctionManagerStub.returns([ + createBidReceived({bidder: 'appnexus', cpm: 7, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-0', adId: 'adid-1'}), + createBidReceived({bidder: 'appnexus', cpm: 5, auctionId: 2, responseTimestamp: 102, adUnitCode: 'code-0', adId: 'adid-2'}), + ]); + + let adUnitCodes = ['code-0']; + targetingInstance.setLatestAuctionForAdUnit('code-0', 2); + + let bids = targetingInstance.getWinningBids(adUnitCodes); + + expect(bids.length).to.equal(1); + expect(bids[0].adId).to.equal('adid-1'); + + useBidCache = false; + + bids = targetingInstance.getWinningBids(adUnitCodes); + + expect(bids.length).to.equal(1); + expect(bids[0].adId).to.equal('adid-2'); + }); + it('should not use rendered bid to get winning bid', function () { let bidsReceived = [ createBidReceived({bidder: 'appnexus', cpm: 8, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-0', adId: 'adid-1', status: 'rendered'}), diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 0edec65da0b..ff9dac55029 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -1361,6 +1361,29 @@ describe('Unit: Prebid Module', function () { .and.to.match(/[a-f0-9\-]{36}/i); }); + it('should notify targeting of the latest auction for each adUnit', function () { + let latestStub = sinon.stub(targeting, 'setLatestAuctionForAdUnit'); + let getAuctionStub = sinon.stub(auction, 'getAuctionId').returns(2); + + $$PREBID_GLOBAL$$.requestBids({ + adUnits: [ + { + code: 'test1', + bids: [] + }, { + code: 'test2', + bids: [] + } + ] + }); + + expect(latestStub.firstCall.calledWith('test1', 2)).to.equal(true); + expect(latestStub.secondCall.calledWith('test2', 2)).to.equal(true); + + latestStub.restore(); + getAuctionStub.restore(); + }); + it('should execute callback immediately if adUnits is empty', function () { var bidsBackHandler = function bidsBackHandlerCallback() {}; var spyExecuteCallback = sinon.spy(bidsBackHandler);