From 9ec218dc37b7d03b7de42bc828e49b1731758054 Mon Sep 17 00:00:00 2001 From: "pratik.ta" <143182729+Pratik3307@users.noreply.github.com> Date: Wed, 11 Dec 2024 22:26:59 +0530 Subject: [PATCH] feat: auctionsCounter at adUnit level (#12557) --- modules/medianetBidAdapter.js | 2 +- src/adUnits.js | 18 ++++++ src/adapterManager.js | 8 +++ test/fixtures/fixtures.js | 62 ++++++++++++++++++++ test/spec/modules/medianetBidAdapter_spec.js | 36 ++++++------ test/spec/unit/adUnits_spec.js | 13 ++++ test/spec/unit/core/adapterManager_spec.js | 31 +++++++++- 7 files changed, 149 insertions(+), 21 deletions(-) diff --git a/modules/medianetBidAdapter.js b/modules/medianetBidAdapter.js index 5adf3f743a7..bd6d684c9a0 100644 --- a/modules/medianetBidAdapter.js +++ b/modules/medianetBidAdapter.js @@ -210,7 +210,7 @@ function slotParams(bidRequest, bidderRequests) { transactionId: bidRequest.ortb2Imp?.ext?.tid, ext: { dfp_id: bidRequest.adUnitCode, - display_count: bidRequest.bidRequestsCount + display_count: bidRequest.auctionsCount }, all: bidRequest.params }; diff --git a/src/adUnits.js b/src/adUnits.js index 413fc6a7c28..5c07718bbea 100644 --- a/src/adUnits.js +++ b/src/adUnits.js @@ -46,6 +46,15 @@ export function incrementBidderWinsCounter(adunit, bidderCode) { return incrementAdUnitCount(adunit, 'winsCounter', bidderCode); } +/** + * Increments and returns current Adunit auctions counter + * @param {string} adunit id + * @returns {number} current adunit auctions count + */ +export function incrementAuctionsCounter(adunit) { + return incrementAdUnitCount(adunit, 'auctionsCounter'); +} + /** * Returns current Adunit counter * @param {string} adunit id @@ -74,3 +83,12 @@ export function getBidderRequestsCounter(adunit, bidder) { export function getBidderWinsCounter(adunit, bidder) { return adUnits?.[adunit]?.bidders?.[bidder]?.winsCounter || 0; } + +/** + * Returns current Adunit auctions counter + * @param {string} adunit id + * @returns {number} current adunit auctions count + */ +export function getAuctionsCounter(adunit) { + return adUnits?.[adunit]?.auctionsCounter || 0; +} diff --git a/src/adapterManager.js b/src/adapterManager.js index fb396d8d794..04bac6eb273 100644 --- a/src/adapterManager.js +++ b/src/adapterManager.js @@ -20,6 +20,7 @@ import { mergeDeep, shuffle, timestamp, + uniques, } from './utils.js'; import {decorateAdUnitsWithNativeParams, nativeAdapters} from './native.js'; import {newBidder} from './adapters/bidderFactory.js'; @@ -28,9 +29,11 @@ import {config, RANDOM} from './config.js'; import {hook} from './hook.js'; import {find, includes} from './polyfill.js'; import { + getAuctionsCounter, getBidderRequestsCounter, getBidderWinsCounter, getRequestsCounter, + incrementAuctionsCounter, incrementBidderRequestsCounter, incrementBidderWinsCounter, incrementRequestsCounter @@ -133,6 +136,7 @@ function getBids({bidderCode, auctionId, bidderRequestId, adUnits, src, metrics} auctionId, src, metrics, + auctionsCount: getAuctionsCounter(adUnit.code), bidRequestsCount: getRequestsCounter(adUnit.code), bidderRequestsCount: getBidderRequestsCounter(adUnit.code, bid.bidder), bidderWinsCount: getBidderWinsCounter(adUnit.code, bid.bidder), @@ -260,6 +264,10 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a if (FEATURES.NATIVE) { decorateAdUnitsWithNativeParams(adUnits); } + adUnits + .map(adUnit => adUnit.code) + .filter(uniques) + .forEach(incrementAuctionsCounter); adUnits.forEach(au => { if (!isPlainObject(au.mediaTypes)) { diff --git a/test/fixtures/fixtures.js b/test/fixtures/fixtures.js index 94513821ce1..b282d9006a6 100644 --- a/test/fixtures/fixtures.js +++ b/test/fixtures/fixtures.js @@ -822,6 +822,68 @@ export function getAdUnits() { ]; }; +export function getTwinAdUnits() { + return [ + { + 'code': '/19968336/header-bid-tag1', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 728, + 90 + ] + ] + } + }, + 'bids': [ + { + 'bidder': 'pubmatic', + 'params': { + 'publisherId': 1234567, + 'adSlot': '1234567@728x90' + } + }, + { + 'bidder': 'medianet', + 'params': { + 'cid': '8CUWQS47C', + 'crid': '241882766' + }, + }, + ] + }, + { + 'code': '/19968336/header-bid-tag1', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [ + 970, + 90 + ] + ] + } + }, + 'bids': [ + { + 'bidder': 'appnexus', + 'params': { + 'placementId': '543221' + } + }, + { + 'bidder': 'medianet', + 'params': { + 'cid': '8CUWQS47C', + 'crid': '241882764' + }, + }, + ] + } + ] +} + export function getBidResponsesFromAPI() { return { '/19968336/header-bid-tag-0': { diff --git a/test/spec/modules/medianetBidAdapter_spec.js b/test/spec/modules/medianetBidAdapter_spec.js index 5f2efc7864f..009af5dbd66 100644 --- a/test/spec/modules/medianetBidAdapter_spec.js +++ b/test/spec/modules/medianetBidAdapter_spec.js @@ -30,7 +30,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1, }, { 'bidder': 'medianet', 'params': { @@ -57,7 +57,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_BID_REQUEST_WITH_CRID = [{ @@ -87,7 +87,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }, { 'bidder': 'medianet', 'params': { @@ -115,7 +115,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_BID_REQUEST_WITH_ORTB2 = [{ 'bidder': 'medianet', @@ -144,7 +144,7 @@ let VALID_BID_REQUEST = [{ 'data': {'pbadslot': '/12345/my-gpt-tag-0'} } }, - 'bidRequestsCount': 1 + 'auctionsCount': 1 }, { 'bidder': 'medianet', 'params': { @@ -173,7 +173,7 @@ let VALID_BID_REQUEST = [{ 'data': {'pbadslot': '/12345/my-gpt-tag-0'} } }, - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], // Protected Audience API Request VALID_BID_REQUEST_WITH_AE_IN_ORTB2IMP = [{ @@ -203,7 +203,7 @@ let VALID_BID_REQUEST = [{ 'ae': 1 } }, - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_BID_REQUEST_WITH_USERID = [{ @@ -235,7 +235,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }, { 'bidder': 'medianet', 'params': { @@ -263,7 +263,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_BID_REQUEST_WITH_USERIDASEIDS = [{ 'bidder': 'medianet', @@ -301,7 +301,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }, { 'bidder': 'medianet', 'params': { @@ -329,7 +329,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_BID_REQUEST_INVALID_BIDFLOOR = [{ @@ -359,7 +359,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }, { 'bidder': 'medianet', 'params': { @@ -386,7 +386,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_NATIVE_BID_REQUEST = [{ 'bidder': 'medianet', @@ -414,7 +414,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1, + 'auctionsCount': 1, 'nativeParams': { 'image': { 'required': true, @@ -471,7 +471,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1, + 'auctionsCount': 1, 'nativeParams': { 'image': { 'required': true, @@ -1244,7 +1244,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_PAYLOAD_PAGE_META = (() => { @@ -1646,7 +1646,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '28f8f8130a583e', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }, { 'bidder': 'medianet', 'params': { @@ -1673,7 +1673,7 @@ let VALID_BID_REQUEST = [{ 'bidId': '3f97ca71b1e5c2', 'bidderRequestId': '1e9b1f07797c1c', 'auctionId': 'aafabfd0-28c0-4ac0-aa09-99689e88b81d', - 'bidRequestsCount': 1 + 'auctionsCount': 1 }], VALID_BIDDER_REQUEST_WITH_GDPR = { 'gdprConsent': { diff --git a/test/spec/unit/adUnits_spec.js b/test/spec/unit/adUnits_spec.js index 01c5bc49f3f..a1215ba3f52 100644 --- a/test/spec/unit/adUnits_spec.js +++ b/test/spec/unit/adUnits_spec.js @@ -61,4 +61,17 @@ describe('Adunit Counter', function () { adunitCounter.incrementBidderWinsCounter(adCode, BIDDER_ID_2); expect(adunitCounter.getBidderWinsCounter(adCode, BIDDER_ID_2)).to.be.equal(1); }); + it('increments and checks auctions counter of adunit 1', function () { + adunitCounter.incrementAuctionsCounter(ADUNIT_ID_1); + expect(adunitCounter.getAuctionsCounter(ADUNIT_ID_1)).to.be.equal(1); + }); + it('increments and checks auctions counter of adunit 2', function () { + adunitCounter.incrementAuctionsCounter(ADUNIT_ID_2); + expect(adunitCounter.getAuctionsCounter(ADUNIT_ID_2)).to.be.equal(1); + }); + it('increments and checks auctions counter if adUnitCode has a dots in it', function () { + const adUnitCode = 'adunit.1' + adunitCounter.incrementAuctionsCounter(adUnitCode); + expect(adunitCounter.getAuctionsCounter(adUnitCode)).to.be.equal(1); + }); }); diff --git a/test/spec/unit/core/adapterManager_spec.js b/test/spec/unit/core/adapterManager_spec.js index 852c84263e9..1aacc518190 100644 --- a/test/spec/unit/core/adapterManager_spec.js +++ b/test/spec/unit/core/adapterManager_spec.js @@ -10,7 +10,8 @@ import { getAdUnits, getServerTestingConfig, getServerTestingsAds, - getBidRequests + getBidRequests, + getTwinAdUnits } from 'test/fixtures/fixtures.js'; import { EVENTS, S2S } from 'src/constants.js'; import * as utils from 'src/utils.js'; @@ -1739,13 +1740,14 @@ describe('adapterManager tests', function () { }); describe('makeBidRequests', function () { - let adUnits; + let adUnits, twinAdUnits; beforeEach(function () { resetAdUnitCounters(); adUnits = utils.deepClone(getAdUnits()).map(adUnit => { adUnit.bids = adUnit.bids.filter(bid => includes(['appnexus', 'rubicon'], bid.bidder)); return adUnit; }) + twinAdUnits = getTwinAdUnits(); }); function makeBidRequests(au = adUnits) { @@ -1862,6 +1864,31 @@ describe('adapterManager tests', function () { }) }); + describe('adUnitAuctionsCounter', () => { + it('should set and increment auctionsCount at adUnitCode level', () => { + const [au1, au2] = adUnits; + makeBidRequests([au1]).flatMap(br => br.bids).forEach(bid => { + expect(bid.auctionsCount).to.eql(1); + }); + makeBidRequests([au1]).flatMap(br => br.bids).forEach(bid => { + expect(bid.auctionsCount).to.eql(2); + }); + makeBidRequests([au1, au2]).flatMap(br => br.bids).forEach(bid => { + expect(bid.auctionsCount).to.eql(bid.adUnitCode === au1.code ? 3 : 1); + }); + }); + + it('should increment the auctionsCount of each adUnitCode exactly once per auction for twin ad units', () => { + const [au1, au2] = twinAdUnits; + makeBidRequests([au1, au2]).flatMap(br => br.bids).forEach(bid => { + expect(bid.auctionsCount).to.eql(1); + }); + makeBidRequests([au1, au2]).flatMap(br => br.bids).forEach(bid => { + expect(bid.auctionsCount).to.eql(2); + }); + }); + }); + describe('and activity controls', () => { let redactOrtb2; let redactBidRequest;