From 545b3c9c703a79dd4b791235692b118e98399dc3 Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Mon, 26 May 2025 17:20:43 +0300 Subject: [PATCH 1/4] Tests: Account auction.cache.enabled Flag --- .../model/config/AccountAuctionConfig.groovy | 1 + .../model/config/AccountCacheConfig.groovy | 9 ++ .../server/functional/tests/CacheSpec.groovy | 133 ++++++++++++++++++ 3 files changed, 143 insertions(+) create mode 100644 src/test/groovy/org/prebid/server/functional/model/config/AccountCacheConfig.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy index 8dc9831e3fa..984ef6409b2 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy @@ -22,6 +22,7 @@ class AccountAuctionConfig { Boolean debugAllow AccountBidValidationConfig bidValidations AccountEventsConfig events + AccountCacheConfig cache AccountPriceFloorsConfig priceFloors Targeting targeting PaaFormat paaformat diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountCacheConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountCacheConfig.groovy new file mode 100644 index 00000000000..121e32f03cd --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountCacheConfig.groovy @@ -0,0 +1,9 @@ +package org.prebid.server.functional.model.config + +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class AccountCacheConfig { + + Boolean enabled +} diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index e145e5a972f..c3d2ac9c75e 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -1,6 +1,7 @@ package org.prebid.server.functional.tests import org.prebid.server.functional.model.config.AccountAuctionConfig +import org.prebid.server.functional.model.config.AccountCacheConfig import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountEventsConfig import org.prebid.server.functional.model.db.Account @@ -42,6 +43,9 @@ class CacheSpec extends BaseSpec { def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) def request = VtrackRequest.getDefaultVtrackRequest(creative) + and: "Flush metrics" + flushMetrics(defaultPbsService) + when: "PBS processes vtrack request" defaultPbsService.sendVtrackRequest(request, accountId) @@ -468,6 +472,9 @@ class CacheSpec extends BaseSpec { "<${impression}> <![CDATA[ ]]> " def request = VtrackRequest.getDefaultVtrackRequest(creative) + and: "Flush metrics" + flushMetrics(defaultPbsService) + when: "PBS processes vtrack request" defaultPbsService.sendVtrackRequest(request, accountId) @@ -492,4 +499,130 @@ class CacheSpec extends BaseSpec { PBSUtils.getRandomCase(" inline ") | " ${PBSUtils.getRandomCase(" impression ")} $PBSUtils.randomNumber " " inline ${PBSUtils.getRandomString()} " | " ImpreSSion " } + + def "PBS should cache bids and add targeting values when account cache config #enabledCacheConcfig"() { + given: "Current value of metric prebid_cache.requests.ok" + def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + + and: "Default BidRequest with cache, targeting" + def bidRequest = BidRequest.getDefaultVideoRequest().tap { + it.enableCache() + } + + and: "Account with cache config" + def account = new Account().tap { + it.uuid = bidRequest.accountId + it.config = new AccountConfig().tap { + it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: enabledCacheConcfig)) + } + } + accountDao.save(account) + + and: "Default bid response" + def presetBidResponse = BidResponse.getDefaultBidResponse(bidRequest) + bidder.setResponse(bidRequest.id, presetBidResponse) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "PBS should call PBC" + assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1 + + and: "BidResponse should contain hb_uuid and hb_cache_id targeting values" + verifyAll (response.seatbid?.first()?.bid?.last()?.ext?.prebid?.targeting) { + it.containsKey('hb_uuid') + it.containsKey('hb_cache_id') + } + + and: "Metrics should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + 1 + assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 + + where: + enabledCacheConcfig << [null, true] + } + + def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() { + given: "Current value of metric prebid_cache.requests.ok" + def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + + and: "Default BidRequest with cache, targeting" + def bidRequest = BidRequest.getDefaultVideoRequest().tap { + it.enableCache() + } + + and: "Account with cache config" + def account = new Account().tap { + it.uuid = bidRequest.accountId + it.config = new AccountConfig().tap { + it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: false)) + } + } + accountDao.save(account) + + and: "Default bid response" + def presetBidResponse = BidResponse.getDefaultBidResponse(bidRequest) + bidder.setResponse(bidRequest.id, presetBidResponse) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + when: "PBS processes auction request" + def response = defaultPbsService.sendAuctionRequest(bidRequest) + + then: "PBS should call PBC" + assert !prebidCache.getRequestCount(bidRequest.imp[0].id) + + and: "BidResponse shouldn't contain hb_uuid and hb_cache_id targeting values" + verifyAll (response.seatbid?.first()?.bid?.last()?.ext?.prebid?.targeting) { + !it.containsKey('hb_uuid') + !it.containsKey('hb_cache_id') + } + + and: "Metrics shouldn't be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + assert !metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] + } + + def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() { + given: "Current value of metric prebid_cache.requests.ok" + def okInitialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) + + and: "Default VtrackRequest" + def accountId = PBSUtils.randomNumber.toString() + def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString)) + def request = VtrackRequest.getDefaultVtrackRequest(creative) + + and: "Create and save enabled events config in account" + def account = new Account().tap { + it.uuid = accountId + it.config = new AccountConfig().tap { + it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: enabledCacheConcfig)) + } + } + accountDao.save(account) + + and: "Flush metrics" + flushMetrics(defaultPbsService) + + when: "PBS processes vtrack request" + defaultPbsService.sendVtrackRequest(request, accountId) + + then: "prebid_cache.creative_size.xml metric should be updated" + def metrics = defaultPbsService.sendCollectedMetricsRequest() + def creativeSize = creative.bytes.length + assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == okInitialValue + 1 + + and: "account..prebid_cache.creative_size.xml should be updated" + assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(accountId)] == 1 + assert metrics[XML_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(accountId)] == creativeSize + + where: + enabledCacheConcfig << [null, false, true] + } } From 70cb38acddb28a7e293037a8f3038f376e729923 Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Tue, 3 Jun 2025 15:47:33 +0300 Subject: [PATCH 2/4] update functional tests --- .../server/functional/tests/CacheSpec.groovy | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index c3d2ac9c75e..ec0ff773cc3 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -15,6 +15,8 @@ import org.prebid.server.functional.model.response.auction.Adm import org.prebid.server.functional.model.response.auction.BidResponse import org.prebid.server.functional.util.PBSUtils +import static org.prebid.server.functional.model.AccountStatus.ACTIVE +import static org.prebid.server.functional.model.bidder.BidderName.GENERIC import static org.prebid.server.functional.model.response.auction.MediaType.BANNER import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO @@ -500,7 +502,7 @@ class CacheSpec extends BaseSpec { " inline ${PBSUtils.getRandomString()} " | " ImpreSSion " } - def "PBS should cache bids and add targeting values when account cache config #enabledCacheConcfig"() { + def "PBS should cache bids and add targeting values when account cache config #accountAuctionConfig"() { given: "Current value of metric prebid_cache.requests.ok" def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC) @@ -509,13 +511,9 @@ class CacheSpec extends BaseSpec { it.enableCache() } - and: "Account with cache config" - def account = new Account().tap { - it.uuid = bidRequest.accountId - it.config = new AccountConfig().tap { - it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: enabledCacheConcfig)) - } - } + and: "Account in the DB" + def accountConfig = new AccountConfig(status: ACTIVE, auction: accountAuctionConfig) + def account = new Account(uuid: bidRequest.accountId, config: accountConfig) accountDao.save(account) and: "Default bid response" @@ -531,11 +529,12 @@ class CacheSpec extends BaseSpec { then: "PBS should call PBC" assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1 - and: "BidResponse should contain hb_uuid and hb_cache_id targeting values" - verifyAll (response.seatbid?.first()?.bid?.last()?.ext?.prebid?.targeting) { - it.containsKey('hb_uuid') - it.containsKey('hb_cache_id') - } + and: "PBS response targeting contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert targetingKeyMap.containsKey('hb_cache_id') + assert targetingKeyMap.containsKey("hb_cache_id_${GENERIC}".toString()) + assert targetingKeyMap.containsKey('hb_uuid') + assert targetingKeyMap.containsKey("hb_uuid_${GENERIC}".toString()) and: "Metrics should be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() @@ -543,7 +542,12 @@ class CacheSpec extends BaseSpec { assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1 where: - enabledCacheConcfig << [null, true] + accountAuctionConfig << [ + new AccountAuctionConfig(), + new AccountAuctionConfig(cache: new AccountCacheConfig()), + new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: null)), + new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: true)) + ] } def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() { @@ -556,12 +560,9 @@ class CacheSpec extends BaseSpec { } and: "Account with cache config" - def account = new Account().tap { - it.uuid = bidRequest.accountId - it.config = new AccountConfig().tap { - it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: false)) - } - } + def accountAuctionConfig = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: false)) + def accountConfig = new AccountConfig(status: ACTIVE, auction: accountAuctionConfig) + def account = new Account(uuid: bidRequest.accountId, config: accountConfig) accountDao.save(account) and: "Default bid response" @@ -577,11 +578,12 @@ class CacheSpec extends BaseSpec { then: "PBS should call PBC" assert !prebidCache.getRequestCount(bidRequest.imp[0].id) - and: "BidResponse shouldn't contain hb_uuid and hb_cache_id targeting values" - verifyAll (response.seatbid?.first()?.bid?.last()?.ext?.prebid?.targeting) { - !it.containsKey('hb_uuid') - !it.containsKey('hb_cache_id') - } + and: "PBS response targeting shouldn't contains bidder specific keys" + def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting + assert !targetingKeyMap.containsKey('hb_cache_id') + assert !targetingKeyMap.containsKey("hb_cache_id_${GENERIC}".toString()) + assert !targetingKeyMap.containsKey('hb_uuid') + assert !targetingKeyMap.containsKey("hb_uuid_${GENERIC}".toString()) and: "Metrics shouldn't be updated" def metrics = defaultPbsService.sendCollectedMetricsRequest() From ae8a8eb7090d56a6b04066eb1301aa087ebe3ac5 Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Tue, 3 Jun 2025 16:09:13 +0300 Subject: [PATCH 3/4] update functional tests --- .../ResponseCorrectionSpec.groovy | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy index b4cbdd3fb88..2426a3fd316 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy @@ -1,5 +1,7 @@ package org.prebid.server.functional.tests.module.responsecorrenction +import org.prebid.server.functional.model.config.AccountAuctionConfig +import org.prebid.server.functional.model.config.AccountCacheConfig import org.prebid.server.functional.model.config.AccountConfig import org.prebid.server.functional.model.config.AccountHooksConfiguration import org.prebid.server.functional.model.config.AppVideoHtml @@ -576,6 +578,61 @@ class ResponseCorrectionSpec extends ModuleBaseSpec { assert !response.ext.warnings } + def "PBS should modify response when requested video impression respond with invalid adm VAST keyword and disabled cache config"() { + given: "Start up time" + def start = Instant.now() + + and: "Default bid request with APP and Video imp" + def bidRequest = getDefaultVideoRequest(APP) + + and: "Set bidder response" + def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap { + seatbid[0].bid[0].setAdm(PBSUtils.getRandomCase(admValue)) + } + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Save account with enabled response correction module" + def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest).tap { + config.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: false)) + } + accountDao.save(accountWithResponseCorrectionModule) + + when: "PBS processes auction request" + def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest) + + then: "PBS should emit log" + def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start) + def bidId = bidResponse.seatbid[0].bid[0].id + def responseCorrection = getLogsByText(logsByTime, bidId) + assert responseCorrection.size() == 1 + assert responseCorrection.any { + it.contains("Bid $bidId of bidder generic: changing media type to banner" as String) + } + + and: "Response should contain seatBid" + assert response.seatbid.size() == 1 + + and: "Response should contain single seatBid with proper media type" + assert response.seatbid.bid.ext.prebid.type.flatten() == [BANNER] + + and: "Response should contain single seatBid with proper meta media type" + assert response.seatbid.bid.ext.prebid.meta.mediaType.flatten() == [VIDEO.value] + + and: "Response shouldn't contain errors" + assert !response.ext.errors + + and: "Response shouldn't contain warnings" + assert !response.ext.warnings + + where: + admValue << [ + "<${' ' * PBSUtils.getRandomNumber(0, OPTIMAL_MAX_LENGTH)}VAST${PBSUtils.randomString}", + "<${' ' * PBSUtils.getRandomNumber(0, OPTIMAL_MAX_LENGTH)}VAST", + "<${' ' * PBSUtils.getRandomNumber(0, OPTIMAL_MAX_LENGTH)}VAST>", + "<${PBSUtils.randomString}VAST${' ' * PBSUtils.getRandomNumber(1, OPTIMAL_MAX_LENGTH)}" + ] + } + private static Account accountConfigWithResponseCorrectionModule(BidRequest bidRequest, Boolean enabledResponseCorrection = true, Boolean enabledAppVideoHtml = true) { def modulesConfig = new PbsModulesConfig(pbResponseCorrection: new PbResponseCorrection( enabled: enabledResponseCorrection, appVideoHtml: new AppVideoHtml(enabled: enabledAppVideoHtml))) From 0a09bcab68399c831fba6f54a54b57138994279c Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Tue, 3 Jun 2025 17:16:43 +0300 Subject: [PATCH 4/4] update after review --- .../groovy/org/prebid/server/functional/tests/CacheSpec.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index ec0ff773cc3..2aec80a7e0a 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -575,7 +575,7 @@ class CacheSpec extends BaseSpec { when: "PBS processes auction request" def response = defaultPbsService.sendAuctionRequest(bidRequest) - then: "PBS should call PBC" + then: "PBS shouldn't call PBC" assert !prebidCache.getRequestCount(bidRequest.imp[0].id) and: "PBS response targeting shouldn't contains bidder specific keys"