Skip to content

Commit

Permalink
video support for adkernel adapter (#1270)
Browse files Browse the repository at this point in the history
  • Loading branch information
ckbo3hrk authored and dbemiller committed Jul 13, 2017
1 parent a440040 commit 7d53893
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 36 deletions.
73 changes: 57 additions & 16 deletions modules/adkernelBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ const AdKernelAdapter = function AdKernelAdapter() {
};
const EMPTY_BID_RESPONSE = {'seatbid': [{'bid': []}]};

const VIDEO_TARGETING = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'linearity', 'sequence',
'boxingallowed', 'playbackmethod', 'delivery', 'pos', 'api', 'ext'];

let baseAdapter = Adapter.createNew('adkernel');

/**
Expand All @@ -26,15 +29,13 @@ const AdKernelAdapter = function AdKernelAdapter() {
function RtbRequestDispatcher() {
const _dispatch = {};
const originalBids = {};
const site = createSite();
const syncedHostZones = {};
const site = createSite();

// translate adunit info into rtb impression dispatched by host/zone
this.addImp = function (bid) {
let host = bid.params.host;
let zone = bid.params.zoneId;
let size = bid.sizes[0];
let bidId = bid.bidId;

if (!(host in _dispatch)) {
_dispatch[host] = {};
Expand All @@ -43,17 +44,10 @@ const AdKernelAdapter = function AdKernelAdapter() {
if (!(zone in _dispatch[host])) {
_dispatch[host][zone] = [];
}
let imp = {
'id': bidId,
'tagid': bid.placementCode,
'banner': {'w': size[0], 'h': size[1]}
};
if (utils.getTopWindowLocation().protocol === 'https:') {
imp.secure = 1;
}
let imp = buildImp(bid);
// save rtb impression for specified ad-network host and zone
_dispatch[host][zone].push(imp);
originalBids[bidId] = bid;
originalBids[bid.bidId] = bid;
// perform user-sync
if (!(host in syncedHostZones)) {
syncedHostZones[host] = [];
Expand All @@ -63,6 +57,33 @@ const AdKernelAdapter = function AdKernelAdapter() {
}
};

function buildImp(bid) {
const size = getBidSize(bid);
const imp = { 'id': bid.bidId, 'tagid': bid.placementCode};

if (bid.mediaType === 'video') {
imp.video = {w: size[0], h: size[1]};
if (bid.params.video) {
Object.keys(bid.params.video)
.filter(param => VIDEO_TARGETING.includes(param))
.forEach(param => imp.video[param] = bid.params.video[param]);
}
} else {
imp.banner = {w: size[0], h: size[1]};
}
if (utils.getTopWindowLocation().protocol === 'https:') {
imp.secure = 1;
}
return imp;
}

function getBidSize(bid) {
if (bid.mediaType === 'video') {
return bid.sizes;
}
return bid.sizes[0];
}

/**
* Main function to get bid requests
*/
Expand Down Expand Up @@ -171,25 +192,43 @@ const AdKernelAdapter = function AdKernelAdapter() {
let adUnitId = bid.placementCode;
if (bidResp) {
utils.logMessage(`got response for ${adUnitId}`);
bidmanager.addBidResponse(adUnitId, createBidObject(bidResp, bid, imp.banner.w, imp.banner.h));
let dimensions = getCreativeSize(imp, bidResp);
bidmanager.addBidResponse(adUnitId, createBidObject(bidResp, bid, dimensions.w, dimensions.h));
} else {
utils.logMessage(`got empty response for ${adUnitId}`);
bidmanager.addBidResponse(adUnitId, createEmptyBidObject(bid));
}
});
}

/**
* Evaluate creative size from response or from request
*/
function getCreativeSize(imp, bid) {
let dimensions = (bid.h && bid.w) ? bid : (imp.banner || imp.video);
return {
w: dimensions.w,
h: dimensions.h
};
}

/**
* Create bid object for the bid manager
*/
function createBidObject(resp, bid, width, height) {
return Object.assign(bidfactory.createBid(1, bid), {
let bidObj = Object.assign(bidfactory.createBid(1, bid), {
bidderCode: bid.bidder,
ad: formatAdMarkup(resp),
width: width,
height: height,
cpm: parseFloat(resp.price)
});
if (bid.mediaType === 'video') {
bidObj.vastUrl = resp.nurl;
bidObj.mediaType = 'video';
} else {
bidObj.ad = formatAdMarkup(resp);
}
return bidObj;
}

/**
Expand Down Expand Up @@ -268,7 +307,9 @@ AdKernelAdapter.createNew = function() {
return new AdKernelAdapter();
};

adaptermanager.registerBidAdapter(new AdKernelAdapter, 'adkernel');
adaptermanager.registerBidAdapter(new AdKernelAdapter, 'adkernel', {
supportedMediaTypes: ['video']
});
adaptermanager.aliasBidAdapter('adkernel', 'headbidding');

module.exports = AdKernelAdapter;
114 changes: 94 additions & 20 deletions test/spec/modules/adkernelBidAdapter_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,31 +36,60 @@ describe('Adkernel adapter', () => {
params: {zoneId: 1},
placementCode: 'ad-unit-1',
sizes: [[728, 90]]
}, bid_video = {
bidder: 'adkernel',
bidId: 'Bid_Video',
sizes: [640, 480],
mediaType: 'video',
params: {
zoneId: 1,
host: 'rtb.adkernel.com',
video: {
mimes: ['video/mp4', 'video/webm', 'video/x-flv']
}
},
placementCode: 'ad-unit-1'
};

const bidResponse1 = {
'id': 'bid1',
'seatbid': [{
'bid': [{
'id': '1',
'impid': 'Bid_01',
'price': 3.01,
'nurl': 'https://rtb.com/win?i=ZjKoPYSFI3Y_0',
'adm': '<!-- admarkup here -->'
id: 'bid1',
seatbid: [{
bid: [{
id: '1',
impid: 'Bid_01',
price: 3.01,
nurl: 'https://rtb.com/win?i=ZjKoPYSFI3Y_0',
adm: '<!-- admarkup here -->'
}]
}],
'cur': 'USD'
cur: 'USD'
}, bidResponse2 = {
'id': 'bid2',
'seatbid': [{
'bid': [{
'id': '2',
'impid': 'Bid_02',
'price': 1.31,
'adm': '<!-- admarkup here -->'
id: 'bid2',
seatbid: [{
bid: [{
id: '2',
impid: 'Bid_02',
price: 1.31,
adm: '<!-- admarkup here -->'
}]
}],
cur: 'USD'
}, videoBidResponse = {
id: '47ce4badcf7482',
seatbid: [{
bid: [{
id: 'sZSYq5zYMxo_0',
impid: 'Bid_Video',
price: 0.00145,
adid: '158801',
nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl',
cid: '16855',
crid: '158801',
w: 600,
h: 400
}]
}],
'cur': 'USD'
cur: 'USD'
};

let adapter,
Expand Down Expand Up @@ -113,7 +142,7 @@ describe('Adkernel adapter', () => {
});
});

describe('request building', () => {
describe('banner request building', () => {
let bidRequest;

beforeEach(() => {
Expand Down Expand Up @@ -150,7 +179,6 @@ describe('Adkernel adapter', () => {
});

it('should have tagid', () => {
// console.warn(bidRequest.imp[0]);
expect(bidRequest.imp[0]).to.have.property('tagid', 'ad-unit-1');
});

Expand All @@ -166,6 +194,38 @@ describe('Adkernel adapter', () => {
})
});

describe('video request building', () => {
let bidRequest;

beforeEach(() => {
sandbox.stub(utils, 'getTopWindowLocation', () => {
return {
protocol: 'https:',
hostname: 'example.com',
host: 'example.com',
pathname: '/index.html',
href: 'http://example.com/index.html'
};
});
ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(videoBidResponse));
doRequest([bid_video]);
bidRequest = JSON.parse(decodeURIComponent(ajaxStub.getCall(0).args[2].r));
});

it('should have video object', () => {
expect(bidRequest.imp[0]).to.have.property('video');
});

it('should have h/w', () => {
expect(bidRequest.imp[0].video).to.have.property('w', 640);
expect(bidRequest.imp[0].video).to.have.property('h', 480);
});

it('should have tagid', () => {
expect(bidRequest.imp[0]).to.have.property('tagid', 'ad-unit-1');
});
});

describe('requests routing', () => {
it('should issue a request for each network', () => {
ajaxStub.onFirstCall().callsArgWith(1, '')
Expand Down Expand Up @@ -210,6 +270,20 @@ describe('Adkernel adapter', () => {
expect(bidResponse.height).to.equal(250);
});

it('should return fully-initialized video bid-response', () => {
ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(videoBidResponse));
doRequest([bid_video]);
let bidResponse = bidmanager.addBidResponse.firstCall.args[1];
expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal('ad-unit-1');
expect(bidResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD);
expect(bidResponse.mediaType).to.equal('video');
expect(bidResponse.bidderCode).to.equal('adkernel');
expect(bidResponse.cpm).to.equal(0.00145);
expect(bidResponse.vastUrl).to.equal('https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl');
expect(bidResponse.width).to.equal(600);
expect(bidResponse.height).to.equal(400);
});

it('should map responses to proper ad units', () => {
ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(bidResponse1));
ajaxStub.onCall(1).callsArgWith(1, JSON.stringify(bidResponse2));
Expand All @@ -234,7 +308,7 @@ describe('Adkernel adapter', () => {
expect(bidmanager.addBidResponse.secondCall.args[0]).to.equal('ad-unit-2');
});

it('should add nurl as pixel', () => {
it('should add nurl as pixel for banner response', () => {
sandbox.spy(utils, 'createTrackPixelHtml');
ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(bidResponse1));
doRequest([bid1_zone1]);
Expand Down

0 comments on commit 7d53893

Please sign in to comment.