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

On set targeting #3203

Merged
merged 10 commits into from
Nov 6, 2018
4 changes: 4 additions & 0 deletions src/adaptermanager.js
Original file line number Diff line number Diff line change
Expand Up @@ -529,3 +529,7 @@ exports.callBidWonBidder = function(bidder, bid, adUnits) {
bid.params = utils.getUserConfiguredParams(adUnits, bid.adUnitCode, bid.bidder);
tryCallBidderMethod(bidder, 'onBidWon', bid);
};

exports.callSetTargetingBidder = function(bidder, bid) {
tryCallBidderMethod(bidder, 'onSetTargeting', bid);
};
5 changes: 5 additions & 0 deletions src/auction.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,11 +289,16 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels})
adaptermanager.callBidWonBidder(winningBid.bidder, winningBid, adUnits);
}

function setBidTargeting(bid) {
adaptermanager.callSetTargetingBidder(bid.bidder, bid);
}

return {
addBidReceived,
executeCallback,
callBids,
addWinningBid,
setBidTargeting,
getWinningBids: () => _winningBids,
getTimeout: () => _timeout,
getAuctionId: () => _auctionId,
Expand Down
5 changes: 5 additions & 0 deletions src/auctionManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ export function newAuctionManager() {
auctionManager.setStatusForBids = function(adId, status) {
let bid = auctionManager.findBidByAdId(adId);
if (bid) bid.status = status;

if (bid && status === CONSTANTS.BID_STATUS.BID_TARGETING_SET) {
const auction = find(_auctions, auction => auction.getAuctionId() === bid.auctionId);
if (auction) auction.setBidTargeting(bid);
}
}

function _addAuction(auction) {
Expand Down
4 changes: 4 additions & 0 deletions src/constants.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,9 @@
"SRC" : "s2s",
"DEFAULT_ENDPOINT" : "https://prebid.adnxs.com/pbs/v1/openrtb2/auction",
"SYNCED_BIDDERS_KEY": "pbjsSyncs"
},
"BID_STATUS" : {
"BID_TARGETING_SET": "targetingSet",
"RENDERED": "rendered"
}
}
10 changes: 5 additions & 5 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { userSync } from 'src/userSync.js';
import { loadScript } from './adloader';
import { config } from './config';
import { auctionManager } from './auctionManager';
import { targeting, getHighestCpmBidsFromBidPool, RENDERED, BID_TARGETING_SET } from './targeting';
import { targeting, getHighestCpmBidsFromBidPool } from './targeting';
import { createHook } from 'src/hook';
import { sessionLoader } from 'src/debugging';
import includes from 'core-js/library/fn/array/includes';
Expand Down Expand Up @@ -180,7 +180,7 @@ $$PREBID_GLOBAL$$.setTargetingForGPTAsync = function (adUnit, customSlotMatching
Object.keys(targetingSet).forEach((adUnitCode) => {
Object.keys(targetingSet[adUnitCode]).forEach((targetingKey) => {
if (targetingKey === 'hb_adid') {
auctionManager.setStatusForBids(targetingSet[adUnitCode][targetingKey], BID_TARGETING_SET);
auctionManager.setStatusForBids(targetingSet[adUnitCode][targetingKey], CONSTANTS.BID_STATUS.BID_TARGETING_SET);
}
});
});
Expand Down Expand Up @@ -234,7 +234,7 @@ $$PREBID_GLOBAL$$.renderAd = function (doc, id) {
// lookup ad by ad Id
const bid = auctionManager.findBidByAdId(id);
if (bid) {
bid.status = RENDERED;
bid.status = CONSTANTS.BID_STATUS.RENDERED;
// replace macros according to openRTB with price paid = bid.cpm
bid.ad = utils.replaceAuctionPrice(bid.ad, bid.cpm);
bid.adUrl = utils.replaceAuctionPrice(bid.adUrl, bid.cpm);
Expand Down Expand Up @@ -586,7 +586,7 @@ $$PREBID_GLOBAL$$.getAllWinningBids = function () {
*/
$$PREBID_GLOBAL$$.getAllPrebidWinningBids = function () {
return auctionManager.getBidsReceived()
.filter(bid => bid.status === BID_TARGETING_SET)
.filter(bid => bid.status === CONSTANTS.BID_STATUS.BID_TARGETING_SET)
.map(removeRequestId);
};

Expand Down Expand Up @@ -626,7 +626,7 @@ $$PREBID_GLOBAL$$.markWinningBidAsUsed = function (markBidRequest) {
}

if (bids.length > 0) {
bids[0].status = RENDERED;
bids[0].status = CONSTANTS.BID_STATUS.RENDERED;
}
};

Expand Down
6 changes: 1 addition & 5 deletions src/targeting.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,6 @@ var CONSTANTS = require('./constants.json');

var pbTargetingKeys = [];

export const BID_TARGETING_SET = 'targetingSet';
export const RENDERED = 'rendered';

const MAX_DFP_KEYLENGTH = 20;
const TTL_BUFFER = 1000;

Expand All @@ -24,7 +21,7 @@ export const TARGETING_KEYS = Object.keys(CONSTANTS.TARGETING_KEYS).map(
export const isBidNotExpired = (bid) => (bid.responseTimestamp + bid.ttl * 1000 + TTL_BUFFER) > timestamp();

// return bids whose status is not set. Winning bid can have status `targetingSet` or `rendered`.
const isUnusedBid = (bid) => bid && ((bid.status && !includes([BID_TARGETING_SET, RENDERED], bid.status)) || !bid.status);
const isUnusedBid = (bid) => bid && ((bid.status && !includes([CONSTANTS.BID_STATUS.BID_TARGETING_SET, CONSTANTS.BID_STATUS.RENDERED], bid.status)) || !bid.status);

// If two bids are found for same adUnitCode, we will use the highest one to take part in auction
// This can happen in case of concurrent auctions
Expand Down Expand Up @@ -214,7 +211,6 @@ export function newTargeting(auctionManager) {
*/
targeting.getWinningBids = function(adUnitCode, bidsReceived = getBidsReceived()) {
const adUnitCodes = getAdUnitCodes(adUnitCode);

return bidsReceived
.filter(bid => includes(adUnitCodes, bid.adUnitCode))
.filter(bid => bid.cpm > 0)
Expand Down
4 changes: 4 additions & 0 deletions test/spec/modules/criteoBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { cryptoVerify, spec, FAST_BID_PUBKEY } from 'modules/criteoBidAdapter';
import * as utils from 'src/utils';

describe('The Criteo bidding adapter', function () {
beforeEach(function () {
// Remove FastBid to avoid side effects.
localStorage.removeItem('criteo_fast_bid');
});
describe('isBidRequestValid', function () {
it('should return false when given an invalid bid', function () {
const bid = {
Expand Down
102 changes: 102 additions & 0 deletions test/spec/unit/core/adapterManager_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,108 @@ describe('adapterManager tests', function () {
});
});

describe('callTimedOutBidders', function () {
var criteoSpec = { onTimeout: sinon.stub() }
var criteoAdapter = {
bidder: 'criteo',
getSpec: function() { return criteoSpec; }
}
before(function () {
config.setConfig({s2sConfig: { enabled: false }});
});

beforeEach(function () {
AdapterManager.bidderRegistry['criteo'] = criteoAdapter;
});

afterEach(function () {
delete AdapterManager.bidderRegistry['criteo'];
});

it('should call spec\'s onTimeout callback when callTimedOutBidders is called', function () {
const adUnits = [{
code: 'adUnit-code',
sizes: [[728, 90]],
bids: [
{bidder: 'criteo', params: {placementId: 'id'}},
]
}];
const timedOutBidders = [{
bidId: 'bidId',
bidder: 'criteo',
adUnitCode: adUnits[0].code,
auctionId: 'auctionId',
}];
AdapterManager.callTimedOutBidders(adUnits, timedOutBidders, CONFIG.timeout);
sinon.assert.called(criteoSpec.onTimeout);
});
}); // end callTimedOutBidders

describe('onBidWon', function () {
var criteoSpec = { onBidWon: sinon.stub() }
var criteoAdapter = {
bidder: 'criteo',
getSpec: function() { return criteoSpec; }
}
before(function () {
config.setConfig({s2sConfig: { enabled: false }});
});

beforeEach(function () {
AdapterManager.bidderRegistry['criteo'] = criteoAdapter;
});

afterEach(function () {
delete AdapterManager.bidderRegistry['criteo'];
});

it('should call spec\'s onBidWon callback when a bid is won', function () {
const bids = [
{bidder: 'criteo', params: {placementId: 'id'}},
];
const adUnits = [{
code: 'adUnit-code',
sizes: [[728, 90]],
bids
}];

AdapterManager.callBidWonBidder(bids[0].bidder, bids[0], adUnits);
sinon.assert.called(criteoSpec.onBidWon);
});
}); // end onBidWon

describe('onSetTargeting', function () {
var criteoSpec = { onSetTargeting: sinon.stub() }
var criteoAdapter = {
bidder: 'criteo',
getSpec: function() { return criteoSpec; }
}
before(function () {
config.setConfig({s2sConfig: { enabled: false }});
});

beforeEach(function () {
AdapterManager.bidderRegistry['criteo'] = criteoAdapter;
});

afterEach(function () {
delete AdapterManager.bidderRegistry['criteo'];
});

it('should call spec\'s onSetTargeting callback when setTargeting is called', function () {
const bids = [
{bidder: 'criteo', params: {placementId: 'id'}},
];
const adUnits = [{
code: 'adUnit-code',
sizes: [[728, 90]],
bids
}];
AdapterManager.callSetTargetingBidder(bids[0].bidder, bids[0], adUnits);
sinon.assert.called(criteoSpec.onSetTargeting);
});
}); // end onSetTargeting

describe('S2S tests', function () {
beforeEach(function () {
config.setConfig({s2sConfig: CONFIG});
Expand Down
61 changes: 55 additions & 6 deletions test/spec/unit/pbjs_api_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
createBidReceived
} from 'test/fixtures/fixtures';
import { auctionManager, newAuctionManager } from 'src/auctionManager';
import { targeting, newTargeting, RENDERED } from 'src/targeting';
import { targeting, newTargeting } from 'src/targeting';
import { config as configObj } from 'src/config';
import * as ajaxLib from 'src/ajax';
import * as auctionModule from 'src/auction';
Expand Down Expand Up @@ -1165,7 +1165,8 @@ describe('Unit: Prebid Module', function () {
isBidRequestValid: sinon.stub(),
buildRequests: sinon.stub(),
interpretResponse: sinon.stub(),
getUserSyncs: sinon.stub()
getUserSyncs: sinon.stub(),
onTimeout: sinon.stub()
};

registerBidder(spec);
Expand All @@ -1190,6 +1191,54 @@ describe('Unit: Prebid Module', function () {

expect(bidsBackHandlerStub.getCall(0).args[1]).to.equal(true,
'bidsBackHandler should be called with timedOut=true');

sinon.assert.called(spec.onTimeout);
});

it('should execute callback after setTargeting', function () {
let spec = {
code: BIDDER_CODE,
isBidRequestValid: sinon.stub(),
buildRequests: sinon.stub(),
interpretResponse: sinon.stub(),
onSetTargeting: sinon.stub()
};

registerBidder(spec);
spec.buildRequests.returns([{'id': 123, 'method': 'POST'}]);
spec.isBidRequestValid.returns(true);
spec.interpretResponse.returns(bids);

const bidId = 1;
const auctionId = 1;
let adResponse = Object.assign({
auctionId: auctionId,
adId: String(bidId),
width: 300,
height: 250,
adUnitCode: bidRequests[0].bids[0].adUnitCode,
adserverTargeting: {
'hb_bidder': BIDDER_CODE,
'hb_adid': bidId,
'hb_pb': bids[0].cpm,
'hb_size': '300x250',
},
bidder: bids[0].bidderCode,
}, bids[0]);
auction.getBidsReceived = function() { return [adResponse]; }
auction.getAuctionId = () => auctionId;

clock = sinon.useFakeTimers();
let requestObj = {
bidsBackHandler: null, // does not need to be defined because of newAuction mock in beforeEach
timeout: 2000,
adUnits: adUnits
};

$$PREBID_GLOBAL$$.requestBids(requestObj);
$$PREBID_GLOBAL$$.setTargetingForGPTAsync();

sinon.assert.called(spec.onSetTargeting);
});
})

Expand Down Expand Up @@ -1851,7 +1900,7 @@ describe('Unit: Prebid Module', function () {
const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids,
bid => bid.adId === winningBid.adId);

expect(markedBid.status).to.equal(RENDERED);
expect(markedBid.status).to.equal(CONSTANTS.BID_STATUS.RENDERED);
resetAuction();
});

Expand All @@ -1865,7 +1914,7 @@ describe('Unit: Prebid Module', function () {
const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids,
bid => bid.adId === winningBid.adId);

expect(markedBid.status).to.not.equal(RENDERED);
expect(markedBid.status).to.not.equal(CONSTANTS.BID_STATUS.RENDERED);
resetAuction();
});

Expand All @@ -1881,7 +1930,7 @@ describe('Unit: Prebid Module', function () {
const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids,
bid => bid.adId === winningBid.adId);

expect(markedBid.status).to.equal(RENDERED);
expect(markedBid.status).to.equal(CONSTANTS.BID_STATUS.RENDERED);
resetAuction();
});

Expand All @@ -1897,7 +1946,7 @@ describe('Unit: Prebid Module', function () {
const markedBid = find($$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode(adUnitCode).bids,
bid => bid.adId === winningBid.adId);

expect(markedBid.status).to.equal(RENDERED);
expect(markedBid.status).to.equal(CONSTANTS.BID_STATUS.RENDERED);
resetAuction();
});
});
Expand Down