From 9c53431b5804b04638a26d8cd032feb65abe46a3 Mon Sep 17 00:00:00 2001 From: Marian Rusnak Date: Fri, 23 Sep 2016 11:11:27 +0100 Subject: [PATCH 1/4] Optimize AOL adapter and heavily reduce the size - no aditional request for a JavaScript library - also supports deals - unit tests - Number.isInterger() polyfill --- src/adapters/aol.js | 252 +++++++++----------- src/polyfill.js | 7 + test/spec/adapters/aol_spec.js | 411 +++++++++++++++++++++++++++++++++ 3 files changed, 521 insertions(+), 149 deletions(-) create mode 100644 test/spec/adapters/aol_spec.js diff --git a/src/adapters/aol.js b/src/adapters/aol.js index 199cebee712..b80b76d98fb 100644 --- a/src/adapters/aol.js +++ b/src/adapters/aol.js @@ -1,183 +1,137 @@ var utils = require('../utils.js'); +var ajax = require('../ajax.js').ajax; var bidfactory = require('../bidfactory.js'); var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); var AolAdapter = function AolAdapter() { - // constants - var ADTECH_URI = 'https://secure-ads.pictela.net/rm/marketplace/pubtaglib/0_4_0/pubtaglib_0_4_0.js'; - var ADTECH_BIDDER_NAME = 'aol'; - var ADTECH_PUBAPI_CONFIG = { - pixelsDivId: 'pixelsDiv', - defaultKey: 'aolBid', - roundingConfig: [ - { - from: 0, - to: 999, - roundFunction: 'tenCentsRound' - }, { - from: 1000, - to: -1, - roundValue: 1000 - } - ], - pubApiOK: _addBid, - pubApiER: _addErrorBid + const pubapiTemplate = template`${'protocol'}://${'host'}/pubapi/3.0/${'network'}/${'placement'}/${'pageid'}/${'sizeid'}/ADTECH;v=2;cmd=bid;cors=yes;alias=${'alias'}${'bidfloor'};misc=${'misc'}`; + const BIDDER_CODE = 'aol'; + const SERVER_MAP = { + us: 'adserver-us.adtech.advertising.com', + eu: 'adserver-eu.adtech.advertising.com', + as: 'adserver-as.adtech.advertising.com' }; - var bids; - var bidsMap = {}; - var d = window.document; - var h = d.getElementsByTagName('HEAD')[0]; - var dummyUnitIdCount = 0; - - /** - * @private create a div that we'll use as the - * location for the AOL unit; AOL will document.write - * if the div is not present in the document. - * @param {String} id to identify the div - * @return {String} the id used with the div - */ - function _dummyUnit(id) { - var div = d.createElement('DIV'); - - if (!id || !id.length) { - id = 'ad-placeholder-' + (++dummyUnitIdCount); - } - - div.id = id + '-head-unit'; - h.appendChild(div); - return div.id; + function template(strings, ...keys) { + return function(...values) { + let dict = values[values.length - 1] || {}; + let result = [strings[0]]; + keys.forEach(function(key, i) { + let value = Number.isInteger(key) ? values[key] : dict[key]; + result.push(value, strings[i + 1]); + }); + return result.join(''); + }; } - /** - * @private Add a succesful bid response for aol - * @param {ADTECHResponse} response the response for the bid - * @param {ADTECHContext} context the context passed from aol - */ - function _addBid(response, context) { - var bid = bidsMap[context.alias]; - var cpm; + function _buildPubapiUrl(bid) { + const params = bid.params; + const serverParam = params.server; + var regionParam = params.region || 'us'; + var server; - if (!bid) { - utils.logError('mismatched bid: ' + context.placement, ADTECH_BIDDER_NAME, context); - return; + if (!SERVER_MAP.hasOwnProperty(regionParam)) { + console.warn(`Unknown region '${regionParam}' for AOL bidder.`); + regionParam = 'us'; // Default region. } - cpm = response.getCPM(); - if (cpm === null || isNaN(cpm)) { - return _addErrorBid(response, context); + if (serverParam) { + server = serverParam; + } else { + server = SERVER_MAP[regionParam]; } - // clean up--we no longer need to store the bid - delete bidsMap[context.alias]; - - var bidResponse = bidfactory.createBid(1); - var ad = response.getCreative(); - if (typeof response.getPixels() !== 'undefined') { - ad += response.getPixels(); - } - bidResponse.bidderCode = ADTECH_BIDDER_NAME; - bidResponse.ad = ad; - bidResponse.cpm = cpm; - bidResponse.width = response.getAdWidth(); - bidResponse.height = response.getAdHeight(); - bidResponse.creativeId = response.getCreativeId(); + // Set region param, used by AOL analytics. + params.region = regionParam; + + return pubapiTemplate({ + protocol: (document.location.protocol === 'https:') ? 'https' : 'http', + host: server, + network: params.network, + placement: parseInt(params.placement), + pageid: params.pageId || 0, + sizeid: params.sizeId || 0, + alias: params.alias || utils.getUniqueIdentifierStr(), + bidfloor: (typeof params.bidFloor !== 'undefined') ? + `;bidfloor=${params.bidFloor.toString()}` : '', + misc: new Date().getTime() // cache busting + }); + } - // add it to the bid manager + function _addErrorBidResponse(bid, response) { + var bidResponse = bidfactory.createBid(2); + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.reason = response.nbr; + bidResponse.raw = response; bidmanager.addBidResponse(bid.placementCode, bidResponse); } - /** - * @private Add an error bid response for aol - * @param {ADTECHResponse} response the response for the bid - * @param {ADTECHContext} context the context passed from aol - */ - function _addErrorBid(response, context) { - var bid = bidsMap[context.alias]; + function _addBidResponse(bid, response) { + var bidData; - if (!bid) { - utils.logError('mismatched bid: ' + context.placement, ADTECH_BIDDER_NAME, context); + try { + bidData = response.seatbid[0].bid[0]; + } catch (e) { + _addErrorBidResponse(bid, response); return; } - // clean up--we no longer need to store the bid - delete bidsMap[context.alias]; + var cpm; - var bidResponse = bidfactory.createBid(2); - bidResponse.bidderCode = ADTECH_BIDDER_NAME; - bidResponse.reason = response.getNbr(); - bidResponse.raw = response.getResponse(); - bidmanager.addBidResponse(bid.placementCode, bidResponse); - } + if (bidData.ext && bidData.ext.encp) { + cpm = bidData.ext.encp; + } else { + cpm = bidData.price; - /** - * @private map a prebid bidrequest to an ADTECH/aol bid request - * @param {Bid} bid the bid request - * @return {Object} the bid request, formatted for the ADTECH/DAC api - */ - function _mapUnit(bid) { - var alias = bid.params.alias || utils.getUniqueIdentifierStr(); - - // save the bid - bidsMap[alias] = bid; - - return { - adContainerId: _dummyUnit(bid.params.adContainerId), - server: bid.params.server, // By default, DAC.js will use the US region endpoint (adserver.adtechus.com) - sizeid: bid.params.sizeId || 0, - pageid: bid.params.pageId, - secure: document.location.protocol === 'https:', - serviceType: 'pubapi', - performScreenDetection: false, - alias: alias, - network: bid.params.network, - placement: parseInt(bid.params.placement), - gpt: { - adUnitPath: bid.params.adUnitPath || bid.placementCode, - size: bid.params.size || (bid.sizes || [])[0] - }, - params: { - cors: 'yes', - cmd: 'bid', - bidfloor: (typeof bid.params.bidFloor !== "undefined") ? bid.params.bidFloor.toString() : '' - }, - pubApiConfig: ADTECH_PUBAPI_CONFIG, - placementCode: bid.placementCode - }; - } + if (cpm === null || isNaN(cpm)) { + _addErrorBidResponse(bid, response); + return; + } + } - /** - * @private once ADTECH is loaded, request bids by - * calling ADTECH.loadAd - */ - function _reqBids() { - if (!window.ADTECH) { - utils.logError('window.ADTECH is not present!', ADTECH_BIDDER_NAME); - return; + var ad = bidData.adm; + if (bidData.ext && bidData.ext.pixels) { + ad += bidData.ext.pixels; } - // get the bids - utils._each(bids, function (bid) { - var bidreq = _mapUnit(bid); - window.ADTECH.loadAd(bidreq); - }); + var bidResponse = bidfactory.createBid(1); + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.ad = ad; + bidResponse.cpm = cpm; + bidResponse.width = bidData.w; + bidResponse.height = bidData.h; + bidResponse.creativeId = bidData.crid; + bidResponse.pubapiId = response.id; + bidResponse.currencyCode = response.cur; + if (bidData.dealid) { + bidResponse.dealId = bidData.dealid; + } + + bidmanager.addBidResponse(bid.placementCode, bidResponse); } - /** - * @public call the bids - * this requests the specified bids - * from aol marketplace - * @param {Object} params - * @param {Array} params.bids the bids to be requested - */ function _callBids(params) { - window.bidRequestConfig = window.bidRequestConfig || {}; - window.dacBidRequestConfigs = window.dacBidRequestConfigs || {}; - bids = params.bids; - if (!bids || !bids.length) return; - adloader.loadScript(ADTECH_URI, _reqBids, true); + utils._each(params.bids, function (bid) { + const pubapiUrl = _buildPubapiUrl(bid); + + ajax(pubapiUrl, (response) => { + if (!response && response.length <= 0) { + utils.logError('Empty bid response', BIDDER_CODE, bid); + return; + } + + try { + response = JSON.parse(response); + } catch (e) { + _addErrorBidResponse(bid, response); + return; + } + + _addBidResponse(bid, response); + + }, null, { withCredentials: true }); + }); } return { diff --git a/src/polyfill.js b/src/polyfill.js index ab21fb66683..467a09f7cba 100644 --- a/src/polyfill.js +++ b/src/polyfill.js @@ -56,3 +56,10 @@ if (!Array.prototype.includes) { } }); } + +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger +Number.isInteger = Number.isInteger || function(value) { + return typeof value === 'number' && + isFinite(value) && + Math.floor(value) === value; +}; diff --git a/test/spec/adapters/aol_spec.js b/test/spec/adapters/aol_spec.js new file mode 100644 index 00000000000..7aa9c293da7 --- /dev/null +++ b/test/spec/adapters/aol_spec.js @@ -0,0 +1,411 @@ +import {expect} from 'chai'; +import _ from 'lodash'; +import AolAdapter from 'src/adapters/aol'; +import bidmanager from 'src/bidmanager'; + +const DEFAULT_BIDDER_REQUEST = { + bidderCode: 'aol', + requestId: 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6', + bidderRequestId: '7101db09af0db2', + start: new Date().getTime(), + bids: [{ + bidder: 'aol', + bidId: '84ab500420319d', + bidderRequestId: '7101db09af0db2', + requestId: 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6', + placementCode: 'foo', + params: { + placement: 1234567, + network: '9599.1' + } + }] +}; +const DEFAULT_PUBAPI_RESPONSE = { + "id": "245730051428950632", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": 1, + "impid": "245730051428950632", + "price": 0.09, + "adm": "", + "crid": "0", + "h": 90, + "w": 728, + "ext": {"sizeid": 225} + }] + }] +}; + +describe('AolAdapter', () => { + + let adapter; + + beforeEach(() => adapter = new AolAdapter()); + + function createBidderRequest({bids, params} = {}) { + var bidderRequest = _.cloneDeep(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'); + }); + + 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).to.be.empty; + }); + + it('should hit the default pubapi endpoint', () => { + adapter.callBids(DEFAULT_BIDDER_REQUEST); + expect(requests[0].url).to.contain('adserver-us.adtech.advertising.com/pubapi/3.0/'); + }); + + it('should hit endpoint based on the region config option', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + region: 'eu' + } + })); + expect(requests[0].url).to.contain('adserver-eu.adtech.advertising.com/pubapi/3.0/'); + }); + + it('should hit the default endpoint in case of unknown region config option', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + region: 'an' + } + })); + expect(requests[0].url).to.contain('adserver-us.adtech.advertising.com/pubapi/3.0/'); + }); + + it('should hit endpoint based on the server config option', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + server: 'adserver-eu.adtech.advertising.com' + } + })); + expect(requests[0].url).to.contain('adserver-eu.adtech.advertising.com/pubapi/3.0/'); + }); + + it('should be the pubapi bid request', () => { + adapter.callBids(DEFAULT_BIDDER_REQUEST); + expect(requests[0].url).to.contain('cmd=bid;'); + }); + + it('should be the version 2 of pubapi', () => { + adapter.callBids(DEFAULT_BIDDER_REQUEST); + expect(requests[0].url).to.contain('v=2;'); + }); + + it('should contain cache busting', () => { + adapter.callBids(DEFAULT_BIDDER_REQUEST); + expect(requests[0].url).to.match(/misc=\d+/); + }); + + it('should contain required params - placement & network', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1' + } + })); + expect(requests[0].url).to.contain('/pubapi/3.0/9599.1/1234567/'); + }); + + it('should contain pageId and sizeId of 0 if params are missing', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1' + } + })); + expect(requests[0].url).to.contain('/pubapi/3.0/9599.1/1234567/0/0/ADTECH;'); + }); + + it('should contain pageId optional param', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + pageId: 12345 + } + })); + expect(requests[0].url).to.contain('/pubapi/3.0/9599.1/1234567/12345/'); + }); + + it('should contain sizeId optional param', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + sizeId: 12345 + } + })); + expect(requests[0].url).to.contain('/12345/ADTECH;'); + }); + + it('should contain generated alias if alias param is missing', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1' + } + })); + expect(requests[0].url).to.match(/alias=\w+?;/); + }); + + it('should contain alias optional param', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + alias: 'desktop_articlepage_something_box_300_250' + } + })); + expect(requests[0].url).to.contain('alias=desktop_articlepage_something_box_300_250'); + }); + + it('should not contain bidfloor if bidFloor param is missing', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1' + } + })); + expect(requests[0].url).not.to.contain('bidfloor='); + }); + + it('should contain bidFloor optional param', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + bidFloor: 0.80 + } + })); + expect(requests[0].url).to.contain('bidfloor=0.8'); + }); + + }); + + 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 returned from pubapi', () => { + server.respondWith(JSON.stringify(DEFAULT_PUBAPI_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_PUBAPI_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', 'aol'); + }); + + it('should not be added to bidmanager if empty response is returned', () => { + server.respondWith(''); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.called).to.be.false; + }); + + it('should be added to bidmanager as invalid in case of invalid JSON response', () => { + server.respondWith('{foo:{bar:{baz:'); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); + }); + + it('should be added to bidmanager as invalid in case of no bid data', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); + }); + + it('should be added to bidmanager as invalid in case of empty price', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": 1, + "impid": "245730051428950632", + "adm": "", + "crid": "0", + "h": 90, + "w": 728, + "ext": {"sizeid": 225} + }] + }] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); + }); + + it('should be added to bidmanager with attributes from pubapi response', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": 1, + "impid": "245730051428950632", + "price": 0.09, + "adm": "", + "crid": "12345", + "h": 90, + "w": 728, + "ext": {"sizeid": 225} + }] + }] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + var bidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(bidResponse.ad).to.equal(""); + expect(bidResponse.cpm).to.equal(0.09); + expect(bidResponse.width).to.equal(728); + expect(bidResponse.height).to.equal(90); + expect(bidResponse.creativeId).to.equal('12345'); + expect(bidResponse.pubapiId).to.equal('245730051428950632'); + }); + + it('should be added to bidmanager including pixels from pubapi response', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": 1, + "impid": "245730051428950632", + "price": 0.09, + "adm": "", + "crid": "12345", + "h": 90, + "w": 728, + "ext": { + "sizeid": 225, + "pixels": "" + } + }] + }] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + var bidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(bidResponse.ad).to.equal( + "" + + "" + ); + }); + + it('should be added to bidmanager including dealid from pubapi response', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": 1, + "impid": "245730051428950632", + "dealid": "12345", + "price": 0.09, + "adm": "", + "crid": "12345", + "h": 90, + "w": 728, + "ext": { + "sizeid": 225 + } + }] + }] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + var bidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(bidResponse.dealId).to.equal('12345'); + }); + + it('should be added to bidmanager including encrypted price from pubapi response', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [{ + "bid": [{ + "id": 1, + "impid": "245730051428950632", + "dealid": "12345", + "price": 0.09, + "adm": "", + "crid": "12345", + "h": 90, + "w": 728, + "ext": { + "sizeid": 225, + "encp": "a9334987" + } + }] + }] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + var bidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(bidResponse.cpm).to.equal('a9334987'); + }); + }); + }); +}); From 67c307ae1f686564e785bb2909388731ff536577 Mon Sep 17 00:00:00 2001 From: Marian Rusnak Date: Wed, 28 Sep 2016 10:36:51 +0100 Subject: [PATCH 2/4] Fix AOL adapter to add invalid bid in case of empty response --- src/adapters/aol.js | 6 +++++- test/spec/adapters/aol_spec.js | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/adapters/aol.js b/src/adapters/aol.js index b80b76d98fb..9521c14d029 100644 --- a/src/adapters/aol.js +++ b/src/adapters/aol.js @@ -59,7 +59,7 @@ var AolAdapter = function AolAdapter() { }); } - function _addErrorBidResponse(bid, response) { + function _addErrorBidResponse(bid, response = {}) { var bidResponse = bidfactory.createBid(2); bidResponse.bidderCode = BIDDER_CODE; bidResponse.reason = response.nbr; @@ -73,6 +73,7 @@ var AolAdapter = function AolAdapter() { try { bidData = response.seatbid[0].bid[0]; } catch (e) { + utils.logError('Invalid bid response', BIDDER_CODE, bid); _addErrorBidResponse(bid, response); return; } @@ -85,6 +86,7 @@ var AolAdapter = function AolAdapter() { cpm = bidData.price; if (cpm === null || isNaN(cpm)) { + utils.logError('Invalid price in bid response', BIDDER_CODE, bid); _addErrorBidResponse(bid, response); return; } @@ -118,12 +120,14 @@ var AolAdapter = function AolAdapter() { ajax(pubapiUrl, (response) => { if (!response && response.length <= 0) { utils.logError('Empty bid response', BIDDER_CODE, bid); + _addErrorBidResponse(bid, response); return; } try { response = JSON.parse(response); } catch (e) { + utils.logError('Invalid JSON in bid response', BIDDER_CODE, bid); _addErrorBidResponse(bid, response); return; } diff --git a/test/spec/adapters/aol_spec.js b/test/spec/adapters/aol_spec.js index 7aa9c293da7..fd2e8f0b6f3 100644 --- a/test/spec/adapters/aol_spec.js +++ b/test/spec/adapters/aol_spec.js @@ -244,11 +244,12 @@ describe('AolAdapter', () => { expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property('bidderCode', 'aol'); }); - it('should not be added to bidmanager if empty response is returned', () => { + it('should be added to bidmanager as invalid in case of empty response', () => { server.respondWith(''); adapter.callBids(DEFAULT_BIDDER_REQUEST); server.respond(); - expect(bidmanager.addBidResponse.called).to.be.false; + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); }); it('should be added to bidmanager as invalid in case of invalid JSON response', () => { From 38bd3aece22ff2be627bdac53aec0de2bc7f8426 Mon Sep 17 00:00:00 2001 From: Marian Rusnak Date: Wed, 12 Oct 2016 14:11:34 +0100 Subject: [PATCH 3/4] Set bid response ID to bid request ID for AOL --- src/adapters/aol.js | 4 ++-- test/spec/adapters/aol_spec.js | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/adapters/aol.js b/src/adapters/aol.js index 9521c14d029..037ce7cd586 100644 --- a/src/adapters/aol.js +++ b/src/adapters/aol.js @@ -60,7 +60,7 @@ var AolAdapter = function AolAdapter() { } function _addErrorBidResponse(bid, response = {}) { - var bidResponse = bidfactory.createBid(2); + const bidResponse = bidfactory.createBid(2, bid); bidResponse.bidderCode = BIDDER_CODE; bidResponse.reason = response.nbr; bidResponse.raw = response; @@ -97,7 +97,7 @@ var AolAdapter = function AolAdapter() { ad += bidData.ext.pixels; } - var bidResponse = bidfactory.createBid(1); + const bidResponse = bidfactory.createBid(1, bid); bidResponse.bidderCode = BIDDER_CODE; bidResponse.ad = ad; bidResponse.cpm = cpm; diff --git a/test/spec/adapters/aol_spec.js b/test/spec/adapters/aol_spec.js index fd2e8f0b6f3..8eb09af4496 100644 --- a/test/spec/adapters/aol_spec.js +++ b/test/spec/adapters/aol_spec.js @@ -244,6 +244,15 @@ describe('AolAdapter', () => { expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property('bidderCode', 'aol'); }); + it('should have adId matching the bidId from related bid request', () => { + server.respondWith(JSON.stringify(DEFAULT_PUBAPI_RESPONSE)); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1]) + .to.have.property('adId', DEFAULT_BIDDER_REQUEST.bids[0].bidId); + }); + it('should be added to bidmanager as invalid in case of empty response', () => { server.respondWith(''); adapter.callBids(DEFAULT_BIDDER_REQUEST); @@ -272,6 +281,19 @@ describe('AolAdapter', () => { expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); }); + it('should have adId matching the bidId from bid request in case of no bid data', () => { + server.respondWith(JSON.stringify({ + "id": "245730051428950632", + "cur": "USD", + "seatbid": [] + })); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1]) + .to.have.property('adId', DEFAULT_BIDDER_REQUEST.bids[0].bidId); + }); + it('should be added to bidmanager as invalid in case of empty price', () => { server.respondWith(JSON.stringify({ "id": "245730051428950632", From 981fb7581aacd98eb528f183a7eaa2ef0ca55970 Mon Sep 17 00:00:00 2001 From: Marian Rusnak Date: Wed, 12 Oct 2016 14:12:27 +0100 Subject: [PATCH 4/4] Remove error logging for empty bids and refactor ES6 --- src/adapters/aol.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/adapters/aol.js b/src/adapters/aol.js index 037ce7cd586..f02e58366a8 100644 --- a/src/adapters/aol.js +++ b/src/adapters/aol.js @@ -1,9 +1,9 @@ -var utils = require('../utils.js'); -var ajax = require('../ajax.js').ajax; -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); +const utils = require('../utils.js'); +const ajax = require('../ajax.js').ajax; +const bidfactory = require('../bidfactory.js'); +const bidmanager = require('../bidmanager.js'); -var AolAdapter = function AolAdapter() { +const AolAdapter = function AolAdapter() { const pubapiTemplate = template`${'protocol'}://${'host'}/pubapi/3.0/${'network'}/${'placement'}/${'pageid'}/${'sizeid'}/ADTECH;v=2;cmd=bid;cors=yes;alias=${'alias'}${'bidfloor'};misc=${'misc'}`; const BIDDER_CODE = 'aol'; @@ -28,8 +28,8 @@ var AolAdapter = function AolAdapter() { function _buildPubapiUrl(bid) { const params = bid.params; const serverParam = params.server; - var regionParam = params.region || 'us'; - var server; + let regionParam = params.region || 'us'; + let server; if (!SERVER_MAP.hasOwnProperty(regionParam)) { console.warn(`Unknown region '${regionParam}' for AOL bidder.`); @@ -68,17 +68,16 @@ var AolAdapter = function AolAdapter() { } function _addBidResponse(bid, response) { - var bidData; + let bidData; try { bidData = response.seatbid[0].bid[0]; } catch (e) { - utils.logError('Invalid bid response', BIDDER_CODE, bid); _addErrorBidResponse(bid, response); return; } - var cpm; + let cpm; if (bidData.ext && bidData.ext.encp) { cpm = bidData.ext.encp; @@ -92,7 +91,7 @@ var AolAdapter = function AolAdapter() { } } - var ad = bidData.adm; + let ad = bidData.adm; if (bidData.ext && bidData.ext.pixels) { ad += bidData.ext.pixels; } @@ -114,10 +113,10 @@ var AolAdapter = function AolAdapter() { } function _callBids(params) { - utils._each(params.bids, function (bid) { + utils._each(params.bids, bid => { const pubapiUrl = _buildPubapiUrl(bid); - ajax(pubapiUrl, (response) => { + ajax(pubapiUrl, response => { if (!response && response.length <= 0) { utils.logError('Empty bid response', BIDDER_CODE, bid); _addErrorBidResponse(bid, response);