Skip to content

Commit

Permalink
Debugging module: add PAAPI support (#11240)
Browse files Browse the repository at this point in the history
* Debugging module: add PAAPI support
  • Loading branch information
dgirardi authored Mar 22, 2024
1 parent 708a696 commit 9088112
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 22 deletions.
27 changes: 23 additions & 4 deletions modules/debugging/bidInterceptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ Object.assign(BidInterceptor.prototype, {
return {
no: ruleNo,
match: this.matcher(ruleDef.when, ruleNo),
replace: this.replacer(ruleDef.then || {}, ruleNo),
replace: this.replacer(ruleDef.then, ruleNo),
options: Object.assign({}, this.DEFAULT_RULE_OPTIONS, ruleDef.options),
paapi: this.paapiReplacer(ruleDef.paapi || [], ruleNo)
}
},
/**
Expand Down Expand Up @@ -114,6 +115,10 @@ Object.assign(BidInterceptor.prototype, {
* @return {ReplacerFn}
*/
replacer(replDef, ruleNo) {
if (replDef === null) {
return () => null
}
replDef = replDef || {};
let replFn;
if (typeof replDef === 'function') {
replFn = ({args}) => replDef(...args);
Expand Down Expand Up @@ -145,6 +150,17 @@ Object.assign(BidInterceptor.prototype, {
return response;
}
},

paapiReplacer(paapiDef, ruleNo) {
if (Array.isArray(paapiDef)) {
return () => paapiDef;
} else if (typeof paapiDef === 'function') {
return paapiDef
} else {
this.logger.logError(`Invalid 'paapi' definition for debug bid interceptor (in rule #${ruleNo})`);
}
},

responseDefaults(bid) {
return {
requestId: bid.bidId,
Expand Down Expand Up @@ -198,11 +214,12 @@ Object.assign(BidInterceptor.prototype, {
* @param {{}[]} bids?
* @param {BidRequest} bidRequest
* @param {function(*)} addBid called once for each mock response
* @param addPaapiConfig called once for each mock PAAPI config
* @param {function()} done called once after all mock responses have been run through `addBid`
* @returns {{bids: {}[], bidRequest: {}} remaining bids that did not match any rule (this applies also to
* bidRequest.bids)
*/
intercept({bids, bidRequest, addBid, done}) {
intercept({bids, bidRequest, addBid, addPaapiConfig, done}) {
if (bids == null) {
bids = bidRequest.bids;
}
Expand All @@ -211,10 +228,12 @@ Object.assign(BidInterceptor.prototype, {
const callDone = delayExecution(done, matches.length);
matches.forEach((match) => {
const mockResponse = match.rule.replace(match.bid, bidRequest);
const mockPaapi = match.rule.paapi(match.bid, bidRequest);
const delay = match.rule.options.delay;
this.logger.logMessage(`Intercepted bid request (matching rule #${match.rule.no}), mocking response in ${delay}ms. Request, response:`, match.bid, mockResponse)
this.logger.logMessage(`Intercepted bid request (matching rule #${match.rule.no}), mocking response in ${delay}ms. Request, response, PAAPI configs:`, match.bid, mockResponse, mockPaapi)
this.setTimeout(() => {
addBid(mockResponse, match.bid);
mockResponse && addBid(mockResponse, match.bid);
mockPaapi.forEach(cfg => addPaapiConfig(cfg, match.bid, bidRequest));
callDone();
}, delay)
});
Expand Down
8 changes: 7 additions & 1 deletion modules/debugging/debugging.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,13 @@ function registerBidInterceptor(getHookFn, interceptor) {

export function bidderBidInterceptor(next, interceptBids, spec, bids, bidRequest, ajax, wrapCallback, cbs) {
const done = delayExecution(cbs.onCompletion, 2);
({bids, bidRequest} = interceptBids({bids, bidRequest, addBid: cbs.onBid, done}));
({bids, bidRequest} = interceptBids({
bids,
bidRequest,
addBid: cbs.onBid,
addPaapiConfig: (config, bidRequest) => cbs.onPaapi({bidId: bidRequest.bidId, config}),
done
}));
if (bids.length === 0) {
done();
} else {
Expand Down
17 changes: 15 additions & 2 deletions modules/debugging/pbsInterceptor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export function makePbsInterceptor({createBid}) {
return function pbsBidInterceptor(next, interceptBids, s2sBidRequest, bidRequests, ajax, {
onResponse,
onError,
onBid
onBid,
onFledge,
}) {
let responseArgs;
const done = delayExecution(() => onResponse(...responseArgs), bidRequests.length + 1)
Expand All @@ -20,7 +21,19 @@ export function makePbsInterceptor({createBid}) {
})
}
bidRequests = bidRequests
.map((req) => interceptBids({bidRequest: req, addBid, done}).bidRequest)
.map((req) => interceptBids({
bidRequest: req,
addBid,
addPaapiConfig(config, bidRequest, bidderRequest) {
onFledge({
adUnitCode: bidRequest.adUnitCode,
ortb2: bidderRequest.ortb2,
ortb2Imp: bidRequest.ortb2Imp,
config
})
},
done
}).bidRequest)
.filter((req) => req.bids.length > 0)

if (bidRequests.length > 0) {
Expand Down
20 changes: 9 additions & 11 deletions src/adapters/bidderFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -293,15 +293,13 @@ export function newBidder(spec) {
onTimelyResponse(spec.code);
responses.push(resp)
},
onFledgeAuctionConfigs: (fledgeAuctionConfigs) => {
fledgeAuctionConfigs.forEach((fledgeAuctionConfig) => {
const bidRequest = bidRequestMap[fledgeAuctionConfig.bidId];
if (bidRequest) {
addComponentAuction(bidRequest, fledgeAuctionConfig.config);
} else {
logWarn('Received fledge auction configuration for an unknown bidId', fledgeAuctionConfig);
}
});
onPaapi: (paapiConfig) => {
const bidRequest = bidRequestMap[paapiConfig.bidId];
if (bidRequest) {
addComponentAuction(bidRequest, paapiConfig.config);
} else {
logWarn('Received fledge auction configuration for an unknown bidId', paapiConfig);
}
},
// If the server responds with an error, there's not much we can do beside logging.
onError: (errorMessage, error) => {
Expand Down Expand Up @@ -378,7 +376,7 @@ export function newBidder(spec) {
* @param onBid {function({})} invoked once for each bid in the response - with the bid as returned by interpretResponse
* @param onCompletion {function()} invoked once when all bid requests have been processed
*/
export const processBidderRequests = hook('sync', function (spec, bids, bidderRequest, ajax, wrapCallback, {onRequest, onResponse, onFledgeAuctionConfigs, onError, onBid, onCompletion}) {
export const processBidderRequests = hook('sync', function (spec, bids, bidderRequest, ajax, wrapCallback, {onRequest, onResponse, onPaapi, onError, onBid, onCompletion}) {
const metrics = adapterMetrics(bidderRequest);
onCompletion = metrics.startTiming('total').stopBefore(onCompletion);

Expand Down Expand Up @@ -427,7 +425,7 @@ export const processBidderRequests = hook('sync', function (spec, bids, bidderRe
let bids;
// Extract additional data from a structured {BidderAuctionResponse} response
if (response && isArray(response.fledgeAuctionConfigs)) {
onFledgeAuctionConfigs(response.fledgeAuctionConfigs);
response.fledgeAuctionConfigs.forEach(onPaapi);
bids = response.bids;
} else {
bids = response;
Expand Down
50 changes: 46 additions & 4 deletions test/spec/modules/debugging_mod_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ describe('bid interceptor', () => {
});

describe('rule', () => {
function matchingRule({replace, options}) {
setRules({when: {}, then: replace, options: options});
function matchingRule({replace, options, paapi}) {
setRules({when: {}, then: replace, options: options, paapi});
return interceptor.match({});
}

Expand Down Expand Up @@ -164,6 +164,24 @@ describe('bid interceptor', () => {
});
});

describe('paapi', () => {
it('should accept literals', () => {
const mockConfig = [
{paapi: 1},
{paapi: 2}
]
const paapi = matchingRule({paapi: mockConfig}).paapi({});
expect(paapi).to.eql(mockConfig);
});

it('should accept a function and pass extra args to it', () => {
const paapiDef = sinon.stub();
const args = [{}, {}, {}];
matchingRule({paapi: paapiDef}).paapi(...args);
expect(paapiDef.calledOnceWith(...args.map(sinon.match.same))).to.be.true;
})
})

describe('.options', () => {
it('should include default rule options', () => {
const optDef = {someOption: 'value'};
Expand All @@ -181,16 +199,17 @@ describe('bid interceptor', () => {
});

describe('intercept()', () => {
let done, addBid;
let done, addBid, addPaapiConfig;

function intercept(args = {}) {
const bidRequest = {bids: args.bids || []};
return interceptor.intercept(Object.assign({bidRequest, done, addBid}, args));
return interceptor.intercept(Object.assign({bidRequest, done, addBid, addPaapiConfig}, args));
}

beforeEach(() => {
done = sinon.spy();
addBid = sinon.spy();
addPaapiConfig = sinon.spy();
});

describe('on no match', () => {
Expand Down Expand Up @@ -253,6 +272,29 @@ describe('bid interceptor', () => {
});
});

it('should call addPaapiConfigs when provided', () => {
const mockPaapiConfigs = [
{paapi: 1},
{paapi: 2}
]
setRules({
when: {id: 2},
paapi: mockPaapiConfigs,
});
intercept({bidRequest: REQUEST});
expect(addPaapiConfig.callCount).to.eql(2);
mockPaapiConfigs.forEach(cfg => sinon.assert.calledWith(addPaapiConfig, cfg))
})

it('should not call onBid when then is null', () => {
setRules({
when: {id: 2},
then: null
});
intercept({bidRequest: REQUEST});
sinon.assert.notCalled(addBid);
})

it('should call done()', () => {
intercept({bidRequest: REQUEST});
expect(done.calledOnce).to.be.true;
Expand Down

0 comments on commit 9088112

Please sign in to comment.