Skip to content

Commit

Permalink
CPMStar Bid Adapter (#3820)
Browse files Browse the repository at this point in the history
* Added CPMStar Bid Adapter

* Updated getPlayerSize for cpmstarBidAdapter

* Improved cpmstarBidAdapter code coverage

* updated test spec, removed empty functions, made imports relative, added warnings to erroneous server responses, and removed the default value for ad in bid response.

* added test video ad unit
  • Loading branch information
JoshuaMGoldstein authored and jsnellbaker committed May 21, 2019
1 parent d3faa6a commit 7846560
Show file tree
Hide file tree
Showing 3 changed files with 326 additions and 0 deletions.
118 changes: 118 additions & 0 deletions modules/cpmstarBidAdapter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

import * as utils from '../src/utils';
import { registerBidder } from '../src/adapters/bidderFactory';
import {VIDEO, BANNER} from '../src/mediaTypes';

const BIDDER_CODE = 'cpmstar';

const ENDPOINT_DEV = '//dev.server.cpmstar.com/view.aspx';
const ENDPOINT_STAGING = '//staging.server.cpmstar.com/view.aspx';
const ENDPOINT_PRODUCTION = '//server.cpmstar.com/view.aspx';

const DEFAULT_TTL = 300;
const DEFAULT_CURRENCY = 'USD';

export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO],
pageID: Math.floor(Math.random() * 10e6),

getMediaType: function(bidRequest) {
if (bidRequest == null) return BANNER;
return !utils.deepAccess(bidRequest, 'mediaTypes.video') ? BANNER : VIDEO;
},

getPlayerSize: function(bidRequest) {
var playerSize = utils.deepAccess(bidRequest, 'mediaTypes.video.playerSize');
if (playerSize == null) return [640, 440];
if (playerSize[0] != null) playerSize = playerSize[0];
if (playerSize == null || playerSize[0] == null || playerSize[1] == null) return [640, 440];
return playerSize;
},

isBidRequestValid: function (bid) {
return ((typeof bid.params.placementId === 'string') && !!bid.params.placementId.length) || (typeof bid.params.placementId === 'number');
},

buildRequests: function (validBidRequests, bidderRequest) {
var requests = [];
// This reference to window.top can cause issues when loaded in an iframe if not protected with a try/catch.

for (var i = 0; i < validBidRequests.length; i++) {
var bidRequest = validBidRequests[i];
var referer = encodeURIComponent(bidderRequest.refererInfo.referer);
var e = utils.getBidIdParameter('endpoint', bidRequest.params);
var ENDPOINT = e == 'dev' ? ENDPOINT_DEV : e == 'staging' ? ENDPOINT_STAGING : ENDPOINT_PRODUCTION;
var mediaType = spec.getMediaType(bidRequest);
var playerSize = spec.getPlayerSize(bidRequest);
var videoArgs = '&fv=0' + (playerSize ? ('&w=' + playerSize[0] + '&h=' + playerSize[1]) : '');
requests.push({
method: 'GET',
url: ENDPOINT + '?media=' + mediaType + (mediaType == VIDEO ? videoArgs : '') + '&json=c_b&mv=1&poolid=' + utils.getBidIdParameter('placementId', bidRequest.params) + '&reachedTop=' + encodeURIComponent(bidderRequest.refererInfo.reachedTop) + '&requestid=' + bidRequest.bidId + '&referer=' + referer,
bidRequest: bidRequest,
});
}

return requests;
},

interpretResponse: function (serverResponse, request) {
var bidRequest = request.bidRequest;
var mediaType = spec.getMediaType(bidRequest);

var bidResponses = [];

if (!Array.isArray(serverResponse.body)) {
serverResponse.body = [serverResponse.body];
}

for (var i = 0; i < serverResponse.body.length; i++) {
var raw = serverResponse.body[i];
var rawBid = raw.creatives[0];
if (!rawBid) {
utils.logWarn('cpmstarBidAdapter: server response failed check');
return;
}
var cpm = (parseFloat(rawBid.cpm) || 0);

if (!cpm) {
utils.logWarn('cpmstarBidAdapter: server response failed check. Missing cpm')
return;
}

var bidResponse = {
requestId: rawBid.requestid,
cpm: cpm,
width: rawBid.width || 0,
height: rawBid.height || 0,
currency: rawBid.currency ? rawBid.currency : DEFAULT_CURRENCY,
netRevenue: rawBid.netRevenue ? rawBid.netRevenue : true,
ttl: rawBid.ttl ? rawBid.ttl : DEFAULT_TTL,
creativeId: rawBid.creativeid || 0,
};

if (rawBid.hasOwnProperty('dealId')) {
bidResponse.dealId = rawBid.dealId
}

if (mediaType == BANNER && rawBid.code) {
bidResponse.ad = rawBid.code + (rawBid.px_cr ? "\n<img width=0 height=0 src='" + rawBid.px_cr + "' />" : '');
} else if (mediaType == VIDEO && rawBid.creativemacros && rawBid.creativemacros.HTML5VID_VASTSTRING) {
var playerSize = spec.getPlayerSize(bidRequest);
if (playerSize != null) {
bidResponse.width = playerSize[0];
bidResponse.height = playerSize[1];
}
bidResponse.mediaType = VIDEO;
bidResponse.vastXml = rawBid.creativemacros.HTML5VID_VASTSTRING;
} else {
return utils.logError('bad response', rawBid);
}

bidResponses.push(bidResponse);
}

return bidResponses;
}
};
registerBidder(spec);
50 changes: 50 additions & 0 deletions modules/cpmstarBidAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Overview

```
Module Name: Cpmstar Bidder Adapter
Module Type: Bidder Adapter
Maintainer: [email protected]
```

# Description

Module that connects to Cpmstar's demand sources

# Test Parameters
```
var adUnits = [
{
code: 'banner-ad-div',
mediaTypes: {
banner: {
sizes: [[300, 250]],
}
},
bids: [
{
bidder: 'cpmstar',
params: {
placementId: 81006
}
},
]
},
{
code: 'video-ad-div',
mediaTypes: {
video: {
context: 'instream',
sizes: [[640, 480]]
}
},
bids:[
{
bidder: 'cpmstar',
params: {
placementId: 81007
}
}
]
}
];
```
158 changes: 158 additions & 0 deletions test/spec/modules/cpmstarBidAdapter_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { expect } from 'chai';
import { spec } from 'modules/cpmstarBidAdapter';
import { deepClone } from 'src/utils';

describe('Cpmstar Bid Adapter', function () {
describe('isBidRequestValid', function () {
it('should return true since the bid is valid',
function () {
var bid = { params: { placementId: 123456 } };
expect(spec.isBidRequestValid(bid)).to.equal(true);
})

it('should return false since the bid is invalid', function () {
var bid = { params: { placementId: '' } };
expect(spec.isBidRequestValid(bid)).to.equal(false);
})

it('should return a valid player size', function() {
var bid = { mediaTypes: {
video: {
playerSize: [[960, 540]]
}
}}
expect(spec.getPlayerSize(bid)[0]).to.equal(960);
expect(spec.getPlayerSize(bid)[1]).to.equal(540);
})

it('should return a default player size', function() {
var bid = { mediaTypes: {
video: {
playerSize: null
}
}}
expect(spec.getPlayerSize(bid)[0]).to.equal(640);
expect(spec.getPlayerSize(bid)[1]).to.equal(440);
})
});

describe('buildRequests', function () {
const valid_bid_requests = [{
'bidder': 'cpmstar',
'params': {
'placementId': '57'
},
'sizes': [[300, 250]],
'bidId': 'bidId'
}];

const bidderRequest = {
refererInfo: {
referer: 'referer',
reachedTop: false,
}

};

it('should produce a valid production request', function () {
var requests = spec.buildRequests(valid_bid_requests, bidderRequest);
expect(requests[0]).to.have.property('method');
expect(requests[0]).to.have.property('url');
expect(requests[0]).to.have.property('bidRequest');
expect(requests[0].url).to.include('//server.cpmstar.com/view.aspx');
});
it('should produce a valid staging request', function () {
var stgReq = deepClone(valid_bid_requests);
stgReq[0].params.endpoint = 'staging';
var requests = spec.buildRequests(stgReq, bidderRequest);
expect(requests[0]).to.have.property('method');
expect(requests[0]).to.have.property('url');
expect(requests[0]).to.have.property('bidRequest');
expect(requests[0].url).to.include('//staging.server.cpmstar.com/view.aspx');
});
it('should produce a valid dev request', function () {
var devReq = deepClone(valid_bid_requests);
devReq[0].params.endpoint = 'dev';
var requests = spec.buildRequests(devReq, bidderRequest);
expect(requests[0]).to.have.property('method');
expect(requests[0]).to.have.property('url');
expect(requests[0]).to.have.property('bidRequest');
expect(requests[0].url).to.include('//dev.server.cpmstar.com/view.aspx');
});
})

describe('interpretResponse', function () {
const request = {
bidRequest: {
mediaType: 'BANNER'
}
};
const serverResponse = {
body: [{
creatives: [{
cpm: 1,
width: 0,
height: 0,
currency: 'USD',
netRevenue: true,
ttl: 1,
creativeid: '1234',
requestid: '11123',
code: 'no idea',
media: 'banner',
}
],
}]
};

it('should return a valid bidresponse array', function () {
var r = spec.interpretResponse(serverResponse, request)
var c = serverResponse.body[0].creatives[0];
expect(r[0].length).to.not.equal(0);
expect(r[0].requestId).equal(c.requestid);
expect(r[0].creativeId).equal(c.creativeid);
expect(r[0].cpm).equal(c.cpm);
expect(r[0].width).equal(c.width);
expect(r[0].height).equal(c.height);
expect(r[0].currency).equal(c.currency);
expect(r[0].netRevenue).equal(c.netRevenue);
expect(r[0].ttl).equal(c.ttl);
expect(r[0].ad).equal(c.code);
});

it('should return a valid bidresponse array from a non-array-body', function () {
var r = spec.interpretResponse({ body: serverResponse.body[0] }, request)
var c = serverResponse.body[0].creatives[0];
expect(r[0].length).to.not.equal(0);
expect(r[0].requestId).equal(c.requestid);
expect(r[0].creativeId).equal(c.creativeid);
expect(r[0].cpm).equal(c.cpm);
expect(r[0].width).equal(c.width);
expect(r[0].height).equal(c.height);
expect(r[0].currency).equal(c.currency);
expect(r[0].netRevenue).equal(c.netRevenue);
expect(r[0].ttl).equal(c.ttl);
expect(r[0].ad).equal(c.code);
});

it('should return undefined due to an invalid cpm value', function () {
var badServer = deepClone(serverResponse);
badServer.body[0].creatives[0].cpm = 0;
var c = spec.interpretResponse(badServer, request);
expect(c).to.be.undefined;
});

it('should return undefined due to a bad response', function () {
var badServer = deepClone(serverResponse);
badServer.body[0].creatives[0].code = null;
var c = spec.interpretResponse(badServer, request);
expect(c).to.be.undefined;
});

it('should return a valid response with a dealId', function () {
var dealServer = deepClone(serverResponse);
dealServer.body[0].creatives[0].dealId = 'deal';
expect(spec.interpretResponse(dealServer, request)[0].dealId).to.equal('deal');
});
});
});

0 comments on commit 7846560

Please sign in to comment.