Skip to content

Commit

Permalink
Rubicon BidAdapter - SRA support for >10 bids (prebid#3514)
Browse files Browse the repository at this point in the history
* added support to use multiple requests for SRA requests with more than 10 bids

* updated unit test to test SRA dividing 100 bids into 10 requests
  • Loading branch information
Isaac Dettman authored and Alex committed Aug 1, 2019
1 parent 083b3dd commit 6336f41
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 36 deletions.
58 changes: 34 additions & 24 deletions modules/rubiconBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,30 +232,30 @@ export const spec = {
return groupedBids;
}, {});

requests = videoRequests.concat(Object.keys(groupedBidRequests).map(bidGroupKey => {
let bidsInGroup = groupedBidRequests[bidGroupKey];

// fastlane SRA has a limit of 10 slots
if (bidsInGroup.length > 10) {
utils.logWarn(`Rubicon bid adapter Warning: single request mode has a limit of 10 bids: ${bidsInGroup.length - 10} bids were not sent`);
bidsInGroup = bidsInGroup.slice(0, 10);
}

const combinedSlotParams = spec.combineSlotUrlParams(bidsInGroup.map(bidRequest => {
return spec.createSlotParams(bidRequest, bidderRequest);
}));

// SRA request returns grouped bidRequest arrays not a plain bidRequest
return {
method: 'GET',
url: FASTLANE_ENDPOINT,
data: spec.getOrderedParams(combinedSlotParams).reduce((paramString, key) => {
const propValue = combinedSlotParams[key];
return ((utils.isStr(propValue) && propValue !== '') || utils.isNumber(propValue)) ? `${paramString}${key}=${encodeURIComponent(propValue)}&` : paramString;
}, '') + `slots=${bidsInGroup.length}&rand=${Math.random()}`,
bidRequest: bidsInGroup,
};
}));
// fastlane SRA has a limit of 10 slots
const SRA_BID_LIMIT = 10;

// multiple requests are used if bids groups have more than 10 bids
requests = videoRequests.concat(Object.keys(groupedBidRequests).reduce((aggregate, bidGroupKey) => {
// for each partioned bidGroup, append a bidRequest to requests list
partitionArray(groupedBidRequests[bidGroupKey], SRA_BID_LIMIT).forEach(bidsInGroup => {
const combinedSlotParams = spec.combineSlotUrlParams(bidsInGroup.map(bidRequest => {
return spec.createSlotParams(bidRequest, bidderRequest);
}));

// SRA request returns grouped bidRequest arrays not a plain bidRequest
aggregate.push({
method: 'GET',
url: FASTLANE_ENDPOINT,
data: spec.getOrderedParams(combinedSlotParams).reduce((paramString, key) => {
const propValue = combinedSlotParams[key];
return ((utils.isStr(propValue) && propValue !== '') || utils.isNumber(propValue)) ? `${paramString}${key}=${encodeURIComponent(propValue)}&` : paramString;
}, '') + `slots=${bidsInGroup.length}&rand=${Math.random()}`,
bidRequest: bidsInGroup
});
});
return aggregate;
}, []));
}
return requests;
},
Expand Down Expand Up @@ -897,6 +897,16 @@ export function hasValidVideoParams(bid) {
return isValid;
}

/**
* split array into multiple arrays of defined size
* @param {Array} array
* @param {number} size
* @returns {Array}
*/
function partitionArray(array, size) {
return array.map((e, i) => (i % size === 0) ? array.slice(i, i + size) : null).filter((e) => e)
}

var hasSynced = false;

export function resetUserSync() {
Expand Down
41 changes: 29 additions & 12 deletions test/spec/modules/rubiconBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -957,35 +957,52 @@ describe('the rubicon adapter', function () {
});
});

it('should not send more than 10 bids in a request', function () {
it('should not send more than 10 bids in a request (split into separate requests with <= 10 bids each)', function () {
sandbox.stub(config, 'getConfig').callsFake((key) => {
const config = {
'rubicon.singleRequest': true
};
return config[key];
});

for (let i = 0; i < 20; i++) {
let serverRequests;
let data;

// TEST '10' BIDS, add 9 to 1 existing bid
for (let i = 0; i < 9; i++) {
let bidCopy = clone(bidderRequest.bids[0]);
bidCopy.params.zoneId = `${i}0000`;
bidderRequest.bids.push(bidCopy);
}

const serverRequests = spec.buildRequests(bidderRequest.bids, bidderRequest);

// if bids are greater than 10, additional bids are dropped
serverRequests = spec.buildRequests(bidderRequest.bids, bidderRequest);
// '10' bids per SRA request: so there should be 1 request
expect(serverRequests.length).to.equal(1);
// and that one request should have data from 10 bids
expect(serverRequests[0].bidRequest).to.have.lengthOf(10);

// check that slots param value matches
const foundSlotsCount = serverRequests[0].data.indexOf('&slots=10&');
expect(foundSlotsCount !== -1).to.equal(true);

expect(serverRequests[0].data.indexOf('&slots=10&') !== -1).to.equal(true);
// check that zone_id has 10 values (since all zone_ids are unique all should exist in get param)
const data = parseQuery(serverRequests[0].data);

data = parseQuery(serverRequests[0].data);
expect(data).to.be.a('object');
expect(data).to.have.property('zone_id');
expect(data.zone_id.split(';')).to.have.lengthOf(10);

// TEST '100' BIDS, add 90 to the previously added 10
for (let i = 0; i < 90; i++) {
let bidCopy = clone(bidderRequest.bids[0]);
bidCopy.params.zoneId = `${(i + 10)}0000`;
bidderRequest.bids.push(bidCopy);
}
serverRequests = spec.buildRequests(bidderRequest.bids, bidderRequest);
// '100' bids: should be '10' SRA requests
expect(serverRequests.length).to.equal(10);
// check that each request has 10 items
serverRequests.forEach((serverRequest) => {
// and that one request should have data from 10 bids
expect(serverRequest.bidRequest).to.have.lengthOf(10);
// check that slots param value matches
expect(serverRequest.data.indexOf('&slots=10&') !== -1).to.equal(true);
});
});

it('should not group bid requests if singleRequest does not equal true', function () {
Expand Down

0 comments on commit 6336f41

Please sign in to comment.