Skip to content

Commit

Permalink
Carambola Adapter (#1221)
Browse files Browse the repository at this point in the history
* Carambola adapter first check in including:

Carambola.js adapters
Carambola_spec.js test

* adapters/carambola.js  updated ad unit code in the response

carambola_spec.js semantic changes

* some small changes to improve code readability

* carambola_spec.js unit test updates

* coding styles changes

* carambola.js :

fixed: response is still a string and needs to be JSON.parsed (#1221)

* carambola.js test commit

* adapters/carambola_spec.js  fixed did in the emulator (#1221)
  • Loading branch information
LiranMotola authored and Nate Cozi committed Jun 13, 2017
1 parent e456fcf commit 961c826
Show file tree
Hide file tree
Showing 3 changed files with 333 additions and 0 deletions.
1 change: 1 addition & 0 deletions adapters.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"appnexusAst",
"beachfront",
"audienceNetwork",
"carambola",
"conversant",
"districtmDMX",
"fidelity",
Expand Down
193 changes: 193 additions & 0 deletions src/adapters/carambola.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
/**
* Carambola adapter
*/

var bidfactory = require('../bidfactory.js');
var bidmanager = require('../bidmanager.js');
const utils = require('../utils.js');
const ajax = require('../ajax.js').ajax;

const CarambolaAdapter = function CarambolaAdapter() {
const BIDDER_CODE = 'carambola';
const REQUEST_PATH = 'hb/inimage/getHbBIdProcessedResponse';

function _addErrorBidResponse(bid, response = {}, errorMsg = '') {
const bidResponse = bidfactory.createBid(2, bid);
bidResponse.bidderCode = BIDDER_CODE;
bidResponse.reason = errorMsg;
bidmanager.addBidResponse(_getCustomAdUnitCode(bid), bidResponse);
}
// looking at the utils.js at getBidderRequest method. this is what is requested.
function _getCustomAdUnitCode(bid) {
return bid.placementCode;
}

function _addBidResponse(bid, response) {
const bidResponse = bidfactory.createBid(1, bid);
bidResponse.bidderCode = BIDDER_CODE;
bidResponse.ad = response.ad;
bidResponse.cpm = response.cpm;
bidResponse.width = response.width;
bidResponse.height = response.height;
bidResponse.currencyCode = response.cur;
bidResponse.token = response.token;
bidResponse.pvid = response.pageViewId;

bidmanager.addBidResponse(_getCustomAdUnitCode(bid), bidResponse);
}

function _getPageViewId() {
window.Cbola = window.Cbola || {};
window.Cbola.HB = window.Cbola.HB || {};
window.Cbola.HB.pvid = window.Cbola.HB.pvid || _createPageViewId();
return window.Cbola.HB.pvid;
}

function _createPageViewId() {
function _pad(number) {
return number > 9 ? number : '0' + number
}

const MIN = 10000;
const MAX = 90000;
let now = new Date();

var pvid =
_pad(now.getDate()) +
_pad(now.getMonth() + 1) +
_pad(now.getFullYear() % 100) +
_pad(now.getHours()) +
_pad(now.getMinutes()) +
_pad(now.getSeconds()) +
_pad(now.getMilliseconds() % 100) +
Math.floor((Math.random() * MAX) + MIN);

return pvid;
}

// sends a request for each bid
function _buildRequest(bids, params) {
if (!utils.isArray(bids)) {
return;
}
// iterate on every bid and return the response to the hb manager
utils._each(bids, bid => {
let tempParams = params || {};
tempParams.cbolaMode = bid.params.cbolaMode || 0;
tempParams.wid = bid.params.wid || 0;
tempParams.pixel = bid.params.pixel || '';
tempParams.bidFloor = bid.params.bidFloor || 0;
tempParams.pageViewId = _getPageViewId();
tempParams.hb_token = utils.generateUUID();
tempParams.sizes = utils.parseSizesInput(bid.sizes) + '';
tempParams.bidsCount = bids.length;

for (let customParam in bid.params.customParams) {
if (bid.params.customParams.hasOwnProperty(customParam)) {
tempParams['c_' + customParam] = bid.params.customParams[customParam];
}
}

let server = bid.params.server || 'route.carambo.la';
let cbolaHbApiUrl = '//' + server + '/' + REQUEST_PATH;

// the responses of the bid requests
ajax(cbolaHbApiUrl + _jsonToQueryString(tempParams), response => {
// no response
if (!response || response.cpm <= 0) {
utils.logError('Empty bid response', BIDDER_CODE, bid);
_addErrorBidResponse(bid, response, 'Empty bid response');
return;
}
try {
response = JSON.parse(response);
if (response && response.cpm <= 0)
{
utils.logError('Bid response returned 0', BIDDER_CODE, bid);
_addErrorBidResponse(bid, response, 'Bid response returned 0');
return;
}
} catch (e) {
utils.logError('Invalid JSON in bid response', BIDDER_CODE, bid);
_addErrorBidResponse(bid, response, 'Invalid JSON in bid response');
return;
}
_addBidResponse(bid, response);
}, null, {method: 'GET'});
});
}

// build the genral request to the server
function _callBids(params) {
let isIfr,
bids = params.bids || [],
currentURL = (window.parent !== window) ? document.referrer : window.location.href;
currentURL = currentURL && encodeURIComponent(currentURL);
try {
isIfr = window.self !== window.top;
}
catch (e) {
isIfr = false;
}
if (bids.length === 0) {
return;
}

_buildRequest(bids, {
pageUrl: currentURL,
did: bids[0].params.did || 0,
pid: bids[0].params.pid || '',
res: _getScreenSize(screen),
ifr: isIfr,
viewPortDim: _getViewportDimensions(isIfr)
});
}

function _getScreenSize(screen) {
return screen ? `${screen.width}x${screen.height}x${screen.colorDepth}` : '0';
}

function _getViewportDimensions(isIfr) {
let width,
height,
tWin = window,
tDoc = document,
docEl = tDoc.documentElement,
body;

if (isIfr) {
try {
tWin = window.top;
tDoc = window.top.document;
}
catch (e) {
return;
}
docEl = tDoc.documentElement;
body = tDoc.body;
width = tWin.innerWidth || docEl.clientWidth || body.clientWidth;
height = tWin.innerHeight || docEl.clientHeight || body.clientHeight;
} else {
docEl = tDoc.documentElement;
width = tWin.innerWidth || docEl.clientWidth;
height = tWin.innerHeight || docEl.clientHeight;
}
return `${width}x${height}`;
}

function _jsonToQueryString(json) {
return '?' +
Object.keys(json).map(function(key) {
return encodeURIComponent(key) + '=' +
encodeURIComponent(json[key]);
}).join('&');
}

// Export the `callBids` function, so that Prebid.js can execute
// this function when the page asks to send out bid requests.
return {
callBids: _callBids
};
};

module.exports = CarambolaAdapter;
139 changes: 139 additions & 0 deletions test/spec/adapters/carambola_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {expect} from 'chai';
import * as utils from 'src/utils';
import CarambolaAdapter from 'src/adapters/carambola';
import bidmanager from 'src/bidmanager';

const DEFAULT_BIDDER_REQUEST = {
bidderCode: 'carambola',
requestId: 'c9ad932a-41d9-4821-b6dc-0c8146029faf',
adId: '2e3daacdeed03d',
start: new Date().getTime(),
bids: [{
bidder: 'carambola',
adId: '2e3daacdeed03d',
requestId: 'c9ad932a-41d9-4821-b6dc-0c8146029faf',
adUnitCode: 'cbola_prebid_code_97',
token: 'CGYCLyIy',
pageViewId: '22478638',
params: {
pid: 'hbtest',
did: 112591,
wid: 0
}
}]
};

const DEFAULT_HB_RESPONSE = {
cpm: 0.1693953107111156,
ad: '<!--Carambola Script --> <script data-cfasync="false" class="carambola_InContent" type="text/javascript" data-hb_pvid="22478638" data-hb_token="9cd6bf9c-433d-4663-b67f-da727f4cebff" cbola_wid="2" >(function (i,d,s,o,m,r,c,l,w,q,y,h,g) { var e=d.getElementById(r);if(e===null){ var t = d.createElement(o); t.src = g; t.id = r; t.setAttribute(m, s);t.async = 1;var n=d.getElementsByTagName(o)[0];n.parentNode.insertBefore(t, n); var dt=new Date().getTime(); try{i[l][w+y](h,i[l][q+y](h)+\'&\'+dt);}catch(er){i[h]=dt;} } else if(typeof i[c]!==\'undefined\'){i[c]++} else{i[c]=1;}})(window, document, \'InContent\', \'script\', \'mediaType\', \'carambola_proxy\',\'Cbola_IC\',\'localStorage\',\'set\',\'get\',\'Item\',\'cbolaDt\',\'//route.carambo.la/hb/inimage/getLayer?pid=hbtest&did=112591&wid=2&hb_token=CGYCLyIy&pvid=22478638&rdn=[RANDOM_NUMBER]\')</script>',
token: '9cd6bf9c-433d-4663-b67f-da727f4cebff',
width: '300',
height: '250',
currencyCode: 'USD',
pageViewId: '22478638',
requestStatus: 1

};

describe('carambolaAdapter', function () {
let adapter;

beforeEach(() => adapter = new CarambolaAdapter());

function createBidderRequest({bids, params} = {}) {
var bidderRequest = utils.cloneJson(DEFAULT_BIDDER_REQUEST);
if (bids && Array.isArray(bids)) {
bidderRequest.bids = bids;
}
if (params) {
bidderRequest.bids.forEach(bid => bid.params = params);
}
return bidderRequest;
}

describe('callBids()', () => {
it('exists and is a function', () => {
expect(adapter.callBids).to.exist.and.to.be.a('function');
});

// bid request starts
describe('bid request', () => {
let xhr;
let requests;

beforeEach(() => {
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = request => requests.push(request);
});

afterEach(() => xhr.restore());

it('requires parameters to be made', () => {
adapter.callBids({});
expect(requests[0]).to.be.empty;
});

it('should hit the default route.carambo.la endpoint', () => {
adapter.callBids(DEFAULT_BIDDER_REQUEST);
expect(requests[0].url).to.contain('route.carambo.la');
});

it('should verifiy that a page_view_id is sent', () => {
adapter.callBids(DEFAULT_BIDDER_REQUEST);
expect(requests[0].url).to.contain('pageViewId=');
});

it('should should send the correct did', () => {
adapter.callBids(createBidderRequest({
params: {
did: 112591,
wid: 0
}
}));
expect(requests[0].url).to.contain('did=112591');
});
});
// bid request ends

// bid response starts
describe('bid response', () => {
let server;

beforeEach(() => {
server = sinon.fakeServer.create();
sinon.stub(bidmanager, 'addBidResponse');
});

afterEach(() => {
server.restore();
bidmanager.addBidResponse.restore();
});

it('should be added to bidmanager if response is valid', () => {
server.respondWith(JSON.stringify(DEFAULT_HB_RESPONSE));
adapter.callBids(DEFAULT_BIDDER_REQUEST);
server.respond();
expect(bidmanager.addBidResponse.calledOnce).to.be.true;
});

it('should be added to bidmanager with correct bidderCode', () => {
server.respondWith(JSON.stringify(DEFAULT_HB_RESPONSE));
adapter.callBids(DEFAULT_BIDDER_REQUEST);
server.respond();
expect(bidmanager.addBidResponse.calledOnce).to.be.true;
expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property('bidderCode', 'carambola');
});

it('should have pageViewId matching the pageViewId from related bid request', () => {
server.respondWith(JSON.stringify(DEFAULT_HB_RESPONSE));
adapter.callBids(DEFAULT_BIDDER_REQUEST);
server.respond();
expect(bidmanager.addBidResponse.calledOnce).to.be.true;
expect(bidmanager.addBidResponse.firstCall.args[1])
.to.have.property('pvid', DEFAULT_BIDDER_REQUEST.bids[0].pageViewId);
});
});
// bid response ends
});
});

0 comments on commit 961c826

Please sign in to comment.