From dce0a8a8b1b482fec901ccd2536e5b3710b6bdce Mon Sep 17 00:00:00 2001 From: Justin Grimes Date: Mon, 2 Oct 2017 14:41:32 -0400 Subject: [PATCH 1/5] Serverbid: fix ad refreshes --- modules/serverbidBidAdapter.js | 78 +++++++++++++++++----------------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/modules/serverbidBidAdapter.js b/modules/serverbidBidAdapter.js index f5044fe4ae1..7d9aac890cd 100644 --- a/modules/serverbidBidAdapter.js +++ b/modules/serverbidBidAdapter.js @@ -62,8 +62,6 @@ ServerBidAdapter = function ServerBidAdapter() { sizeMap[123] = '970x250'; sizeMap[43] = '300x600'; - const bidIds = []; - baseAdapter.callBids = function(params) { if (params && params.bids && utils.isArray(params.bids) && @@ -115,8 +113,6 @@ ServerBidAdapter = function ServerBidAdapter() { for (let i = 0; i < bids.length; i++) { const bid = bids[i]; - bidIds.push(bid.bidId); - const placement = Object.assign({ divName: bid.bidId, adTypes: bid.adTypes || getSize(bid.sizes) @@ -128,50 +124,52 @@ ServerBidAdapter = function ServerBidAdapter() { } if (data.placements.length) { - ajax(config.BASE_URI, _responseCallback, JSON.stringify(data), { method: 'POST', withCredentials: true, contentType: 'application/json' }); + ajax(config.BASE_URI, _responseCallback(bids), JSON.stringify(data), { method: 'POST', withCredentials: true, contentType: 'application/json' }); } } - function _responseCallback(result) { - let bid; - let bidId; - let bidObj; - let bidCode; - let placementCode; - - try { - result = JSON.parse(result); - } catch (error) { - utils.logError(error); - } - - for (let i = 0; i < bidIds.length; i++) { - bidId = bidIds[i]; - bidObj = utils.getBidRequest(bidId); - bidCode = bidObj.bidder; - placementCode = bidObj.placementCode; - - if (result) { - const decision = result.decisions && result.decisions[bidId]; - const price = decision && decision.pricing && decision.pricing.clearPrice; + function _responseCallback(bids) { + return (function (result) { + let bid; + let bidId; + let bidObj; + let bidCode; + let placementCode; + + try { + result = JSON.parse(result); + } catch (error) { + utils.logError(error); + } - if (decision && price) { - bid = bidfactory.createBid(1, bidObj); - bid.bidderCode = bidCode; - bid.cpm = price; - bid.width = decision.width; - bid.height = decision.height; - bid.ad = retrieveAd(decision); + for (let i = 0; i < bids.length; i++) { + bidObj = bids[i]; + bidId = bidObj.bidId; + bidCode = bidObj.bidder; + placementCode = bidObj.placementCode; + + if (result) { + const decision = result.decisions && result.decisions[bidId]; + const price = decision && decision.pricing && decision.pricing.clearPrice; + + if (decision && price) { + bid = bidfactory.createBid(1); + bid.bidderCode = bidCode; + bid.cpm = price; + bid.width = decision.width; + bid.height = decision.height; + bid.ad = retrieveAd(decision); + } else { + bid = bidfactory.createBid(2); + bid.bidderCode = bidCode; + } } else { - bid = bidfactory.createBid(2, bidObj); + bid = bidfactory.createBid(2); bid.bidderCode = bidCode; } - } else { - bid = bidfactory.createBid(2, bidObj); - bid.bidderCode = bidCode; + bidmanager.addBidResponse(placementCode, bid); } - bidmanager.addBidResponse(placementCode, bid); - } + }); } function retrieveAd(decision) { From 0189c7191aab0e5d1a88ca88288eda8295d32b5f Mon Sep 17 00:00:00 2001 From: Justin Grimes Date: Wed, 25 Oct 2017 15:53:14 -0400 Subject: [PATCH 2/5] Serverbid 1.0 Adapter --- modules/serverbidBidAdapter.js | 332 +++++++++--------- modules/serverbidBidAdapter.md | 44 +++ test/spec/modules/serverbidBidAdapter_spec.js | 297 ++++++++-------- 3 files changed, 361 insertions(+), 312 deletions(-) create mode 100644 modules/serverbidBidAdapter.md diff --git a/modules/serverbidBidAdapter.js b/modules/serverbidBidAdapter.js index 7d9aac890cd..fda05154ee2 100644 --- a/modules/serverbidBidAdapter.js +++ b/modules/serverbidBidAdapter.js @@ -1,103 +1,61 @@ -import Adapter from 'src/adapter'; -import bidfactory from 'src/bidfactory'; -import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; -import { ajax } from 'src/ajax'; -import adaptermanager from 'src/adaptermanager'; - -var ServerBidAdapter; -ServerBidAdapter = function ServerBidAdapter() { - const baseAdapter = new Adapter('serverbid'); - - const CONFIG = { - 'serverbid': { - 'BASE_URI': 'https://e.serverbid.com/api/v2', - 'SMARTSYNC_BASE_URI': 'https://s.zkcdn.net/ss' - }, - 'connectad': { - 'BASE_URI': 'https://i.connectad.io/api/v2', - 'SMARTSYNC_BASE_URI': 'https://s.zkcdn.net/ss' - }, - 'onefiftytwo': { - 'BASE_URI': 'https://e.serverbid.com/api/v2', - 'SMARTSYNC_BASE_URI': 'https://s.zkcdn.net/ss' - } - }; - - const SMARTSYNC_CALLBACK = 'serverbidCallBids'; - - const sizeMap = [ - null, - '120x90', - '120x90', - '468x60', - '728x90', - '300x250', - '160x600', - '120x600', - '300x100', - '180x150', - '336x280', - '240x400', - '234x60', - '88x31', - '120x60', - '120x240', - '125x125', - '220x250', - '250x250', - '250x90', - '0x0', - '200x90', - '300x50', - '320x50', - '320x480', - '185x185', - '620x45', - '300x125', - '800x250' - ]; - - sizeMap[77] = '970x90'; - sizeMap[123] = '970x250'; - sizeMap[43] = '300x600'; - - baseAdapter.callBids = function(params) { - if (params && params.bids && - utils.isArray(params.bids) && - params.bids.length && - CONFIG[params.bidderCode]) { - const config = CONFIG[params.bidderCode]; - config.request = window[params.bidderCode.toUpperCase() + '_CONFIG']; - if (!window.SMARTSYNC) { - _callBids(config, params); - } else { - window[SMARTSYNC_CALLBACK] = function() { - window[SMARTSYNC_CALLBACK] = function() {}; - _callBids(config, params); - }; - - const siteId = params.bids[0].params.siteId; - _appendScript(config.SMARTSYNC_BASE_URI + '/' + siteId + '.js'); - - const sstimeout = window.SMARTSYNC_TIMEOUT || ((params.timeout || 500) / 2); - setTimeout(function() { - var cb = window[SMARTSYNC_CALLBACK]; - window[SMARTSYNC_CALLBACK] = function() {}; - cb(); - }, sstimeout); - } +import { registerBidder } from 'src/adapters/bidderFactory'; + +const BIDDER_CODE = 'serverbid'; + +const CONFIG = { + 'serverbid': { + 'BASE_URI': 'https://e.serverbid.com/api/v2' + }, + 'connectad': { + 'BASE_URI': 'https://i.connectad.io/api/v2' + }, + 'onefiftytwo': { + 'BASE_URI': 'https://e.serverbid.com/api/v2' + }, + 'insticator': { + 'BASE_URI': 'https://e.serverbid.com/api/v2' + } +}; + +export const spec = { + code: BIDDER_CODE, + aliases: ['connectad', 'onefiftytwo', 'insticator'], + + /** + * Determines whether or not the given bid request is valid. + * + * @param {BidRequest} bid The bid params to validate. + * @return boolean True if this is a valid bid, and false otherwise. + */ + isBidRequestValid: function(bid) { + return !!(bid.params.networkId && bid.params.siteId); + }, + + /** + * Make a server request from the list of BidRequests. + * + * @param {validBidRequests[]} - an array of bids + * @return ServerRequest Info describing the request to the server. + */ + + buildRequests: function(validBidRequests) { + // Do we need to group by bidder? i.e. to make multiple requests for + // different endpoints. + + let ret = { + method: 'POST', + url: '', + data: '', + bidRequest: [] + }; + + if (validBidRequests.length < 1) { + return ret; } - }; - function _appendScript(src) { - var script = document.createElement('script'); - script.type = 'text/javascript'; - script.src = src; - document.getElementsByTagName('head')[0].appendChild(script); - } + let ENDPOINT_URL; - function _callBids(config, params) { const data = Object.assign({ placements: [], time: Date.now(), @@ -105,13 +63,13 @@ ServerBidAdapter = function ServerBidAdapter() { url: utils.getTopWindowUrl(), referrer: document.referrer, enableBotFiltering: true, - includePricingData: true - }, config.request); - - const bids = params.bids || []; + includePricingData: true, + parallel: true + }, validBidRequests[0].params); - for (let i = 0; i < bids.length; i++) { - const bid = bids[i]; + validBidRequests.map(bid => { + let config = CONFIG[bid.bidder]; + ENDPOINT_URL = config.BASE_URI; const placement = Object.assign({ divName: bid.bidId, @@ -121,86 +79,114 @@ ServerBidAdapter = function ServerBidAdapter() { if (placement.networkId && placement.siteId) { data.placements.push(placement); } - } + }); - if (data.placements.length) { - ajax(config.BASE_URI, _responseCallback(bids), JSON.stringify(data), { method: 'POST', withCredentials: true, contentType: 'application/json' }); - } - } + ret.data = JSON.stringify(data); + ret.bidRequest = validBidRequests; + ret.url = ENDPOINT_URL; - function _responseCallback(bids) { - return (function (result) { - let bid; - let bidId; - let bidObj; - let bidCode; - let placementCode; - - try { - result = JSON.parse(result); - } catch (error) { - utils.logError(error); - } + return ret; + }, + + /** + * Unpack the response from the server into a list of bids. + * + * @param {*} serverResponse A successful response from the server. + * @return {Bid[]} An array of bids which were nested inside the server. + */ + interpretResponse: function(serverResponse, bidRequest) { + let bid; + let bids; + let bidId; + let bidObj; + let bidResponses = []; - for (let i = 0; i < bids.length; i++) { - bidObj = bids[i]; - bidId = bidObj.bidId; - bidCode = bidObj.bidder; - placementCode = bidObj.placementCode; - - if (result) { - const decision = result.decisions && result.decisions[bidId]; - const price = decision && decision.pricing && decision.pricing.clearPrice; - - if (decision && price) { - bid = bidfactory.createBid(1); - bid.bidderCode = bidCode; - bid.cpm = price; - bid.width = decision.width; - bid.height = decision.height; - bid.ad = retrieveAd(decision); - } else { - bid = bidfactory.createBid(2); - bid.bidderCode = bidCode; - } - } else { - bid = bidfactory.createBid(2); - bid.bidderCode = bidCode; + bids = bidRequest.bidRequest; + + for (let i = 0; i < bids.length; i++) { + bid = {}; + bidObj = bids[i]; + bidId = bidObj.bidId; + bid.bidderCode = bidObj.bidder; + + if (serverResponse) { + const decision = serverResponse.decisions && serverResponse.decisions[bidId]; + const price = decision && decision.pricing && decision.pricing.clearPrice; + + if (decision && price) { + bid.requestId = bidId; + bid.cpm = price; + bid.width = decision.width; + bid.height = decision.height; + bid.ad = retrieveAd(decision); + bid.currency = 'USD'; + bid.creativeId = decision.adId; + bid.ttl = 360; + bid.netRevenue = true; + bid.referrer = utils.getTopWindowUrl(); + + bidResponses.push(bid); } - bidmanager.addBidResponse(placementCode, bid); } - }); - } + } - function retrieveAd(decision) { - return decision.contents && decision.contents[0] && decision.contents[0].body + utils.createTrackPixelHtml(decision.impressionUrl); - } + return bidResponses; + }, - function getSize(sizes) { - const result = []; - sizes.forEach(function(size) { - const index = sizeMap.indexOf(size[0] + 'x' + size[1]); - if (index >= 0) { - result.push(index); - } - }); - return result; + getUserSyncs: function(syncOptions) { + return []; } - - // Export the `callBids` function, so that Prebid.js can execute - // this function when the page asks to send out bid requests. - return Object.assign(this, { - callBids: baseAdapter.callBids, - setBidderCode: baseAdapter.setBidderCode - }); }; -ServerBidAdapter.createNew = function() { - return new ServerBidAdapter(); -}; +const sizeMap = [ + null, + '120x90', + '120x90', + '468x60', + '728x90', + '300x250', + '160x600', + '120x600', + '300x100', + '180x150', + '336x280', + '240x400', + '234x60', + '88x31', + '120x60', + '120x240', + '125x125', + '220x250', + '250x250', + '250x90', + '0x0', + '200x90', + '300x50', + '320x50', + '320x480', + '185x185', + '620x45', + '300x125', + '800x250' +]; + +sizeMap[77] = '970x90'; +sizeMap[123] = '970x250'; +sizeMap[43] = '300x600'; + +function getSize(sizes) { + const result = []; + sizes.forEach(function(size) { + const index = sizeMap.indexOf(size[0] + 'x' + size[1]); + if (index >= 0) { + result.push(index); + } + }); + return result; +} -adaptermanager.registerBidAdapter(new ServerBidAdapter(), 'serverbid'); -adaptermanager.aliasBidAdapter('serverbid', 'connectad'); -adaptermanager.aliasBidAdapter('serverbid', 'onefiftytwo'); +function retrieveAd(decision) { + return decision.contents && decision.contents[0] && decision.contents[0].body + utils.createTrackPixelHtml(decision.impressionUrl); +} -module.exports = ServerBidAdapter; +registerBidder(spec); diff --git a/modules/serverbidBidAdapter.md b/modules/serverbidBidAdapter.md new file mode 100644 index 00000000000..8df2d551033 --- /dev/null +++ b/modules/serverbidBidAdapter.md @@ -0,0 +1,44 @@ +# Overview + +Module Name: Serverbid Bid Adapter + +Module Type: Bid Adapter + +Maintainer: jgrimes@serverbid.com + +# Description + +Connects to Serverbid for receiving bids from configured demand sources. + +# Test Parameters +```javascript + var adUnits = [ + { + code: 'test-ad-1', + sizes: [[300, 250]], + bids: [ + { + bidder: 'serverbid', + params: { + networkId: '9969', + siteId: '45678' + } + } + ] + }, + { + code: 'test-ad-2', + sizes: [[300, 250]], + bids: [ + { + bidder: 'serverbid', + params: { + networkId: '9969', + siteId: '45678', + zoneId: '56789' + } + } + ] + } + ]; +``` diff --git a/test/spec/modules/serverbidBidAdapter_spec.js b/test/spec/modules/serverbidBidAdapter_spec.js index dcbd644b715..93d8749a3a8 100644 --- a/test/spec/modules/serverbidBidAdapter_spec.js +++ b/test/spec/modules/serverbidBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import Adapter from 'modules/serverbidBidAdapter'; +import { spec } from 'modules/serverbidBidAdapter'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; @@ -10,7 +10,7 @@ const REQUEST = { 'bidderCode': 'serverbid', 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d', 'bidderRequestId': '109f2a181342a9', - 'bids': [{ + 'bidRequest': [{ 'bidder': 'serverbid', 'params': { 'networkId': 9969, @@ -24,6 +24,21 @@ const REQUEST = { 'bidId': '2b0f82502298c9', 'bidderRequestId': '109f2a181342a9', 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d' + }, + { + 'bidder': 'serverbid', + 'params': { + 'networkId': 9969, + 'siteId': 730181 + }, + 'placementCode': 'div-gpt-ad-1487778092495-0', + 'sizes': [ + [728, 90], + [970, 90] + ], + 'bidId': '123', + 'bidderRequestId': '109f2a181342a9', + 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d' }], 'start': 1487883186070, 'auctionStart': 1487883186069, @@ -56,178 +71,182 @@ const RESPONSE = { 'events': [], 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} }, + '123': { + 'adId': 2364764, + 'creativeId': 1950991, + 'flightId': 2788300, + 'campaignId': 542982, + 'clickUrl': 'https://e.serverbid.com/r', + 'impressionUrl': 'https://e.serverbid.com/i.gif', + 'contents': [{ + 'type': 'html', + 'body': '', + 'data': { + 'height': 90, + 'width': 728, + 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', + 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' + }, + 'template': 'image' + }], + 'height': 90, + 'width': 728, + 'events': [], + 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} + } } }; -describe('serverbidAdapter', () => { - let adapter; - - beforeEach(() => adapter = new Adapter()); +describe('Serverbid BidAdapter', () => { + let bidRequests; + let adapter = spec; + + beforeEach(() => { + bidRequests = [ + { + bidder: 'serverbid', + params: { + networkId: '9969', + siteId: '730181' + }, + placementCode: 'header-bid-tag-1', + sizes: [[300, 250], [300, 600]], + bidId: '23acc48ad47af5', + requestId: '0fb4905b-9456-4152-86be-c6f6d259ba99', + bidderRequestId: '1c56ad30b9b8ca8', + transactionId: '92489f71-1bf2-49a0-adf9-000cea934729' + } + ]; + }); - describe('request function', () => { - let xhr; - let requests; - let pbConfig; + describe('bid request validation', () => { + it('should accept valid bid requests', () => { + let bid = { + bidder: 'serverbid', + params: { + networkId: '9969', + siteId: '123' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); + }); - beforeEach(() => { - xhr = sinon.useFakeXMLHttpRequest(); - requests = []; - xhr.onCreate = request => requests.push(request); - pbConfig = REQUEST; - // just a single slot - pbConfig.bids = [pbConfig.bids[0]]; + it('should accept valid bid requests with extra fields', () => { + let bid = { + bidder: 'serverbid', + params: { + networkId: '9969', + siteId: '123', + zoneId: '123' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(true); }); - afterEach(() => xhr.restore()); + it('should reject bid requests without siteId', () => { + let bid = { + bidder: 'serverbid', + params: { + networkId: '9969' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); + it('should reject bid requests without networkId', () => { + let bid = { + bidder: 'serverbid', + params: { + siteId: '9969' + } + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); }); + }); - it('requires paramaters to make request', () => { - adapter.callBids({}); - expect(requests).to.be.empty; + describe('buildRequests validation', () => { + it('creates request data', () => { + let request = spec.buildRequests(bidRequests); + + expect(request).to.exist.and.to.be.a('object'); }); - it('requires networkId and siteId', () => { - let backup = pbConfig.bids[0].params; - pbConfig.bids[0].params = { networkId: 1234 }; // no hbid - adapter.callBids(pbConfig); - expect(requests).to.be.empty; + it('request to serverbid should contain a url', () => { + let request = spec.buildRequests(bidRequests); - pbConfig.bids[0].params = { siteId: 1234 }; // no placementid - adapter.callBids(pbConfig); - expect(requests).to.be.empty; + expect(request.url).to.have.string('serverbid.com'); + }); - pbConfig.bids[0].params = backup; + it('requires valid bids to make request', () => { + let request = spec.buildRequests([]); + expect(request.bidRequest).to.be.empty; }); it('sends bid request to ENDPOINT via POST', () => { - adapter.callBids(pbConfig); - expect(requests[0].url).to.equal(ENDPOINT); - expect(requests[0].method).to.equal('POST'); + let request = spec.buildRequests(bidRequests); + + expect(request.method).to.have.string('POST'); }); }); - describe('response handler', () => { - let server; + describe('interpretResponse validation', () => { + it('response should have valid bidderCode', () => { + let bids = spec.interpretResponse(RESPONSE, REQUEST); - beforeEach(() => { - server = sinon.fakeServer.create(); - sinon.stub(bidmanager, 'addBidResponse'); - sinon.stub(utils, 'getBidRequest').returns(REQUEST); + expect(bids[0].bidderCode).to.equal('serverbid'); }); - afterEach(() => { - server.restore(); - bidmanager.addBidResponse.restore(); - utils.getBidRequest.restore(); + it('response should include objects for all bids', () => { + let bids = spec.interpretResponse(RESPONSE, REQUEST); + + expect(bids.length).to.equal(2); }); it('registers bids', () => { - server.respondWith(JSON.stringify(RESPONSE)); + let bids = spec.interpretResponse(RESPONSE, REQUEST); + for (var b of bids) { + expect(b).to.have.property('cpm'); + expect(b.cpm).to.be.above(0); + expect(b).to.have.property('requestId'); + expect(b).to.have.property('cpm'); + expect(b).to.have.property('width'); + expect(b).to.have.property('height'); + expect(b).to.have.property('ad'); + expect(b).to.have.property('currency', 'USD'); + expect(b).to.have.property('creativeId'); + expect(b).to.have.property('ttl', 360); + expect(b).to.have.property('netRevenue', true); + expect(b).to.have.property('referrer'); + } + }); - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); + it('handles nobid responses', () => { + let EMPTY_RESP = Object.assign({}, RESPONSE, {'decisions': null}) + let bids = spec.interpretResponse(EMPTY_RESP, REQUEST); - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm'); - expect(response.cpm).to.be.above(0); + expect(bids).to.be.empty; }); - describe('with SMARTSYNC=true', () => { - it('registers bids when callback is called promptly by smartsync', (done) => { - window.SMARTSYNC = true; - server.respondWith(JSON.stringify(RESPONSE)); - - adapter.callBids(REQUEST); - - setTimeout(() => { - window[SMARTSYNC_CALLBACK](); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm'); - expect(response.cpm).to.be.above(0); - window.SMARTSYNC = false; - done(); - }, 0); - }); - - it('registers bids when callback is never called by smartsync', (done) => { - window.SMARTSYNC = true; - window.SMARTSYNC_TIMEOUT = 100; - - server.respondWith(JSON.stringify(RESPONSE)); - - adapter.callBids(REQUEST); - setTimeout(() => { - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm'); - expect(response.cpm).to.be.above(0); - window.SMARTSYNC = false; - done(); - }, window.SMARTSYNC_TIMEOUT * 2); - }); - - it('registers bids when callback is called (but late) by smartsync', (done) => { - window.SMARTSYNC = true; - window.SMARTSYNC_TIMEOUT = 100; - - server.respondWith(JSON.stringify(RESPONSE)); - - adapter.callBids(REQUEST); - setTimeout(() => { - window[SMARTSYNC_CALLBACK](); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm'); - expect(response.cpm).to.be.above(0); - window.SMARTSYNC = false; - done(); - }, window.SMARTSYNC_TIMEOUT * 2); - }); - }); + it('handles no server response', () => { + let bids = spec.interpretResponse(null, REQUEST); - it('handles nobid responses', () => { - server.respondWith(JSON.stringify({ - 'decisions': [] - })); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property( - 'statusMessage', - 'Bid returned empty or error response' - ); + expect(bids).to.be.empty; }); + }); - it('handles JSON.parse errors', () => { - server.respondWith(''); + describe('getUserSyncs', () => { + let syncOptions = {'iframeEnabled': true}; + + it('handles empty sync options', () => { + let opts = spec.getUserSyncs({}); + + expect(opts).to.be.empty; + }); - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); + it('should always return empty array', () => { + let opts = spec.getUserSyncs(syncOptions); - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property( - 'statusMessage', - 'Bid returned empty or error response' - ); + expect(opts).to.be.empty; }); }); }); From 99c5991afe033b9961c84b93062da101a2eba429 Mon Sep 17 00:00:00 2001 From: Jarrod Swart Date: Tue, 14 Nov 2017 11:33:51 -0500 Subject: [PATCH 3/5] Add adsparc alias, maintainer email. --- modules/serverbidBidAdapter.js | 2 +- modules/serverbidBidAdapter.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/serverbidBidAdapter.js b/modules/serverbidBidAdapter.js index fda05154ee2..8525eacb3bb 100644 --- a/modules/serverbidBidAdapter.js +++ b/modules/serverbidBidAdapter.js @@ -20,7 +20,7 @@ const CONFIG = { export const spec = { code: BIDDER_CODE, - aliases: ['connectad', 'onefiftytwo', 'insticator'], + aliases: ['connectad', 'onefiftytwo', 'insticator', 'adsparc'], /** * Determines whether or not the given bid request is valid. diff --git a/modules/serverbidBidAdapter.md b/modules/serverbidBidAdapter.md index 8df2d551033..8f747e97996 100644 --- a/modules/serverbidBidAdapter.md +++ b/modules/serverbidBidAdapter.md @@ -4,7 +4,7 @@ Module Name: Serverbid Bid Adapter Module Type: Bid Adapter -Maintainer: jgrimes@serverbid.com +Maintainer: jgrimes@serverbid.com, jswart@serverbid.com # Description From 64a08fee121d66aa64d55f5263769746be34dbd0 Mon Sep 17 00:00:00 2001 From: Justin Grimes Date: Mon, 27 Nov 2017 12:59:09 -0500 Subject: [PATCH 4/5] serverbidBidAdapter: updated docs with working examples --- modules/serverbidBidAdapter.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/serverbidBidAdapter.md b/modules/serverbidBidAdapter.md index 8df2d551033..66231d0f135 100644 --- a/modules/serverbidBidAdapter.md +++ b/modules/serverbidBidAdapter.md @@ -21,7 +21,7 @@ Connects to Serverbid for receiving bids from configured demand sources. bidder: 'serverbid', params: { networkId: '9969', - siteId: '45678' + siteId: '980639' } } ] @@ -34,8 +34,8 @@ Connects to Serverbid for receiving bids from configured demand sources. bidder: 'serverbid', params: { networkId: '9969', - siteId: '45678', - zoneId: '56789' + siteId: '980639', + zoneId: '178503' } } ] From a441b2c4bbc68f5ade7ba23a75ca6d270d807bda Mon Sep 17 00:00:00 2001 From: Jarrod Swart Date: Sat, 2 Dec 2017 14:04:27 -0500 Subject: [PATCH 5/5] Updates per PR feedback. --- modules/serverbidBidAdapter.js | 2 +- test/spec/modules/serverbidBidAdapter_spec.js | 110 +++++++++--------- 2 files changed, 57 insertions(+), 55 deletions(-) diff --git a/modules/serverbidBidAdapter.js b/modules/serverbidBidAdapter.js index 8525eacb3bb..bca1f8a5ac0 100644 --- a/modules/serverbidBidAdapter.js +++ b/modules/serverbidBidAdapter.js @@ -103,11 +103,11 @@ export const spec = { bids = bidRequest.bidRequest; + serverResponse = (serverResponse || {}).body; for (let i = 0; i < bids.length; i++) { bid = {}; bidObj = bids[i]; bidId = bidObj.bidId; - bid.bidderCode = bidObj.bidder; if (serverResponse) { const decision = serverResponse.decisions && serverResponse.decisions[bidId]; diff --git a/test/spec/modules/serverbidBidAdapter_spec.js b/test/spec/modules/serverbidBidAdapter_spec.js index 93d8749a3a8..ad6edaba3bc 100644 --- a/test/spec/modules/serverbidBidAdapter_spec.js +++ b/test/spec/modules/serverbidBidAdapter_spec.js @@ -1,7 +1,7 @@ import { expect } from 'chai'; import { spec } from 'modules/serverbidBidAdapter'; -import bidmanager from 'src/bidmanager'; -import * as utils from 'src/utils'; + +var bidFactory = require('src/bidfactory.js'); const ENDPOINT = 'https://e.serverbid.com/api/v2'; const SMARTSYNC_CALLBACK = 'serverbidCallBids'; @@ -46,53 +46,56 @@ const REQUEST = { }; const RESPONSE = { - 'user': { 'key': 'ue1-2d33e91b71e74929b4aeecc23f4376f1' }, - 'decisions': { - '2b0f82502298c9': { - 'adId': 2364764, - 'creativeId': 1950991, - 'flightId': 2788300, - 'campaignId': 542982, - 'clickUrl': 'https://e.serverbid.com/r', - 'impressionUrl': 'https://e.serverbid.com/i.gif', - 'contents': [{ - 'type': 'html', - 'body': '', - 'data': { - 'height': 90, - 'width': 728, - 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', - 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' - }, - 'template': 'image' - }], - 'height': 90, - 'width': 728, - 'events': [], - 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} - }, - '123': { - 'adId': 2364764, - 'creativeId': 1950991, - 'flightId': 2788300, - 'campaignId': 542982, - 'clickUrl': 'https://e.serverbid.com/r', - 'impressionUrl': 'https://e.serverbid.com/i.gif', - 'contents': [{ - 'type': 'html', - 'body': '', - 'data': { - 'height': 90, - 'width': 728, - 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', - 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' - }, - 'template': 'image' - }], - 'height': 90, - 'width': 728, - 'events': [], - 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} + 'headers': null, + 'body': { + 'user': { 'key': 'ue1-2d33e91b71e74929b4aeecc23f4376f1' }, + 'decisions': { + '2b0f82502298c9': { + 'adId': 2364764, + 'creativeId': 1950991, + 'flightId': 2788300, + 'campaignId': 542982, + 'clickUrl': 'https://e.serverbid.com/r', + 'impressionUrl': 'https://e.serverbid.com/i.gif', + 'contents': [{ + 'type': 'html', + 'body': '', + 'data': { + 'height': 90, + 'width': 728, + 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', + 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' + }, + 'template': 'image' + }], + 'height': 90, + 'width': 728, + 'events': [], + 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} + }, + '123': { + 'adId': 2364764, + 'creativeId': 1950991, + 'flightId': 2788300, + 'campaignId': 542982, + 'clickUrl': 'https://e.serverbid.com/r', + 'impressionUrl': 'https://e.serverbid.com/i.gif', + 'contents': [{ + 'type': 'html', + 'body': '', + 'data': { + 'height': 90, + 'width': 728, + 'imageUrl': 'https://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', + 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' + }, + 'template': 'image' + }], + 'height': 90, + 'width': 728, + 'events': [], + 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} + } } } }; @@ -188,12 +191,12 @@ describe('Serverbid BidAdapter', () => { expect(request.method).to.have.string('POST'); }); }); - describe('interpretResponse validation', () => { it('response should have valid bidderCode', () => { - let bids = spec.interpretResponse(RESPONSE, REQUEST); + let bidRequest = spec.buildRequests(REQUEST.bidRequest); + let bid = bidFactory.createBid(1, bidRequest.bidRequest[0]); - expect(bids[0].bidderCode).to.equal('serverbid'); + expect(bid.bidderCode).to.equal('serverbid'); }); it('response should include objects for all bids', () => { @@ -221,7 +224,7 @@ describe('Serverbid BidAdapter', () => { }); it('handles nobid responses', () => { - let EMPTY_RESP = Object.assign({}, RESPONSE, {'decisions': null}) + let EMPTY_RESP = Object.assign({}, RESPONSE, {'body': {'decisions': null}}) let bids = spec.interpretResponse(EMPTY_RESP, REQUEST); expect(bids).to.be.empty; @@ -233,7 +236,6 @@ describe('Serverbid BidAdapter', () => { expect(bids).to.be.empty; }); }); - describe('getUserSyncs', () => { let syncOptions = {'iframeEnabled': true};