diff --git a/modules/aolBidAdapter.js b/modules/aolBidAdapter.js index 42aff892b75..5c3dd430693 100644 --- a/modules/aolBidAdapter.js +++ b/modules/aolBidAdapter.js @@ -4,6 +4,13 @@ const bidfactory = require('src/bidfactory.js'); const bidmanager = require('src/bidmanager.js'); const constants = require('src/constants.json'); const adaptermanager = require('src/adaptermanager'); +const BaseAdapter = require('src/adapter'); + +const AOL_BIDDERS_CODES = { + aol: 'aol', + onemobile: 'onemobile', + onedisplay: 'onedisplay' +}; $$PREBID_GLOBAL$$.aolGlobals = { pixelsDropped: false @@ -14,7 +21,6 @@ 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 nexageBaseApiTemplate = template`${'protocol'}://${'host'}/bidRequest?`; const nexageGetApiTemplate = template`dcn=${'dcn'}&pos=${'pos'}&cmd=bid${'ext'}`; - const BIDDER_CODE = 'aol'; const MP_SERVER_MAP = { us: 'adserver-us.adtech.advertising.com', eu: 'adserver-eu.adtech.advertising.com', @@ -175,7 +181,7 @@ const AolAdapter = function AolAdapter() { function _addErrorBidResponse(bid, response = {}) { const bidResponse = bidfactory.createBid(2, bid); - bidResponse.bidderCode = BIDDER_CODE; + bidResponse.bidderCode = bid.bidder; bidResponse.reason = response.nbr; bidResponse.raw = response; bidmanager.addBidResponse(bid.placementCode, bidResponse); @@ -199,7 +205,7 @@ const AolAdapter = function AolAdapter() { cpm = bidData.price; if (cpm === null || isNaN(cpm)) { - utils.logError('Invalid price in bid response', BIDDER_CODE, bid); + utils.logError('Invalid price in bid response', AOL_BIDDERS_CODES.aol, bid); _addErrorBidResponse(bid, response); return; } @@ -219,7 +225,7 @@ const AolAdapter = function AolAdapter() { } const bidResponse = bidfactory.createBid(1, bid); - bidResponse.bidderCode = BIDDER_CODE; + bidResponse.bidderCode = bid.bidder; bidResponse.ad = ad; bidResponse.cpm = cpm; bidResponse.width = bidData.w; @@ -234,8 +240,16 @@ const AolAdapter = function AolAdapter() { bidmanager.addBidResponse(bid.placementCode, bidResponse); } + function _isMarketplaceBidder(bidder) { + return bidder === AOL_BIDDERS_CODES.aol || bidder === AOL_BIDDERS_CODES.onedisplay; + } + + function _isNexageBidder(bidder) { + return bidder === AOL_BIDDERS_CODES.aol || bidder === AOL_BIDDERS_CODES.onemobile; + } + function _isNexageRequestPost(bid) { - if (bid.params.id && bid.params.imp && bid.params.imp[0]) { + if (_isNexageBidder(bid.bidder) && bid.params.id && bid.params.imp && bid.params.imp[0]) { let imp = bid.params.imp[0]; return imp.id && imp.tagid && ((imp.banner && imp.banner.w && imp.banner.h) || @@ -243,6 +257,14 @@ const AolAdapter = function AolAdapter() { } } + function _isNexageRequestGet(bid) { + return _isNexageBidder(bid.bidder) && bid.params.dcn && bid.params.pos; + } + + function _isMarketplaceRequest(bid) { + return _isMarketplaceBidder(bid.bidder) && bid.params.placement && bid.params.network; + } + function _callBids(params) { utils._each(params.bids, bid => { let apiUrl; @@ -251,9 +273,10 @@ const AolAdapter = function AolAdapter() { withCredentials: true }; let isNexageRequestPost = _isNexageRequestPost(bid); - if (bid.params.placement && bid.params.network) { - apiUrl = _buildMarketplaceUrl(bid); - } else if (bid.params.dcn && bid.params.pos || isNexageRequestPost) { + let isNexageRequestGet = _isNexageRequestGet(bid); + let isMarketplaceRequest = _isMarketplaceRequest(bid); + + if (isNexageRequestGet || isNexageRequestPost) { apiUrl = _buildNexageApiUrl(bid); if (isNexageRequestPost) { data = bid.params; @@ -263,7 +286,10 @@ const AolAdapter = function AolAdapter() { options.method = 'POST'; options.contentType = 'application/json'; } + } else if (isMarketplaceRequest) { + apiUrl = _buildMarketplaceUrl(bid); } + if (apiUrl) { ajax(apiUrl, response => { // Needs to be here in case bidderSettings are defined after requestBids() is called @@ -279,7 +305,7 @@ const AolAdapter = function AolAdapter() { showCpmAdjustmentWarning = false; // warning is shown at most once if (!response && response.length <= 0) { - utils.logError('Empty bid response', BIDDER_CODE, bid); + utils.logError('Empty bid response', AOL_BIDDERS_CODES.aol, bid); _addErrorBidResponse(bid, response); return; } @@ -287,7 +313,7 @@ const AolAdapter = function AolAdapter() { try { response = JSON.parse(response); } catch (e) { - utils.logError('Invalid JSON in bid response', BIDDER_CODE, bid); + utils.logError('Invalid JSON in bid response', AOL_BIDDERS_CODES.aol, bid); _addErrorBidResponse(bid, response); return; } @@ -298,11 +324,16 @@ const AolAdapter = function AolAdapter() { }); } - return { - callBids: _callBids - }; + return Object.assign(BaseAdapter.createNew(AOL_BIDDERS_CODES.aol), { + callBids: _callBids, + createNew: function () { + return new AolAdapter(); + } + }); }; -adaptermanager.registerBidAdapter(new AolAdapter(), 'aol'); +adaptermanager.registerBidAdapter(new AolAdapter(), AOL_BIDDERS_CODES.aol); +adaptermanager.aliasBidAdapter(AOL_BIDDERS_CODES.aol, AOL_BIDDERS_CODES.onedisplay); +adaptermanager.aliasBidAdapter(AOL_BIDDERS_CODES.aol, AOL_BIDDERS_CODES.onemobile); module.exports = AolAdapter; diff --git a/test/spec/modules/aolBidAdapter_spec.js b/test/spec/modules/aolBidAdapter_spec.js index d48de9eb37b..188c5375b89 100644 --- a/test/spec/modules/aolBidAdapter_spec.js +++ b/test/spec/modules/aolBidAdapter_spec.js @@ -22,6 +22,34 @@ let getDefaultBidResponse = () => { }; }; +let getMarketplaceBidParams = () => { + return { + placement: 1234567, + network: '9599.1' + }; +}; + +let getNexageGetBidParams = () => { + return { + dcn: '2c9d2b50015c5ce9db6aeeed8b9500d6', + pos: 'header' + }; +}; + +let getNexagePostBidParams = () => { + return { + id: 'id-1', + imp: [{ + id: 'id-2', + banner: { + w: '100', + h: '100' + }, + tagid: 'header1' + }] + }; +}; + let getDefaultBidRequest = () => { return { bidderCode: 'aol', @@ -34,15 +62,15 @@ let getDefaultBidRequest = () => { bidderRequestId: '7101db09af0db2', requestId: 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6', placementCode: 'foo', - params: { - placement: 1234567, - network: '9599.1' - } + params: getMarketplaceBidParams() }] }; }; describe('AolAdapter', () => { + const MARKETPLACE_URL = 'adserver-us.adtech.advertising.com/pubapi/3.0/'; + const NEXAGE_URL = 'hb.nexage.com/bidRequest?'; + let adapter; beforeEach(() => adapter = new AolAdapter()); @@ -83,7 +111,57 @@ describe('AolAdapter', () => { it('should hit the Marketplace api endpoint with the Marketplace config', () => { adapter.callBids(getDefaultBidRequest()); - expect(requests[0].url).to.contain('adserver-us.adtech.advertising.com/pubapi/3.0/'); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should hit the Marketplace via onedisplay bidder code', () => { + let bidRequest = createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: getMarketplaceBidParams() + }); + + adapter.callBids(bidRequest); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should hit the Marketplace via onedisplay bidder code when Marketplace and Nexage params are present', () => { + let bidParams = Object.assign(getMarketplaceBidParams(), getNexageGetBidParams()); + let bidRequest = createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: bidParams + }); + + adapter.callBids(bidRequest); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should hit the Marketplace via onedisplay bidder code when Nexage params are present', () => { + let bidParams = Object.assign(getMarketplaceBidParams(), getNexageGetBidParams(), getNexagePostBidParams()); + let bidRequest = createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: bidParams + }); + + adapter.callBids(bidRequest); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should not resolve endpoint for onedisplay bidder code when only Nexage params are present', () => { + let bidParams = Object.assign(getNexageGetBidParams(), getNexagePostBidParams()); + + adapter.callBids(createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: bidParams + })); + expect(requests.length).to.equal(0); }); it('should hit endpoint based on the region config option', () => { @@ -105,7 +183,7 @@ describe('AolAdapter', () => { region: 'an' } })); - expect(requests[0].url).to.contain('adserver-us.adtech.advertising.com/pubapi/3.0/'); + expect(requests[0].url).to.contain(MARKETPLACE_URL); }); it('should hit endpoint based on the server config option', () => { @@ -238,33 +316,61 @@ describe('AolAdapter', () => { it('should hit the nexage api endpoint with the nexage config', () => { adapter.callBids(createBidderRequest({ - params: { - dcn: '11223344', - pos: 'header-2324' - } + params: getNexageGetBidParams() })); - expect(requests[0].url).to.contain('hb.nexage.com/bidRequest?'); + + expect(requests[0].url).to.contain(NEXAGE_URL); }); it('should hit the nexage api custom endpoint if specified in the nexage config', () => { + let bidParams = Object.assign({ + host: 'qa-hb.nexage.com' + }, getNexageGetBidParams()); + adapter.callBids(createBidderRequest({ - params: { - host: 'qa-hb.nexage.com', - dcn: '11223344', - pos: 'header-2324' - } + params: bidParams })); expect(requests[0].url).to.contain('qa-hb.nexage.com/bidRequest?'); }); + it('should hit nexage api when nexage and marketplace params are present', () => { + let bidParams = Object.assign(getNexageGetBidParams(), getMarketplaceBidParams()); + + adapter.callBids(createBidderRequest({ + params: bidParams + })); + expect(requests[0].url).to.contain(NEXAGE_URL); + }); + + it('should hit nexage api via onemobile bidder code when nexage and marketplace params are present', () => { + let bidParams = Object.assign(getNexageGetBidParams(), getMarketplaceBidParams()); + + adapter.callBids(createBidderRequest({ + bids: [{ + bidder: 'onemobile' + }], + params: bidParams + })); + expect(requests[0].url).to.contain(NEXAGE_URL); + }); + + it('should not resolve endpoint for onemobile bidder code when only Marketplace params are present', () => { + adapter.callBids(createBidderRequest({ + bids: [{ + bidder: 'onemobile' + }], + params: getMarketplaceBidParams() + })); + + expect(requests.length).to.equal(0); + }); + it('should contain required params - dcn & pos', () => { adapter.callBids(createBidderRequest({ - params: { - dcn: '54321123', - pos: 'footer-2324' - } + params: getNexageGetBidParams() })); - expect(requests[0].url).to.contain('hb.nexage.com/bidRequest?dcn=54321123&pos=footer-2324'); + + expect(requests[0].url).to.contain(NEXAGE_URL + 'dcn=2c9d2b50015c5ce9db6aeeed8b9500d6&pos=header'); }); it('should contain cmd=bid by default', () => { @@ -295,38 +401,21 @@ describe('AolAdapter', () => { }); it('should hit the nexage api endpoint with post data with the openrtb config', () => { - let bidConfig = { - id: 'id-1', - imp: [{ - id: 'id-2', - banner: { - w: '100', - h: '100' - }, - tagid: 'header1' - }] - }; + let bidConfig = getNexagePostBidParams(); + adapter.callBids(createBidderRequest({ params: bidConfig })); - expect(requests[0].url).to.contain('hb.nexage.com/bidRequest?'); + expect(requests[0].url).to.contain(NEXAGE_URL); expect(requests[0].requestBody).to.deep.equal(bidConfig); expect(requests[0].requestHeaders).to.have.property('x-openrtb-version'); }); it('should not hit the nexage api endpoint with post data with the openrtb config' + ' if a required parameter is missing', () => { - let bidConfig = { - id: 'id-1', - imp: [{ - // id: 'id-2', - banner: { - w: '100', - h: '100' - }, - tagid: 'header1' - }] - }; + let bidConfig = getNexagePostBidParams(); + + bidConfig.imp[0].id = null; adapter.callBids(createBidderRequest({ params: bidConfig }));