Skip to content

Commit

Permalink
Prebid Core: Support for multiple bidder codes from a single adapter (#…
Browse files Browse the repository at this point in the history
…8216)

Support for multiple bidder codes from a single adapter (#8216)
Co-authored-by: Azhar <[email protected]>
  • Loading branch information
pm-azhar-mulla authored Apr 25, 2022
1 parent 23297f0 commit f395eac
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/adapters/bidderFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ADPOD } from '../mediaTypes.js';
import { getHook, hook } from '../hook.js';
import { getCoreStorageManager } from '../storageManager.js';
import {auctionManager} from '../auctionManager.js';
import { bidderSettings } from '../bidderSettings.js';

export const storage = getCoreStorageManager('bidderFactory');

Expand Down Expand Up @@ -235,6 +236,11 @@ export function newBidder(spec) {
onBid: (bid) => {
const bidRequest = bidRequestMap[bid.requestId];
if (bidRequest) {
bid.adapterCode = bidRequest.bidder;
if (isInvalidAlternateBidder(bid.bidderCode, bidRequest.bidder)) {
logWarn(`${bid.bidderCode} is not a registered partner or known bidder of ${bidRequest.bidder}, hence continuing without bid. If you wish to support this bidder, please mark allowAlternateBidderCodes as true in bidderSettings.`);
return;
}
// creating a copy of original values as cpm and currency are modified later
bid.originalCpm = bid.cpm;
bid.originalCurrency = bid.currency;
Expand All @@ -250,6 +256,17 @@ export function newBidder(spec) {
}
});

function isInvalidAlternateBidder(responseBidder, requestBidder) {
let allowAlternateBidderCodes = bidderSettings.get(requestBidder, 'allowAlternateBidderCodes');
let alternateBiddersList = bidderSettings.get(requestBidder, 'allowedAlternateBidderCodes');
if (!!responseBidder && !!requestBidder && requestBidder !== responseBidder) {
if ((allowAlternateBidderCodes !== undefined && !allowAlternateBidderCodes) || (isArray(alternateBiddersList) && (alternateBiddersList[0] !== '*' && !alternateBiddersList.includes(responseBidder)))) {
return true;
}
}
return false;
}

function registerSyncs(responses, gdprConsent, uspConsent) {
registerSyncInner(spec, responses, gdprConsent, uspConsent);
}
Expand Down
137 changes: 137 additions & 0 deletions test/spec/unit/core/bidderFactory_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as events from 'src/events.js';
import {hook} from '../../../../src/hook.js';
import {auctionManager} from '../../../../src/auctionManager.js';
import {stubAuctionIndex} from '../../../helpers/indexStub.js';
import { bidderSettings } from '../../../../src/bidderSettings.js';

const CODE = 'sampleBidder';
const MOCK_BIDS_REQUEST = {
Expand Down Expand Up @@ -1022,6 +1023,142 @@ describe('validate bid response: ', function () {
expect(addBidResponseStub.firstCall.args[0]).to.equal('mock/placement');
expect(logErrorSpy.callCount).to.equal(0);
});

describe(' Check for alternateBiddersList ', function() {
let bidRequest;
let bids1;
let logWarnSpy;
let bidderSettingStub, aliasRegistryStub;
let aliasRegistry;

beforeEach(function () {
bidRequest = {
bids: [{
bidId: '1',
bidder: CODE,
auctionId: 'first-bid-id',
adUnitCode: 'mock/placement',
transactionId: 'au',
}]
};

bids1 = Object.assign({},
bids[0],
{
bidderCode: 'validAlternateBidder',
adapterCode: 'knownAdapter1'
}
);
logWarnSpy = sinon.spy(utils, 'logWarn');
bidderSettingStub = sinon.stub(bidderSettings, 'get');
aliasRegistry = {};
aliasRegistryStub = sinon.stub(adapterManager, 'aliasRegistry');
aliasRegistryStub.get(() => aliasRegistry);
});

afterEach(function () {
logWarnSpy.restore();
bidderSettingStub.restore();
aliasRegistryStub.restore();
});

it('should log warning when bidder is unknown and allowAlternateBidderCodes flag is false', function () {
bidderSettingStub.returns(false);

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(false);
expect(logWarnSpy.callCount).to.equal(1);
});

it('should accept the bid, when allowAlternateBidderCodes flag is undefined (default should be true)', function () {
bidderSettingStub.returns(undefined);

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(true);
expect(logWarnSpy.callCount).to.equal(0);
expect(logErrorSpy.callCount).to.equal(0);
});

it('should log warning when the particular bidder is not specified in allowedAlternateBidderCodes and allowAlternateBidderCodes flag is true', function () {
bidderSettingStub.withArgs(CODE, 'allowAlternateBidderCodes').returns(true);
bidderSettingStub.withArgs(CODE, 'allowedAlternateBidderCodes').returns(['invalidAlternateBidder02']);

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(false);
expect(logWarnSpy.callCount).to.equal(1);
});

it('should accept the bid, when allowedAlternateBidderCodes is empty and allowAlternateBidderCodes flag is true', function () {
bidderSettingStub.withArgs(CODE, 'allowAlternateBidderCodes').returns(true);
bidderSettingStub.withArgs(CODE, 'allowedAlternateBidderCodes').returns();

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(true);
expect(logWarnSpy.callCount).to.equal(0);
expect(logErrorSpy.callCount).to.equal(0);
});

it('should accept the bid, when allowedAlternateBidderCodes is marked as * and allowAlternateBidderCodes flag is true', function () {
bidderSettingStub.withArgs(CODE, 'allowAlternateBidderCodes').returns(true);
bidderSettingStub.withArgs(CODE, 'allowedAlternateBidderCodes').returns(['*']);

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(true);
expect(logWarnSpy.callCount).to.equal(0);
expect(logErrorSpy.callCount).to.equal(0);
});

it('should accept the bid, when allowedAlternateBidderCodes contains bidder name and allowAlternateBidderCodes flag is true', function () {
bidderSettingStub.withArgs(CODE, 'allowAlternateBidderCodes').returns(true);
bidderSettingStub.withArgs(CODE, 'allowedAlternateBidderCodes').returns(['validAlternateBidder']);

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(true);
expect(logWarnSpy.callCount).to.equal(0);
expect(logErrorSpy.callCount).to.equal(0);
});

it('should not accept the bid, when bidder is an alias but bidderSetting is missing for the bidder. It should fallback to standard setting and reject the bid', function () {
bidderSettingStub.withArgs(CODE, 'allowAlternateBidderCodes').returns(false);
aliasRegistry = {'validAlternateBidder': CODE};

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(false);
expect(logWarnSpy.callCount).to.equal(1);
});

it('should not accept the bid, when bidderSetting is missing for the bidder. It should fallback to standard setting and reject the bid', function () {
bidderSettingStub.withArgs(CODE, 'allowAlternateBidderCodes').returns(false);

const bidder = newBidder(spec);
spec.interpretResponse.returns(bids1);
bidder.callBids(bidRequest, addBidResponseStub, doneStub, ajaxStub, onTimelyResponseStub, wrappedCallback);

expect(addBidResponseStub.calledOnce).to.equal(false);
expect(logWarnSpy.callCount).to.equal(1);
});
})
});

describe('preload mapping url hook', function() {
Expand Down

0 comments on commit f395eac

Please sign in to comment.