Skip to content

Commit

Permalink
New debugging functionality with bid overrides (prebid#2492)
Browse files Browse the repository at this point in the history
* new debugging functionality with bid overrides

* update name from bidderOverrides to debugging

* change sessionStorage to window.sessionStorage
  • Loading branch information
snapwich authored May 30, 2018
1 parent e093302 commit 48bd7b8
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 0 deletions.
89 changes: 89 additions & 0 deletions src/debugging.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

import { config } from 'src/config';
import { logMessage as utilsLogMessage, logWarn as utilsLogWarn } from 'src/utils';
import { addBidResponse } from 'src/auction';

const OVERRIDE_KEY = '$$PREBID_GLOBAL$$:debugging';

export let boundHook;

function logMessage(msg) {
utilsLogMessage('DEBUG: ' + msg);
}

function logWarn(msg) {
utilsLogWarn('DEBUG: ' + msg);
}

function enableOverrides(overrides, fromSession = false) {
config.setConfig({'debug': true});
logMessage(`bidder overrides enabled${fromSession ? ' from session' : ''}`);

if (boundHook) {
addBidResponse.removeHook(boundHook);
}

boundHook = addBidResponseHook.bind(null, overrides);
addBidResponse.addHook(boundHook, 5);
}

export function disableOverrides() {
if (boundHook) {
addBidResponse.removeHook(boundHook);
logMessage('bidder overrides disabled');
}
}

export function addBidResponseHook(overrides, adUnitCode, bid, next) {
if (Array.isArray(overrides.bidders) && overrides.bidders.indexOf(bid.bidderCode) === -1) {
logWarn(`bidder '${bid.bidderCode}' excluded from auction by bidder overrides`);
return;
}

if (Array.isArray(overrides.bids)) {
overrides.bids.forEach(overrideBid => {
if (overrideBid.bidder && overrideBid.bidder !== bid.bidderCode) {
return;
}
if (overrideBid.adUnitCode && overrideBid.adUnitCode !== adUnitCode) {
return;
}

bid = Object.assign({}, bid);

Object.keys(overrideBid).filter(key => ['bidder', 'adUnitCode'].indexOf(key) === -1).forEach((key) => {
let value = overrideBid[key];
logMessage(`bidder overrides changed '${adUnitCode}/${bid.bidderCode}' bid.${key} from '${bid[key]}' to '${value}'`);
bid[key] = value;
});
});
}

next(adUnitCode, bid);
}

export function getConfig(debugging) {
if (!debugging.enabled) {
disableOverrides();
try {
window.sessionStorage.removeItem(OVERRIDE_KEY);
} catch (e) {}
} else {
try {
window.sessionStorage.setItem(OVERRIDE_KEY, JSON.stringify(debugging));
} catch (e) {}
enableOverrides(debugging);
}
}
config.getConfig('debugging', ({debugging}) => getConfig(debugging));

export function sessionLoader() {
let overrides;
try {
overrides = JSON.parse(window.sessionStorage.getItem(OVERRIDE_KEY));
} catch (e) {
}
if (overrides) {
enableOverrides(overrides, true);
}
}
3 changes: 3 additions & 0 deletions src/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export function createHook(type, fn, hookName) {
},
removeHook: function(removeFn) {
_hooks = _hooks.filter(hook => hook.fn === fn || hook.fn !== removeFn);
},
hasHook: function(fn) {
return _hooks.some(hook => hook.fn === fn);
}
};

Expand Down
4 changes: 4 additions & 0 deletions src/prebid.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { config } from './config';
import { auctionManager } from './auctionManager';
import { targeting, getOldestBid, RENDERED, BID_TARGETING_SET } from './targeting';
import { createHook } from 'src/hook';
import { sessionLoader } from 'src/debugging';
import includes from 'core-js/library/fn/array/includes';

const $$PREBID_GLOBAL$$ = getGlobal();
Expand All @@ -27,6 +28,9 @@ const eventValidators = {
bidWon: checkDefinedPlacement
};

// initialize existing debugging sessions if present
sessionLoader();

/* Public vars */
$$PREBID_GLOBAL$$.bidderSettings = $$PREBID_GLOBAL$$.bidderSettings || {};

Expand Down
141 changes: 141 additions & 0 deletions test/spec/debugging_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@

import { expect } from 'chai';
import { sessionLoader, addBidResponseHook, getConfig, disableOverrides, boundHook } from 'src/debugging';
import { addBidResponse } from 'src/auction';
import { config } from 'src/config';

describe('bid overrides', () => {
let sandbox;

beforeEach(() => {
sandbox = sinon.sandbox.create();
});

afterEach(() => {
sandbox.restore();
});

describe('initialization', () => {
beforeEach(() => {
sandbox.stub(config, 'setConfig');
sandbox.stub(window.sessionStorage, 'setItem');
sandbox.stub(window.sessionStorage, 'removeItem');
});

afterEach(() => {
disableOverrides();
});

it('should happen when enabled with setConfig', () => {
getConfig({
enabled: true
});

expect(addBidResponse.hasHook(boundHook)).to.equal(true);
});

it('should happen when configuration found in sessionStorage', () => {
sandbox.stub(window.sessionStorage, 'getItem').returns('{"enabled": true}');

sessionLoader();
expect(addBidResponse.hasHook(boundHook)).to.equal(true);
});

it('should not throw if sessionStorage is inaccessible', () => {
sandbox.stub(window.sessionStorage, 'getItem').throws();

expect(() => {
sessionLoader();
}).not.to.throw();
});
});

describe('hook', () => {
let mockBids;
let bids;

beforeEach(() => {
let baseBid = {
'bidderCode': 'rubicon',
'width': 970,
'height': 250,
'statusMessage': 'Bid available',
'mediaType': 'banner',
'source': 'client',
'currency': 'USD',
'cpm': 0.5,
'ttl': 300,
'netRevenue': false,
'adUnitCode': '/19968336/header-bid-tag-0'
};
mockBids = [];
mockBids.push(baseBid);
mockBids.push(Object.assign({}, baseBid, {
bidderCode: 'appnexus'
}));

bids = [];
});

function run(overrides) {
mockBids.forEach(bid => {
addBidResponseHook(overrides, bid.adUnitCode, bid, (adUnitCode, bid) => {
bids.push(bid);
})
});
}

it('should allow us to exclude bidders', () => {
run({
enabled: true,
bidders: ['appnexus']
});

expect(bids.length).to.equal(1);
expect(bids[0].bidderCode).to.equal('appnexus');
});

it('should allow us to override all bids', () => {
run({
enabled: true,
bids: [{
cpm: 2
}]
});

expect(bids.length).to.equal(2);
expect(bids[0].cpm).to.equal(2);
expect(bids[1].cpm).to.equal(2);
});

it('should allow us to override bids by bidder', () => {
run({
enabled: true,
bids: [{
bidder: 'rubicon',
cpm: 2
}]
});

expect(bids.length).to.equal(2);
expect(bids[0].cpm).to.equal(2);
expect(bids[1].cpm).to.equal(0.5);
});

it('should allow us to override bids by adUnitCode', () => {
mockBids[1].adUnitCode = 'test';

run({
enabled: true,
bids: [{
adUnitCode: 'test',
cpm: 2
}]
});

expect(bids.length).to.equal(2);
expect(bids[0].cpm).to.equal(0.5);
expect(bids[1].cpm).to.equal(2);
});
});
});

0 comments on commit 48bd7b8

Please sign in to comment.