Skip to content

Commit

Permalink
Prebid 3 adbutler (prebid#4612)
Browse files Browse the repository at this point in the history
* Adding AdButler Adapter

* Prevent AdButler TypeError

Only attempt to build a bid response if we have the information of which
bid to respond to.

* Refactor AdButler Testing

Now stubbing adLoader instead of spying. Additional changes to ensure
all tests still passed.

* Prevent AdButler TypeErrors

Prevent AdButler TypeErrors and pass bid request object into the bid
response.

* Add optional domain parameter.

Add optional domain parameter to AdButler adapter.

* Update AdButler adapter to 3.0 spec
  • Loading branch information
dharton authored and jsnellbaker committed Dec 18, 2019
1 parent 4c9bf6f commit bb7ecad
Show file tree
Hide file tree
Showing 3 changed files with 352 additions and 0 deletions.
131 changes: 131 additions & 0 deletions modules/adbutlerBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
'use strict';

import * as utils from '../src/utils';
import {config} from '../src/config';
import {registerBidder} from '../src/adapters/bidderFactory';

const BIDDER_CODE = 'adbutler';

export const spec = {
code: BIDDER_CODE,
pageID: Math.floor(Math.random() * 10e6),
aliases: ['divreach'],

isBidRequestValid: function (bid) {
return !!(bid.params.accountID && bid.params.zoneID);
},

buildRequests: function (validBidRequests) {
let i;
let zoneID;
let bidRequest;
let accountID;
let keyword;
let domain;
let requestURI;
let serverRequests = [];
let zoneCounters = {};

for (i = 0; i < validBidRequests.length; i++) {
bidRequest = validBidRequests[i];
zoneID = utils.getBidIdParameter('zoneID', bidRequest.params);
accountID = utils.getBidIdParameter('accountID', bidRequest.params);
keyword = utils.getBidIdParameter('keyword', bidRequest.params);
domain = utils.getBidIdParameter('domain', bidRequest.params);

if (!(zoneID in zoneCounters)) {
zoneCounters[zoneID] = 0;
}

if (typeof domain === 'undefined' || domain.length === 0) {
domain = 'servedbyadbutler.com';
}

requestURI = 'https://' + domain + '/adserve/;type=hbr;';
requestURI += 'ID=' + encodeURIComponent(accountID) + ';';
requestURI += 'setID=' + encodeURIComponent(zoneID) + ';';
requestURI += 'pid=' + encodeURIComponent(spec.pageID) + ';';
requestURI += 'place=' + encodeURIComponent(zoneCounters[zoneID]) + ';';

// append the keyword for targeting if one was passed in
if (keyword !== '') {
requestURI += 'kw=' + encodeURIComponent(keyword) + ';';
}

zoneCounters[zoneID]++;
serverRequests.push({
method: 'GET',
url: requestURI,
data: {},
bidRequest: bidRequest
});
}
return serverRequests;
},

interpretResponse: function (serverResponse, bidRequest) {
const bidObj = bidRequest.bidRequest;
let bidResponses = [];
let bidResponse = {};
let isCorrectSize = false;
let isCorrectCPM = true;
let CPM;
let minCPM;
let maxCPM;
let width;
let height;

serverResponse = serverResponse.body;
if (serverResponse && serverResponse.status === 'SUCCESS' && bidObj) {
CPM = serverResponse.cpm;
minCPM = utils.getBidIdParameter('minCPM', bidObj.params);
maxCPM = utils.getBidIdParameter('maxCPM', bidObj.params);
width = parseInt(serverResponse.width);
height = parseInt(serverResponse.height);

// Ensure response CPM is within the given bounds
if (minCPM !== '' && CPM < parseFloat(minCPM)) {
isCorrectCPM = false;
}
if (maxCPM !== '' && CPM > parseFloat(maxCPM)) {
isCorrectCPM = false;
}

// Ensure that response ad matches one of the placement sizes.
utils._each(utils.deepAccess(bidObj, 'mediaTypes.banner.sizes', []), function (size) {
if (width === size[0] && height === size[1]) {
isCorrectSize = true;
}
});
if (isCorrectCPM && isCorrectSize) {
bidResponse.requestId = bidObj.bidId;
bidResponse.bidderCode = bidObj.bidder;
bidResponse.creativeId = serverResponse.placement_id;
bidResponse.cpm = CPM;
bidResponse.width = width;
bidResponse.height = height;
bidResponse.ad = serverResponse.ad_code;
bidResponse.ad += spec.addTrackingPixels(serverResponse.tracking_pixels);
bidResponse.currency = 'USD';
bidResponse.netRevenue = true;
bidResponse.ttl = config.getConfig('_bidderTimeout');
bidResponse.referrer = utils.deepAccess(bidObj, 'refererInfo.referer');
bidResponses.push(bidResponse);
}
}
return bidResponses;
},

addTrackingPixels: function (trackingPixels) {
let trackingPixelMarkup = '';
utils._each(trackingPixels, function (pixelURL) {
let trackingPixel = '<img height="0" width="0" border="0" style="display:none;" src="';
trackingPixel += pixelURL;
trackingPixel += '">';

trackingPixelMarkup += trackingPixel;
});
return trackingPixelMarkup;
}
};
registerBidder(spec);
Empty file.
221 changes: 221 additions & 0 deletions test/spec/modules/adbutlerBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import {expect} from 'chai';
import {spec} from 'modules/adbutlerBidAdapter';

describe('AdButler adapter', function () {
let bidRequests;

beforeEach(function () {
bidRequests = [
{
bidder: 'adbutler',
params: {
accountID: '167283',
zoneID: '210093',
keyword: 'red',
minCPM: '1.00',
maxCPM: '5.00'
},
placementCode: '/19968336/header-bid-tag-1',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600]],
},
},
bidId: '23acc48ad47af5',
auctionId: '0fb4905b-9456-4152-86be-c6f6d259ba99',
bidderRequestId: '1c56ad30b9b8ca8',
transactionId: '92489f71-1bf2-49a0-adf9-000cea934729'
}
];
});

describe('implementation', function () {
describe('for requests', function () {
it('should accept valid bid', function () {
let validBid = {
bidder: 'adbutler',
params: {
accountID: '167283',
zoneID: '210093'
}
},
isValid = spec.isBidRequestValid(validBid);

expect(isValid).to.equal(true);
});

it('should reject invalid bid', function () {
let invalidBid = {
bidder: 'adbutler',
params: {
accountID: '167283',
}
},
isValid = spec.isBidRequestValid(invalidBid);

expect(isValid).to.equal(false);
});

it('should use custom domain string', function () {
let bidRequests = [
{
bidId: '3c9408cdbf2f68',
sizes: [[300, 250]],
bidder: 'adbutler',
params: {
accountID: '107878',
zoneID: '86133',
domain: 'servedbyadbutler.com.dan.test'
},
auctionId: '10b327aa396609',
placementCode: '/123456/header-bid-tag-1'
}
],
requests = spec.buildRequests(bidRequests),
requestURL = requests[0].url;

expect(requestURL).to.have.string('.dan.test');
});

it('should set default domain', function () {
let requests = spec.buildRequests(bidRequests),
request = requests[0];

let [domain] = request.url.split('/adserve/');

expect(domain).to.equal('https://servedbyadbutler.com');
});

it('should set the keyword parameter', function () {
let requests = spec.buildRequests(bidRequests),
requestURL = requests[0].url;

expect(requestURL).to.have.string(';kw=red;');
});

it('should increment the count for the same zone', function () {
let bidRequests = [
{
sizes: [[300, 250]],
bidder: 'adbutler',
params: {
accountID: '107878',
zoneID: '86133',
}
}, {
sizes: [[300, 250]],
bidder: 'adbutler',
params: {
accountID: '107878',
zoneID: '86133',
}
},
],
requests = spec.buildRequests(bidRequests),
firstRequest = requests[0].url,
secondRequest = requests[1].url;

expect(firstRequest).to.have.string(';place=0;');
expect(secondRequest).to.have.string(';place=1;');
});
});

describe('bid responses', function () {
it('should return complete bid response', function () {
let serverResponse = {
body: {
status: 'SUCCESS',
account_id: 167283,
zone_id: 210093,
cpm: 1.5,
width: 300,
height: 250,
place: 0,
ad_code: '<img src="http://image.source.com/img" alt="" title="" border="0" width="300" height="250">',
tracking_pixels: [
'http://tracking.pixel.com/params=info'
]
}
},
bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});

expect(bids).to.be.lengthOf(1);

expect(bids[0].bidderCode).to.equal('adbutler');
expect(bids[0].cpm).to.equal(1.5);
expect(bids[0].width).to.equal(300);
expect(bids[0].height).to.equal(250);
expect(bids[0].currency).to.equal('USD');
expect(bids[0].netRevenue).to.equal(true);
expect(bids[0].ad).to.have.length.above(1);
expect(bids[0].ad).to.have.string('http://tracking.pixel.com/params=info');
});

it('should return empty bid response', function () {
let serverResponse = {
body: {
status: 'NO_ELIGIBLE_ADS',
zone_id: 210083,
width: 300,
height: 250,
place: 0
}
},
bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});

expect(bids).to.be.lengthOf(0);
});

it('should return empty bid response on incorrect size', function () {
let serverResponse = {
body: {
status: 'SUCCESS',
account_id: 167283,
zone_id: 210083,
cpm: 1.5,
width: 728,
height: 90,
place: 0
}
},
bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});

expect(bids).to.be.lengthOf(0);
});

it('should return empty bid response with CPM too low', function () {
let serverResponse = {
body: {
status: 'SUCCESS',
account_id: 167283,
zone_id: 210093,
cpm: 0.75,
width: 300,
height: 250,
place: 0
}
},
bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});

expect(bids).to.be.lengthOf(0);
});

it('should return empty bid response with CPM too high', function () {
let serverResponse = {
body: {
status: 'SUCCESS',
account_id: 167283,
zone_id: 210093,
cpm: 7,
width: 300,
height: 250,
place: 0
}
},
bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]});

expect(bids).to.be.lengthOf(0);
});
});
});
});

0 comments on commit bb7ecad

Please sign in to comment.