Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prebid Targeting: add a configurable "bidCacheFilterFunction" (#7993) #7997

Merged
merged 1 commit into from
Feb 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/targeting.js
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,15 @@ export function newTargeting(auctionManager) {
let bidsReceived = auctionManager.getBidsReceived();

if (!config.getConfig('useBidCache')) {
// don't use bid cache (i.e. filter out bids not in the latest auction)
bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId)
} else {
// if custom bid cache filter function exists, run for each bid from
// previous auctions. If it returns true, include bid in bid pool
const filterFunction = config.getConfig('bidCacheFilterFunction');
if (typeof filterFunction === 'function') {
bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId || !!filterFunction(bid))
}
}

bidsReceived = bidsReceived
Expand Down
3 changes: 2 additions & 1 deletion test/fixtures/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -1231,7 +1231,7 @@ export function getCurrencyRates() {
};
}

export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, adUnitCode, adId, status, ttl, requestId}) {
export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, adUnitCode, adId, status, ttl, requestId, mediaType}) {
let bid = {
'bidderCode': bidder,
'width': '300',
Expand Down Expand Up @@ -1259,6 +1259,7 @@ export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, ad
'hb_pb': cpm,
'foobar': '300x250'
}),
'mediaType': mediaType,
'netRevenue': true,
'currency': 'USD',
'ttl': (!ttl) ? 300 : ttl
Expand Down
93 changes: 93 additions & 0 deletions test/spec/unit/core/targeting_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ describe('targeting tests', function () {
let sandbox;
let enableSendAllBids = false;
let useBidCache;
let bidCacheFilterFunction;
let undef;

beforeEach(function() {
sandbox = sinon.sandbox.create();
Expand All @@ -241,12 +243,16 @@ describe('targeting tests', function () {
if (key === 'useBidCache') {
return useBidCache;
}
if (key === 'bidCacheFilterFunction') {
return bidCacheFilterFunction;
}
return origGetConfig.apply(config, arguments);
});
});

afterEach(function () {
sandbox.restore();
bidCacheFilterFunction = undef;
});

describe('getAllTargeting', function () {
Expand Down Expand Up @@ -785,6 +791,93 @@ describe('targeting tests', function () {
expect(bids[0].adId).to.equal('adid-2');
});

it('should use bidCacheFilterFunction', function() {
auctionManagerStub.returns([
createBidReceived({bidder: 'appnexus', cpm: 7, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-0', adId: 'adid-1', mediaType: 'banner'}),
createBidReceived({bidder: 'appnexus', cpm: 5, auctionId: 2, responseTimestamp: 102, adUnitCode: 'code-0', adId: 'adid-2', mediaType: 'banner'}),
createBidReceived({bidder: 'appnexus', cpm: 6, auctionId: 1, responseTimestamp: 101, adUnitCode: 'code-1', adId: 'adid-3', mediaType: 'banner'}),
createBidReceived({bidder: 'appnexus', cpm: 8, auctionId: 2, responseTimestamp: 103, adUnitCode: 'code-1', adId: 'adid-4', mediaType: 'banner'}),
createBidReceived({bidder: 'appnexus', cpm: 27, auctionId: 1, responseTimestamp: 100, adUnitCode: 'code-2', adId: 'adid-5', mediaType: 'video'}),
createBidReceived({bidder: 'appnexus', cpm: 25, auctionId: 2, responseTimestamp: 102, adUnitCode: 'code-2', adId: 'adid-6', mediaType: 'video'}),
createBidReceived({bidder: 'appnexus', cpm: 26, auctionId: 1, responseTimestamp: 101, adUnitCode: 'code-3', adId: 'adid-7', mediaType: 'video'}),
createBidReceived({bidder: 'appnexus', cpm: 28, auctionId: 2, responseTimestamp: 103, adUnitCode: 'code-3', adId: 'adid-8', mediaType: 'video'}),
]);

let adUnitCodes = ['code-0', 'code-1', 'code-2', 'code-3'];
targetingInstance.setLatestAuctionForAdUnit('code-0', 2);
targetingInstance.setLatestAuctionForAdUnit('code-1', 2);
targetingInstance.setLatestAuctionForAdUnit('code-2', 2);
targetingInstance.setLatestAuctionForAdUnit('code-3', 2);

// Bid Caching On, No Filter Function
useBidCache = true;
bidCacheFilterFunction = undef;
let bids = targetingInstance.getWinningBids(adUnitCodes);

expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-1');
expect(bids[1].adId).to.equal('adid-4');
expect(bids[2].adId).to.equal('adid-5');
expect(bids[3].adId).to.equal('adid-8');

// Bid Caching Off, No Filter Function
useBidCache = false;
bidCacheFilterFunction = undef;
bids = targetingInstance.getWinningBids(adUnitCodes);

expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-2');
expect(bids[1].adId).to.equal('adid-4');
expect(bids[2].adId).to.equal('adid-6');
expect(bids[3].adId).to.equal('adid-8');

// Bid Caching On AGAIN, No Filter Function (should be same as first time)
useBidCache = true;
bidCacheFilterFunction = undef;
bids = targetingInstance.getWinningBids(adUnitCodes);

expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-1');
expect(bids[1].adId).to.equal('adid-4');
expect(bids[2].adId).to.equal('adid-5');
expect(bids[3].adId).to.equal('adid-8');

// Bid Caching On, with Filter Function to Exclude video
useBidCache = true;
let bcffCalled = 0;
bidCacheFilterFunction = bid => {
bcffCalled++;
return bid.mediaType !== 'video';
}
bids = targetingInstance.getWinningBids(adUnitCodes);

expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-1');
expect(bids[1].adId).to.equal('adid-4');
expect(bids[2].adId).to.equal('adid-6');
expect(bids[3].adId).to.equal('adid-8');
// filter function should have been called for each cached bid (4 times)
expect(bcffCalled).to.equal(4);

// Bid Caching Off, with Filter Function to Exclude video
// - should not use cached bids or call the filter function
useBidCache = false;
bcffCalled = 0;
bidCacheFilterFunction = bid => {
bcffCalled++;
return bid.mediaType !== 'video';
}
bids = targetingInstance.getWinningBids(adUnitCodes);

expect(bids.length).to.equal(4);
expect(bids[0].adId).to.equal('adid-2');
expect(bids[1].adId).to.equal('adid-4');
expect(bids[2].adId).to.equal('adid-6');
expect(bids[3].adId).to.equal('adid-8');
// filter function should not have been called
expect(bcffCalled).to.equal(0);
});

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'}),
Expand Down