diff --git a/modules/medianetAnalyticsAdapter.js b/modules/medianetAnalyticsAdapter.js index 62958cfbfd26..9d47e10ec503 100644 --- a/modules/medianetAnalyticsAdapter.js +++ b/modules/medianetAnalyticsAdapter.js @@ -2,6 +2,7 @@ import adapter from '../src/AnalyticsAdapter.js'; import adapterManager from '../src/adapterManager.js'; import CONSTANTS from '../src/constants.json'; import * as utils from '../src/utils.js'; +import from from 'core-js-pure/features/array/from.js'; import { ajax } from '../src/ajax.js'; import { getRefererInfo } from '../src/refererDetection.js'; import { AUCTION_COMPLETED, AUCTION_IN_PROGRESS, getPriceGranularity } from '../src/auction.js' @@ -11,6 +12,7 @@ const ENDPOINT = 'https://pb-logs.media.net/log?logid=kfk&evtid=prebid_analytics const CONFIG_URL = 'https://prebid.media.net/rtb/prebid/analytics/config'; const EVENT_PIXEL_URL = 'https://qsearch-a.akamaihd.net/log'; const DEFAULT_LOGGING_PERCENT = 50; +const ANALYTICS_VERSION = '1.0.0'; const PRICE_GRANULARITY = { 'auto': 'pbAg', @@ -39,6 +41,18 @@ const CONFIG_ERROR = 3; const VALID_URL_KEY = ['canonical_url', 'og_url', 'twitter_url']; const DEFAULT_URL_KEY = 'page'; +const LOG_TYPE = { + AP: 'AP', + PR: 'PR', + APPR: 'APPR', + RA: 'RA' +}; + +const BATCHING = { + SINGLE: 'SINGLE', + MULTI: 'MULTI' +} + let auctions = {}; let config; let pageDetails; @@ -73,7 +87,14 @@ class Configure { this.urlToConsume = DEFAULT_URL_KEY; this.debug = false; this.gdprConsent = undefined; + this.gdprApplies = undefined; this.uspConsent = undefined; + this.pixelWaitTime = 0; + this.apLoggingPct = 0; + this.prLoggingPct = 0; + this.batching = BATCHING.SINGLE; + this.shouldBeLogged = {}; + this.mnetDebugConfig = ''; } set publisherLper(plper) { @@ -85,10 +106,12 @@ class Configure { cid: this.cid, lper: Math.round(100 / this.loggingPercent), plper: this.pubLper, - gdpr: this.gdprConsent, + gdpr: this.gdprApplies ? '1' : '0', + gdprConsent: this.gdprConsent, ccpa: this.uspConsent, ajx: this.ajaxState, pbv: PREBID_VERSION, + pbav: ANALYTICS_VERSION, flt: 1, } } @@ -100,10 +123,9 @@ class Configure { _parseResponse(response) { try { response = JSON.parse(response); - if (isNaN(response.percentage)) { - throw new Error('not a number'); - } - this.loggingPercent = response.percentage; + this.setDataFromResponse(response); + this.overrideDomainLevelData(response); + this.overrideToDebug(this.mnetDebugConfig); this.urlToConsume = VALID_URL_KEY.includes(response.urlKey) ? response.urlKey : this.urlToConsume; this.ajaxState = CONFIG_PASS; } catch (e) { @@ -112,6 +134,38 @@ class Configure { new ErrorLogger(ERROR_CONFIG_JSON_PARSE, e).send(); } } + setDataFromResponse(response) { + if (!isNaN(response.percentage)) { + this.loggingPercent = response.percentage; + } + if (!isNaN(response.pixelwaittime)) { + this.pixelWaitTime = response.pixelwaittime; + } + + if (!isNaN(response.aplper)) { + this.apLoggingPct = response.aplper; + this.batching = BATCHING.MULTI; + } + + if (!isNaN(response.prlper)) { + this.prLoggingPct = response.prlper; + this.batching = BATCHING.MULTI; + } + } + + overrideDomainLevelData(response) { + const domain = utils.deepAccess(response, 'domain.' + pageDetails.domain); + if (domain) { + this.setDataFromResponse(domain); + } + } + overrideToDebug(response) { + if (response === '') return; + try { + this.setDataFromResponse(JSON.parse(decodeURIComponent(response))); + } catch (e) { + } + } _errorFetch() { this.ajaxState = CONFIG_ERROR; @@ -128,6 +182,9 @@ class Configure { this.debug = true; return; } + if (utils.deepAccess(urlObj, 'search.mnet_setconfig')) { + this.mnetDebugConfig = utils.deepAccess(urlObj, 'search.mnet_setconfig'); + } ajax( this._configURL(), { @@ -145,7 +202,7 @@ class PageDetail { const twitterUrl = this._getUrlFromSelector('meta[name="twitter:url"]', 'content'); const refererInfo = getRefererInfo(); - this.domain = URL.parseUrl(refererInfo.referer).host; + this.domain = URL.parseUrl(refererInfo.referer).hostname; this.page = refererInfo.referer; this.is_top = refererInfo.reachedTop; this.referrer = this._getTopWindowReferrer(); @@ -202,39 +259,34 @@ class PageDetail { } class AdSlot { - constructor(mediaTypes, allMediaTypeSizes, tmax, supplyAdCode, adext, context, adSize) { - this.mediaTypes = mediaTypes; - this.allMediaTypeSizes = allMediaTypeSizes; + constructor(tmax, supplyAdCode, context, adext) { this.tmax = tmax; this.supplyAdCode = supplyAdCode; + this.context = context; this.adext = adext; - this.logged = false; + this.logged = {}; + this.logged[LOG_TYPE.PR] = false; + this.logged[LOG_TYPE.AP] = false; + this.logged[LOG_TYPE.APPR] = false; this.targeting = undefined; this.medianetPresent = 0; - // shouldBeLogged is assigned when requested, - // since we are waiting for logging percent response - this.shouldBeLogged = undefined; - this.context = context; - this.adSize = adSize; // old ad unit sizes } - getShouldBeLogged() { - if (this.shouldBeLogged === undefined) { - this.shouldBeLogged = isSampled(); + getShouldBeLogged(logType) { + if (logType in config.shouldBeLogged) { + return config.shouldBeLogged[logType]; } - return this.shouldBeLogged; + config.shouldBeLogged[logType] = isSampled(logType); + return config.shouldBeLogged[logType]; } getLoggingData() { return Object.assign({ supcrid: this.supplyAdCode, - mediaTypes: this.mediaTypes && this.mediaTypes.join('|'), - szs: this.allMediaTypeSizes.map(sz => sz.join('x')).join('|'), tmax: this.tmax, targ: JSON.stringify(this.targeting), ismn: this.medianetPresent, vplcmtt: this.context, - sz2: this.adSize.map(sz => sz.join('x')).join('|'), }, this.adext && {'adext': JSON.stringify(this.adext)}, ); @@ -242,12 +294,13 @@ class AdSlot { } class Bid { - constructor(bidId, bidder, src, start, supplyAdCode) { + constructor(bidId, bidder, src, start, adUnitCode, mediaType, allMediaTypeSizes) { this.bidId = bidId; this.bidder = bidder; this.src = src; this.start = start; - this.supplyAdCode = supplyAdCode; + this.adUnitCode = adUnitCode; + this.allMediaTypeSizes = allMediaTypeSizes; this.iwb = 0; this.winner = 0; this.status = bidder === DUMMY_BIDDER ? BID_SUCCESS : BID_TIMEOUT; @@ -257,7 +310,7 @@ class Bid { this.dfpbd = undefined; this.width = undefined; this.height = undefined; - this.mediaType = undefined; + this.mediaType = mediaType; this.timeToRespond = undefined; this.dealId = undefined; this.creativeId = undefined; @@ -268,6 +321,7 @@ class Bid { this.mpvid = undefined; this.floorPrice = undefined; this.floorRule = undefined; + this.serverLatencyMillis = undefined; } get size() { @@ -286,6 +340,7 @@ class Bid { bdp: this.cpm, cbdp: this.dfpbd, dfpbd: this.dfpbd, + szs: this.allMediaTypeSizes.map(sz => sz.join('x')).join('|'), size: this.size, mtype: this.mediaType, dId: this.dealId, @@ -299,7 +354,8 @@ class Bid { mpvid: this.mpvid, bidflr: this.floorPrice, flrrule: this.floorRule, - ext: JSON.stringify(this.ext) + ext: JSON.stringify(this.ext), + rtime: this.serverLatencyMillis, } } } @@ -342,12 +398,10 @@ class Auction { } } - addSlot(supplyAdCode, { mediaTypes, allMediaTypeSizes, tmax, adext, context, adSize }) { - if (supplyAdCode && this.adSlots[supplyAdCode] === undefined) { - this.adSlots[supplyAdCode] = new AdSlot(mediaTypes, allMediaTypeSizes, tmax, supplyAdCode, adext, context, adSize); - this.addBid( - new Bid('-1', DUMMY_BIDDER, 'client', '-1', supplyAdCode) - ); + addSlot({ adUnitCode, supplyAdCode, mediaTypes, allMediaTypeSizes, tmax, adext, context }) { + if (adUnitCode && this.adSlots[adUnitCode] === undefined) { + this.adSlots[adUnitCode] = new AdSlot(tmax, supplyAdCode, context, adext); + this.addBid(new Bid('-1', DUMMY_BIDDER, 'client', '-1', adUnitCode, mediaTypes, allMediaTypeSizes)); } } @@ -363,7 +417,7 @@ class Auction { getAdslotBids(adslot) { return this.bids - .filter((bid) => bid.supplyAdCode === adslot) + .filter((bid) => bid.adUnitCode === adslot) .map((bid) => bid.getLoggingData()); } @@ -382,46 +436,66 @@ class Auction { } } -function auctionInitHandler({auctionId, timestamp, bidderRequests}) { +function auctionInitHandler({auctionId, adUnits, timeout, timestamp, bidderRequests}) { if (auctionId && auctions[auctionId] === undefined) { auctions[auctionId] = new Auction(auctionId); auctions[auctionId].auctionInitTime = timestamp; } + addAddSlots(auctionId, adUnits, timeout); const floorData = utils.deepAccess(bidderRequests, '0.bids.0.floorData'); if (floorData) { auctions[auctionId].floorData = {...floorData}; } } -function bidRequestedHandler({ auctionId, auctionStart, bids, start, timeout, uspConsent, gdpr }) { +function addAddSlots(auctionId, adUnits, tmax) { + adUnits = adUnits || []; + const groupedAdUnits = utils.groupBy(adUnits, 'code'); + Object.keys(groupedAdUnits).forEach((adUnitCode) => { + const adUnits = groupedAdUnits[adUnitCode]; + const supplyAdCode = utils.deepAccess(adUnits, '0.adUnitCode') || adUnitCode; + let context = ''; + let adext = {}; + + const mediaTypeMap = {}; + let oSizes = {banner: new Set(), video: new Set()}; + adUnits.forEach(({mediaTypes, sizes, ext}) => { + mediaTypes = mediaTypes || {}; + adext = Object.assign(adext, ext || utils.deepAccess(mediaTypes, 'banner.ext')); + context = utils.deepAccess(mediaTypes, 'video.context') || ''; + Object.keys(mediaTypes).forEach((mediaType) => mediaTypeMap[mediaType] = 1); + const sizeObject = _getSizes(mediaTypes, sizes); + sizeObject.banner.forEach(size => oSizes.banner.add(size)); + sizeObject.video.forEach(size => oSizes.video.add(size)); + }); + + adext = utils.isEmpty(adext) ? undefined : adext; + oSizes.native = mediaTypeMap.native === 1 ? [[1, 1]] : []; + const allMediaTypeSizes = [].concat(from(oSizes.banner), oSizes.native, from(oSizes.video)); + const mediaTypes = Object.keys(mediaTypeMap).join('|'); + + auctions[auctionId].addSlot({adUnitCode, supplyAdCode, mediaTypes, allMediaTypeSizes, context, tmax, adext}); + }); +} + +function bidRequestedHandler({ auctionId, auctionStart, bids, start, uspConsent, gdpr }) { if (!(auctions[auctionId] instanceof Auction)) { return; } - if (gdpr && gdpr.gdprApplies) { + config.gdprApplies = !!(gdpr && gdpr.gdprApplies); + if (config.gdprApplies) { config.gdprConsent = gdpr.consentString || ''; } config.uspConsent = config.uspConsent || uspConsent; + auctions[auctionId].auctionStartTime = auctionStart; bids.forEach(bid => { - const { adUnitCode, bidder, mediaTypes, sizes, bidId, src } = bid; - if (!auctions[auctionId].adSlots[adUnitCode]) { - auctions[auctionId].auctionStartTime = auctionStart; - const sizeObject = _getSizes(mediaTypes, sizes); - auctions[auctionId].addSlot( - adUnitCode, - Object.assign({}, - (mediaTypes instanceof Object) && { mediaTypes: Object.keys(mediaTypes) }, - { allMediaTypeSizes: [].concat(sizeObject.banner, sizeObject.native, sizeObject.video) }, - { adext: utils.deepAccess(mediaTypes, 'banner.ext') || '' }, - { tmax: timeout }, - { context: utils.deepAccess(mediaTypes, 'video.context') || '' }, - { adSize: sizeObject.banner } - ) - ); - } - let bidObj = new Bid(bidId, bidder, src, start, adUnitCode); + const { adUnitCode, bidder, bidId, src, mediaTypes, sizes } = bid; + const sizeObject = _getSizes(mediaTypes, sizes); + const requestSizes = [].concat(sizeObject.banner, sizeObject.native, sizeObject.video); + const bidObj = new Bid(bidId, bidder, src, start, adUnitCode, mediaTypes && Object.keys(mediaTypes).join('|'), requestSizes); auctions[auctionId].addBid(bidObj); if (bidder === MEDIANET_BIDDER_CODE) { bidObj.crid = utils.deepAccess(bid, 'params.crid'); @@ -482,6 +556,9 @@ function bidResponseHandler(bid) { bid.ext.crid && { 'crid': bid.ext.crid } ); } + if (typeof bid.serverResponseTimeMs !== 'undefined') { + bidObj.serverLatencyMillis = bid.serverResponseTimeMs; + } } function noBidResponseHandler({ auctionId, bidId }) { @@ -511,12 +588,18 @@ function bidTimeoutHandler(timedOutBids) { }) } -function auctionEndHandler({ auctionId, auctionEnd }) { +function auctionEndHandler({auctionId, auctionEnd, adUnitCodes}) { if (!(auctions[auctionId] instanceof Auction)) { return; } auctions[auctionId].status = AUCTION_COMPLETED; auctions[auctionId].auctionEndTime = auctionEnd; + + if (config.batching === BATCHING.MULTI) { + adUnitCodes.forEach(function (adUnitCode) { + sendEvent(auctionId, adUnitCode, LOG_TYPE.PR); + }); + } } function setTargetingHandler(params) { @@ -530,20 +613,51 @@ function setTargetingHandler(params) { adunitObj.targeting = params[adunit]; auctionObj.setTargetingTime = Date.now(); let targetingObj = Object.keys(params[adunit]).reduce((result, key) => { - if (key.indexOf('hb_adid') !== -1) { + if (key.indexOf(CONSTANTS.TARGETING_KEYS.AD_ID) !== -1) { result[key] = params[adunit][key] } return result; }, {}); + const winnerAdId = params[adunit][CONSTANTS.TARGETING_KEYS.AD_ID]; + let winningBid; let bidAdIds = Object.keys(targetingObj).map(k => targetingObj[k]); auctionObj.bids.filter((bid) => bidAdIds.indexOf(bid.adId) !== -1).map(function(bid) { bid.iwb = 1; + if (bid.adId === winnerAdId) { + winningBid = bid; + } + }); + auctionObj.bids.forEach(bid => { + if (bid.bidder === DUMMY_BIDDER && bid.adUnitCode === adunit) { + bid.iwb = bidAdIds.length === 0 ? 0 : 1; + bid.width = utils.deepAccess(winningBid, 'width'); + bid.height = utils.deepAccess(winningBid, 'height'); + } }); - sendEvent(auctionId, adunit, false); + sendEvent(auctionId, adunit, getLogType()); } } } +function getLogType() { + if (config.batching === BATCHING.SINGLE) { + return LOG_TYPE.APPR; + } + return LOG_TYPE.AP; +} + +function setBidderDone(params) { + if (config.pixelWaitTime != null && config.pixelWaitTime > 0) { + setTimeout(fireApAfterWait, config.pixelWaitTime, params) + } +} + +function fireApAfterWait(params) { + params.bids.forEach(function (adUnit) { + sendEvent(params.auctionId, adUnit.adUnitCode, LOG_TYPE.AP); + }); +} + function bidWonHandler(bid) { const { requestId, auctionId, adUnitCode } = bid; if (!(auctions[auctionId] instanceof Auction)) { @@ -555,26 +669,50 @@ function bidWonHandler(bid) { } auctions[auctionId].bidWonTime = Date.now(); bidObj.winner = 1; - sendEvent(auctionId, adUnitCode, true); + sendEvent(auctionId, adUnitCode, LOG_TYPE.RA); } -function isSampled() { - return Math.random() * 100 < parseFloat(config.loggingPercent); +function isSampled(logType) { + return Math.random() * 100 < parseFloat(getLogPercentage(logType)); +} + +function getLogPercentage(logType) { + let logPercentage = config.loggingPercent; + if (config.batching === BATCHING.MULTI) { + if (logType === LOG_TYPE.AP) { + logPercentage = config.apLoggingPct; + } else if (logType === LOG_TYPE.PR) { + logPercentage = config.prLoggingPct; + } + } + return logPercentage; } function isValidAuctionAdSlot(acid, adtag) { return (auctions[acid] instanceof Auction) && (auctions[acid].adSlots[adtag] instanceof AdSlot); } -function sendEvent(id, adunit, isBidWonEvent) { +function sendEvent(id, adunit, logType) { if (!isValidAuctionAdSlot(id, adunit)) { return; } - if (isBidWonEvent) { - fireAuctionLog(id, adunit, isBidWonEvent); - } else if (auctions[id].adSlots[adunit].getShouldBeLogged() && !auctions[id].adSlots[adunit].logged) { - auctions[id].adSlots[adunit].logged = true; - fireAuctionLog(id, adunit, isBidWonEvent); + if (logType === LOG_TYPE.RA) { + fireAuctionLog(id, adunit, logType); + } else { + fireApPrLog(id, adunit, logType) + } +} + +function fireApPrLog(auctionId, adUnitName, logType) { + const adSlot = auctions[auctionId].adSlots[adUnitName]; + if (adSlot.getShouldBeLogged(logType) && !adSlot.logged[logType]) { + if (config.batching === BATCHING.SINGLE) { + adSlot.logged[LOG_TYPE.AP] = true; + adSlot.logged[LOG_TYPE.PR] = true; + } else { + adSlot.logged[logType] = true; + } + fireAuctionLog(auctionId, adUnitName, logType); } } @@ -585,8 +723,9 @@ function getCommonLoggingData(acid, adtag) { return Object.assign(commonParams, adunitParams, auctionParams); } -function fireAuctionLog(acid, adtag, isBidWonEvent) { +function fireAuctionLog(acid, adtag, logType) { let commonParams = getCommonLoggingData(acid, adtag); + commonParams.lgtp = logType; let targeting = utils.deepAccess(commonParams, 'targ'); Object.keys(commonParams).forEach((key) => (commonParams[key] == null) && delete commonParams[key]); @@ -594,7 +733,7 @@ function fireAuctionLog(acid, adtag, isBidWonEvent) { let bidParams; - if (isBidWonEvent) { + if (logType === LOG_TYPE.RA) { bidParams = auctions[acid].getWinnerAdslotBid(adtag); commonParams.lper = 1; } else { @@ -700,6 +839,10 @@ let medianetAnalytics = Object.assign(adapter({URL, analyticsType}), { setTargetingHandler(args); break; } + case CONSTANTS.EVENTS.BIDDER_DONE : { + setBidderDone(args); + break; + } case CONSTANTS.EVENTS.BID_WON: { bidWonHandler(args); break; diff --git a/test/spec/modules/medianetAnalyticsAdapter_spec.js b/test/spec/modules/medianetAnalyticsAdapter_spec.js index 97b45cef00c0..41a6338225ef 100644 --- a/test/spec/modules/medianetAnalyticsAdapter_spec.js +++ b/test/spec/modules/medianetAnalyticsAdapter_spec.js @@ -9,20 +9,23 @@ const { } = CONSTANTS; const MOCK = { - AUCTION_INIT: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739}, - AUCTION_INIT_WITH_FLOOR: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739, 'bidderRequests': [{'bids': [{ 'floorData': {'enforcements': {'enforceJS': true}} }]}]}, + Ad_Units: [{'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'banner': {'sizes': [[300, 250]]}}, 'bids': [], 'ext': {'prop1': 'value1'}}], + MULTI_FORMAT_TWIN_AD_UNITS: [{'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'native': {'image': {'required': true, 'sizes': [150, 50]}}}, 'bids': [], 'ext': {'prop1': 'value1'}}, {'code': 'div-gpt-ad-1460505748561-0', 'mediaTypes': {'video': {'playerSize': [640, 480], 'context': 'instream'}}, 'bids': [], 'ext': {'prop1': 'value1'}}], + AUCTION_INIT: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739, 'timeout': 6000}, + AUCTION_INIT_WITH_FLOOR: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'timestamp': 1584563605739, 'timeout': 6000, 'bidderRequests': [{'bids': [{ 'floorData': {'enforcements': {'enforceJS': true}} }]}]}, BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743}, - MULTI_FORMAT_BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'video': {'playerSize': [640, 480], 'context': 'instream'}, 'native': {'image': {'required': true, 'sizes': [150, 50]}, 'title': {'required': true, 'len': 80}}, 'ext': ['asdads']}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743}, + MULTI_FORMAT_BID_REQUESTED: {'bidderCode': 'medianet', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'bids': [{'bidder': 'medianet', 'params': {'cid': 'TEST_CID', 'crid': '451466393'}, 'mediaTypes': {'banner': {'sizes': [[300, 250]]}, 'video': {'playerSize': [640, 480], 'context': 'instream'}, 'native': {'image': {'required': true, 'sizes': [150, 50]}, 'title': {'required': true, 'len': 80}}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'sizes': [[300, 250]], 'bidId': '28248b0e6aece2', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}], 'auctionStart': 1584563605739, 'timeout': 6000, 'uspConsent': '1YY', 'start': 1584563605743}, BID_RESPONSE: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'ext': {'pvid': 123, 'crid': '321'}, 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'floorData': {'floorValue': 1.10, 'floorRule': 'banner'}, 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, AUCTION_END: {'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'auctionEnd': 1584563605739}, SET_TARGETING: {'div-gpt-ad-1460505748561-0': {'prebid_test': '1', 'hb_format': 'banner', 'hb_source': 'client', 'hb_size': '300x250', 'hb_pb': '2.00', 'hb_adid': '3e6e4bce5c8fb3', 'hb_bidder': 'medianet', 'hb_format_medianet': 'banner', 'hb_source_medianet': 'client', 'hb_size_medianet': '300x250', 'hb_pb_medianet': '2.00', 'hb_adid_medianet': '3e6e4bce5c8fb3', 'hb_bidder_medianet': 'medianet'}}, + NO_BID_SET_TARGETING: {'div-gpt-ad-1460505748561-0': {}}, BID_WON: {'bidderCode': 'medianet', 'width': 300, 'height': 250, 'statusMessage': 'Bid available', 'adId': '3e6e4bce5c8fb3', 'requestId': '28248b0e6aece2', 'mediaType': 'banner', 'source': 'client', 'no_bid': false, 'cpm': 2.299, 'ad': 'AD_CODE', 'ttl': 180, 'creativeId': 'Test1', 'netRevenue': true, 'currency': 'USD', 'dfp_id': 'div-gpt-ad-1460505748561-0', 'originalCpm': 1.1495, 'originalCurrency': 'USD', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'responseTimestamp': 1584563606009, 'requestTimestamp': 1584563605743, 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'timeToRespond': 266, 'pbLg': '2.00', 'pbMg': '2.20', 'pbHg': '2.29', 'pbAg': '2.25', 'pbDg': '2.29', 'pbCg': '2.00', 'size': '300x250', 'adserverTargeting': {'hb_bidder': 'medianet', 'hb_adid': '3e6e4bce5c8fb3', 'hb_pb': '2.00', 'hb_size': '300x250', 'hb_source': 'client', 'hb_format': 'banner', 'prebid_test': 1}, 'status': 'rendered', 'params': [{'cid': 'test123', 'crid': '451466393'}]}, NO_BID: {'bidder': 'medianet', 'params': {'cid': 'test123', 'crid': '451466393', 'site': {}}, 'mediaTypes': {'banner': {'sizes': [[300, 250]], 'ext': ['asdads']}}, 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'transactionId': '303fa0c6-682f-4aea-8e4a-dc68f0d5c7d5', 'sizes': [[300, 250], [300, 600]], 'bidId': '28248b0e6aece2', 'bidderRequestId': '13fccf3809fe43', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'src': 'client'}, BID_TIMEOUT: [{'bidId': '28248b0e6aece2', 'bidder': 'medianet', 'adUnitCode': 'div-gpt-ad-1460505748561-0', 'auctionId': '8e0d5245-deb3-406c-96ca-9b609e077ff7', 'params': [{'cid': 'test123', 'crid': '451466393', 'site': {}}, {'cid': '8CUX0H51P', 'crid': '451466393', 'site': {}}], 'timeout': 6}] } function performAuctionWithFloorConfig() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT_WITH_FLOOR); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT_WITH_FLOOR, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); events.emit(AUCTION_END, MOCK.AUCTION_END); @@ -31,7 +34,7 @@ function performAuctionWithFloorConfig() { } function performStandardAuctionWithWinner() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); events.emit(AUCTION_END, MOCK.AUCTION_END); @@ -40,27 +43,27 @@ function performStandardAuctionWithWinner() { } function performMultiFormatAuctionWithNoBid() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.MULTI_FORMAT_TWIN_AD_UNITS}); events.emit(BID_REQUESTED, MOCK.MULTI_FORMAT_BID_REQUESTED); - events.emit(BID_RESPONSE, MOCK.BID_RESPONSE); + events.emit(NO_BID, MOCK.NO_BID); events.emit(AUCTION_END, MOCK.AUCTION_END); - events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(SET_TARGETING, MOCK.NO_BID_SET_TARGETING); } function performStandardAuctionWithNoBid() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(NO_BID, MOCK.NO_BID); events.emit(AUCTION_END, MOCK.AUCTION_END); - events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(SET_TARGETING, MOCK.NO_BID_SET_TARGETING); } function performStandardAuctionWithTimeout() { - events.emit(AUCTION_INIT, MOCK.AUCTION_INIT); + events.emit(AUCTION_INIT, {...MOCK.AUCTION_INIT, adUnits: MOCK.Ad_Units}); events.emit(BID_REQUESTED, MOCK.BID_REQUESTED); events.emit(BID_TIMEOUT, MOCK.BID_TIMEOUT); events.emit(AUCTION_END, MOCK.AUCTION_END); - events.emit(SET_TARGETING, MOCK.SET_TARGETING); + events.emit(SET_TARGETING, MOCK.NO_BID_SET_TARGETING); } function getQueryData(url) { @@ -123,8 +126,10 @@ describe('Media.net Analytics Adapter', function() { cid: 'test123' } }); + medianetAnalytics.clearlogsQueue(); }); afterEach(function () { + medianetAnalytics.clearlogsQueue(); medianetAnalytics.disableAnalytics(); }); @@ -139,10 +144,9 @@ describe('Media.net Analytics Adapter', function() { performMultiFormatAuctionWithNoBid(); const noBidLog = medianetAnalytics.getlogsQueue().map((log) => getQueryData(log))[0]; medianetAnalytics.clearlogsQueue(); - - expect(noBidLog.szs).to.equal(encodeURIComponent('300x250|1x1|640x480')); + expect(noBidLog.mtype).to.have.ordered.members([encodeURIComponent('banner|native|video'), encodeURIComponent('banner|video|native')]); + expect(noBidLog.szs).to.have.ordered.members([encodeURIComponent('300x250|1x1|640x480'), encodeURIComponent('300x250|1x1|640x480')]); expect(noBidLog.vplcmtt).to.equal('instream'); - expect(noBidLog.sz2).to.equal(encodeURIComponent('300x250')); }); it('should have winner log in standard auction', function() { @@ -167,6 +171,7 @@ describe('Media.net Analytics Adapter', function() { src: 'client', size: '300x250', mtype: 'banner', + gdpr: '0', cid: 'test123', lper: '1', ogbdp: '1.1495', @@ -205,7 +210,7 @@ describe('Media.net Analytics Adapter', function() { expect(noBidLog.status).to.have.ordered.members(['1', '2']); expect(noBidLog.src).to.have.ordered.members(['client', 'client']); expect(noBidLog.curr).to.have.ordered.members(['', '']); - expect(noBidLog.mtype).to.have.ordered.members(['', '']); + expect(noBidLog.mtype).to.have.ordered.members(['banner', 'banner']); expect(noBidLog.ogbdp).to.have.ordered.members(['', '']); expect(noBidLog.mpvid).to.have.ordered.members(['', '']); expect(noBidLog.crid).to.have.ordered.members(['', '451466393']); @@ -223,7 +228,7 @@ describe('Media.net Analytics Adapter', function() { expect(timeoutLog.status).to.have.ordered.members(['1', '3']); expect(timeoutLog.src).to.have.ordered.members(['client', 'client']); expect(timeoutLog.curr).to.have.ordered.members(['', '']); - expect(timeoutLog.mtype).to.have.ordered.members(['', '']); + expect(timeoutLog.mtype).to.have.ordered.members(['banner', 'banner']); expect(timeoutLog.ogbdp).to.have.ordered.members(['', '']); expect(timeoutLog.mpvid).to.have.ordered.members(['', '']); expect(timeoutLog.crid).to.have.ordered.members(['', '451466393']);