Skip to content

Commit

Permalink
Prebid Core: Fix wrong targeting being applied when multibid module i…
Browse files Browse the repository at this point in the history
…s included (#12716)

* 12238 - Azerion / Improve: does not properly support currency module

* **Type:** Fix
* **Scope:** improvedigitalBidAdapter
* **Subject:** Bid floors are always converted to USD.
* **Details:**
* Adds `DEFAULT_CURRENCY` variable which is set to USD
* Adds `convertBidFloorCurrency` function which in used to convert the bid floor when both `imp.bidfloor` and `imp.bidfloorcur` are present, and `imp.bidfloorcur` is not equal to the adapter's `DEFAULT_CURRENCY`;
* **Breaks:** N/A

* restored accidentally discarded change from unit test expect

* * Modifies behavior to pass bid floor as is when it cannot be converted to USD;
* Removes rounding of bid floor when converting its currency to USD;

* remove unnecessary uses of `toUpperCase()`

* * fix `convertCurrency` mock
* remove redundant checks for type and NaN from `convertBidFloorCurrency` function

* Restores the logic of choosing the winning bid for targeting inside getWinningBids instead of the using the hookable getHighestCpmBidsFromBidPool which has a logic to return bids unchanged, to sort them causing wrong targeting being applied when multibid module is included.

* Adds unit test

---------

Co-authored-by: Lyubomir Shishkov <[email protected]>
Co-authored-by: Jozef Bartek <[email protected]>
Co-authored-by: Catalin Ciocov <[email protected]>
  • Loading branch information
4 people authored Feb 10, 2025
1 parent 47678b4 commit 0c1a859
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 31 deletions.
44 changes: 14 additions & 30 deletions src/targeting.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export function newTargeting(auctionManager) {
if (enableSendAllBids || (deals && bid.dealId)) {
const targetingValue = getTargetingMap(bid, standardKeys.filter(
key => typeof bid.adserverTargeting[key] !== 'undefined' &&
(deals || allowedSendAllBidTargeting.indexOf(key) !== -1)));
(deals || allowedSendAllBidTargeting.indexOf(key) !== -1)));

if (targetingValue) {
result.push({[bid.adUnitCode]: targetingValue})
Expand Down Expand Up @@ -290,7 +290,7 @@ export function newTargeting(auctionManager) {
const adUnitBidLimit = (sendAllBids && (bidLimit || bidLimitConfigValue)) || 0;
const { customKeysByUnit, filteredBids } = getfilteredBidsAndCustomKeys(adUnitCodes, bidsReceived);
const bidsSorted = getHighestCpmBidsFromBidPool(filteredBids, winReducer, adUnitBidLimit, undefined, winSorter);
let targeting = getTargetingLevels(bidsSorted, customKeysByUnit);
let targeting = getTargetingLevels(bidsSorted, customKeysByUnit, adUnitCodes);

const defaultKeys = Object.keys(Object.assign({}, DEFAULT_TARGETING_KEYS, NATIVE_KEYS));
let allowedKeys = config.getConfig(CFG_ALLOW_TARGETING_KEYS);
Expand Down Expand Up @@ -337,8 +337,8 @@ export function newTargeting(auctionManager) {
});
}

function getTargetingLevels(bidsSorted, customKeysByUnit) {
const targeting = getWinningBidTargeting(bidsSorted)
function getTargetingLevels(bidsSorted, customKeysByUnit, adUnitCodes) {
const targeting = getWinningBidTargeting(bidsSorted, adUnitCodes)
.concat(getCustomBidTargeting(bidsSorted, customKeysByUnit))
.concat(getBidderTargeting(bidsSorted))
.concat(getAdUnitTargeting());
Expand Down Expand Up @@ -568,25 +568,17 @@ export function newTargeting(auctionManager) {
* @return {Array<Object>} - An array of winning bids.
*/
targeting.getWinningBids = function(adUnitCode, bids, winReducer = getHighestCpm, winSorter = sortByHighestCpm) {
const usedCodes = [];
const bidsReceived = bids || getBidsReceived(winReducer, winSorter);
const adUnitCodes = getAdUnitCodes(adUnitCode);

return bidsReceived
.reduce((result, bid) => {
const code = bid.adUnitCode;
const cpmEligible = bidderSettings.get(code, 'allowZeroCpmBids') === true ? bid.cpm >= 0 : bid.cpm > 0;
const isPreferredDeal = config.getConfig('targetingControls.alwaysIncludeDeals') && bid.dealId;
const eligible = includes(adUnitCodes, code) &&
!includes(usedCodes, code) &&
(isPreferredDeal || cpmEligible)
if (eligible) {
result.push(bid);
usedCodes.push(code);
}

return result;
}, []);
.filter(bid => includes(adUnitCodes, bid.adUnitCode))
.filter(bid => (bidderSettings.get(bid.bidderCode, 'allowZeroCpmBids') === true) ? bid.cpm >= 0 : bid.cpm > 0)
.map(bid => bid.adUnitCode)
.filter(uniques)
.map(adUnitCode => bidsReceived
.filter(bid => bid.adUnitCode === adUnitCode ? bid : null)
.reduce(getHighestCpm));
};

/**
Expand Down Expand Up @@ -624,19 +616,11 @@ export function newTargeting(auctionManager) {
/**
* Get targeting key value pairs for winning bid.
* @param {Array<Object>} bidsReceived code array
* @param {string[]} adUnitCodes code array
* @return {targetingArray} winning bids targeting
*/
function getWinningBidTargeting(bidsReceived) {
let usedAdUnitCodes = [];
let winners = bidsReceived
.reduce((bids, bid) => {
if (!includes(usedAdUnitCodes, bid.adUnitCode)) {
bids.push(bid);
usedAdUnitCodes.push(bid.adUnitCode);
}
return bids;
}, []);

function getWinningBidTargeting(bidsReceived, adUnitCodes) {
let winners = targeting.getWinningBids(adUnitCodes, bidsReceived);
let standardKeys = getStandardKeys();

winners = winners.map(winner => {
Expand Down
36 changes: 35 additions & 1 deletion test/spec/unit/core/targeting_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {auctionManager} from 'src/auctionManager.js';
import * as utils from 'src/utils.js';
import {deepClone} from 'src/utils.js';
import {createBid} from '../../../../src/bidfactory.js';
import {hook} from '../../../../src/hook.js';
import { hook, setupBeforeHookFnOnce } from '../../../../src/hook.js';
import {getHighestCpm} from '../../../../src/utils/reducers.js';

function mkBid(bid, status = STATUS.GOOD) {
Expand Down Expand Up @@ -956,6 +956,40 @@ describe('targeting tests', function () {
});
}); // end getAllTargeting tests

describe('getAllTargeting will work correctly when a hook raises has modified flag in getHighestCpmBidsFromBidPool', function () {
let bidsReceived;
let amGetAdUnitsStub;
let amBidsReceivedStub;
let bidExpiryStub;

beforeEach(function () {
bidsReceived = [bid2, bid1].map(deepClone);

amBidsReceivedStub = sandbox.stub(auctionManager, 'getBidsReceived').callsFake(function() {
return bidsReceived;
});
amGetAdUnitsStub = sandbox.stub(auctionManager, 'getAdUnitCodes').callsFake(function() {
return ['/123456/header-bid-tag-0'];
});
bidExpiryStub = sandbox.stub(filters, 'isBidNotExpired').returns(true);

setupBeforeHookFnOnce(getHighestCpmBidsFromBidPool, function (fn, bidsReceived, highestCpmCallback, adUnitBidLimit = 0, hasModified = false) {
fn.call(this, bidsReceived, highestCpmCallback, adUnitBidLimit, true);
});
});

afterEach(function () {
getHighestCpmBidsFromBidPool.getHooks().remove();
})

it('will apply correct targeting', function () {
let targeting = targetingInstance.getAllTargeting(['/123456/header-bid-tag-0']);

expect(targeting['/123456/header-bid-tag-0']['hb_pb']).to.equal('0.53');
expect(targeting['/123456/header-bid-tag-0']['hb_adid']).to.equal('148018fe5e');
})
});

describe('getAllTargeting without bids return empty object', function () {
let amBidsReceivedStub;
let amGetAdUnitsStub;
Expand Down

0 comments on commit 0c1a859

Please sign in to comment.