From f824d56191316d234461736796898a5c0f40f515 Mon Sep 17 00:00:00 2001 From: rpanchyk Date: Fri, 5 Nov 2021 09:58:02 +0200 Subject: [PATCH 1/3] Add category mapping feature toggle in application config --- .../server/auction/BidResponseCreator.java | 178 ++++++++++-------- .../auction/CategoryMappingService.java | 16 +- .../auction/VideoStoredRequestProcessor.java | 118 ++++++------ .../auction/model/CategoryMappingResult.java | 9 + .../org/prebid/server/cache/CacheService.java | 47 +++-- .../openrtb/ext/ExtIncludeBrandCategory.java | 4 +- .../spring/config/ServiceConfiguration.java | 10 +- src/main/resources/application.yaml | 1 + .../auction/BidResponseCreatorTest.java | 19 +- .../auction/CategoryMappingServiceTest.java | 161 ++++++++++------ .../handler/ForceDealsUpdateHandlerTest.java | 5 +- .../server/it/test-application.properties | 1 + 12 files changed, 334 insertions(+), 235 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 529ec9196b9..aa7a5ec5138 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -86,6 +86,7 @@ import org.prebid.server.settings.model.AccountEventsConfig; import org.prebid.server.settings.model.VideoStoredDataResult; import org.prebid.server.util.LineItemUtil; +import org.prebid.server.util.StreamUtil; import org.prebid.server.vast.VastModifier; import java.math.BigDecimal; @@ -96,7 +97,6 @@ import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -104,7 +104,6 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import java.util.stream.StreamSupport; public class BidResponseCreator { @@ -113,13 +112,14 @@ public class BidResponseCreator { private static final Integer DEFAULT_BID_LIMIT_MIN = 1; private final CacheService cacheService; - private final CategoryMappingService categoryMappingService; private final BidderCatalog bidderCatalog; private final VastModifier vastModifier; private final EventsService eventsService; private final StoredRequestProcessor storedRequestProcessor; + private final WinningBidComparatorFactory winningBidComparatorFactory; private final IdGenerator bidIdGenerator; private final HookStageExecutor hookStageExecutor; + private final CategoryMappingService categoryMappingService; private final int truncateAttrChars; private final Clock clock; private final JacksonMapper mapper; @@ -127,10 +127,8 @@ public class BidResponseCreator { private final String cacheHost; private final String cachePath; private final String cacheAssetUrlTemplate; - private final WinningBidComparatorFactory winningBidComparatorFactory; public BidResponseCreator(CacheService cacheService, - CategoryMappingService categoryMappingService, BidderCatalog bidderCatalog, VastModifier vastModifier, EventsService eventsService, @@ -138,12 +136,12 @@ public BidResponseCreator(CacheService cacheService, WinningBidComparatorFactory winningBidComparatorFactory, IdGenerator bidIdGenerator, HookStageExecutor hookStageExecutor, + CategoryMappingService categoryMappingService, int truncateAttrChars, Clock clock, JacksonMapper mapper) { this.cacheService = Objects.requireNonNull(cacheService); - this.categoryMappingService = Objects.requireNonNull(categoryMappingService); this.bidderCatalog = Objects.requireNonNull(bidderCatalog); this.vastModifier = Objects.requireNonNull(vastModifier); this.eventsService = Objects.requireNonNull(eventsService); @@ -151,6 +149,7 @@ public BidResponseCreator(CacheService cacheService, this.winningBidComparatorFactory = Objects.requireNonNull(winningBidComparatorFactory); this.bidIdGenerator = Objects.requireNonNull(bidIdGenerator); this.hookStageExecutor = Objects.requireNonNull(hookStageExecutor); + this.categoryMappingService = categoryMappingService; this.truncateAttrChars = validateTruncateAttrChars(truncateAttrChars); this.clock = Objects.requireNonNull(clock); this.mapper = Objects.requireNonNull(mapper); @@ -183,20 +182,14 @@ Future create(List bidderResponses, .compose(videoStoredDataResult -> { final List modifiedBidderResponses = updateBids(bidderResponses, videoStoredDataResult, auctionContext, eventsContext, imps); - final BidRequest bidRequest = auctionContext.getBidRequest(); - final ExtRequestTargeting targeting = targeting(bidRequest); return invokeProcessedBidderResponseHooks(modifiedBidderResponses, auctionContext) - .compose(updatedBidderResponses -> - categoryMappingService.createCategoryMapping(updatedBidderResponses, - bidRequest, - targeting, - auctionContext.getTimeout())) - .map(categoryMappingResult -> - updateWithCategoryErrors(categoryMappingResult, auctionContext)) + + .compose(updatedByHooksBidderResponses -> + createCategoryMapping(auctionContext, updatedByHooksBidderResponses)) + .compose(categoryMappingResult -> cacheBidsAndCreateResponse( - toBidderResponseInfos( - categoryMappingResult.getBidderResponses(), imps, categoryMappingResult), + toBidderResponseInfos(categoryMappingResult, imps), auctionContext, cacheInfo, bidderToMultiBids, @@ -205,12 +198,6 @@ Future create(List bidderResponses, }); } - private static CategoryMappingResult updateWithCategoryErrors(CategoryMappingResult categoryMappingResult, - AuctionContext auctionContext) { - auctionContext.getPrebidErrors().addAll(CollectionUtils.emptyIfNull(categoryMappingResult.getErrors())); - return categoryMappingResult; - } - private List updateBids(List bidderResponses, VideoStoredDataResult videoStoredDataResult, AuctionContext auctionContext, @@ -218,6 +205,7 @@ private List updateBids(List bidderResponses, List imps) { final List result = new ArrayList<>(); + for (final BidderResponse bidderResponse : bidderResponses) { final String bidder = bidderResponse.getBidder(); @@ -231,14 +219,15 @@ private List updateBids(List bidderResponses, final ExtDealLine extDealLine = LineItemUtil.extDealLineFrom(receivedBid, correspondingImp, mapper); final String lineItemId = extDealLine != null ? extDealLine.getLineItemId() : null; - final Bid modifiedBid = updateBid( + final Bid updatedBid = updateBid( receivedBid, bidType, bidder, videoStoredDataResult, auctionContext, eventsContext, lineItemId); - modifiedBidderBids.add(bidderBid.with(modifiedBid)); + modifiedBidderBids.add(bidderBid.with(updatedBid)); } final BidderSeatBid modifiedSeatBid = seatBid.with(modifiedBidderBids); result.add(bidderResponse.with(modifiedSeatBid)); } + return result; } @@ -280,15 +269,14 @@ private Bid updateBid(Bid bid, .build(); } - private String updateBidAdm( - Bid bid, - BidType bidType, - String bidder, - Account account, - EventsContext eventsContext, - String effectiveBidId, - List debugWarnings, - String lineItemId) { + private String updateBidAdm(Bid bid, + BidType bidType, + String bidder, + Account account, + EventsContext eventsContext, + String effectiveBidId, + List debugWarnings, + String lineItemId) { final String bidAdm = bid.getAdm(); return BidType.video.equals(bidType) @@ -337,16 +325,15 @@ private ObjectNode updateBidExt(Bid bid, return updatedBidExt; } - private ExtBidPrebid updateBidExtPrebid( - Bid bid, - BidType bidType, - String bidder, - Account account, - VideoStoredDataResult videoStoredDataResult, - EventsContext eventsContext, - String generatedBidId, - String effectiveBidId, - String lineItemId) { + private ExtBidPrebid updateBidExtPrebid(Bid bid, + BidType bidType, + String bidder, + Account account, + VideoStoredDataResult videoStoredDataResult, + EventsContext eventsContext, + String generatedBidId, + String effectiveBidId, + String lineItemId) { final Video storedVideo = videoStoredDataResult.getImpIdToStoredVideo().get(bid.getImpid()); final Events events = createEvents(bidder, account, effectiveBidId, eventsContext, lineItemId); @@ -375,10 +362,12 @@ private static boolean isEmptyBidderResponses(List bidderRes .allMatch(CollectionUtils::isEmpty); } - private List toBidderResponseInfos(List bidderResponses, - List imps, - CategoryMappingResult categoryMappingResult) { + private List toBidderResponseInfos(CategoryMappingResult categoryMappingResult, + List imps) { + final List result = new ArrayList<>(); + + final List bidderResponses = categoryMappingResult.getBidderResponses(); for (final BidderResponse bidderResponse : bidderResponses) { final String bidder = bidderResponse.getBidder(); @@ -408,17 +397,19 @@ private BidInfo toBidInfo(Bid bid, List imps, String bidder, CategoryMappingResult categoryMappingResult) { + final Imp correspondingImp = correspondingImp(bid, imps); final ExtDealLine extDealLine = LineItemUtil.extDealLineFrom(bid, correspondingImp, mapper); final String lineItemId = extDealLine != null ? extDealLine.getLineItemId() : null; + return BidInfo.builder() - .satisfiedPriority(categoryMappingResult.isBidSatisfiesPriority(bid)) - .category(categoryMappingResult.getCategory(bid)) .bid(bid) .bidType(type) .bidder(bidder) .correspondingImp(correspondingImp) .lineItemId(lineItemId) + .category(categoryMappingResult.getCategory(bid)) + .satisfiedPriority(categoryMappingResult.isBidSatisfiesPriority(bid)) .build(); } @@ -455,6 +446,30 @@ private static BidderResponse rejectBidderResponseOrProceed( .with(bids)); } + private Future createCategoryMapping(AuctionContext auctionContext, + List bidderResponses) { + + if (categoryMappingService != null) { + return categoryMappingService.createCategoryMapping( + bidderResponses, + auctionContext.getBidRequest(), + auctionContext.getTimeout()) + + .map(categoryMappingResult -> addCategoryMappingErrors(categoryMappingResult, auctionContext)); + } + + return Future.succeededFuture(CategoryMappingResult.of(bidderResponses)); + } + + private static CategoryMappingResult addCategoryMappingErrors(CategoryMappingResult categoryMappingResult, + AuctionContext auctionContext) { + + auctionContext.getPrebidErrors() + .addAll(CollectionUtils.emptyIfNull(categoryMappingResult.getErrors())); + + return categoryMappingResult; + } + private Future cacheBidsAndCreateResponse(List bidderResponses, AuctionContext auctionContext, BidRequestCacheInfo cacheInfo, @@ -522,8 +537,8 @@ private Future cacheBidsAndCreateResponse(List } private static ExtRequestTargeting targeting(BidRequest bidRequest) { - final ExtRequest requestExt = bidRequest.getExt(); - final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; + final ExtRequest ext = bidRequest.getExt(); + final ExtRequestPrebid prebid = ext != null ? ext.getPrebid() : null; return prebid != null ? prebid.getTargeting() : null; } @@ -632,11 +647,11 @@ private static void updateTopMatchAndLostAuctionLineItemsMetric(Set win } } - private BidderResponseInfo injectBidInfoWithTargeting(BidderResponseInfo bidderResponseInfo, - List bidderBidInfos, - Map bidderToMultiBids, - Set winningBids, - Set winningBidsByBidder) { + private static BidderResponseInfo injectBidInfoWithTargeting(BidderResponseInfo bidderResponseInfo, + List bidderBidInfos, + Map bidderToMultiBids, + Set winningBids, + Set winningBidsByBidder) { final String bidder = bidderResponseInfo.getBidder(); final List bidInfosWithTargeting = toBidInfoWithTargeting(bidderBidInfos, bidder, bidderToMultiBids, @@ -647,11 +662,11 @@ private BidderResponseInfo injectBidInfoWithTargeting(BidderResponseInfo bidderR return bidderResponseInfo.with(modifiedSeatBid); } - private List toBidInfoWithTargeting(List bidderBidInfos, - String bidder, - Map bidderToMultiBids, - Set winningBids, - Set winningBidsByBidder) { + private static List toBidInfoWithTargeting(List bidderBidInfos, + String bidder, + Map bidderToMultiBids, + Set winningBids, + Set winningBidsByBidder) { final Map> impIdToBidInfos = bidderBidInfos.stream() .collect(Collectors.groupingBy(bidInfo -> bidInfo.getCorrespondingImp().getId())); @@ -662,11 +677,11 @@ private List toBidInfoWithTargeting(List bidderBidInfos, .collect(Collectors.toList()); } - private List injectTargeting(List bidderImpIdBidInfos, - String bidder, - Map bidderToMultiBids, - Set winningBids, - Set winningBidsByBidder) { + private static List injectTargeting(List bidderImpIdBidInfos, + String bidder, + Map bidderToMultiBids, + Set winningBids, + Set winningBidsByBidder) { final List result = new ArrayList<>(); @@ -700,7 +715,7 @@ private List injectTargeting(List bidderImpIdBidInfos, /** * Increments sent to client metrics for each bid with deal. */ - private void updateSentToClientTxnLog(TxnLog txnLog, Set bidInfos) { + private static void updateSentToClientTxnLog(TxnLog txnLog, Set bidInfos) { bidInfos.stream() .map(BidInfo::getLineItemId) .filter(Objects::nonNull) @@ -739,10 +754,10 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI .build(); } - private ExtResponseDebug toExtResponseDebug(List bidderResponseInfos, - AuctionContext auctionContext, - CacheServiceResult cacheResult, - boolean debugEnabled) { + private static ExtResponseDebug toExtResponseDebug(List bidderResponseInfos, + AuctionContext auctionContext, + CacheServiceResult cacheResult, + boolean debugEnabled) { final DeepDebugLog deepDebugLog = auctionContext.getDeepDebugLog(); @@ -768,6 +783,7 @@ private Future cacheBids(Set bidsToCache, AuctionContext auctionContext, BidRequestCacheInfo cacheInfo, EventsContext eventsContext) { + if (!cacheInfo.isDoCaching()) { return Future.succeededFuture(CacheServiceResult.of(null, null, toMapBidsWithEmptyCacheIds(bidsToCache))); } @@ -822,9 +838,9 @@ private static CacheServiceResult addNotCachedBids(CacheServiceResult cacheResul return cacheResult; } - private Map> toExtHttpCalls(List bidderResponses, - CacheServiceResult cacheResult, - Map> contextHttpCalls) { + private static Map> toExtHttpCalls(List bidderResponses, + CacheServiceResult cacheResult, + Map> contextHttpCalls) { final Map> bidderHttpCalls = bidderResponses.stream() .filter(bidderResponse -> CollectionUtils.isNotEmpty(bidderResponse.getSeatBid().getHttpCalls())) @@ -940,7 +956,7 @@ private static List errorsDetails(List errors) { private Map> extractDeprecatedBiddersErrors(BidRequest bidRequest) { return bidRequest.getImp().stream() .filter(imp -> imp.getExt() != null) - .flatMap(imp -> asStream(imp.getExt().fieldNames())) + .flatMap(imp -> StreamUtil.asStream(imp.getExt().fieldNames())) .distinct() .filter(bidderCatalog::isDeprecatedName) .collect(Collectors.toMap(Function.identity(), @@ -953,6 +969,7 @@ private Map> extractDeprecatedBiddersErrors(BidRequ */ private static Map> extractPrebidErrors(VideoStoredDataResult videoStoredDataResult, AuctionContext auctionContext) { + final List storedErrors = extractStoredErrors(videoStoredDataResult); final List contextErrors = extractContextErrors(auctionContext); if (storedErrors.isEmpty() && contextErrors.isEmpty()) { @@ -1004,6 +1021,7 @@ private static Map> extractCacheErrors(CacheService */ private static void addBidErrors(Map> errors, Map> bidErrors) { + for (Map.Entry> errorEntry : bidErrors.entrySet()) { final List extBidderErrors = errors.get(errorEntry.getKey()); if (extBidderErrors != null) { @@ -1014,7 +1032,7 @@ private static void addBidErrors(Map> errors, } } - private Map> toExtBidderWarnings(AuctionContext auctionContext) { + private static Map> toExtBidderWarnings(AuctionContext auctionContext) { final Map> warnings = new HashMap<>(extractContextWarnings(auctionContext)); return warnings.isEmpty() ? null : warnings; @@ -1030,16 +1048,12 @@ private static Map> extractContextWarnings(AuctionC : Collections.singletonMap(PREBID_EXT, contextWarnings); } - private static Stream asStream(Iterator iterator) { - final Iterable iterable = () -> iterator; - return StreamSupport.stream(iterable.spliterator(), false); - } - /** * Returns a map with response time by bidders and cache. */ private static Map toResponseTimes(Collection bidderResponses, CacheServiceResult cacheResult) { + final Map responseTimeMillis = bidderResponses.stream() .collect(Collectors.toMap(BidderResponseInfo::getBidder, BidderResponseInfo::getResponseTime)); @@ -1259,6 +1273,7 @@ private Bid toBid(BidInfo bidInfo, ExtRequestTargeting targeting, BidRequest bid ? extBidPrebid.toBuilder() : ExtBidPrebid.builder(); final Boolean dealsTierSatisfied = bidInfo.getSatisfiedPriority(); + final ExtBidPrebid updatedExtBidPrebid = extBidPrebidBuilder .targeting(MapUtils.isEmpty(targetingKeywords) ? null : targetingKeywords) .targetBidderCode(targetingInfo.isAddTargetBidderCode() ? bidderCode : null) @@ -1332,6 +1347,7 @@ private static void setAssetTypes(Asset responseAsset, List requestAssets) { + return requestAssets.stream() .filter(asset -> asset.getId() == assetId) .findFirst() diff --git a/src/main/java/org/prebid/server/auction/CategoryMappingService.java b/src/main/java/org/prebid/server/auction/CategoryMappingService.java index 88eb136ac01..80eea42f475 100644 --- a/src/main/java/org/prebid/server/auction/CategoryMappingService.java +++ b/src/main/java/org/prebid/server/auction/CategoryMappingService.java @@ -80,19 +80,15 @@ public CategoryMappingService(ApplicationSettings applicationSettings, JacksonMa */ public Future createCategoryMapping(List bidderResponses, BidRequest bidRequest, - ExtRequestTargeting targeting, Timeout timeout) { + final ExtRequestTargeting targeting = targeting(bidRequest); + final ExtIncludeBrandCategory includeBrandCategory = ObjectUtil.getIfNotNull( targeting, ExtRequestTargeting::getIncludebrandcategory); if (includeBrandCategory == null) { - return Future.succeededFuture( - CategoryMappingResult.of( - Collections.emptyMap(), - Collections.emptyMap(), - bidderResponses, - Collections.emptyList())); + return Future.succeededFuture(CategoryMappingResult.of(bidderResponses)); } final boolean withCategory = BooleanUtils.toBooleanDefaultIfNull( @@ -116,6 +112,12 @@ public Future createCategoryMapping(List bidderResponses, categoryBidContexts, bidRequest, targeting, withCategory, rejectedBids)); } + private static ExtRequestTargeting targeting(BidRequest bidRequest) { + final ExtRequest ext = bidRequest.getExt(); + final ExtRequestPrebid prebid = ext != null ? ext.getPrebid() : null; + return prebid != null ? prebid.getTargeting() : null; + } + /** * Converts integer ad server to string representation or throws exception if unknown. */ diff --git a/src/main/java/org/prebid/server/auction/VideoStoredRequestProcessor.java b/src/main/java/org/prebid/server/auction/VideoStoredRequestProcessor.java index d6d307f153a..dd1cd540bdb 100644 --- a/src/main/java/org/prebid/server/auction/VideoStoredRequestProcessor.java +++ b/src/main/java/org/prebid/server/auction/VideoStoredRequestProcessor.java @@ -74,7 +74,7 @@ public class VideoStoredRequestProcessor { private VideoStoredRequestProcessor(boolean enforceStoredRequest, List blacklistedAccounts, long defaultTimeout, - String adServerCurrency, + String currency, BidRequest defaultBidRequest, ApplicationSettings applicationSettings, VideoRequestValidator validator, @@ -87,7 +87,7 @@ private VideoStoredRequestProcessor(boolean enforceStoredRequest, this.enforceStoredRequest = enforceStoredRequest; this.blacklistedAccounts = blacklistedAccounts; this.defaultTimeout = defaultTimeout; - this.currency = StringUtils.isBlank(adServerCurrency) ? DEFAULT_CURRENCY : adServerCurrency; + this.currency = currency; this.defaultBidRequest = defaultBidRequest; this.applicationSettings = applicationSettings; this.validator = validator; @@ -116,7 +116,7 @@ public static VideoStoredRequestProcessor create(boolean enforceStoredRequest, enforceStoredRequest, Objects.requireNonNull(blacklistedAccounts), defaultTimeout, - adServerCurrency, + StringUtils.isBlank(adServerCurrency) ? DEFAULT_CURRENCY : adServerCurrency, readBidRequest( defaultBidRequestPath, Objects.requireNonNull(fileSystem), Objects.requireNonNull(mapper)), Objects.requireNonNull(applicationSettings), @@ -137,39 +137,44 @@ public Future> processVideoRequest(String accountId, BidRequestVideo videoRequest) { final Set storedRequestIds = StringUtils.isNotBlank(storedBidRequestId) - ? Collections.singleton(storedBidRequestId) - : Collections.emptySet(); + ? Collections.singleton(storedBidRequestId) + : Collections.emptySet(); return applicationSettings.getVideoStoredData(accountId, storedRequestIds, podIds, timeoutFactory.create(defaultTimeout)) - .compose(storedDataResult -> updateMetrics(storedDataResult, storedRequestIds, podIds)) - .map(storedData -> mergeToBidRequest(storedData, videoRequest, storedBidRequestId)) + + .map(storedDataResult -> updateMetrics(storedDataResult, storedRequestIds, podIds)) + + .map(storedData -> toBidRequestWithPodErrors(storedData, videoRequest, storedBidRequestId)) + .recover(exception -> Future.failedFuture(new InvalidRequestException( String.format("Stored request fetching failed: %s", exception.getMessage())))); } - private static BidRequest readBidRequest(String defaultBidRequestPath, FileSystem fileSystem, + private static BidRequest readBidRequest(String defaultBidRequestPath, + FileSystem fileSystem, JacksonMapper mapper) { return StringUtils.isNotBlank(defaultBidRequestPath) - ? mapper.decodeValue(fileSystem.readFileBlocking(defaultBidRequestPath), BidRequest.class) - : null; + ? mapper.decodeValue(fileSystem.readFileBlocking(defaultBidRequestPath), BidRequest.class) + : null; } - private Future updateMetrics(StoredDataResult storedDataResult, - Set requestIds, - Set impIds) { + private StoredDataResult updateMetrics(StoredDataResult storedDataResult, + Set requestIds, + Set impIds) { + requestIds.forEach( id -> metrics.updateStoredRequestMetric(storedDataResult.getStoredIdToRequest().containsKey(id))); impIds.forEach( id -> metrics.updateStoredImpsMetric(storedDataResult.getStoredIdToImp().containsKey(id))); - return Future.succeededFuture(storedDataResult); + return storedDataResult; } - private WithPodErrors mergeToBidRequest(StoredDataResult storedResult, - BidRequestVideo videoRequest, - String storedBidRequestId) { + private WithPodErrors toBidRequestWithPodErrors(StoredDataResult storedResult, + BidRequestVideo videoRequest, + String storedBidRequestId) { final BidRequestVideo mergedStoredRequest = mergeBidRequest(videoRequest, storedBidRequestId, storedResult); validator.validateStoredBidRequest(mergedStoredRequest, enforceStoredRequest, blacklistedAccounts); @@ -194,8 +199,8 @@ private BidRequestVideo mergeBidRequest(BidRequestVideo originalRequest, } return StringUtils.isNotBlank(storedRequest) - ? jsonMerger.merge(originalRequest, storedRequest, storedRequestId, BidRequestVideo.class) - : originalRequest; + ? jsonMerger.merge(originalRequest, storedRequest, storedRequestId, BidRequestVideo.class) + : originalRequest; } private WithPodErrors> mergeStoredImps(Podconfig podconfig, @@ -306,28 +311,27 @@ private static Video updateVideo(Video video, Integer minDuration, Integer maxDu private BidRequest mergeWithDefaultBidRequest(BidRequestVideo videoRequest, List imps) { final BidRequest.BidRequestBuilder bidRequestBuilder = defaultBidRequest != null - ? defaultBidRequest.toBuilder() - : BidRequest.builder(); + ? defaultBidRequest.toBuilder() + : BidRequest.builder(); final Site site = videoRequest.getSite(); if (site != null) { - final Site.SiteBuilder siteBuilder = site.toBuilder(); final Content content = videoRequest.getContent(); if (content != null) { - siteBuilder.content(content); + bidRequestBuilder.site(site.toBuilder() + .content(content) + .build()); } - siteBuilder.content(content); - bidRequestBuilder.site(siteBuilder.build()); } final App app = videoRequest.getApp(); if (app != null) { - final App.AppBuilder appBuilder = app.toBuilder(); final Content content = videoRequest.getContent(); if (content != null) { - appBuilder.content(content); + bidRequestBuilder.app(app.toBuilder() + .content(content) + .build()); } - bidRequestBuilder.app(appBuilder.build()); } final Device device = videoRequest.getDevice(); @@ -355,8 +359,8 @@ private BidRequest mergeWithDefaultBidRequest(BidRequestVideo videoRequest, List bidRequestBuilder.regs(regs); } - final Long videoTmax = timeoutResolver.resolve(videoRequest.getTmax()); - bidRequestBuilder.tmax(videoTmax); + final long timeout = timeoutResolver.resolve(videoRequest.getTmax()); + bidRequestBuilder.tmax(timeout); addRequiredOpenRtbFields(bidRequestBuilder); @@ -373,48 +377,50 @@ private void addRequiredOpenRtbFields(BidRequest.BidRequestBuilder bidRequestBui } private ExtRequest createExtRequest(BidRequestVideo videoRequest) { - final ExtIncludeBrandCategory extIncludeBrandCategory; - final IncludeBrandCategory includebrandcategory = videoRequest.getIncludebrandcategory(); - if (includebrandcategory != null) { - extIncludeBrandCategory = ExtIncludeBrandCategory.of( - includebrandcategory.getPrimaryAdserver(), - includebrandcategory.getPublisher(), - true, - includebrandcategory.getTranslateCategories()); - } else { - extIncludeBrandCategory = ExtIncludeBrandCategory.of(null, null, false, null); - } + final ExtRequestPrebidCache cache = ExtRequestPrebidCache.of(null, + ExtRequestPrebidCacheVastxml.of(null, null), null); - List durationRangeSec = null; - if (BooleanUtils.isFalse(videoRequest.getPodconfig().getRequireExactDuration())) { - durationRangeSec = videoRequest.getPodconfig().getDurationRangeSec(); - } + final ExtIncludeBrandCategory extIncludeBrandCategory = createExtIncludeBrandCategory(videoRequest); + + final Podconfig podconfig = videoRequest.getPodconfig(); + final List durationRangeSec = BooleanUtils.isFalse(podconfig.getRequireExactDuration()) + ? podconfig.getDurationRangeSec() + : null; final PriceGranularity priceGranularity = videoRequest.getPricegranularity(); final Integer precision = priceGranularity != null - ? priceGranularity.getPrecision() - : null; - - PriceGranularity updatedPriceGranularity = precision != null && precision != 0 - ? priceGranularity - : PriceGranularity.createFromString("med"); + ? priceGranularity.getPrecision() + : null; + final PriceGranularity updatedPriceGranularity = precision != null && precision != 0 + ? priceGranularity + : PriceGranularity.createFromString("med"); final ExtRequestTargeting targeting = ExtRequestTargeting.builder() - .pricegranularity(mapper.mapper().valueToTree(updatedPriceGranularity)) .includebidderkeys(true) .includebrandcategory(extIncludeBrandCategory) .durationrangesec(durationRangeSec) + .pricegranularity(mapper.mapper().valueToTree(updatedPriceGranularity)) .appendbiddernames(videoRequest.getAppendbiddernames()) .build(); - final ExtRequestPrebidCache extReqPrebidCache = ExtRequestPrebidCache.of(null, - ExtRequestPrebidCacheVastxml.of(null, null), null); - final ExtRequestPrebid extRequestPrebid = ExtRequestPrebid.builder() - .cache(extReqPrebidCache) + .cache(cache) .targeting(targeting) .build(); return ExtRequest.of(extRequestPrebid); } + + private static ExtIncludeBrandCategory createExtIncludeBrandCategory(BidRequestVideo videoRequest) { + final IncludeBrandCategory includeBrandCategory = videoRequest.getIncludebrandcategory(); + if (includeBrandCategory != null) { + return ExtIncludeBrandCategory.of( + includeBrandCategory.getPrimaryAdserver(), + includeBrandCategory.getPublisher(), + true, + includeBrandCategory.getTranslateCategories()); + } + + return ExtIncludeBrandCategory.of(null, null, false, null); + } } diff --git a/src/main/java/org/prebid/server/auction/model/CategoryMappingResult.java b/src/main/java/org/prebid/server/auction/model/CategoryMappingResult.java index 664ba8f7c01..5657cf9ad05 100644 --- a/src/main/java/org/prebid/server/auction/model/CategoryMappingResult.java +++ b/src/main/java/org/prebid/server/auction/model/CategoryMappingResult.java @@ -3,6 +3,7 @@ import com.iab.openrtb.response.Bid; import lombok.Value; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -17,6 +18,14 @@ public class CategoryMappingResult { List errors; + public static CategoryMappingResult of(List bidderResponses) { + return CategoryMappingResult.of( + Collections.emptyMap(), + Collections.emptyMap(), + bidderResponses, + Collections.emptyList()); + } + public String getCategory(Bid bid) { return biddersToBidsCategories.get(bid); } diff --git a/src/main/java/org/prebid/server/cache/CacheService.java b/src/main/java/org/prebid/server/cache/CacheService.java index 32e17de1676..40a6d7d222c 100644 --- a/src/main/java/org/prebid/server/cache/CacheService.java +++ b/src/main/java/org/prebid/server/cache/CacheService.java @@ -152,8 +152,10 @@ private CachedCreative makeDebugCacheCreative(CachedDebugLog videoCacheDebugLog, /** * Asks external prebid cache service to store the given value. */ - private Future makeRequest( - BidCacheRequest bidCacheRequest, int bidCount, Timeout timeout, String accountId) { + private Future makeRequest(BidCacheRequest bidCacheRequest, + int bidCount, + Timeout timeout, + String accountId) { if (bidCount == 0) { return Future.succeededFuture(BidCacheResponse.of(Collections.emptyList())); @@ -197,6 +199,7 @@ public Future cachePutObjects(List putObjects, String accountId, String integration, Timeout timeout) { + final List cachedCreatives = updatePutObjects(putObjects, isEventsEnabled, biddersAllowingVastUpdate, accountId, integration); @@ -213,6 +216,7 @@ private List updatePutObjects(List putObjects, Set allowedBidders, String accountId, String integration) { + return putObjects.stream() .map(putObject -> putObject.toBuilder() // remove "/vtrack" specific fields @@ -233,6 +237,7 @@ public Future cacheBidsOpenrtb(List bidsToCache, AuctionContext auctionContext, CacheContext cacheContext, EventsContext eventsContext) { + if (CollectionUtils.isEmpty(bidsToCache)) { return Future.succeededFuture(CacheServiceResult.empty()); } @@ -275,6 +280,7 @@ private CacheTtl accountCacheTtl(boolean impWithNoExpExists, Account account) { private List getCacheBids(List bidInfos, Integer cacheBidsTtl, CacheTtl accountCacheTtl) { + return bidInfos.stream() .map(bidInfo -> toCacheBid(bidInfo, cacheBidsTtl, accountCacheTtl, false)) .collect(Collectors.toList()); @@ -283,6 +289,7 @@ private List getCacheBids(List bidInfos, private List getVideoCacheBids(List bidInfos, Integer cacheBidsTtl, CacheTtl accountCacheTtl) { + return bidInfos.stream() .filter(bidInfo -> Objects.equals(bidInfo.getBidType(), BidType.video)) .map(bidInfo -> toCacheBid(bidInfo, cacheBidsTtl, accountCacheTtl, true)) @@ -296,6 +303,7 @@ private CacheBid toCacheBid(BidInfo bidInfo, Integer requestTtl, CacheTtl accountCacheTtl, boolean isVideoBid) { + final com.iab.openrtb.response.Bid bid = bidInfo.getBid(); final Integer bidTtl = bid.getExp(); final Imp correspondingImp = bidInfo.getCorrespondingImp(); @@ -409,6 +417,7 @@ private CacheServiceResult failResponseOpenrtb(Throwable exception, String accountId, CacheHttpRequest request, long startTime) { + logger.warn("Error occurred while interacting with cache service: {0}", exception.getMessage()); logger.debug("Error occurred while interacting with cache service", exception); @@ -422,8 +431,11 @@ private CacheServiceResult failResponseOpenrtb(Throwable exception, * Creates {@link DebugHttpCall} from {@link CacheHttpRequest} and {@link CacheHttpResponse}, endpoint * and starttime. */ - private DebugHttpCall makeDebugHttpCall(String endpoint, CacheHttpRequest httpRequest, - CacheHttpResponse httpResponse, long startTime) { + private DebugHttpCall makeDebugHttpCall(String endpoint, + CacheHttpRequest httpRequest, + CacheHttpResponse httpResponse, + long startTime) { + return DebugHttpCall.builder() .endpoint(endpoint) .requestUri(httpRequest != null ? httpRequest.getUri() : null) @@ -449,6 +461,7 @@ private int responseTime(long startTime) { private CachedCreative createJsonPutObjectOpenrtb(CacheBid cacheBid, String accountId, EventsContext eventsContext) { + final BidInfo bidInfo = cacheBid.getBidInfo(); final com.iab.openrtb.response.Bid bid = bidInfo.getBid(); final ObjectNode bidObjectNode = mapper.mapper().valueToTree(bid); @@ -481,8 +494,7 @@ private CachedCreative createXmlPutObjectOpenrtb(CacheBid cacheBid, String reque final com.iab.openrtb.response.Bid bid = bidInfo.getBid(); final String vastXml = bid.getAdm(); - final String bidder = bidInfo.getBidder(); - final String customCacheKey = resolveCustomCacheKey(hbCacheId, bidInfo.getCategory(), bidder); + final String customCacheKey = resolveCustomCacheKey(hbCacheId, bidInfo.getCategory()); final PutObject payload = PutObject.builder() .aid(requestId) @@ -495,11 +507,10 @@ private CachedCreative createXmlPutObjectOpenrtb(CacheBid cacheBid, String reque return CachedCreative.of(payload, creativeSizeFromTextNode(payload.getValue())); } - private static String resolveCustomCacheKey(String hbCacheId, String categoryDuration, String bidder) { - if (hbCacheId == null || bidder == null) { - return null; - } - return StringUtils.isNotEmpty(categoryDuration) ? String.format("%s_%s", categoryDuration, hbCacheId) : null; + private static String resolveCustomCacheKey(String hbCacheId, String category) { + return StringUtils.isNoneEmpty(category, hbCacheId) + ? String.format("%s_%s", category, hbCacheId) + : null; } private String generateWinUrl(String bidId, @@ -507,6 +518,7 @@ private String generateWinUrl(String bidId, String accountId, EventsContext eventsContext, String lineItemId) { + if (!eventsContext.isEnabledForAccount()) { return null; } @@ -528,8 +540,11 @@ private String generateWinUrl(String bidId, * Handles http response, analyzes response status and creates {@link BidCacheResponse} from response body * or throws {@link PreBidException} in case of errors. */ - private BidCacheResponse toBidCacheResponse( - int statusCode, String responseBody, int bidCount, String accountId, long startTime) { + private BidCacheResponse toBidCacheResponse(int statusCode, + String responseBody, + int bidCount, + String accountId, + long startTime) { if (statusCode != 200) { throw new PreBidException(String.format("HTTP status code %d", statusCode)); @@ -569,6 +584,7 @@ private static Map toResultMap(List cacheVideoBids, List uuids, String hbCacheId) { + final Map result = new HashMap<>(uuids.size()); // here we assume "videoBids" is a sublist of "bids" @@ -625,8 +641,11 @@ public static URL getCacheEndpointUrl(String cacheSchema, String cacheHost, Stri /** * Composes cached asset url template against the given query, schema and host. */ - public static String getCachedAssetUrlTemplate(String cacheSchema, String cacheHost, String path, + public static String getCachedAssetUrlTemplate(String cacheSchema, + String cacheHost, + String path, String cacheQuery) { + try { final URL baseUrl = getCacheBaseUrl(cacheSchema, cacheHost); return new URL(baseUrl, path + "?" + cacheQuery).toString(); diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/ExtIncludeBrandCategory.java b/src/main/java/org/prebid/server/proto/openrtb/ext/ExtIncludeBrandCategory.java index d6ebc50cadd..0c61a578986 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/ExtIncludeBrandCategory.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/ExtIncludeBrandCategory.java @@ -4,6 +4,9 @@ import lombok.AllArgsConstructor; import lombok.Value; +/** + * Defines the contract for bidrequest.ext.prebid.targeting.includebrandcategory + */ @AllArgsConstructor(staticName = "of") @Value public class ExtIncludeBrandCategory { @@ -19,4 +22,3 @@ public class ExtIncludeBrandCategory { @JsonProperty("translatecategories") Boolean translateCategories; } - diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index 3286eb2c705..c3c85b747ac 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -131,8 +131,10 @@ VastModifier vastModifier(BidderCatalog bidderCatalog, EventsService eventsServi } @Bean - CategoryMappingService categoryMapper(ApplicationSettings applicationSettings, - JacksonMapper jacksonMapper) { + @ConditionalOnProperty(prefix = "auction", name = "category-mapping-enabled", havingValue = "true") + CategoryMappingService categoryMappingService(ApplicationSettings applicationSettings, + JacksonMapper jacksonMapper) { + return new CategoryMappingService(applicationSettings, jacksonMapper); } @@ -526,7 +528,6 @@ BidderErrorNotifier bidderErrorNotifier( @Bean BidResponseCreator bidResponseCreator( CacheService cacheService, - CategoryMappingService categoryMappingService, BidderCatalog bidderCatalog, VastModifier vastModifier, EventsService eventsService, @@ -534,13 +535,13 @@ BidResponseCreator bidResponseCreator( WinningBidComparatorFactory winningBidComparatorFactory, IdGenerator bidIdGenerator, HookStageExecutor hookStageExecutor, + @Autowired(required = false) CategoryMappingService categoryMappingService, @Value("${settings.targeting.truncate-attr-chars}") int truncateAttrChars, Clock clock, JacksonMapper mapper) { return new BidResponseCreator( cacheService, - categoryMappingService, bidderCatalog, vastModifier, eventsService, @@ -548,6 +549,7 @@ BidResponseCreator bidResponseCreator( winningBidComparatorFactory, bidIdGenerator, hookStageExecutor, + categoryMappingService, truncateAttrChars, clock, mapper); diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 509bfba6af6..7ce457621f1 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -129,6 +129,7 @@ auction: banner-creative-max-size: skip secure-markup: skip host-schain-node: + category-mapping-enabled: false video: stored-request-required: false stored-requests-timeout-ms: 90 diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 27141fddf22..75a44eec576 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -180,13 +180,14 @@ public void setUp() { given(cacheService.getEndpointHost()).willReturn("testHost"); given(cacheService.getEndpointPath()).willReturn("testPath"); given(cacheService.getCachedAssetURLTemplate()).willReturn("uuid="); - given(categoryMappingService.createCategoryMapping(any(), any(), any(), any())).willAnswer(invocationOnMock -> - Future.succeededFuture(CategoryMappingResult.of(emptyMap(), emptyMap(), - invocationOnMock.getArgument(0), null)) - ); + + given(categoryMappingService.createCategoryMapping(any(), any(), any())) + .willAnswer(invocationOnMock -> Future.succeededFuture( + CategoryMappingResult.of(emptyMap(), emptyMap(), invocationOnMock.getArgument(0), null))); given(storedRequestProcessor.videoStoredDataResult(any(), anyList(), anyList(), any())) .willReturn(Future.succeededFuture(VideoStoredDataResult.empty())); + given(idGenerator.getType()).willReturn(IdGeneratorType.none); given(hookStageExecutor.executeProcessedBidderResponseStage(any(), any())) @@ -200,7 +201,6 @@ public void setUp() { bidResponseCreator = new BidResponseCreator( cacheService, - categoryMappingService, bidderCatalog, vastModifier, eventsService, @@ -208,6 +208,7 @@ public void setUp() { winningBidComparatorFactory, idGenerator, hookStageExecutor, + categoryMappingService, 0, clock, jacksonMapper); @@ -912,7 +913,7 @@ public void shouldUseBidsReturnedInCategoryMapperResultAndUpdateErrors() { final List bidderResponses = singletonList(BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid1, banner, "USD"), BidderBid.of(bid2, banner, "USD")), 100)); - given(categoryMappingService.createCategoryMapping(any(), any(), any(), any())) + given(categoryMappingService.createCategoryMapping(any(), any(), any())) .willReturn(Future.succeededFuture(CategoryMappingResult.of(emptyMap(), emptyMap(), singletonList(BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid1, banner, "USD")), 100)), @@ -941,7 +942,7 @@ public void shouldThrowExceptionWhenCategoryMappingThrowsPrebidException() { final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(5.67)).impid(IMP_ID).build(); final List bidderResponses = singletonList(BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); - given(categoryMappingService.createCategoryMapping(any(), any(), any(), any())) + given(categoryMappingService.createCategoryMapping(any(), any(), any())) .willReturn(Future.failedFuture(new InvalidRequestException("category exception"))); // when @@ -1394,7 +1395,6 @@ public void shouldTruncateTargetingKeywordsByGlobalConfig() { final BidResponseCreator bidResponseCreator = new BidResponseCreator( cacheService, - categoryMappingService, bidderCatalog, vastModifier, eventsService, @@ -1402,6 +1402,7 @@ public void shouldTruncateTargetingKeywordsByGlobalConfig() { winningBidComparatorFactory, idGenerator, hookStageExecutor, + categoryMappingService, 20, clock, jacksonMapper); @@ -2162,7 +2163,7 @@ public void shouldAddDealTierSatisfiedToExtBidPrebidWhenBidsPrioritySatisfiedMin ExtBidPrebid.builder().video(ExtBidPrebidVideo.of(1, "category")).build()))).build(); final List bidderResponses = singletonList(BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); - given(categoryMappingService.createCategoryMapping(anyList(), any(), any(), any())) + given(categoryMappingService.createCategoryMapping(any(), any(), any())) .willReturn(Future.succeededFuture(CategoryMappingResult.of(emptyMap(), Collections.singletonMap(bid, true), bidderResponses, emptyList()))); diff --git a/src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java b/src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java index c2ebd311d5a..e02a419b302 100644 --- a/src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java +++ b/src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java @@ -102,7 +102,7 @@ public void applyCategoryMappingShouldReturnFilteredBidsWithCategory() { // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -142,7 +142,7 @@ public void applyCategoryMappingShouldTolerateBidsWithSameIdWithingDifferentBidd // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -171,7 +171,7 @@ public void applyCategoryMappingShouldNotCallFetchCategoryWhenTranslateCategorie // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then verifyZeroInteractions(applicationSettings); @@ -192,7 +192,7 @@ public void applyCategoryMappingShouldReturnFailedFutureWhenTranslateTrueAndAdSe // when assertThatThrownBy(() -> categoryMappingService.createCategoryMapping( - bidderResponses, BidRequest.builder().build(), extRequestTargeting, timeout)) + bidderResponses, givenBidRequestWithTargeting(extRequestTargeting), timeout)) .isInstanceOf(InvalidRequestException.class) .hasMessage("Primary ad server required but was not defined when translate category is enabled"); } @@ -208,7 +208,7 @@ public void applyCategoryMappingShouldReturnFailedFutureWhenTranslateTrueAndAdSe // when and then assertThatThrownBy(() -> categoryMappingService.createCategoryMapping( - bidderResponses, BidRequest.builder().build(), extRequestTargeting, timeout)) + bidderResponses, givenBidRequestWithTargeting(extRequestTargeting), timeout)) .isInstanceOf(InvalidRequestException.class) .hasMessage("Primary ad server `3` is not recognized"); } @@ -227,7 +227,7 @@ public void applyCategoryMappingShouldReturnUseFreewheelAdServerWhenAdServerIs1( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when - categoryMappingService.createCategoryMapping(bidderResponses, BidRequest.builder().build(), extRequestTargeting, + categoryMappingService.createCategoryMapping(bidderResponses, givenBidRequestWithTargeting(extRequestTargeting), timeout); // then @@ -248,7 +248,7 @@ public void applyCategoryMappingShouldReturnUseDpfAdServerWhenAdServerIs2() { Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when - categoryMappingService.createCategoryMapping(bidderResponses, BidRequest.builder().build(), extRequestTargeting, + categoryMappingService.createCategoryMapping(bidderResponses, givenBidRequestWithTargeting(extRequestTargeting), timeout); // then @@ -272,7 +272,7 @@ public void applyCategoryMappingShouldRejectBidsWithFailedCategoryFetch() { // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -299,7 +299,7 @@ public void applyCategoryMappingShouldRejectBidsWithCatLengthMoreThanOne() { Future.succeededFuture(singletonMap("cat2", "fetchedCat2"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -327,7 +327,7 @@ public void applyCategoryMappingShouldRejectBidsWithWhenCatIsNull() { Future.succeededFuture(singletonMap("cat2", "fetchedCat2"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -355,7 +355,7 @@ public void applyCategoryMappingShouldRejectBidWhenNullCategoryReturnedFromSourc Future.succeededFuture(null)); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -386,7 +386,7 @@ public void applyCategoryMappingShouldUseMediaTypePriceGranularityIfDefined() { Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -411,7 +411,7 @@ public void applyCategoryMappingShouldRejectBidIfItsDurationLargerThanTargetingM Future.succeededFuture(singletonMap("cat2", "fetchedCat2"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -434,7 +434,7 @@ public void applyCategoryMappingShouldReturnEmptyCategoryMappingResult() { // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -463,7 +463,7 @@ public void applyCategoryMappingShouldReturnFirstVideoCategoryIfPresent() { // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -488,7 +488,7 @@ public void applyCategoryMappingShouldReturnEmptyCategoryIfNotWithCategory() { // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -513,7 +513,7 @@ public void applyCategoryMappingShouldReturnFirstIabBidCategoryIfWithCategoryAnd // when final Future resultFuture = categoryMappingService.createCategoryMapping( - bidderResponses, BidRequest.builder().build(), extRequestTargeting, timeout); + bidderResponses, givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -541,7 +541,7 @@ public void applyCategoryMappingShouldReturnFetchedCategoryIfWithCategoryAndTran // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -563,7 +563,7 @@ public void applyCategoryMappingShouldSetFirstDurationFromRangeIfDurationIsNull( // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -589,7 +589,7 @@ public void applyCategoryMappingShouldDeduplicateBidsByFetchedCategoryWhenWithCa // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -616,7 +616,7 @@ public void applyCategoryMappingShouldDeduplicateBidsByBidCatWhenWithCategoryIsT // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -644,7 +644,7 @@ public void applyCategoryMappingShouldDeduplicateBidsByPriceAndDurationIfWithCat // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -668,7 +668,7 @@ public void applyCategoryMappingShouldReturnDurCatBuiltFromPriceAndFetchedCatego // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -690,7 +690,7 @@ public void applyCategoryMappingShouldReturnDurCatBuiltFromPriceAndBidCatAndDura // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -713,7 +713,7 @@ public void applyCategoryMappingShouldReturnDurCatBuiltFromPriceAndBidCatAndDura // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -735,7 +735,7 @@ public void applyCategoryMappingShouldReturnDurCatBuiltFromPriceAndDuration() { // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -750,19 +750,22 @@ public void applyCategoryMappingShouldReturnDurCatBuiltFromPriorityAndDuration() .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", givenDealTier("rubiconPrefix", 3))) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), false, null)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), false, null); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -784,19 +787,22 @@ public void applyCategoryMappingShouldUseDealTierFromImpExtPrebidBidders() { .bidder(mapper.createObjectNode() .set("rubicon", givenDealTier("prebidPrefix", 4))).build(), null))) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), false, null)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), false, null); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -820,19 +826,22 @@ public void applyCategoryMappingShouldPrecedencePriorityAndDurationFromPrebidOve .imp(singletonList(Imp.builder().id("impId1") .ext(impExt) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), false, null)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), false, null); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -852,19 +861,22 @@ public void applyCategoryMappingShouldReturnDurCatBuiltFromPriorityCatAndDuratio .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", givenDealTier("rubiconPrefix", 3))) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -886,19 +898,22 @@ public void applyCategoryMappingShouldBuildCatDurFromPriceCatAndDurIfSupportDeal .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", givenDealTier("rubiconPrefix", 3))) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(false).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(false) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -918,19 +933,22 @@ public void applyCategoryMappingShouldBuildCatDurFromPriceCatAndDurIfBidPriority .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", givenDealTier("rubiconPrefix", 10))) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -955,19 +973,22 @@ public void applyCategoryMappingShouldIgnoreContextAndPrebidInImpExt() { .imp(singletonList(Imp.builder().id("impId1") .ext(impExt) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -987,19 +1008,22 @@ public void applyCategoryMappingShouldAddErrorIfImpBidderDoesNotHaveDealTierAndC .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", mapper.createObjectNode())) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -1022,19 +1046,22 @@ public void applyCategoryMappingShouldAddErrorIfPrefixIsNullAndCreateRegularCatD .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", dealTier)) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -1058,19 +1085,22 @@ public void applyCategoryMappingShouldAddErrorIfMinDealTierIsNullAndCreateRegula .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", dealTier)) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -1092,19 +1122,22 @@ public void applyCategoryMappingShouldAddErrorIfMinDealTierLessThanZeroAndCreate .imp(singletonList(Imp.builder().id("impId1") .ext(mapper.createObjectNode().set("rubicon", givenDealTier("prefix", -1))) .build())) - .ext(ExtRequest.of(ExtRequestPrebid.builder().supportdeals(true).build())).build(); + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(givenTargeting(1, "publisher", asList(10, 15, 5), true, true)) + .supportdeals(true) + .build())) + .build(); final List bidderResponses = singletonList( givenBidderResponse("rubicon", givenBidderBid(givenBid("1", "impId1", "10", singletonList("cat1")), BidType.video, 10))); - final ExtRequestTargeting extRequestTargeting = givenTargeting(1, "publisher", asList(10, 15, 5), true, true); given(applicationSettings.getCategories(anyString(), anyString(), any())).willReturn( Future.succeededFuture(singletonMap("cat1", "fetchedCat1"))); // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - bidRequest, extRequestTargeting, timeout); + bidRequest, timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -1135,7 +1168,7 @@ public void applyCategoryMappingShouldRejectAllBidsFromBidderInDifferentReasons( // when final Future resultFuture = categoryMappingService.createCategoryMapping(bidderResponses, - BidRequest.builder().build(), extRequestTargeting, timeout); + givenBidRequestWithTargeting(extRequestTargeting), timeout); // then assertThat(resultFuture.succeeded()).isTrue(); @@ -1198,6 +1231,14 @@ private static ExtRequestTargeting givenTargeting(Integer primaryAdServer, .build(); } + private static BidRequest givenBidRequestWithTargeting(ExtRequestTargeting extRequestTargeting) { + return BidRequest.builder() + .ext(ExtRequest.of(ExtRequestPrebid.builder() + .targeting(extRequestTargeting) + .build())) + .build(); + } + private static JsonNode givenDealTier(String prefix, Integer minDealTier) { return mapper.createObjectNode().set("dealTier", mapper.createObjectNode().put("prefix", prefix).put("minDealTier", minDealTier)); diff --git a/src/test/java/org/prebid/server/handler/ForceDealsUpdateHandlerTest.java b/src/test/java/org/prebid/server/handler/ForceDealsUpdateHandlerTest.java index a971a70824d..ffa68797376 100644 --- a/src/test/java/org/prebid/server/handler/ForceDealsUpdateHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/ForceDealsUpdateHandlerTest.java @@ -46,7 +46,6 @@ public class ForceDealsUpdateHandlerTest { private LineItemService lineItemService; private ForceDealsUpdateHandler handler; - @Mock private RoutingContext routingContext; @Mock @@ -80,7 +79,7 @@ public void shouldReturnBadRequestWhenActionParamIsMissing() { // when handler.handle(routingContext); - // then + // then verify(httpRequest).getParam(eq(ACTION_NAME_PARAM)); verify(httpResponse).setStatusCode(400); @@ -96,7 +95,7 @@ public void shouldReturnBadRequestWhenBadActionParamIsGiven() { // when handler.handle(routingContext); - // then + // then verify(httpRequest).getParam(eq(ACTION_NAME_PARAM)); verify(httpResponse).setStatusCode(400); diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 32a0971a03c..5cc7be651b9 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -275,6 +275,7 @@ http-client.circuit-breaker.closing-interval-ms=10000 auction.default-timeout-ms=2000 auction.timeout-adjustment-ms=0 auction.generate-source-tid=false +auction.category-mapping-enabled=true currency-converter.external-rates.enabled=true currency-converter.external-rates.url=http://localhost:8090/currency-rates amp.custom-targeting=rubicon From 9756a67ad8aed80c1076d7e3b2a5e54bbe0b8401 Mon Sep 17 00:00:00 2001 From: rpanchyk Date: Fri, 5 Nov 2021 10:02:27 +0200 Subject: [PATCH 2/3] Update docs --- docs/config-app.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config-app.md b/docs/config-app.md index c7f3a13339b..b46daa0e9f6 100644 --- a/docs/config-app.md +++ b/docs/config-app.md @@ -78,6 +78,7 @@ Removes and downloads file again if depending service cant process probably corr - `auction.validations.banner-creative-max-size` - enables creative max size validation for banners. Possible values: `skip`, `enforce`, `warn`. Default is `skip`. - `auction.validations.secure-markup` - enables secure markup validation. Possible values: `skip`, `enforce`, `warn`. Default is `skip`. - `auction.host-schain-node` - defines global schain node that will be appended to `request.source.ext.schain.nodes` passed to bidders +- `auction.category-mapping-enabled` - if equals to `true` the category mapping feature will be active while auction. ## Event - `event.default-timeout-ms` - timeout for event notifications From 97d17b059201cfb3bf89d4ca7e738bffc83c1f33 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 5 Nov 2021 12:49:42 +0200 Subject: [PATCH 3/3] Add category mapping enabled toggle - proposal (#1566) * Added NoOpCategoryMappingService * Fixes after review --- .../server/auction/BidResponseCreator.java | 17 ++++++-------- .../server/auction/PriceGranularity.java | 4 ++-- .../BasicCategoryMappingService.java} | 11 ++++++---- .../CategoryMappingService.java | 16 ++++++++++++++ .../NoOpCategoryMappingService.java | 20 +++++++++++++++++ .../spring/config/ServiceConfiguration.java | 22 ++++++++++++++----- ...a => BasicCategoryMappingServiceTest.java} | 7 +++--- .../auction/BidResponseCreatorTest.java | 1 + 8 files changed, 74 insertions(+), 24 deletions(-) rename src/main/java/org/prebid/server/auction/{CategoryMappingService.java => categorymapping/BasicCategoryMappingService.java} (98%) create mode 100644 src/main/java/org/prebid/server/auction/categorymapping/CategoryMappingService.java create mode 100644 src/main/java/org/prebid/server/auction/categorymapping/NoOpCategoryMappingService.java rename src/test/java/org/prebid/server/auction/{CategoryMappingServiceTest.java => BasicCategoryMappingServiceTest.java} (99%) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index aa7a5ec5138..7a774978794 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -22,6 +22,7 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.prebid.server.auction.categorymapping.CategoryMappingService; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidInfo; import org.prebid.server.auction.model.BidRequestCacheInfo; @@ -149,7 +150,7 @@ public BidResponseCreator(CacheService cacheService, this.winningBidComparatorFactory = Objects.requireNonNull(winningBidComparatorFactory); this.bidIdGenerator = Objects.requireNonNull(bidIdGenerator); this.hookStageExecutor = Objects.requireNonNull(hookStageExecutor); - this.categoryMappingService = categoryMappingService; + this.categoryMappingService = Objects.requireNonNull(categoryMappingService); this.truncateAttrChars = validateTruncateAttrChars(truncateAttrChars); this.clock = Objects.requireNonNull(clock); this.mapper = Objects.requireNonNull(mapper); @@ -449,16 +450,12 @@ private static BidderResponse rejectBidderResponseOrProceed( private Future createCategoryMapping(AuctionContext auctionContext, List bidderResponses) { - if (categoryMappingService != null) { - return categoryMappingService.createCategoryMapping( - bidderResponses, - auctionContext.getBidRequest(), - auctionContext.getTimeout()) + return categoryMappingService.createCategoryMapping( + bidderResponses, + auctionContext.getBidRequest(), + auctionContext.getTimeout()) - .map(categoryMappingResult -> addCategoryMappingErrors(categoryMappingResult, auctionContext)); - } - - return Future.succeededFuture(CategoryMappingResult.of(bidderResponses)); + .map(categoryMappingResult -> addCategoryMappingErrors(categoryMappingResult, auctionContext)); } private static CategoryMappingResult addCategoryMappingErrors(CategoryMappingResult categoryMappingResult, diff --git a/src/main/java/org/prebid/server/auction/PriceGranularity.java b/src/main/java/org/prebid/server/auction/PriceGranularity.java index e262d4052e1..f08e24151b2 100644 --- a/src/main/java/org/prebid/server/auction/PriceGranularity.java +++ b/src/main/java/org/prebid/server/auction/PriceGranularity.java @@ -57,7 +57,7 @@ private PriceGranularity(List ranges, BigDecimal rangesMax, /** * Creates {@link PriceGranularity} from {@link ExtPriceGranularity}. */ - static PriceGranularity createFromExtPriceGranularity(ExtPriceGranularity extPriceGranularity) { + public static PriceGranularity createFromExtPriceGranularity(ExtPriceGranularity extPriceGranularity) { return createFromRanges(extPriceGranularity.getPrecision(), extPriceGranularity.getRanges()); } @@ -107,7 +107,7 @@ private static void putStringPriceGranularity(PriceGranularityType type, Integer /** * Creates {@link PriceGranularity} from list of {@link ExtGranularityRange}s and validates it. */ - private static PriceGranularity createFromRanges(Integer precision, List ranges) { + public static PriceGranularity createFromRanges(Integer precision, List ranges) { final BigDecimal rangeMax = CollectionUtils.emptyIfNull(ranges).stream() .filter(Objects::nonNull) diff --git a/src/main/java/org/prebid/server/auction/CategoryMappingService.java b/src/main/java/org/prebid/server/auction/categorymapping/BasicCategoryMappingService.java similarity index 98% rename from src/main/java/org/prebid/server/auction/CategoryMappingService.java rename to src/main/java/org/prebid/server/auction/categorymapping/BasicCategoryMappingService.java index 80eea42f475..5ba917e4a54 100644 --- a/src/main/java/org/prebid/server/auction/CategoryMappingService.java +++ b/src/main/java/org/prebid/server/auction/categorymapping/BasicCategoryMappingService.java @@ -1,4 +1,4 @@ -package org.prebid.server.auction; +package org.prebid.server.auction.categorymapping; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; @@ -19,6 +19,8 @@ import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.prebid.server.auction.CpmRange; +import org.prebid.server.auction.PriceGranularity; import org.prebid.server.auction.model.BidderResponse; import org.prebid.server.auction.model.CategoryMappingResult; import org.prebid.server.auction.requestfactory.Ortb2ImplicitParametersResolver; @@ -55,7 +57,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class CategoryMappingService { +public class BasicCategoryMappingService implements CategoryMappingService { private static final TypeReference> EXT_IMP_DEAL_TIER_REFERENCE = new TypeReference<>() { @@ -67,7 +69,7 @@ public class CategoryMappingService { private final ApplicationSettings applicationSettings; private final JacksonMapper jacksonMapper; - public CategoryMappingService(ApplicationSettings applicationSettings, JacksonMapper jacksonMapper) { + public BasicCategoryMappingService(ApplicationSettings applicationSettings, JacksonMapper jacksonMapper) { this.applicationSettings = Objects.requireNonNull(applicationSettings); this.jacksonMapper = Objects.requireNonNull(jacksonMapper); } @@ -78,6 +80,7 @@ public CategoryMappingService(ApplicationSettings applicationSettings, JacksonMa * Removes the bids with duplicated category key, leaving one with the highest price. * Returns list of errors for each dropped bid. */ + @Override public Future createCategoryMapping(List bidderResponses, BidRequest bidRequest, Timeout timeout) { @@ -594,7 +597,7 @@ private static Set collectRejectedDuplicatedBids( return categoryToDuplicatedCategoryBids.values().stream() .filter(categoryBids -> categoryBids.size() > 1) - .flatMap(CategoryMappingService::getDuplicatedForCategory) + .flatMap(BasicCategoryMappingService::getDuplicatedForCategory) .map(categoryBidContext -> RejectedBid.of( extractBidId(categoryBidContext), categoryBidContext.getBidder(), diff --git a/src/main/java/org/prebid/server/auction/categorymapping/CategoryMappingService.java b/src/main/java/org/prebid/server/auction/categorymapping/CategoryMappingService.java new file mode 100644 index 00000000000..088a9604b9d --- /dev/null +++ b/src/main/java/org/prebid/server/auction/categorymapping/CategoryMappingService.java @@ -0,0 +1,16 @@ +package org.prebid.server.auction.categorymapping; + +import com.iab.openrtb.request.BidRequest; +import io.vertx.core.Future; +import org.prebid.server.auction.model.BidderResponse; +import org.prebid.server.auction.model.CategoryMappingResult; +import org.prebid.server.execution.Timeout; + +import java.util.List; + +public interface CategoryMappingService { + + Future createCategoryMapping(List bidderResponses, + BidRequest bidRequest, + Timeout timeout); +} diff --git a/src/main/java/org/prebid/server/auction/categorymapping/NoOpCategoryMappingService.java b/src/main/java/org/prebid/server/auction/categorymapping/NoOpCategoryMappingService.java new file mode 100644 index 00000000000..f6161fa6f90 --- /dev/null +++ b/src/main/java/org/prebid/server/auction/categorymapping/NoOpCategoryMappingService.java @@ -0,0 +1,20 @@ +package org.prebid.server.auction.categorymapping; + +import com.iab.openrtb.request.BidRequest; +import io.vertx.core.Future; +import org.prebid.server.auction.model.BidderResponse; +import org.prebid.server.auction.model.CategoryMappingResult; +import org.prebid.server.execution.Timeout; + +import java.util.List; + +public class NoOpCategoryMappingService implements CategoryMappingService { + + @Override + public Future createCategoryMapping(List bidderResponses, + BidRequest bidRequest, + Timeout timeout) { + + return Future.succeededFuture(CategoryMappingResult.of(bidderResponses)); + } +} diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index c3c85b747ac..8a12aee7b98 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -9,7 +9,6 @@ import org.prebid.server.auction.AmpResponsePostProcessor; import org.prebid.server.auction.BidResponseCreator; import org.prebid.server.auction.BidResponsePostProcessor; -import org.prebid.server.auction.CategoryMappingService; import org.prebid.server.auction.DebugResolver; import org.prebid.server.auction.ExchangeService; import org.prebid.server.auction.FpdResolver; @@ -25,6 +24,9 @@ import org.prebid.server.auction.VideoResponseFactory; import org.prebid.server.auction.VideoStoredRequestProcessor; import org.prebid.server.auction.WinningBidComparatorFactory; +import org.prebid.server.auction.categorymapping.BasicCategoryMappingService; +import org.prebid.server.auction.categorymapping.CategoryMappingService; +import org.prebid.server.auction.categorymapping.NoOpCategoryMappingService; import org.prebid.server.auction.requestfactory.AmpRequestFactory; import org.prebid.server.auction.requestfactory.AuctionRequestFactory; import org.prebid.server.auction.requestfactory.Ortb2ImplicitParametersResolver; @@ -132,10 +134,20 @@ VastModifier vastModifier(BidderCatalog bidderCatalog, EventsService eventsServi @Bean @ConditionalOnProperty(prefix = "auction", name = "category-mapping-enabled", havingValue = "true") - CategoryMappingService categoryMappingService(ApplicationSettings applicationSettings, - JacksonMapper jacksonMapper) { + CategoryMappingService basicCategoryMappingService(ApplicationSettings applicationSettings, + JacksonMapper jacksonMapper) { - return new CategoryMappingService(applicationSettings, jacksonMapper); + return new BasicCategoryMappingService(applicationSettings, jacksonMapper); + } + + @Bean + @ConditionalOnProperty( + prefix = "auction", + name = "category-mapping-enabled", + matchIfMissing = true, + havingValue = "false") + CategoryMappingService noOpCategoryMappingService() { + return new NoOpCategoryMappingService(); } @Bean @@ -535,7 +547,7 @@ BidResponseCreator bidResponseCreator( WinningBidComparatorFactory winningBidComparatorFactory, IdGenerator bidIdGenerator, HookStageExecutor hookStageExecutor, - @Autowired(required = false) CategoryMappingService categoryMappingService, + CategoryMappingService categoryMappingService, @Value("${settings.targeting.truncate-attr-chars}") int truncateAttrChars, Clock clock, JacksonMapper mapper) { diff --git a/src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java b/src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java similarity index 99% rename from src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java rename to src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java index e02a419b302..603d4b9cd64 100644 --- a/src/test/java/org/prebid/server/auction/CategoryMappingServiceTest.java +++ b/src/test/java/org/prebid/server/auction/BasicCategoryMappingServiceTest.java @@ -13,6 +13,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.VertxTest; +import org.prebid.server.auction.categorymapping.BasicCategoryMappingService; import org.prebid.server.auction.model.BidderResponse; import org.prebid.server.auction.model.CategoryMappingResult; import org.prebid.server.bidder.model.BidderBid; @@ -55,7 +56,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; -public class CategoryMappingServiceTest extends VertxTest { +public class BasicCategoryMappingServiceTest extends VertxTest { private static final PriceGranularity PRICE_GRANULARITY = PriceGranularity.DEFAULT; @@ -65,13 +66,13 @@ public class CategoryMappingServiceTest extends VertxTest { @Mock ApplicationSettings applicationSettings; - private CategoryMappingService categoryMappingService; + private BasicCategoryMappingService categoryMappingService; private Timeout timeout; @Before public void setUp() { - categoryMappingService = new CategoryMappingService(applicationSettings, jacksonMapper); + categoryMappingService = new BasicCategoryMappingService(applicationSettings, jacksonMapper); timeout = new TimeoutFactory(Clock.fixed(Instant.now(), ZoneId.systemDefault())).create(500); } diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 75a44eec576..e03502d9769 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -31,6 +31,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.VertxTest; +import org.prebid.server.auction.categorymapping.CategoryMappingService; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidInfo; import org.prebid.server.auction.model.BidRequestCacheInfo;