Skip to content

Commit bb997b2

Browse files
authored
Prebid Core: emit seatnonbid from prebid server (#9453)
* Parse and emit seatnonbid from server * Fix testing adjustments * Use onResponse for seatNonBids * Fix linting error * Emit to auction and add unit tests * Use optional property chaining * returnallbidstatus * fix varname in spec
1 parent 72ad8f0 commit bb997b2

File tree

5 files changed

+57
-3
lines changed

5 files changed

+57
-3
lines changed

modules/prebidServerBidAdapter/index.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,10 +469,13 @@ export function PrebidServer() {
469469
}
470470

471471
processPBSRequest(s2sBidRequest, bidRequests, ajax, {
472-
onResponse: function (isValid, requestedBidders) {
472+
onResponse: function (isValid, requestedBidders, response) {
473473
if (isValid) {
474474
bidRequests.forEach(bidderRequest => events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest));
475475
}
476+
if (shouldEmitNonbids(s2sBidRequest.s2sConfig, response)) {
477+
emitNonBids(response.ext.seatnonbid, bidRequests[0].auctionId);
478+
}
476479
done();
477480
doClientSideSyncs(requestedBidders, gdprConsent, uspConsent, gppConsent);
478481
},
@@ -551,7 +554,7 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques
551554
logError('error parsing response: ', result ? result.status : 'not valid JSON');
552555
onResponse(false, requestedBidders);
553556
} else {
554-
onResponse(true, requestedBidders);
557+
onResponse(true, requestedBidders, result);
555558
}
556559
},
557560
error: function () {
@@ -567,6 +570,17 @@ export const processPBSRequest = hook('sync', function (s2sBidRequest, bidReques
567570
}
568571
}, 'processPBSRequest');
569572

573+
function shouldEmitNonbids(s2sConfig, response) {
574+
return s2sConfig?.extPrebid?.returnallbidstatus && response?.ext?.seatnonbid;
575+
}
576+
577+
function emitNonBids(seatnonbid, auctionId) {
578+
events.emit(CONSTANTS.EVENTS.SEAT_NON_BID, {
579+
seatnonbid,
580+
auctionId
581+
});
582+
}
583+
570584
/**
571585
* Global setter that sets eids permissions for bidders
572586
* This setter is to be used by userId module when included

src/auction.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,13 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
151151
let _auctionEnd;
152152
let _timer;
153153
let _auctionStatus;
154+
let _nonBids = [];
154155

155156
function addBidRequests(bidderRequests) { _bidderRequests = _bidderRequests.concat(bidderRequests); }
156157
function addBidReceived(bidsReceived) { _bidsReceived = _bidsReceived.concat(bidsReceived); }
157158
function addBidRejected(bidsRejected) { _bidsRejected = _bidsRejected.concat(bidsRejected); }
158159
function addNoBid(noBid) { _noBids = _noBids.concat(noBid); }
160+
function addNonBids(seatnonbids) { _nonBids = _nonBids.concat(seatnonbids); }
159161

160162
function getProperties() {
161163
return {
@@ -172,7 +174,8 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
172174
bidsRejected: _bidsRejected,
173175
winningBids: _winningBids,
174176
timeout: _timeout,
175-
metrics: metrics
177+
metrics: metrics,
178+
seatNonBids: _nonBids
176179
};
177180
}
178181

@@ -369,6 +372,12 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
369372
adapterManager.callSetTargetingBidder(bid.adapterCode || bid.bidder, bid);
370373
}
371374

375+
events.on(CONSTANTS.EVENTS.SEAT_NON_BID, (event) => {
376+
if (event.auctionId === _auctionId) {
377+
addNonBids(event.seatnonbid)
378+
}
379+
});
380+
372381
return {
373382
addBidReceived,
374383
addBidRejected,
@@ -387,6 +396,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
387396
getBidRequests: () => _bidderRequests,
388397
getBidsReceived: () => _bidsReceived,
389398
getNoBids: () => _noBids,
399+
getNonBids: () => _nonBids,
390400
getFPD: () => ortb2Fragments,
391401
getMetrics: () => metrics,
392402
};

src/constants.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"BID_RESPONSE": "bidResponse",
3232
"BID_REJECTED": "bidRejected",
3333
"NO_BID": "noBid",
34+
"SEAT_NON_BID": "seatNonBid",
3435
"BID_WON": "bidWon",
3536
"BIDDER_DONE": "bidderDone",
3637
"BIDDER_ERROR": "bidderError",

test/spec/auctionmanager_spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,20 @@ describe('auctionmanager.js', function () {
759759
sinon.assert.calledWith(stubMakeBidRequests, ...anyArgs.slice(0, 5).concat([sinon.match.same(ortb2Fragments)]));
760760
sinon.assert.calledWith(stubCallAdapters, ...anyArgs.slice(0, 7).concat([sinon.match.same(ortb2Fragments)]));
761761
});
762+
763+
it('correctly adds nonbids when they are emitted', () => {
764+
const ortb2Fragments = {
765+
global: {},
766+
bidder: {}
767+
}
768+
const auction = auctionManager.createAuction({adUnits, ortb2Fragments});
769+
expect(auction.getNonBids()[0]).to.equal(undefined);
770+
events.emit(CONSTANTS.EVENTS.SEAT_NON_BID, {
771+
auctionId: auction.getAuctionId(),
772+
seatnonbid: ['test']
773+
});
774+
expect(auction.getNonBids()[0]).to.equal('test');
775+
});
762776
});
763777

764778
describe('addBidResponse #1', function () {

test/spec/modules/prebidServerBidAdapter_spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2928,6 +2928,21 @@ describe('S2S Adapter', function () {
29282928
expect(response).to.have.property('ttl', 60);
29292929
});
29302930

2931+
it('handles seatnonbid responses and calls SEAT_NON_BID', function () {
2932+
const original = CONFIG;
2933+
CONFIG.extPrebid = { returnallbidstatus: true };
2934+
const nonbidResponse = {...RESPONSE_OPENRTB, ext: {seatnonbid: [{}]}};
2935+
config.setConfig({ CONFIG });
2936+
CONFIG = original;
2937+
adapter.callBids(REQUEST, BID_REQUESTS, addBidResponse, done, ajax);
2938+
const responding = deepClone(nonbidResponse);
2939+
Object.assign(responding.ext.seatnonbid, [{auctionId: 2}])
2940+
server.requests[0].respond(200, {}, JSON.stringify(responding));
2941+
const event = events.emit.secondCall.args;
2942+
expect(event[0]).to.equal(CONSTANTS.EVENTS.SEAT_NON_BID);
2943+
expect(event[1].seatnonbid[0]).to.have.property('auctionId', 2);
2944+
});
2945+
29312946
it('respects defaultTtl', function () {
29322947
const s2sConfig = Object.assign({}, CONFIG, {
29332948
defaultTtl: 30

0 commit comments

Comments
 (0)