Skip to content

Commit a877687

Browse files
Add Account auction.cache.enabled Flag (#3955)
1 parent fba26a6 commit a877687

File tree

9 files changed

+268
-3
lines changed

9 files changed

+268
-3
lines changed

docs/application-settings.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Keep in mind following restrictions:
5050
- `auction.preferredmediatype.<bidder>.<media-type>` - <media-type> that will be left for <bidder> that doesn't support multi-format. Other media types will be removed. Acceptable values: `banner`, `video`, `audio`, `native`.
5151
- `auction.privacysandbox.cookiedeprecation.enabled` - boolean that turns on setting and reading of the Chrome Privacy Sandbox testing label header. Defaults to false.
5252
- `auction.privacysandbox.cookiedeprecation.ttlsec` - if the above setting is true, how long to set the receive-cookie-deprecation cookie's expiration
53+
- `auction.cache.enabled` - enables bids caching for account if true. Defaults to true.
5354
- `privacy.gdpr.enabled` - enables gdpr verifications if true. Has higher priority than configuration in
5455
application.yaml.
5556
- `privacy.gdpr.eea-countries` - overrides the host-level list of 2-letter country codes where TCF processing is applied

src/main/java/org/prebid/server/auction/ExchangeService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@
9494
import org.prebid.server.proto.openrtb.ext.request.ExtUser;
9595
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
9696
import org.prebid.server.settings.model.Account;
97+
import org.prebid.server.settings.model.AccountAuctionConfig;
98+
import org.prebid.server.settings.model.AccountCacheConfig;
9799
import org.prebid.server.util.HttpUtil;
98100
import org.prebid.server.util.ListUtil;
99101
import org.prebid.server.util.PbsUtil;
@@ -241,7 +243,7 @@ private Future<AuctionContext> runAuction(AuctionContext receivedContext) {
241243

242244
final List<SeatBid> storedAuctionResponses = new ArrayList<>();
243245
final BidderAliases aliases = aliases(bidRequest, account);
244-
final BidRequestCacheInfo cacheInfo = bidRequestCacheInfo(bidRequest);
246+
final BidRequestCacheInfo cacheInfo = bidRequestCacheInfo(bidRequest, account);
245247
final Map<String, MultiBidConfig> bidderToMultiBid = bidderToMultiBids(bidRequest, debugWarnings);
246248
receivedContext.getBidRejectionTrackers().putAll(makeBidRejectionTrackers(bidRequest, aliases));
247249

@@ -311,12 +313,18 @@ private static ExtRequestTargeting targeting(BidRequest bidRequest) {
311313
return prebid != null ? prebid.getTargeting() : null;
312314
}
313315

314-
private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest) {
316+
private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest, Account account) {
317+
final boolean cachingEnabled = Optional.ofNullable(account)
318+
.map(Account::getAuction)
319+
.map(AccountAuctionConfig::getCache)
320+
.map(AccountCacheConfig::getEnabled)
321+
.orElse(true);
322+
315323
final ExtRequestTargeting targeting = targeting(bidRequest);
316324
final ExtRequestPrebid prebid = PbsUtil.extRequestPrebid(bidRequest);
317325
final ExtRequestPrebidCache cache = prebid != null ? prebid.getCache() : null;
318326

319-
if (targeting != null && cache != null) {
327+
if (cachingEnabled && targeting != null && cache != null) {
320328
final boolean shouldCacheBids = cache.getBids() != null;
321329
final boolean shouldCacheVideoBids = cache.getVastxml() != null;
322330
final boolean shouldCacheWinningBidsOnly = !targeting.getIncludebidderkeys()
@@ -345,6 +353,7 @@ private static BidRequestCacheInfo bidRequestCacheInfo(BidRequest bidRequest) {
345353
.build();
346354
}
347355
}
356+
348357
return BidRequestCacheInfo.noCache();
349358
}
350359

src/main/java/org/prebid/server/settings/model/AccountAuctionConfig.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,6 @@ public class AccountAuctionConfig {
5353

5454
@JsonProperty("paaformat")
5555
PaaFormat paaFormat;
56+
57+
AccountCacheConfig cache;
5658
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.prebid.server.settings.model;
2+
3+
import lombok.Value;
4+
5+
@Value(staticConstructor = "of")
6+
public class AccountCacheConfig {
7+
8+
Boolean enabled;
9+
}

src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class AccountAuctionConfig {
2222
Boolean debugAllow
2323
AccountBidValidationConfig bidValidations
2424
AccountEventsConfig events
25+
AccountCacheConfig cache
2526
AccountPriceFloorsConfig priceFloors
2627
Targeting targeting
2728
PaaFormat paaformat
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.prebid.server.functional.model.config
2+
3+
import groovy.transform.ToString
4+
5+
@ToString(includeNames = true, ignoreNulls = true)
6+
class AccountCacheConfig {
7+
8+
Boolean enabled
9+
}

src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.prebid.server.functional.tests
22

33
import org.prebid.server.functional.model.config.AccountAuctionConfig
4+
import org.prebid.server.functional.model.config.AccountCacheConfig
45
import org.prebid.server.functional.model.config.AccountConfig
56
import org.prebid.server.functional.model.config.AccountEventsConfig
67
import org.prebid.server.functional.model.db.Account
@@ -14,6 +15,8 @@ import org.prebid.server.functional.model.response.auction.Adm
1415
import org.prebid.server.functional.model.response.auction.BidResponse
1516
import org.prebid.server.functional.util.PBSUtils
1617

18+
import static org.prebid.server.functional.model.AccountStatus.ACTIVE
19+
import static org.prebid.server.functional.model.bidder.BidderName.GENERIC
1720
import static org.prebid.server.functional.model.response.auction.MediaType.BANNER
1821
import static org.prebid.server.functional.model.response.auction.MediaType.VIDEO
1922

@@ -42,6 +45,9 @@ class CacheSpec extends BaseSpec {
4245
def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString))
4346
def request = VtrackRequest.getDefaultVtrackRequest(creative)
4447

48+
and: "Flush metrics"
49+
flushMetrics(defaultPbsService)
50+
4551
when: "PBS processes vtrack request"
4652
defaultPbsService.sendVtrackRequest(request, accountId)
4753

@@ -468,6 +474,9 @@ class CacheSpec extends BaseSpec {
468474
"<${impression}> &lt;![CDATA[ ]]&gt; </${impression}><Creatives></Creatives></${wrapper}></Ad></VAST>"
469475
def request = VtrackRequest.getDefaultVtrackRequest(creative)
470476

477+
and: "Flush metrics"
478+
flushMetrics(defaultPbsService)
479+
471480
when: "PBS processes vtrack request"
472481
defaultPbsService.sendVtrackRequest(request, accountId)
473482

@@ -492,4 +501,130 @@ class CacheSpec extends BaseSpec {
492501
PBSUtils.getRandomCase(" inline ") | " ${PBSUtils.getRandomCase(" impression ")} $PBSUtils.randomNumber "
493502
" inline ${PBSUtils.getRandomString()} " | " ImpreSSion "
494503
}
504+
505+
def "PBS should cache bids and add targeting values when account cache config #accountAuctionConfig"() {
506+
given: "Current value of metric prebid_cache.requests.ok"
507+
def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC)
508+
509+
and: "Default BidRequest with cache, targeting"
510+
def bidRequest = BidRequest.getDefaultVideoRequest().tap {
511+
it.enableCache()
512+
}
513+
514+
and: "Account in the DB"
515+
def accountConfig = new AccountConfig(status: ACTIVE, auction: accountAuctionConfig)
516+
def account = new Account(uuid: bidRequest.accountId, config: accountConfig)
517+
accountDao.save(account)
518+
519+
and: "Default bid response"
520+
def presetBidResponse = BidResponse.getDefaultBidResponse(bidRequest)
521+
bidder.setResponse(bidRequest.id, presetBidResponse)
522+
523+
and: "Flush metrics"
524+
flushMetrics(defaultPbsService)
525+
526+
when: "PBS processes auction request"
527+
def response = defaultPbsService.sendAuctionRequest(bidRequest)
528+
529+
then: "PBS should call PBC"
530+
assert prebidCache.getRequestCount(bidRequest.imp[0].id) == 1
531+
532+
and: "PBS response targeting contains bidder specific keys"
533+
def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting
534+
assert targetingKeyMap.containsKey('hb_cache_id')
535+
assert targetingKeyMap.containsKey("hb_cache_id_${GENERIC}".toString())
536+
assert targetingKeyMap.containsKey('hb_uuid')
537+
assert targetingKeyMap.containsKey("hb_uuid_${GENERIC}".toString())
538+
539+
and: "Metrics should be updated"
540+
def metrics = defaultPbsService.sendCollectedMetricsRequest()
541+
assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue + 1
542+
assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)] == 1
543+
544+
where:
545+
accountAuctionConfig << [
546+
new AccountAuctionConfig(),
547+
new AccountAuctionConfig(cache: new AccountCacheConfig()),
548+
new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: null)),
549+
new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: true))
550+
]
551+
}
552+
553+
def "PBS shouldn't cache bids and add targeting values when account cache config disabled"() {
554+
given: "Current value of metric prebid_cache.requests.ok"
555+
def initialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC)
556+
557+
and: "Default BidRequest with cache, targeting"
558+
def bidRequest = BidRequest.getDefaultVideoRequest().tap {
559+
it.enableCache()
560+
}
561+
562+
and: "Account with cache config"
563+
def accountAuctionConfig = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: false))
564+
def accountConfig = new AccountConfig(status: ACTIVE, auction: accountAuctionConfig)
565+
def account = new Account(uuid: bidRequest.accountId, config: accountConfig)
566+
accountDao.save(account)
567+
568+
and: "Default bid response"
569+
def presetBidResponse = BidResponse.getDefaultBidResponse(bidRequest)
570+
bidder.setResponse(bidRequest.id, presetBidResponse)
571+
572+
and: "Flush metrics"
573+
flushMetrics(defaultPbsService)
574+
575+
when: "PBS processes auction request"
576+
def response = defaultPbsService.sendAuctionRequest(bidRequest)
577+
578+
then: "PBS shouldn't call PBC"
579+
assert !prebidCache.getRequestCount(bidRequest.imp[0].id)
580+
581+
and: "PBS response targeting shouldn't contains bidder specific keys"
582+
def targetingKeyMap = response.seatbid?.first()?.bid?.first()?.ext?.prebid?.targeting
583+
assert !targetingKeyMap.containsKey('hb_cache_id')
584+
assert !targetingKeyMap.containsKey("hb_cache_id_${GENERIC}".toString())
585+
assert !targetingKeyMap.containsKey('hb_uuid')
586+
assert !targetingKeyMap.containsKey("hb_uuid_${GENERIC}".toString())
587+
588+
and: "Metrics shouldn't be updated"
589+
def metrics = defaultPbsService.sendCollectedMetricsRequest()
590+
assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == initialValue
591+
assert !metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(bidRequest.accountId)]
592+
}
593+
594+
def "PBS should update prebid_cache.creative_size.xml metric when account cache config #enabledCacheConcfig"() {
595+
given: "Current value of metric prebid_cache.requests.ok"
596+
def okInitialValue = getCurrentMetricValue(defaultPbsService, CACHE_REQUEST_OK_GLOBAL_METRIC)
597+
598+
and: "Default VtrackRequest"
599+
def accountId = PBSUtils.randomNumber.toString()
600+
def creative = encodeXml(Vast.getDefaultVastModel(PBSUtils.randomString))
601+
def request = VtrackRequest.getDefaultVtrackRequest(creative)
602+
603+
and: "Create and save enabled events config in account"
604+
def account = new Account().tap {
605+
it.uuid = accountId
606+
it.config = new AccountConfig().tap {
607+
it.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: enabledCacheConcfig))
608+
}
609+
}
610+
accountDao.save(account)
611+
612+
and: "Flush metrics"
613+
flushMetrics(defaultPbsService)
614+
615+
when: "PBS processes vtrack request"
616+
defaultPbsService.sendVtrackRequest(request, accountId)
617+
618+
then: "prebid_cache.creative_size.xml metric should be updated"
619+
def metrics = defaultPbsService.sendCollectedMetricsRequest()
620+
def creativeSize = creative.bytes.length
621+
assert metrics[CACHE_REQUEST_OK_GLOBAL_METRIC] == okInitialValue + 1
622+
623+
and: "account.<account-id>.prebid_cache.creative_size.xml should be updated"
624+
assert metrics[CACHE_REQUEST_OK_ACCOUNT_METRIC.formatted(accountId)] == 1
625+
assert metrics[XML_CREATIVE_SIZE_ACCOUNT_METRIC.formatted(accountId)] == creativeSize
626+
627+
where:
628+
enabledCacheConcfig << [null, false, true]
629+
}
495630
}

src/test/groovy/org/prebid/server/functional/tests/module/responsecorrenction/ResponseCorrectionSpec.groovy

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package org.prebid.server.functional.tests.module.responsecorrenction
22

3+
import org.prebid.server.functional.model.config.AccountAuctionConfig
4+
import org.prebid.server.functional.model.config.AccountCacheConfig
35
import org.prebid.server.functional.model.config.AccountConfig
46
import org.prebid.server.functional.model.config.AccountHooksConfiguration
57
import org.prebid.server.functional.model.config.AppVideoHtml
@@ -576,6 +578,61 @@ class ResponseCorrectionSpec extends ModuleBaseSpec {
576578
assert !response.ext.warnings
577579
}
578580

581+
def "PBS should modify response when requested video impression respond with invalid adm VAST keyword and disabled cache config"() {
582+
given: "Start up time"
583+
def start = Instant.now()
584+
585+
and: "Default bid request with APP and Video imp"
586+
def bidRequest = getDefaultVideoRequest(APP)
587+
588+
and: "Set bidder response"
589+
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
590+
seatbid[0].bid[0].setAdm(PBSUtils.getRandomCase(admValue))
591+
}
592+
bidder.setResponse(bidRequest.id, bidResponse)
593+
594+
and: "Save account with enabled response correction module"
595+
def accountWithResponseCorrectionModule = accountConfigWithResponseCorrectionModule(bidRequest).tap {
596+
config.auction = new AccountAuctionConfig(cache: new AccountCacheConfig(enabled: false))
597+
}
598+
accountDao.save(accountWithResponseCorrectionModule)
599+
600+
when: "PBS processes auction request"
601+
def response = pbsServiceWithResponseCorrectionModule.sendAuctionRequest(bidRequest)
602+
603+
then: "PBS should emit log"
604+
def logsByTime = pbsServiceWithResponseCorrectionModule.getLogsByTime(start)
605+
def bidId = bidResponse.seatbid[0].bid[0].id
606+
def responseCorrection = getLogsByText(logsByTime, bidId)
607+
assert responseCorrection.size() == 1
608+
assert responseCorrection.any {
609+
it.contains("Bid $bidId of bidder generic: changing media type to banner" as String)
610+
}
611+
612+
and: "Response should contain seatBid"
613+
assert response.seatbid.size() == 1
614+
615+
and: "Response should contain single seatBid with proper media type"
616+
assert response.seatbid.bid.ext.prebid.type.flatten() == [BANNER]
617+
618+
and: "Response should contain single seatBid with proper meta media type"
619+
assert response.seatbid.bid.ext.prebid.meta.mediaType.flatten() == [VIDEO.value]
620+
621+
and: "Response shouldn't contain errors"
622+
assert !response.ext.errors
623+
624+
and: "Response shouldn't contain warnings"
625+
assert !response.ext.warnings
626+
627+
where:
628+
admValue << [
629+
"<${' ' * PBSUtils.getRandomNumber(0, OPTIMAL_MAX_LENGTH)}VAST${PBSUtils.randomString}",
630+
"<${' ' * PBSUtils.getRandomNumber(0, OPTIMAL_MAX_LENGTH)}VAST",
631+
"<${' ' * PBSUtils.getRandomNumber(0, OPTIMAL_MAX_LENGTH)}VAST>",
632+
"<${PBSUtils.randomString}VAST${' ' * PBSUtils.getRandomNumber(1, OPTIMAL_MAX_LENGTH)}"
633+
]
634+
}
635+
579636
private static Account accountConfigWithResponseCorrectionModule(BidRequest bidRequest, Boolean enabledResponseCorrection = true, Boolean enabledAppVideoHtml = true) {
580637
def modulesConfig = new PbsModulesConfig(pbResponseCorrection: new PbResponseCorrection(
581638
enabled: enabledResponseCorrection, appVideoHtml: new AppVideoHtml(enabled: enabledAppVideoHtml)))

src/test/java/org/prebid/server/auction/ExchangeServiceTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
import org.prebid.server.settings.model.AccountAlternateBidderCodesBidder;
152152
import org.prebid.server.settings.model.AccountAnalyticsConfig;
153153
import org.prebid.server.settings.model.AccountAuctionConfig;
154+
import org.prebid.server.settings.model.AccountCacheConfig;
154155
import org.prebid.server.settings.model.AccountEventsConfig;
155156
import org.prebid.server.spring.config.bidder.model.CompressionType;
156157
import org.prebid.server.spring.config.bidder.model.Ortb;
@@ -1635,6 +1636,47 @@ public void shouldCallBidResponseCreatorWithWinningOnlyTrueWhenIncludeBidderKeys
16351636
.containsOnly(true);
16361637
}
16371638

1639+
@Test
1640+
public void shouldCallBidResponseCreatorWithCachingDisabledWhenCachingIsNotEnabledOnAccountLevel() {
1641+
// given
1642+
givenBidder("bidder1", mock(Bidder.class), givenEmptySeatBid());
1643+
1644+
final Bid thirdBid = Bid.builder().id("bidId3").impid("impId3").price(BigDecimal.valueOf(7.89)).build();
1645+
givenBidder("bidder2", mock(Bidder.class), givenSeatBid(singletonList(givenBidderBid(thirdBid))));
1646+
1647+
final ExtRequestTargeting targeting = givenTargeting(false);
1648+
1649+
final BidRequest bidRequest = givenBidRequest(asList(
1650+
// imp ids are not really used for matching, included them here for clarity
1651+
givenImp(singletonMap("bidder1", 1), builder -> builder.id("impId1")),
1652+
givenImp(Map.of("bidder1", 1, "bidder2", 2), builder -> builder.id("impId2"))),
1653+
builder -> builder.ext(ExtRequest.of(ExtRequestPrebid.builder()
1654+
.targeting(targeting)
1655+
.cache(ExtRequestPrebidCache.of(ExtRequestPrebidCacheBids.of(53, true),
1656+
ExtRequestPrebidCacheVastxml.of(34, true), true))
1657+
.auctiontimestamp(1000L)
1658+
.build())));
1659+
1660+
// when
1661+
target.holdAuction(givenRequestContext(
1662+
bidRequest,
1663+
Account.builder()
1664+
.id("accountId")
1665+
.auction(AccountAuctionConfig.builder()
1666+
.events(AccountEventsConfig.of(true))
1667+
.cache(AccountCacheConfig.of(false))
1668+
.build())
1669+
.build()));
1670+
1671+
// then
1672+
final ArgumentCaptor<AuctionContext> auctionContextArgumentCaptor =
1673+
ArgumentCaptor.forClass(AuctionContext.class);
1674+
verify(bidResponseCreator).create(
1675+
auctionContextArgumentCaptor.capture(),
1676+
eq(BidRequestCacheInfo.noCache()),
1677+
eq(emptyMap()));
1678+
}
1679+
16381680
@Test
16391681
public void shouldCallBidResponseCreatorWithWinningOnlyFalseWhenWinningOnlyIsNull() {
16401682
// given

0 commit comments

Comments
 (0)