From 1810e87e310e635b80863beeb5f697f1e586155f Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Mon, 16 Dec 2024 13:49:00 +0200 Subject: [PATCH 01/24] Added new PAA iab model. --- .../bidder/model/CompositeBidderResponse.java | 4 ++++ .../openrtb/ext/response/ExtBidResponse.java | 5 +++++ .../proto/openrtb/ext/response/ExtIgi.java | 20 +++++++++++++++++ .../proto/openrtb/ext/response/ExtIgiIgb.java | 22 +++++++++++++++++++ .../proto/openrtb/ext/response/ExtIgiIgs.java | 16 ++++++++++++++ .../openrtb/ext/response/ExtIgiIgsExt.java | 11 ++++++++++ 6 files changed, 78 insertions(+) create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgb.java create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgsExt.java diff --git a/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java b/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java index 7e5a31f16b0..8e80ea8b604 100644 --- a/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java +++ b/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java @@ -3,6 +3,7 @@ import lombok.Builder; import lombok.Value; import org.prebid.server.bidder.Bidder; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; import java.util.Collections; @@ -26,6 +27,9 @@ public class CompositeBidderResponse { */ List fledgeAuctionConfigs; + + List igi; + public static CompositeBidderResponse empty() { return builder().build(); } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java index 115ce7b3ff9..6f4b3904fd7 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java @@ -48,6 +48,11 @@ public class ExtBidResponse { */ Map usersync; + /** + * Defines the contract for bidresponse.ext.igi + */ + List igi; + /** * Defines the contract for bidresponse.ext.prebid */ diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java new file mode 100644 index 00000000000..fc63c1288bc --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java @@ -0,0 +1,20 @@ +package org.prebid.server.proto.openrtb.ext.response; + +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +/** + * Defines the contract for bidresponse.ext.igi + */ +@Value +@Builder +public class ExtIgi { + + String impid; + + List igb; + + List igs; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgb.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgb.java new file mode 100644 index 00000000000..aca3758c7aa --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgb.java @@ -0,0 +1,22 @@ +package org.prebid.server.proto.openrtb.ext.response; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ExtIgiIgb { + + String origin; + + Double maxbid; + + @Builder.Default + String cur = "USD"; + + JsonNode pbs; + + ObjectNode ps; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java new file mode 100644 index 00000000000..3330f1fa37c --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java @@ -0,0 +1,16 @@ +package org.prebid.server.proto.openrtb.ext.response; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ExtIgiIgs { + + String impid; + + ObjectNode config; + + ExtIgiIgsExt ext; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgsExt.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgsExt.java new file mode 100644 index 00000000000..979b7fe6e13 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgsExt.java @@ -0,0 +1,11 @@ +package org.prebid.server.proto.openrtb.ext.response; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtIgiIgsExt { + + String bidder; + + String adapter; +} From abd310491ef079f27c69b6b114b750fedc580d0c Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 20 Dec 2024 14:44:23 +0200 Subject: [PATCH 02/24] PAA WIP. --- .../server/auction/BidResponseCreator.java | 27 +++++++++++++++++- .../bidder/consumable/ConsumableBidder.java | 9 ++++-- .../server/bidder/criteo/CriteoBidder.java | 28 +++++++------------ .../bidder/criteo/CriteoExtBidResponse.java | 3 +- .../criteo/CriteoIgiExtBidResponse.java | 13 --------- .../criteo/CriteoIgsIgiExtBidResponse.java | 10 ------- .../org/prebid/server/bidder/ix/IxBidder.java | 23 +++++++-------- .../bidder/medianet/MedianetBidder.java | 18 ++++++------ .../server/bidder/model/BidderSeatBid.java | 5 ++++ .../bidder/model/BidderSeatBidInfo.java | 12 +++++++- .../bidder/model/CompositeBidderResponse.java | 9 ------ .../server/bidder/openx/OpenxBidder.java | 21 +++++++++----- .../bidder/pubmatic/PubmaticBidder.java | 22 +++++++++------ .../proto/openrtb/ext/response/ExtIgi.java | 2 +- .../proto/openrtb/ext/response/ExtIgiIgs.java | 6 ++-- 15 files changed, 114 insertions(+), 94 deletions(-) delete mode 100644 src/main/java/org/prebid/server/bidder/criteo/CriteoIgiExtBidResponse.java delete mode 100644 src/main/java/org/prebid/server/bidder/criteo/CriteoIgsIgiExtBidResponse.java diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 31ed4ee1403..a41c0d9d38b 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -82,6 +82,9 @@ import org.prebid.server.proto.openrtb.ext.response.ExtBidderError; import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgsExt; import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; import org.prebid.server.proto.openrtb.ext.response.ExtResponseDebug; import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityInfrastructure; @@ -414,7 +417,8 @@ private List toBidderResponseInfos(CategoryMappingResult cat seatBid.getHttpCalls(), seatBid.getErrors(), seatBid.getWarnings(), - seatBid.getFledgeAuctionConfigs()); + seatBid.getFledgeAuctionConfigs(), + seatBid.getIgi()); result.add(BidderResponseInfo.of(bidder, bidderSeatBidInfo, bidderResponse.getResponseTime())); } @@ -762,6 +766,7 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI final Map responseTimeMillis = toResponseTimes(bidderResponseInfos, cacheResult); + final List extIgi = toExtBidResponseIgi(bidderResponseInfos); final ExtBidResponseFledge extBidResponseFledge = toExtBidResponseFledge(bidderResponseInfos, auctionContext); final ExtBidResponsePrebid prebid = toExtBidResponsePrebid( auctionTimestamp, auctionContext.getBidRequest(), extBidResponseFledge); @@ -772,6 +777,7 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI .warnings(warnings) .responsetimemillis(responseTimeMillis) .tmaxrequest(auctionContext.getBidRequest().getTmax()) + .igi(extIgi) .prebid(prebid) .build(); } @@ -827,6 +833,25 @@ private static FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fl .build(); } + private static List toExtBidResponseIgi(List bidderResponseInfos) { + return bidderResponseInfos.stream() + .flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream() + .map(igi -> extIgiWithBidder(igi, responseInfo.getBidder()))) + .toList(); + } + + private static ExtIgi extIgiWithBidder(ExtIgi extIgi, String bidderName) { + final List extIgiIgs = CollectionUtils.emptyIfNull(extIgi.getIgs()).stream() + .map(igs -> Optional.ofNullable(igs) + .map(ExtIgiIgs::toBuilder) + .orElseGet(ExtIgiIgs::builder) + .ext(ExtIgiIgsExt.of(bidderName, bidderName)) + .build()) + .toList(); + + return extIgi.toBuilder().igs(extIgiIgs).build(); + } + private static ExtResponseDebug toExtResponseDebug(List bidderResponseInfos, AuctionContext auctionContext, CacheServiceResult cacheResult, diff --git a/src/main/java/org/prebid/server/bidder/consumable/ConsumableBidder.java b/src/main/java/org/prebid/server/bidder/consumable/ConsumableBidder.java index 344680b9aa4..5b70032a98d 100644 --- a/src/main/java/org/prebid/server/bidder/consumable/ConsumableBidder.java +++ b/src/main/java/org/prebid/server/bidder/consumable/ConsumableBidder.java @@ -121,9 +121,12 @@ public Result> makeBids(BidderCall httpCall, BidRequ public CompositeBidderResponse makeBidderResponse(BidderCall httpCall, BidRequest bidRequest) { try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - final List bidderErrors = new ArrayList<>(); - return CompositeBidderResponse.builder().bids(extractConsumableBids(bidRequest, bidResponse, bidderErrors)) - .errors(bidderErrors).build(); + final List errors = new ArrayList<>(); + + return CompositeBidderResponse.builder() + .bids(extractConsumableBids(bidRequest, bidResponse, errors)) + .errors(errors) + .build(); } catch (DecodeException e) { return CompositeBidderResponse.withError(BidderError.badServerResponse(e.getMessage())); } diff --git a/src/main/java/org/prebid/server/bidder/criteo/CriteoBidder.java b/src/main/java/org/prebid/server/bidder/criteo/CriteoBidder.java index 064bac48c48..9bf68e89e24 100644 --- a/src/main/java/org/prebid/server/bidder/criteo/CriteoBidder.java +++ b/src/main/java/org/prebid/server/bidder/criteo/CriteoBidder.java @@ -19,7 +19,7 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; @@ -31,7 +31,6 @@ public class CriteoBidder implements Bidder { - private static final String BIDDER_NAME = "criteo"; private final String endpointUrl; private final JacksonMapper mapper; @@ -55,9 +54,12 @@ public Result> makeBids(BidderCall httpCall, BidRequ public CompositeBidderResponse makeBidderResponse(BidderCall httpCall, BidRequest bidRequest) { try { final CriteoBidResponse bidResponse = mapper.decodeValue( - httpCall.getResponse().getBody(), - CriteoBidResponse.class); - return CompositeBidderResponse.withBids(extractBids(bidResponse), extractFledge(bidResponse)); + httpCall.getResponse().getBody(), CriteoBidResponse.class); + + return CompositeBidderResponse.builder() + .bids(extractBids(bidResponse)) + .igi(extractIgi(bidResponse)) + .build(); } catch (DecodeException | PreBidException e) { return CompositeBidderResponse.withError(BidderError.badServerResponse(e.getMessage())); } @@ -105,21 +107,11 @@ private ObjectNode makeExt(String networkName) { .build()); } - private static List extractFledge(CriteoBidResponse bidResponse) { - final List fledgeConfigs = Optional.ofNullable(bidResponse) + private static List extractIgi(CriteoBidResponse bidResponse) { + return Optional.ofNullable(bidResponse) .map(CriteoBidResponse::getExt) .map(CriteoExtBidResponse::getIgi) .filter(CollectionUtils::isNotEmpty) - .orElse(Collections.emptyList()) - .stream() - .filter(igi -> CollectionUtils.isNotEmpty(igi.getIgs()) && igi.getIgs().getFirst() != null) - .map(igi -> FledgeAuctionConfig.builder() - .impId(igi.getImpId()) - .bidder(BIDDER_NAME) - .config(igi.getIgs().getFirst().getConfig()) - .build()) - .toList(); - - return CollectionUtils.isEmpty(fledgeConfigs) ? null : fledgeConfigs; + .orElse(Collections.emptyList()); } } diff --git a/src/main/java/org/prebid/server/bidder/criteo/CriteoExtBidResponse.java b/src/main/java/org/prebid/server/bidder/criteo/CriteoExtBidResponse.java index 8f332b2f3bd..dda26a73ef7 100644 --- a/src/main/java/org/prebid/server/bidder/criteo/CriteoExtBidResponse.java +++ b/src/main/java/org/prebid/server/bidder/criteo/CriteoExtBidResponse.java @@ -1,11 +1,12 @@ package org.prebid.server.bidder.criteo; import lombok.Value; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; import java.util.List; @Value(staticConstructor = "of") public class CriteoExtBidResponse { - List igi; + List igi; } diff --git a/src/main/java/org/prebid/server/bidder/criteo/CriteoIgiExtBidResponse.java b/src/main/java/org/prebid/server/bidder/criteo/CriteoIgiExtBidResponse.java deleted file mode 100644 index 6bdac80ad2f..00000000000 --- a/src/main/java/org/prebid/server/bidder/criteo/CriteoIgiExtBidResponse.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.prebid.server.bidder.criteo; - -import lombok.Value; - -import java.util.List; - -@Value(staticConstructor = "of") -public class CriteoIgiExtBidResponse { - - String impId; - - List igs; -} diff --git a/src/main/java/org/prebid/server/bidder/criteo/CriteoIgsIgiExtBidResponse.java b/src/main/java/org/prebid/server/bidder/criteo/CriteoIgsIgiExtBidResponse.java deleted file mode 100644 index b34d76e0646..00000000000 --- a/src/main/java/org/prebid/server/bidder/criteo/CriteoIgsIgiExtBidResponse.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.prebid.server.bidder.criteo; - -import com.fasterxml.jackson.databind.node.ObjectNode; -import lombok.Value; - -@Value(staticConstructor = "of") -public class CriteoIgsIgiExtBidResponse { - - ObjectNode config; -} diff --git a/src/main/java/org/prebid/server/bidder/ix/IxBidder.java b/src/main/java/org/prebid/server/bidder/ix/IxBidder.java index 5fb26e698fd..de3b080d6a7 100644 --- a/src/main/java/org/prebid/server/bidder/ix/IxBidder.java +++ b/src/main/java/org/prebid/server/bidder/ix/IxBidder.java @@ -42,7 +42,8 @@ import org.prebid.server.proto.openrtb.ext.request.ix.ExtImpIx; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; @@ -233,11 +234,12 @@ public Result> makeBids(BidderCall httpCall, BidRequ public CompositeBidderResponse makeBidderResponse(BidderCall httpCall, BidRequest bidRequest) { try { final IxBidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), IxBidResponse.class); - final List bidderErrors = new ArrayList<>(); + final List errors = new ArrayList<>(); + return CompositeBidderResponse.builder() - .bids(extractBids(bidRequest, bidResponse, bidderErrors)) - .fledgeAuctionConfigs(extractFledge(bidResponse)) - .errors(bidderErrors) + .bids(extractBids(bidRequest, bidResponse, errors)) + .igi(extractIgi(bidResponse)) + .errors(errors) .build(); } catch (DecodeException e) { return CompositeBidderResponse.withError(BidderError.badServerResponse(e.getMessage())); @@ -406,17 +408,16 @@ private static ExtBidPrebidVideo videoInfo(ExtBidPrebidVideo extBidPrebidVideo) : null; } - private List extractFledge(IxBidResponse bidResponse) { - return Optional.ofNullable(bidResponse) + private List extractIgi(IxBidResponse bidResponse) { + final List igs = Optional.ofNullable(bidResponse) .map(IxBidResponse::getExt) .map(IxExtBidResponse::getProtectedAudienceAuctionConfigs) .orElse(Collections.emptyList()) .stream() .filter(Objects::nonNull) - .map(ixAuctionConfig -> FledgeAuctionConfig.builder() - .impId(ixAuctionConfig.getBidId()) - .config(ixAuctionConfig.getConfig()) - .build()) + .map(config -> ExtIgiIgs.builder().impId(config.getBidId()).config(config.getConfig()).build()) .toList(); + + return Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java b/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java index d184aefc297..8ad676c0eed 100644 --- a/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java +++ b/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java @@ -19,7 +19,8 @@ import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.response.BidType; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; @@ -64,12 +65,9 @@ public final CompositeBidderResponse makeBidderResponse(BidderCall h } final List errors = new ArrayList<>(); - final List bids = extractBids(httpCall.getRequest().getPayload(), bidResponse, errors); - final List fledgeAuctionConfigs = extractFledge(bidResponse); - return CompositeBidderResponse.builder() - .bids(bids) - .fledgeAuctionConfigs(fledgeAuctionConfigs) + .bids(extractBids(httpCall.getRequest().getPayload(), bidResponse, errors)) + .igi(extractIgi(bidResponse)) .errors(errors) .build(); } @@ -138,15 +136,17 @@ private static BidType resolveBidTypeFromImpId(String impId, List imps) { return BidType.banner; } - private static List extractFledge(MedianetBidResponse bidResponse) { - return Optional.ofNullable(bidResponse) + private static List extractIgi(MedianetBidResponse bidResponse) { + final List igs = Optional.ofNullable(bidResponse) .map(MedianetBidResponse::getExt) .map(MedianetBidResponseExt::getIgi) .orElse(Collections.emptyList()) .stream() .map(InterestGroupAuctionIntent::getIgs) .flatMap(Collection::stream) - .map(e -> FledgeAuctionConfig.builder().impId(e.getImpId()).config(e.getConfig()).build()) + .map(e -> ExtIgiIgs.builder().impId(e.getImpId()).config(e.getConfig()).build()) .toList(); + + return Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/bidder/model/BidderSeatBid.java b/src/main/java/org/prebid/server/bidder/model/BidderSeatBid.java index 6cdc55cccb9..8022b8667f1 100644 --- a/src/main/java/org/prebid/server/bidder/model/BidderSeatBid.java +++ b/src/main/java/org/prebid/server/bidder/model/BidderSeatBid.java @@ -4,6 +4,7 @@ import lombok.Value; import org.prebid.server.bidder.Bidder; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; import java.util.Collections; @@ -53,9 +54,13 @@ public class BidderSeatBid { @Builder.Default List warnings = Collections.emptyList(); + @Deprecated @Builder.Default List fledgeAuctionConfigs = Collections.emptyList(); + @Builder.Default + List igi = Collections.emptyList(); + public BidderSeatBid with(List bids) { return toBuilder().bids(bids).build(); } diff --git a/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java b/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java index 37ff7cccfc2..1cc6f182343 100644 --- a/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java +++ b/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java @@ -4,6 +4,7 @@ import lombok.Value; import org.prebid.server.auction.model.BidInfo; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; import java.util.List; @@ -20,9 +21,18 @@ public class BidderSeatBidInfo { List warnings; + @Deprecated List fledgeAuctionConfigs; + List igi; + public BidderSeatBidInfo with(List bids) { - return BidderSeatBidInfo.of(bids, this.httpCalls, this.errors, this.warnings, this.fledgeAuctionConfigs); + return BidderSeatBidInfo.of( + bids, + this.httpCalls, + this.errors, + this.warnings, + this.fledgeAuctionConfigs, + this.igi); } } diff --git a/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java b/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java index 8e80ea8b604..31db729e326 100644 --- a/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java +++ b/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java @@ -34,15 +34,6 @@ public static CompositeBidderResponse empty() { return builder().build(); } - public static CompositeBidderResponse withBids(List bids, - List fledgeAuctionConfigs) { - - return builder() - .bids(bids) - .fledgeAuctionConfigs(fledgeAuctionConfigs) - .build(); - } - public static CompositeBidderResponse withError(BidderError error) { return builder().errors(Collections.singletonList(error)).build(); } diff --git a/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java b/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java index 2ef79d3bfd4..dda14dd2c4e 100644 --- a/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java +++ b/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java @@ -30,7 +30,8 @@ import org.prebid.server.proto.openrtb.ext.request.openx.ExtImpOpenx; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; @@ -84,9 +85,13 @@ public Result>> makeHttpRequests(BidRequest bidRequ @Override public CompositeBidderResponse makeBidderResponse(BidderCall httpCall, BidRequest bidRequest) { try { - final OpenxBidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), - OpenxBidResponse.class); - return CompositeBidderResponse.withBids(extractBids(bidRequest, bidResponse), extractFledge(bidResponse)); + final OpenxBidResponse bidResponse = mapper.decodeValue( + httpCall.getResponse().getBody(), OpenxBidResponse.class); + + return CompositeBidderResponse.builder() + .bids(extractBids(bidRequest, bidResponse)) + .igi(extractIgi(bidResponse)) + .build(); } catch (DecodeException e) { return CompositeBidderResponse.withError(BidderError.badServerResponse(e.getMessage())); } @@ -283,14 +288,16 @@ private static BidType getBidType(Bid bid, Map impIdToBidType) return impIdToBidType.getOrDefault(bid.getImpid(), BidType.banner); } - private static List extractFledge(OpenxBidResponse bidResponse) { - return Optional.ofNullable(bidResponse) + private static List extractIgi(OpenxBidResponse bidResponse) { + final List igs = Optional.ofNullable(bidResponse) .map(OpenxBidResponse::getExt) .map(OpenxBidResponseExt::getFledgeAuctionConfigs) .orElse(Collections.emptyMap()) .entrySet() .stream() - .map(e -> FledgeAuctionConfig.builder().impId(e.getKey()).config(e.getValue()).build()) + .map(e -> ExtIgiIgs.builder().impId(e.getKey()).config(e.getValue()).build()) .toList(); + + return Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index a60a6ab2efa..723ccceea3c 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -39,7 +39,8 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.StreamUtil; @@ -458,11 +459,14 @@ public Result> makeBids(BidderCall httpCall, BidRequ @Override public CompositeBidderResponse makeBidderResponse(BidderCall httpCall, BidRequest bidRequest) { try { - final List bidderErrors = new ArrayList<>(); final PubmaticBidResponse bidResponse = mapper.decodeValue( - httpCall.getResponse().getBody(), - PubmaticBidResponse.class); - return CompositeBidderResponse.withBids(extractBids(bidResponse, bidderErrors), extractFledge(bidResponse)); + httpCall.getResponse().getBody(), PubmaticBidResponse.class); + final List errors = new ArrayList<>(); + + return CompositeBidderResponse.builder() + .bids(extractBids(bidResponse, errors)) + .igi(extractIgi(bidResponse)) + .build(); } catch (DecodeException | PreBidException e) { return CompositeBidderResponse.withError(BidderError.badServerResponse(e.getMessage())); } @@ -571,14 +575,16 @@ private static Integer getDealPriority(PubmaticBidExt bidExt) { .orElse(null); } - private static List extractFledge(PubmaticBidResponse bidResponse) { - return Optional.ofNullable(bidResponse) + private static List extractIgi(PubmaticBidResponse bidResponse) { + final List igs = Optional.ofNullable(bidResponse) .map(PubmaticBidResponse::getExt) .map(PubmaticExtBidResponse::getFledgeAuctionConfigs) .orElse(Collections.emptyMap()) .entrySet() .stream() - .map(e -> FledgeAuctionConfig.builder().impId(e.getKey()).config(e.getValue()).build()) + .map(e -> ExtIgiIgs.builder().impId(e.getKey()).config(e.getValue()).build()) .toList(); + + return Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java index fc63c1288bc..6df4b2db44d 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java @@ -9,7 +9,7 @@ * Defines the contract for bidresponse.ext.igi */ @Value -@Builder +@Builder(toBuilder = true) public class ExtIgi { String impid; diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java index 3330f1fa37c..ac05c677cf7 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java @@ -1,14 +1,16 @@ package org.prebid.server.proto.openrtb.ext.response; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Builder; import lombok.Value; @Value -@Builder +@Builder(toBuilder = true) public class ExtIgiIgs { - String impid; + @JsonProperty("impid") + String impId; ObjectNode config; From ebfa6df2f37a946b4c54302773cb56dfd7f6bedc Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 20 Dec 2024 14:46:48 +0200 Subject: [PATCH 03/24] Refactoring. --- src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java b/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java index dda14dd2c4e..2f84fefe8c7 100644 --- a/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java +++ b/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java @@ -295,7 +295,7 @@ private static List extractIgi(OpenxBidResponse bidResponse) { .orElse(Collections.emptyMap()) .entrySet() .stream() - .map(e -> ExtIgiIgs.builder().impId(e.getKey()).config(e.getValue()).build()) + .map(ext -> ExtIgiIgs.builder().impId(ext.getKey()).config(ext.getValue()).build()) .toList(); return Collections.singletonList(ExtIgi.builder().igs(igs).build()); From e4a45ef02dd8917aacf773f5d40f32f35741b3a3 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Thu, 26 Dec 2024 22:28:10 +0200 Subject: [PATCH 04/24] Refactoring. --- .../server/auction/BidResponseCreator.java | 77 ++++++++++++++++--- .../server/auction/model/PaaFormat.java | 12 +++ .../bidder/model/BidderSeatBidInfo.java | 6 +- .../openrtb/ext/request/ExtRequestPrebid.java | 6 ++ .../settings/model/AccountAuctionConfig.java | 4 + 5 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/prebid/server/auction/model/PaaFormat.java diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index a41c0d9d38b..355ccfc129b 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -34,6 +34,7 @@ import org.prebid.server.auction.model.CachedDebugLog; import org.prebid.server.auction.model.CategoryMappingResult; import org.prebid.server.auction.model.MultiBidConfig; +import org.prebid.server.auction.model.PaaFormat; import org.prebid.server.auction.model.TargetingInfo; import org.prebid.server.auction.model.debug.DebugContext; import org.prebid.server.auction.requestfactory.Ortb2ImplicitParametersResolver; @@ -766,10 +767,12 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI final Map responseTimeMillis = toResponseTimes(bidderResponseInfos, cacheResult); - final List extIgi = toExtBidResponseIgi(bidderResponseInfos); - final ExtBidResponseFledge extBidResponseFledge = toExtBidResponseFledge(bidderResponseInfos, auctionContext); + final PaaResult paaResult = toPaaOutput(bidderResponseInfos, auctionContext); + final List igi = paaResult.igis(); + final ExtBidResponseFledge fledge = paaResult.fledge(); + final ExtBidResponsePrebid prebid = toExtBidResponsePrebid( - auctionTimestamp, auctionContext.getBidRequest(), extBidResponseFledge); + auctionTimestamp, auctionContext.getBidRequest(), fledge); return ExtBidResponse.builder() .debug(extResponseDebug) @@ -777,11 +780,12 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI .warnings(warnings) .responsetimemillis(responseTimeMillis) .tmaxrequest(auctionContext.getBidRequest().getTmax()) - .igi(extIgi) + .igi(igi) .prebid(prebid) .build(); } + private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp, BidRequest bidRequest, ExtBidResponseFledge extBidResponseFledge) { @@ -799,17 +803,52 @@ private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp, .build(); } - private ExtBidResponseFledge toExtBidResponseFledge(List bidderResponseInfos, - AuctionContext auctionContext) { + private PaaResult toPaaOutput(List bidderResponseInfos, AuctionContext auctionContext) { + final PaaFormat paaFormat = resolvePaaFormat(auctionContext); + final List extIgi = paaFormat == PaaFormat.IAB ? toExtBidResponseIgi(bidderResponseInfos) : null; final List imps = auctionContext.getBidRequest().getImp(); - final List fledgeConfigs = bidderResponseInfos.stream() - .flatMap(bidderResponseInfo -> fledgeConfigsForBidder(bidderResponseInfo, imps)) + + // TODO: Remove after transition period + final Stream deprecatedFledgeConfigs = bidderResponseInfos.stream() + .flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps)); + + final Stream fledgeConfigs = paaFormat == PaaFormat.ORIGINAL + ? bidderResponseInfos.stream().flatMap(BidResponseCreator::toOriginalFledgeFormat) + : Stream.empty(); + + final List combinedFledgeConfigs = Stream.concat(deprecatedFledgeConfigs, fledgeConfigs) .toList(); - return !fledgeConfigs.isEmpty() ? ExtBidResponseFledge.of(fledgeConfigs) : null; + + final ExtBidResponseFledge extBidResponseFledge = combinedFledgeConfigs.isEmpty() + ? null + : ExtBidResponseFledge.of(combinedFledgeConfigs); + + return new PaaResult(extIgi, extBidResponseFledge); + } + + private static Stream toOriginalFledgeFormat(BidderResponseInfo bidderResponseInfo) { + return Optional.ofNullable(bidderResponseInfo.getSeatBid().getIgi()).stream() + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .map(ExtIgi::getIgs) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .map(extIgiIgs -> extIgiIgsToFledgeConfig(extIgiIgs, bidderResponseInfo.getBidder())); } - private Stream fledgeConfigsForBidder(BidderResponseInfo bidderResponseInfo, List imps) { + private static FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs, String bidder) { + return FledgeAuctionConfig.builder() + .bidder(bidder) + .adapter(bidder) + .impId(extIgiIgs.getImpId()) + .config(extIgiIgs.getConfig()) + .build(); + } + + private Stream toDeprecatedFledgeConfigs(BidderResponseInfo bidderResponseInfo, + List imps) { + return Optional.ofNullable(bidderResponseInfo.getSeatBid().getFledgeAuctionConfigs()) .stream() .flatMap(Collection::stream) @@ -849,7 +888,9 @@ private static ExtIgi extIgiWithBidder(ExtIgi extIgi, String bidderName) { .build()) .toList(); - return extIgi.toBuilder().igs(extIgiIgs).build(); + return extIgiIgs.isEmpty() + ? extIgi + : extIgi.toBuilder().igs(extIgiIgs).build(); } private static ExtResponseDebug toExtResponseDebug(List bidderResponseInfos, @@ -1163,6 +1204,17 @@ private static Map toResponseTimes(Collection Optional.ofNullable(auctionContext.getAccount()) + .map(Account::getAuction) + .map(AccountAuctionConfig::getPaaFormat)) + .orElse(PaaFormat.IAB); // TODO: Decide what default value to use + } + /** * Returns {@link BidResponse} based on list of {@link BidderResponse}s and {@link CacheServiceResult}. */ @@ -1809,4 +1861,7 @@ private T convertValue(JsonNode jsonNode, String key, Class typeClass) { return null; } } + + private record PaaResult(List igis, ExtBidResponseFledge fledge) { + } } diff --git a/src/main/java/org/prebid/server/auction/model/PaaFormat.java b/src/main/java/org/prebid/server/auction/model/PaaFormat.java new file mode 100644 index 00000000000..8367b61c0f2 --- /dev/null +++ b/src/main/java/org/prebid/server/auction/model/PaaFormat.java @@ -0,0 +1,12 @@ +package org.prebid.server.auction.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum PaaFormat { + + @JsonProperty("original") + ORIGINAL, + + @JsonProperty("iab") + IAB +} diff --git a/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java b/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java index 1cc6f182343..38c9f86433c 100644 --- a/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java +++ b/src/main/java/org/prebid/server/bidder/model/BidderSeatBidInfo.java @@ -1,6 +1,5 @@ package org.prebid.server.bidder.model; -import lombok.AllArgsConstructor; import lombok.Value; import org.prebid.server.auction.model.BidInfo; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; @@ -9,8 +8,7 @@ import java.util.List; -@AllArgsConstructor(staticName = "of") -@Value +@Value(staticConstructor = "of") public class BidderSeatBidInfo { List bidsInfos; @@ -21,7 +19,7 @@ public class BidderSeatBidInfo { List warnings; - @Deprecated + @Deprecated(forRemoval = true) List fledgeAuctionConfigs; List igi; diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java index cb325bd088a..33b326b2638 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Builder; import lombok.Value; +import org.prebid.server.auction.model.PaaFormat; import org.prebid.server.floors.model.PriceFloorRules; import org.prebid.server.json.deserializer.IntegerFlagDeserializer; @@ -184,4 +185,9 @@ public class ExtRequestPrebid { */ ExtRequestPrebidSdk sdk; + /** + * Defines the contract for bidrequest.ext.prebid.paaformat + */ + @JsonProperty("paaformat") + PaaFormat paaFormat; } diff --git a/src/main/java/org/prebid/server/settings/model/AccountAuctionConfig.java b/src/main/java/org/prebid/server/settings/model/AccountAuctionConfig.java index 9943535aa7e..ac7da04dd31 100644 --- a/src/main/java/org/prebid/server/settings/model/AccountAuctionConfig.java +++ b/src/main/java/org/prebid/server/settings/model/AccountAuctionConfig.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Builder; import lombok.Value; +import org.prebid.server.auction.model.PaaFormat; import org.prebid.server.spring.config.bidder.model.MediaType; import java.util.Map; @@ -49,4 +50,7 @@ public class AccountAuctionConfig { @JsonProperty("privacysandbox") AccountPrivacySandboxConfig privacySandbox; + + @JsonProperty("paaformat") + PaaFormat paaFormat; } From 824d279af6d77b93fd8f55d1280f7f07ab48d2db Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Thu, 26 Dec 2024 23:38:44 +0200 Subject: [PATCH 05/24] Refactoring. --- .../prebid/server/bidder/HttpBidderRequester.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/bidder/HttpBidderRequester.java b/src/main/java/org/prebid/server/bidder/HttpBidderRequester.java index 787ee1f96d2..8b6a25ea231 100644 --- a/src/main/java/org/prebid/server/bidder/HttpBidderRequester.java +++ b/src/main/java/org/prebid/server/bidder/HttpBidderRequester.java @@ -31,6 +31,7 @@ import org.prebid.server.log.LoggerFactory; import org.prebid.server.model.CaseInsensitiveMultiMap; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.HttpClient; @@ -248,7 +249,7 @@ private static byte[] gzip(byte[] value) { */ private Future> failResponse(Throwable exception, HttpRequest httpRequest) { conditionalLogger.warn("Error occurred while sending HTTP request to a bidder url: %s with message: %s" - .formatted(httpRequest.getUri(), exception.getMessage()), logSamplingRate); + .formatted(httpRequest.getUri(), exception.getMessage()), logSamplingRate); logger.debug("Error occurred while sending HTTP request to a bidder url: {}", exception, httpRequest.getUri()); @@ -346,6 +347,7 @@ private static class ResultBuilder { private final Map, BidderCall> bidderCallsRecorded = new HashMap<>(); private final List bidsRecorded = new ArrayList<>(); private final List errorsRecorded = new ArrayList<>(); + private final List igiRecorded = new ArrayList<>(); private final List fledgeRecorded = new ArrayList<>(); ResultBuilder(List> httpRequests, @@ -366,6 +368,7 @@ void addHttpCall(BidderCall bidderCall, CompositeBidderResponse bidderRespons handleBids(bidderResponse); handleBidderErrors(bidderResponse); handleBidderCallError(bidderCall); + handleIgis(bidderResponse); handleFledgeAuctionConfigs(bidderResponse); } @@ -429,6 +432,12 @@ private void handleFledgeAuctionConfigs(CompositeBidderResponse bidderResponse) .ifPresent(fledgeRecorded::addAll); } + private void handleIgis(CompositeBidderResponse bidderResponse) { + Optional.ofNullable(bidderResponse) + .map(CompositeBidderResponse::getIgi) + .ifPresent(igiRecorded::addAll); + } + BidderSeatBid toBidderSeatBid(boolean debugEnabled) { final List> httpCalls = new ArrayList<>(bidderCallsRecorded.values()); httpRequests.stream() @@ -446,6 +455,7 @@ BidderSeatBid toBidderSeatBid(boolean debugEnabled) { .bids(bidsRecorded) .httpCalls(extHttpCalls) .errors(errors) + .igi(igiRecorded) .fledgeAuctionConfigs(fledgeRecorded) .build(); } From 4b60b5159bfc9c3224ff278fc26a92287c0d86f4 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Tue, 7 Jan 2025 15:50:48 +0200 Subject: [PATCH 06/24] Partly fixed unit tests. --- .../server/auction/BidResponseCreator.java | 25 ++++++------ .../bidder/medianet/MedianetBidder.java | 2 +- .../bidder/model/CompositeBidderResponse.java | 1 - .../bidder/pubmatic/PubmaticBidder.java | 2 +- .../proto/openrtb/ext/response/ExtIgi.java | 2 +- .../proto/openrtb/ext/response/ExtIgiIgs.java | 2 +- .../bidder/HttpBidderRequesterTest.java | 22 +++++----- .../bidder/criteo/CriteoBidderTest.java | 40 ++++++++----------- .../server/bidder/openx/OpenxBidderTest.java | 29 +++++++++----- .../bidder/pubmatic/PubmaticBidderTest.java | 15 +++---- 10 files changed, 71 insertions(+), 69 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 355ccfc129b..473c09fee39 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -785,7 +785,6 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI .build(); } - private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp, BidRequest bidRequest, ExtBidResponseFledge extBidResponseFledge) { @@ -814,7 +813,7 @@ private PaaResult toPaaOutput(List bidderResponseInfos, Auct .flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps)); final Stream fledgeConfigs = paaFormat == PaaFormat.ORIGINAL - ? bidderResponseInfos.stream().flatMap(BidResponseCreator::toOriginalFledgeFormat) + ? bidderResponseInfos.stream().flatMap(this::toOriginalFledgeFormat) : Stream.empty(); final List combinedFledgeConfigs = Stream.concat(deprecatedFledgeConfigs, fledgeConfigs) @@ -827,7 +826,7 @@ private PaaResult toPaaOutput(List bidderResponseInfos, Auct return new PaaResult(extIgi, extBidResponseFledge); } - private static Stream toOriginalFledgeFormat(BidderResponseInfo bidderResponseInfo) { + private Stream toOriginalFledgeFormat(BidderResponseInfo bidderResponseInfo) { return Optional.ofNullable(bidderResponseInfo.getSeatBid().getIgi()).stream() .flatMap(Collection::stream) .filter(Objects::nonNull) @@ -837,10 +836,10 @@ private static Stream toOriginalFledgeFormat(BidderResponse .map(extIgiIgs -> extIgiIgsToFledgeConfig(extIgiIgs, bidderResponseInfo.getBidder())); } - private static FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs, String bidder) { + private FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs, String bidder) { return FledgeAuctionConfig.builder() .bidder(bidder) - .adapter(bidder) + .adapter(bidderCatalog.resolveBaseBidder(bidder)) .impId(extIgiIgs.getImpId()) .config(extIgiIgs.getConfig()) .build(); @@ -865,26 +864,28 @@ private boolean validateFledgeConfig(FledgeAuctionConfig fledgeAuctionConfig, Li return fledgeEnabled == ExtImpAuctionEnvironment.ON_DEVICE_IG_AUCTION_FLEDGE; } - private static FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidderName) { + private FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidder) { return fledgeConfig.toBuilder() - .bidder(bidderName) - .adapter(bidderName) + .bidder(bidder) + .adapter(bidderCatalog.resolveBaseBidder(bidder)) .build(); } - private static List toExtBidResponseIgi(List bidderResponseInfos) { - return bidderResponseInfos.stream() + private List toExtBidResponseIgi(List bidderResponseInfos) { + final List extIgi = bidderResponseInfos.stream() .flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream() .map(igi -> extIgiWithBidder(igi, responseInfo.getBidder()))) .toList(); + + return extIgi.isEmpty() ? null : extIgi; } - private static ExtIgi extIgiWithBidder(ExtIgi extIgi, String bidderName) { + private ExtIgi extIgiWithBidder(ExtIgi extIgi, String bidder) { final List extIgiIgs = CollectionUtils.emptyIfNull(extIgi.getIgs()).stream() .map(igs -> Optional.ofNullable(igs) .map(ExtIgiIgs::toBuilder) .orElseGet(ExtIgiIgs::builder) - .ext(ExtIgiIgsExt.of(bidderName, bidderName)) + .ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder))) .build()) .toList(); diff --git a/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java b/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java index 8ad676c0eed..2829754dddf 100644 --- a/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java +++ b/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java @@ -144,7 +144,7 @@ private static List extractIgi(MedianetBidResponse bidResponse) { .stream() .map(InterestGroupAuctionIntent::getIgs) .flatMap(Collection::stream) - .map(e -> ExtIgiIgs.builder().impId(e.getImpId()).config(e.getConfig()).build()) + .map(igiIgs -> ExtIgiIgs.builder().impId(igiIgs.getImpId()).config(igiIgs.getConfig()).build()) .toList(); return Collections.singletonList(ExtIgi.builder().igs(igs).build()); diff --git a/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java b/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java index 31db729e326..75a71e0864a 100644 --- a/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java +++ b/src/main/java/org/prebid/server/bidder/model/CompositeBidderResponse.java @@ -27,7 +27,6 @@ public class CompositeBidderResponse { */ List fledgeAuctionConfigs; - List igi; public static CompositeBidderResponse empty() { diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index 723ccceea3c..1382e99ac39 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -582,7 +582,7 @@ private static List extractIgi(PubmaticBidResponse bidResponse) { .orElse(Collections.emptyMap()) .entrySet() .stream() - .map(e -> ExtIgiIgs.builder().impId(e.getKey()).config(e.getValue()).build()) + .map(config -> ExtIgiIgs.builder().impId(config.getKey()).config(config.getValue()).build()) .toList(); return Collections.singletonList(ExtIgi.builder().igs(igs).build()); diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java index 6df4b2db44d..49e84d9739f 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgi.java @@ -8,8 +8,8 @@ /** * Defines the contract for bidresponse.ext.igi */ -@Value @Builder(toBuilder = true) +@Value(staticConstructor = "of") public class ExtIgi { String impid; diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java index ac05c677cf7..a243380bb4e 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtIgiIgs.java @@ -5,8 +5,8 @@ import lombok.Builder; import lombok.Value; -@Value @Builder(toBuilder = true) +@Value(staticConstructor = "of") public class ExtIgiIgs { @JsonProperty("impid") diff --git a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java index 81180793e22..179f2a1ceeb 100644 --- a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java +++ b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java @@ -196,7 +196,7 @@ public void shouldPassStoredResponseToBidderMakeBidsMethodAndReturnSeatBids() { emptyList())); final List bids = asList(BidderBid.of(null, null, null), BidderBid.of(null, null, null)); - given(bidder.makeBidderResponse(any(), any())).willReturn(CompositeBidderResponse.withBids(bids, emptyList())); + given(bidder.makeBidderResponse(any(), any())).willReturn(CompositeBidderResponse.builder().bids(bids).build()); final BidderRequest bidderRequest = BidderRequest.builder() .bidder("bidder") @@ -346,7 +346,7 @@ public void shouldReturnBidsCreatedByBidder() { givenSuccessfulBidderMakeHttpRequests(); final List bids = asList(BidderBid.of(null, null, null), BidderBid.of(null, null, null)); - given(bidder.makeBidderResponse(any(), any())).willReturn(CompositeBidderResponse.withBids(bids, emptyList())); + given(bidder.makeBidderResponse(any(), any())).willReturn(CompositeBidderResponse.builder().bids(bids).build()); final BidderRequest bidderRequest = BidderRequest.builder() .bidder("bidder") @@ -379,8 +379,7 @@ public void shouldReturnBidsCreatedByMakeBids() { givenSuccessfulBidderMakeHttpRequests(); final List bids = emptyList(); - given(bidder.makeBidderResponse(any(), any())) - .willReturn(CompositeBidderResponse.withBids(bids, null)); + given(bidder.makeBidderResponse(any(), any())).willReturn(CompositeBidderResponse.builder().bids(bids).build()); final BidderRequest bidderRequest = BidderRequest.builder() .bidder("bidder") @@ -417,8 +416,11 @@ public void shouldReturnFledgeCreatedByBidder() { givenFledgeAuctionConfig("imp-2")); final List bids = emptyList(); - given(bidder.makeBidderResponse(any(), any())) - .willReturn(CompositeBidderResponse.withBids(bids, fledgeAuctionConfigs)); + given(bidder.makeBidderResponse(any(), any())).willReturn( + CompositeBidderResponse.builder() + .bids(bids) + .fledgeAuctionConfigs(fledgeAuctionConfigs) + .build()); final BidderRequest bidderRequest = BidderRequest.builder() .bidder("bidder") @@ -555,8 +557,8 @@ public void processBids(List bids) { final BidderBid bidderBidDeal1 = BidderBid.of(Bid.builder().impid("deal1").dealid("deal1").build(), null, null); final BidderBid bidderBidDeal2 = BidderBid.of(Bid.builder().impid("deal2").dealid("deal2").build(), null, null); given(bidder.makeBidderResponse(any(), any())).willReturn( - CompositeBidderResponse.withBids(singletonList(bidderBidDeal1), emptyList()), - CompositeBidderResponse.withBids(singletonList(bidderBidDeal2), emptyList())); + CompositeBidderResponse.builder().bids(singletonList(bidderBidDeal1)).build(), + CompositeBidderResponse.builder().bids(singletonList(bidderBidDeal2)).build()); // when final BidderSeatBid bidderSeatBid = target.requestBids( @@ -604,7 +606,7 @@ public void shouldFinishWhenAllDealRequestsAreFinishedAndNoDealsProvided() { final BidderBid bidderBid = BidderBid.of(Bid.builder().dealid("deal2").build(), null, null); given(bidder.makeBidderResponse(any(), any())).willReturn( - CompositeBidderResponse.withBids(singletonList(bidderBid), emptyList())); + CompositeBidderResponse.builder().bids(singletonList(bidderBid)).build()); // when final BidderSeatBid bidderSeatBid = @@ -737,7 +739,7 @@ public void shouldReturnRecordBidRejections() throws JsonProcessingException { .bid(Bid.builder().impid("2").build()) .build()); given(bidder.makeBidderResponse(any(), any())) - .willReturn(CompositeBidderResponse.withBids(secondRequestBids, null)); + .willReturn(CompositeBidderResponse.builder().bids(secondRequestBids).build()); final BidderRequest bidderRequest = BidderRequest.builder() .bidder("bidder") diff --git a/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java b/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java index 09f2f113fb1..291dd35d415 100644 --- a/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java @@ -20,7 +20,8 @@ import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; import org.prebid.server.proto.openrtb.ext.response.BidType; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import java.util.List; import java.util.Set; @@ -199,7 +200,7 @@ public void makeBidderResponseShouldReturnBidWithNetworkNameFromExtPrebid() thro // given final BidderCall httpCall = givenHttpCall( givenBidResponse(bid -> bid - .impid("123") + .impid("123") .ext(givenBidExtWithNetwork("anyNetworkName")))); // when @@ -236,18 +237,16 @@ public void makeBidderResponseShouldReturnEmptyNetworkNameWhenBidExtPrebidNotCon @Test public void makeBidderResponseShouldReturnFledgeConfigs() throws JsonProcessingException { // given + final List igs = List.of( + ExtIgiIgs.builder().config(mapper.createObjectNode().put("proterty1", "value1")).build(), + ExtIgiIgs.builder().config(mapper.createObjectNode().put("proterty2", "value2")).build()); + final CriteoBidResponse bidResponseWithFledge = CriteoBidResponse.builder() .ext(CriteoExtBidResponse.of(List.of( - CriteoIgiExtBidResponse.of("imp_id1", List.of( - CriteoIgsIgiExtBidResponse.of( - mapper.createObjectNode().put("proterty1", "value1")), - CriteoIgsIgiExtBidResponse.of( - mapper.createObjectNode().put("proterty2", "value2")))), - CriteoIgiExtBidResponse.of("imp_id2", List.of( - CriteoIgsIgiExtBidResponse.of( - mapper.createObjectNode().put("proterty3", "value3")), - CriteoIgsIgiExtBidResponse.of( - mapper.createObjectNode().put("proterty4", "value4"))))))) + ExtIgi.builder() + .impid("imp_id1") + .igs(igs) + .build()))) .build(); final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponseWithFledge)); @@ -255,19 +254,12 @@ public void makeBidderResponseShouldReturnFledgeConfigs() throws JsonProcessingE final CompositeBidderResponse result = target.makeBidderResponse(httpCall, null); // then + final List expectedIgs = List.of( + ExtIgiIgs.builder().config(mapper.createObjectNode().put("proterty1", "value1")).build(), + ExtIgiIgs.builder().config(mapper.createObjectNode().put("proterty2", "value2")).build()); + assertThat(result.getErrors()).isEmpty(); - assertThat(result.getFledgeAuctionConfigs()) - .containsExactlyInAnyOrder( - FledgeAuctionConfig.builder() - .bidder("criteo") - .impId("imp_id1") - .config(mapper.createObjectNode().put("proterty1", "value1")) - .build(), - FledgeAuctionConfig.builder() - .bidder("criteo") - .impId("imp_id2") - .config(mapper.createObjectNode().put("proterty3", "value3")) - .build()); + assertThat(result.getIgi()).containsExactly(ExtIgi.builder().impid("imp_id1").igs(expectedIgs).build()); } @Test diff --git a/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java b/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java index 1f218984f91..092d6edbe1a 100644 --- a/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java @@ -35,7 +35,8 @@ import org.prebid.server.proto.openrtb.ext.request.openx.ExtImpOpenx; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import java.math.BigDecimal; import java.util.Collections; @@ -504,6 +505,13 @@ public void makeBidsShouldReturnResultWithExpectedFields() throws JsonProcessing final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then + final ExtIgi igi = ExtIgi.builder() + .igs(singletonList(ExtIgiIgs.builder() + .impId("impId1") + .config(mapper.createObjectNode().put("somevalue", 1)) + .build())) + .build(); + assertThat(result.getErrors()).isEmpty(); assertThat(result.getBids()).hasSize(1) .containsOnly(BidderBid.of( @@ -516,11 +524,7 @@ public void makeBidsShouldReturnResultWithExpectedFields() throws JsonProcessing .adm("
This is an Ad
") .build(), BidType.banner, "UAH")); - assertThat(result.getFledgeAuctionConfigs()) - .containsOnly(FledgeAuctionConfig.builder() - .impId("impId1") - .config(mapper.createObjectNode().put("somevalue", 1)) - .build()); + assertThat(result.getIgi()).containsExactly(igi); } @Test @@ -579,13 +583,16 @@ public void makeBidsShouldReturnFledgeConfigEvenIfNoBids() throws JsonProcessing final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getBids()).isEmpty(); - assertThat(result.getFledgeAuctionConfigs()) - .containsOnly(FledgeAuctionConfig.builder() + final ExtIgi igi = ExtIgi.builder() + .igs(singletonList(ExtIgiIgs.builder() .impId("impId1") .config(mapper.createObjectNode().put("somevalue", 1)) - .build()); + .build())) + .build(); + + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getBids()).isEmpty(); + assertThat(result.getIgi()).containsExactly(igi); } @Test diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java index 2f0b5ccd49a..a1de06c9d1e 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -40,7 +40,8 @@ import org.prebid.server.proto.openrtb.ext.request.pubmatic.ExtImpPubmaticKeyVal; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.util.HttpUtil; import java.math.BigDecimal; @@ -1225,11 +1226,11 @@ public void makeBidderResponseShouldReturnBannerBidIfExtBidContainsIllegalBidTyp public void makeBidderResponseShouldReturnFledgeAuctionConfig() throws JsonProcessingException { // given final BidResponse bidResponse = givenBidResponse(bidBuilder -> bidBuilder.impid("imp_id")); - final ObjectNode fledgeAuctionConfig = mapper.createObjectNode(); + final ObjectNode auctionConfig = mapper.createObjectNode(); final PubmaticBidResponse bidResponseWithFledge = PubmaticBidResponse.builder() .cur(bidResponse.getCur()) .seatbid(bidResponse.getSeatbid()) - .ext(PubmaticExtBidResponse.of(Map.of("imp_id", fledgeAuctionConfig))) + .ext(PubmaticExtBidResponse.of(Map.of("imp_id", auctionConfig))) .build(); final BidderCall httpCall = givenHttpCall(mapper.writeValueAsString(bidResponseWithFledge)); @@ -1241,11 +1242,11 @@ public void makeBidderResponseShouldReturnFledgeAuctionConfig() throws JsonProce assertThat(result.getBids()) .containsExactly(BidderBid.of(Bid.builder().impid("imp_id").build(), banner, "USD")); - final FledgeAuctionConfig expectedFledge = FledgeAuctionConfig.builder() - .impId("imp_id") - .config(fledgeAuctionConfig) + final ExtIgi igi = ExtIgi.builder() + .igs(singletonList(ExtIgiIgs.builder().impId("imp_id").config(auctionConfig).build())) .build(); - assertThat(result.getFledgeAuctionConfigs()).containsExactly(expectedFledge); + + assertThat(result.getIgi()).containsExactly(igi); } @Test From 5bf42c60e4703f3fae0a076a545996feb5ee590f Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Tue, 7 Jan 2025 16:21:06 +0200 Subject: [PATCH 07/24] Fixed unit tests. --- .../org/prebid/server/bidder/ix/IxBidder.java | 2 +- .../bidder/medianet/MedianetBidder.java | 2 +- .../server/bidder/openx/OpenxBidder.java | 2 +- .../bidder/pubmatic/PubmaticBidder.java | 2 +- .../auction/BidResponseCreatorTest.java | 6 ++- .../prebid/server/bidder/ix/IxBidderTest.java | 18 ++++---- .../bidder/medianet/MedianetBidderTest.java | 25 ++++++----- .../openrtb2/ix/test-auction-ix-response.json | 42 +------------------ .../it/openrtb2/ix/test-ix-bid-response.json | 40 +----------------- 9 files changed, 34 insertions(+), 105 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/ix/IxBidder.java b/src/main/java/org/prebid/server/bidder/ix/IxBidder.java index de3b080d6a7..be29b4d1d4a 100644 --- a/src/main/java/org/prebid/server/bidder/ix/IxBidder.java +++ b/src/main/java/org/prebid/server/bidder/ix/IxBidder.java @@ -418,6 +418,6 @@ private List extractIgi(IxBidResponse bidResponse) { .map(config -> ExtIgiIgs.builder().impId(config.getBidId()).config(config.getConfig()).build()) .toList(); - return Collections.singletonList(ExtIgi.builder().igs(igs).build()); + return igs.isEmpty() ? null : Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java b/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java index 2829754dddf..a82d6a72e63 100644 --- a/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java +++ b/src/main/java/org/prebid/server/bidder/medianet/MedianetBidder.java @@ -147,6 +147,6 @@ private static List extractIgi(MedianetBidResponse bidResponse) { .map(igiIgs -> ExtIgiIgs.builder().impId(igiIgs.getImpId()).config(igiIgs.getConfig()).build()) .toList(); - return Collections.singletonList(ExtIgi.builder().igs(igs).build()); + return igs.isEmpty() ? null : Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java b/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java index 2f84fefe8c7..99f35592ea1 100644 --- a/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java +++ b/src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java @@ -298,6 +298,6 @@ private static List extractIgi(OpenxBidResponse bidResponse) { .map(ext -> ExtIgiIgs.builder().impId(ext.getKey()).config(ext.getValue()).build()) .toList(); - return Collections.singletonList(ExtIgi.builder().igs(igs).build()); + return igs.isEmpty() ? null : Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index 1382e99ac39..e1e6650e357 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -585,6 +585,6 @@ private static List extractIgi(PubmaticBidResponse bidResponse) { .map(config -> ExtIgiIgs.builder().impId(config.getKey()).config(config.getValue()).build()) .toList(); - return Collections.singletonList(ExtIgi.builder().igs(igs).build()); + return igs.isEmpty() ? null : Collections.singletonList(ExtIgi.builder().igs(igs).build()); } } diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 0e3d0220ba1..f9bade83d18 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -3468,6 +3468,7 @@ public void shouldCopyImpExtPrebidPassThroughToResponseBidExtPrebidPassThroughWh @Test public void shouldAddExtPrebidFledgeIfAvailable() { // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); final Imp imp = givenImp("i1").toBuilder() .ext(mapper.createObjectNode().put("ae", 1)) .build(); @@ -3497,13 +3498,14 @@ public void shouldAddExtPrebidFledgeIfAvailable() { .usingRecursiveComparison() .isEqualTo(fledgeAuctionConfig.toBuilder() .bidder("bidder1") - .adapter("bidder1") + .adapter("adapter1") .build()); } @Test public void shouldAddExtPrebidFledgeIfAvailableEvenIfBidsEmpty() { // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); final Imp imp = givenImp("i1").toBuilder() .ext(mapper.createObjectNode().put("ae", 1)) .build(); @@ -3532,7 +3534,7 @@ public void shouldAddExtPrebidFledgeIfAvailableEvenIfBidsEmpty() { .usingRecursiveComparison() .isEqualTo(fledgeAuctionConfig.toBuilder() .bidder("bidder1") - .adapter("bidder1") + .adapter("adapter1") .build()); } diff --git a/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java b/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java index 35726f5a205..e91a0300df1 100644 --- a/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java @@ -46,7 +46,8 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.version.PrebidVersionProvider; import java.util.List; @@ -771,14 +772,14 @@ public void makeBidderResponseShouldReturnFledgeAuctionConfig() throws JsonProce // given final String impId = "imp_id"; final BidResponse bidResponse = givenBidResponse(bidBuilder -> bidBuilder.impid(impId).mtype(1)); - final ObjectNode fledgeAuctionConfig = mapper.createObjectNode(); + final ObjectNode auctionConfig = mapper.createObjectNode(); final BidRequest bidRequest = BidRequest.builder() .imp(List.of(Imp.builder().id(impId).build())) .build(); final IxBidResponse bidResponseWithFledge = IxBidResponse.builder() .cur(bidResponse.getCur()) .seatbid(bidResponse.getSeatbid()) - .ext(IxExtBidResponse.of(List.of(AuctionConfigExtBidResponse.of(impId, fledgeAuctionConfig)))) + .ext(IxExtBidResponse.of(List.of(AuctionConfigExtBidResponse.of(impId, auctionConfig)))) .build(); final BidderCall httpCall = givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponseWithFledge)); @@ -787,14 +788,15 @@ public void makeBidderResponseShouldReturnFledgeAuctionConfig() throws JsonProce final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then + final ExtIgiIgs igs = ExtIgiIgs.builder() + .impId(impId) + .config(auctionConfig) + .build(); + assertThat(result.getErrors()).isEmpty(); assertThat(result.getBids()) .containsOnly(BidderBid.of(Bid.builder().impid(impId).mtype(1).build(), banner, bidResponse.getCur())); - final FledgeAuctionConfig expectedFledge = FledgeAuctionConfig.builder() - .impId(impId) - .config(fledgeAuctionConfig) - .build(); - assertThat(result.getFledgeAuctionConfigs()).containsExactly(expectedFledge); + assertThat(result.getIgi()).containsExactly(ExtIgi.builder().igs(singletonList(igs)).build()); } private static ExtRequest givenExtRequest(String pbjsv) { diff --git a/src/test/java/org/prebid/server/bidder/medianet/MedianetBidderTest.java b/src/test/java/org/prebid/server/bidder/medianet/MedianetBidderTest.java index 15e67bb5e25..03a3cba66f8 100644 --- a/src/test/java/org/prebid/server/bidder/medianet/MedianetBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/medianet/MedianetBidderTest.java @@ -21,7 +21,8 @@ import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; import org.prebid.server.proto.openrtb.ext.ExtPrebid; -import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import java.util.ArrayList; import java.util.List; @@ -215,13 +216,14 @@ public void makeBidsShouldReturnFledgeConfigIfBidIsPresent() throws JsonProcessi final CompositeBidderResponse result = target.makeBidderResponse(httpCall, null); // then + final ExtIgiIgs igs = ExtIgiIgs.builder() + .impId("imp_id") + .config(mapper.createObjectNode().put("someKey", "someValue")) + .build(); + assertThat(result.getErrors()).isEmpty(); assertThat(result.getBids()).hasSize(1); - assertThat(result.getFledgeAuctionConfigs()) - .containsOnly(FledgeAuctionConfig.builder() - .impId("imp_id") - .config(mapper.createObjectNode().put("someKey", "someValue")) - .build()); + assertThat(result.getIgi()).containsExactly(ExtIgi.builder().igs(singletonList(igs)).build()); } @Test @@ -235,13 +237,14 @@ public void makeBidsShouldReturnFledgeConfigIfBidIsAbsent() throws JsonProcessin final CompositeBidderResponse result = target.makeBidderResponse(httpCall, null); // then + final ExtIgiIgs igs = ExtIgiIgs.builder() + .impId("imp_id") + .config(mapper.createObjectNode().put("someKey", "someValue")) + .build(); + assertThat(result.getErrors()).isEmpty(); assertThat(result.getBids()).isEmpty(); - assertThat(result.getFledgeAuctionConfigs()) - .containsOnly(FledgeAuctionConfig.builder() - .impId("imp_id") - .config(mapper.createObjectNode().put("someKey", "someValue")) - .build()); + assertThat(result.getIgi()).containsExactly(ExtIgi.builder().igs(singletonList(igs)).build()); } private static MedianetBidResponse sampleBidResponse(Function Date: Wed, 8 Jan 2025 13:45:15 +0200 Subject: [PATCH 08/24] Added unit tests for BidResponseCreator and HttpBidderRequester --- .../auction/BidResponseCreatorTest.java | 44 +++++++++++++++++ .../bidder/HttpBidderRequesterTest.java | 49 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index f9bade83d18..2256518bb80 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -97,6 +97,9 @@ import org.prebid.server.proto.openrtb.ext.response.ExtBidderError; import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgsExt; import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; import org.prebid.server.proto.openrtb.ext.response.ExtResponseDebug; import org.prebid.server.proto.openrtb.ext.response.ExtTraceActivityInfrastructure; @@ -3502,6 +3505,47 @@ public void shouldAddExtPrebidFledgeIfAvailable() { .build()); } + @Test + public void shouldAddExtIgiIfAvailable() { + // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); + final Imp imp = givenImp("i1").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), identity(), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("i1").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt().getIgi()).containsExactly( + ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder() + .config(mapper.createObjectNode()) + .ext(ExtIgiIgsExt.of("bidder1", "adapter1")) + .build())) + .build()); + } + @Test public void shouldAddExtPrebidFledgeIfAvailableEvenIfBidsEmpty() { // given diff --git a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java index 179f2a1ceeb..6b8772dcbc7 100644 --- a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java +++ b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java @@ -37,6 +37,8 @@ import org.prebid.server.execution.timeout.TimeoutFactory; import org.prebid.server.model.CaseInsensitiveMultiMap; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; +import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.HttpClient; @@ -448,6 +450,53 @@ public void shouldReturnFledgeCreatedByBidder() { verify(bidRejectionTracker, never()).reject(anyList(), any()); } + @Test + public void shouldReturnExtIgiCreatedByBidder() { + // given + givenSuccessfulBidderMakeHttpRequests(); + + final List igi = List.of( + ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder() + .config(mapper.createObjectNode()) + .build())) + .build()); + + final List bids = emptyList(); + + given(bidder.makeBidderResponse(any(), any())).willReturn( + CompositeBidderResponse.builder() + .bids(bids) + .igi(igi) + .build()); + + final BidderRequest bidderRequest = BidderRequest.builder() + .bidder("bidder") + .bidRequest(BidRequest.builder().build()) + .build(); + + // when + final BidderSeatBid bidderSeatBid = + target + .requestBids( + bidder, + bidderRequest, + bidRejectionTracker, + timeout, + CaseInsensitiveMultiMap.empty(), + bidderAliases, + false) + .result(); + + // then + assertThat(bidderSeatBid.getBids()).hasSameElementsAs(bids); + assertThat(bidderSeatBid.getIgi()).containsExactlyElementsOf(igi); + + verify(bidRejectionTracker, never()).reject(anyString(), any()); + verify(bidRejectionTracker, never()).reject(anyList(), any()); + } + @Test public void shouldCompressRequestBodyIfContentEncodingHeaderIsGzip() { // given From 5d6d88b21d499c11cf397f6dc69584b5cdcae21e Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Thu, 9 Jan 2025 16:07:47 +0200 Subject: [PATCH 09/24] Added igs.ae mapping. --- .../prebid/server/auction/ImpAdjuster.java | 31 ++++++++ .../server/auction/ImpAdjusterTest.java | 74 +++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/src/main/java/org/prebid/server/auction/ImpAdjuster.java b/src/main/java/org/prebid/server/auction/ImpAdjuster.java index 86e581b06e8..e34bee7d638 100644 --- a/src/main/java/org/prebid/server/auction/ImpAdjuster.java +++ b/src/main/java/org/prebid/server/auction/ImpAdjuster.java @@ -1,20 +1,26 @@ package org.prebid.server.auction; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.IntNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.Imp; import org.prebid.server.json.JacksonMapper; import org.prebid.server.json.JsonMerger; import org.prebid.server.validation.ImpValidator; +import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; +import java.util.stream.StreamSupport; public class ImpAdjuster { private static final String IMP_EXT = "ext"; + private static final String EXT_AE = "ae"; + private static final String EXT_IGS = "igs"; private static final String EXT_PREBID = "prebid"; private static final String EXT_PREBID_BIDDER = "bidder"; private static final String EXT_PREBID_IMP = "imp"; @@ -33,6 +39,8 @@ public ImpAdjuster(JacksonMapper jacksonMapper, } public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, List debugMessages) { + setEaParams(originalImp.getExt()); + final JsonNode impExtPrebidImp = bidderParamsFromImpExtPrebidImp(originalImp.getExt()); if (impExtPrebidImp == null) { return originalImp; @@ -65,6 +73,29 @@ public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, L } } + private void setEaParams(ObjectNode ext) { + final int extEa = Optional.ofNullable(ext) + .map(extNode -> extNode.get(EXT_AE)) + .filter(JsonNode::isInt) + .map(JsonNode::asInt) + .orElse(-1); + + boolean extIgsEaPresent = Optional.ofNullable(ext) + .map(extNode -> extNode.get(EXT_IGS)) + .filter(JsonNode::isArray) + .map(extNode -> StreamSupport.stream(extNode.spliterator(), false).toList()) + .stream() + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .anyMatch(igsElementNode -> igsElementNode.has(EXT_AE)); + + if (!extIgsEaPresent && (extEa == 0 || extEa == 1)) { + final ArrayNode extIgs = jacksonMapper.mapper().createArrayNode(); + extIgs.add(jacksonMapper.mapper().createObjectNode().set(EXT_AE, IntNode.valueOf(extEa))); + ext.set(EXT_IGS, extIgs); + } + } + private static JsonNode bidderParamsFromImpExtPrebidImp(ObjectNode ext) { return Optional.ofNullable(ext) .map(extNode -> extNode.get(EXT_PREBID)) diff --git a/src/test/java/org/prebid/server/auction/ImpAdjusterTest.java b/src/test/java/org/prebid/server/auction/ImpAdjusterTest.java index 717ca62dedd..30148ed35b9 100644 --- a/src/test/java/org/prebid/server/auction/ImpAdjusterTest.java +++ b/src/test/java/org/prebid/server/auction/ImpAdjusterTest.java @@ -1,6 +1,7 @@ package org.prebid.server.auction; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.IntNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.Deal; import com.iab.openrtb.request.Imp; @@ -77,6 +78,79 @@ public void adjustShouldReturnOriginalImpWhenImpExtPrebidImpIsAbsent() { assertThat(debugMessages).isEmpty(); } + @Test + public void adjustShouldSetImpExtIgsAeWhenImpExtAeIsZero() { + // given + final ObjectNode ext = mapper.createObjectNode(); + ext.set("ae", IntNode.valueOf(0)); + + final Imp givenImp = Imp.builder().ext(ext).build(); + + final List debugMessages = new ArrayList<>(); + + // when + final Imp result = target.adjust(givenImp, "someBidder", bidderAliases, debugMessages); + + // then + assertThat(result.getExt().get("igs").get(0).get("ae")).isEqualTo(IntNode.valueOf(0)); + assertThat(debugMessages).isEmpty(); + } + + @Test + public void adjustShouldSetImpExtIgsAeWhenImpExtAeIsOne() { + // given + final ObjectNode ext = mapper.createObjectNode(); + ext.set("ae", IntNode.valueOf(1)); + + final Imp givenImp = Imp.builder().ext(ext).build(); + + final List debugMessages = new ArrayList<>(); + + // when + final Imp result = target.adjust(givenImp, "someBidder", bidderAliases, debugMessages); + + // then + assertThat(result.getExt().get("igs").get(0).get("ae")).isEqualTo(IntNode.valueOf(1)); + assertThat(debugMessages).isEmpty(); + } + + @Test + public void adjustShouldNotSetImpExtIgsAeWhenImpExtAeIsNotZeroOrOne() { + // given + final ObjectNode ext = mapper.createObjectNode(); + ext.set("ae", IntNode.valueOf(3)); + + final Imp givenImp = Imp.builder().ext(ext).build(); + + final List debugMessages = new ArrayList<>(); + + // when + final Imp result = target.adjust(givenImp, "someBidder", bidderAliases, debugMessages); + + // then + assertThat(result.getExt().get("igs")).isNull(); + assertThat(debugMessages).isEmpty(); + } + + @Test + public void adjustShouldNotModifyImpExtIgsAeWhenImpExtIgsAePresent() { + // given + final ObjectNode ext = mapper.createObjectNode(); + ext.set("ae", IntNode.valueOf(0)); + ext.set("igs", mapper.createArrayNode().add(mapper.createObjectNode().set("ae", IntNode.valueOf(123)))); + + final Imp givenImp = Imp.builder().ext(ext).build(); + + final List debugMessages = new ArrayList<>(); + + // when + final Imp result = target.adjust(givenImp, "someBidder", bidderAliases, debugMessages); + + // then + assertThat(result.getExt().get("igs").get(0).get("ae")).isEqualTo(IntNode.valueOf(123)); + assertThat(debugMessages).isEmpty(); + } + @Test public void adjustShouldRemoveExpImpFromOriginalImpWhenImpExtPrebidImpHasEmptyBidder() { // given From 4ca36ba489bf3e8469885767bc7fc6f0b196dd50 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Thu, 9 Jan 2025 16:09:53 +0200 Subject: [PATCH 10/24] Removed TODOs. --- src/main/java/org/prebid/server/auction/BidResponseCreator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 473c09fee39..691bc693a7e 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -1213,7 +1213,7 @@ private static PaaFormat resolvePaaFormat(AuctionContext auctionContext) { .or(() -> Optional.ofNullable(auctionContext.getAccount()) .map(Account::getAuction) .map(AccountAuctionConfig::getPaaFormat)) - .orElse(PaaFormat.IAB); // TODO: Decide what default value to use + .orElse(PaaFormat.IAB); } /** From 9e492ba442a850ca4fcb4889e83d4048b95482f6 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Thu, 9 Jan 2025 16:13:41 +0200 Subject: [PATCH 11/24] Fixed styling. --- src/main/java/org/prebid/server/auction/ImpAdjuster.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/auction/ImpAdjuster.java b/src/main/java/org/prebid/server/auction/ImpAdjuster.java index e34bee7d638..c53a61a9896 100644 --- a/src/main/java/org/prebid/server/auction/ImpAdjuster.java +++ b/src/main/java/org/prebid/server/auction/ImpAdjuster.java @@ -80,7 +80,7 @@ private void setEaParams(ObjectNode ext) { .map(JsonNode::asInt) .orElse(-1); - boolean extIgsEaPresent = Optional.ofNullable(ext) + final boolean extIgsEaPresent = Optional.ofNullable(ext) .map(extNode -> extNode.get(EXT_IGS)) .filter(JsonNode::isArray) .map(extNode -> StreamSupport.stream(extNode.spliterator(), false).toList()) From 8333f7c9cde946e96c3187b201a049c3677bebaf Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Thu, 9 Jan 2025 16:16:00 +0200 Subject: [PATCH 12/24] Fixed naming. --- .../java/org/prebid/server/auction/ImpAdjuster.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/ImpAdjuster.java b/src/main/java/org/prebid/server/auction/ImpAdjuster.java index c53a61a9896..6b03d006079 100644 --- a/src/main/java/org/prebid/server/auction/ImpAdjuster.java +++ b/src/main/java/org/prebid/server/auction/ImpAdjuster.java @@ -39,7 +39,7 @@ public ImpAdjuster(JacksonMapper jacksonMapper, } public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, List debugMessages) { - setEaParams(originalImp.getExt()); + setAeParams(originalImp.getExt()); final JsonNode impExtPrebidImp = bidderParamsFromImpExtPrebidImp(originalImp.getExt()); if (impExtPrebidImp == null) { @@ -73,14 +73,14 @@ public Imp adjust(Imp originalImp, String bidder, BidderAliases bidderAliases, L } } - private void setEaParams(ObjectNode ext) { - final int extEa = Optional.ofNullable(ext) + private void setAeParams(ObjectNode ext) { + final int extAe = Optional.ofNullable(ext) .map(extNode -> extNode.get(EXT_AE)) .filter(JsonNode::isInt) .map(JsonNode::asInt) .orElse(-1); - final boolean extIgsEaPresent = Optional.ofNullable(ext) + final boolean extIgsAePresent = Optional.ofNullable(ext) .map(extNode -> extNode.get(EXT_IGS)) .filter(JsonNode::isArray) .map(extNode -> StreamSupport.stream(extNode.spliterator(), false).toList()) @@ -89,9 +89,9 @@ private void setEaParams(ObjectNode ext) { .filter(Objects::nonNull) .anyMatch(igsElementNode -> igsElementNode.has(EXT_AE)); - if (!extIgsEaPresent && (extEa == 0 || extEa == 1)) { + if (!extIgsAePresent && (extAe == 0 || extAe == 1)) { final ArrayNode extIgs = jacksonMapper.mapper().createArrayNode(); - extIgs.add(jacksonMapper.mapper().createObjectNode().set(EXT_AE, IntNode.valueOf(extEa))); + extIgs.add(jacksonMapper.mapper().createObjectNode().set(EXT_AE, IntNode.valueOf(extAe))); ext.set(EXT_IGS, extIgs); } } From b0c7f3162be3b705258386404e854042cb4c03b6 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 10 Jan 2025 15:50:51 +0200 Subject: [PATCH 13/24] Fixes after merging master --- .../server/auction/model/BidRejectionTracker.java | 11 ----------- .../prebid/server/bidder/HttpBidderRequesterTest.java | 4 ++-- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/model/BidRejectionTracker.java b/src/main/java/org/prebid/server/auction/model/BidRejectionTracker.java index 9810606ada3..476e61fac09 100644 --- a/src/main/java/org/prebid/server/auction/model/BidRejectionTracker.java +++ b/src/main/java/org/prebid/server/auction/model/BidRejectionTracker.java @@ -47,10 +47,6 @@ public BidRejectionTracker(String bidder, Set involvedImpIds, double log rejectedBids = new HashMap<>(); } - /** - * Restores ONLY imps from rejection, rejected bids are preserved for analytics. - * A bid can be rejected only once. - */ public void succeed(Collection bids) { bids.stream() .map(BidderBid::getBid) @@ -124,10 +120,6 @@ public void rejectAllImps(BidRejectionReason reason) { involvedImpIds.forEach(impId -> rejectImp(impId, reason)); } - /** - * If an impression has at least one valid bid, it's not considered rejected. - * If no valid bids are returned for the impression, only the first one rejected reason will be returned - */ public Map getRejectedImps() { final Map rejectedImpIds = new HashMap<>(); for (String impId : involvedImpIds) { @@ -144,9 +136,6 @@ public Map getRejectedImps() { return rejectedImpIds; } - /** - * Bid is absent for the non-bid code from 0 to 299 - */ public Map>> getRejectedBids() { final Map>> missingImpIds = new HashMap<>(); for (String impId : involvedImpIds) { diff --git a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java index c4f81dd2713..2b067ab06d8 100644 --- a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java +++ b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java @@ -493,8 +493,8 @@ public void shouldReturnExtIgiCreatedByBidder() { assertThat(bidderSeatBid.getBids()).hasSameElementsAs(bids); assertThat(bidderSeatBid.getIgi()).containsExactlyElementsOf(igi); - verify(bidRejectionTracker, never()).reject(anyString(), any()); - verify(bidRejectionTracker, never()).reject(anyList(), any()); + verify(bidRejectionTracker, never()).rejectImp(anyString(), any()); + verify(bidRejectionTracker, never()).rejectImps(anyList(), any()); } @Test From 85208f5bc4a04c085e642eace242f66a48b1c9bc Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 10 Jan 2025 16:34:48 +0200 Subject: [PATCH 14/24] Fixed IxTest. --- .../prebid/server/it/openrtb2/ix/test-ix-bid-request.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request.json index ef303b14b8e..5478c38a82b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request.json @@ -16,6 +16,11 @@ }, "ext": { "ae": 1, + "igs": [ + { + "ae": 1 + } + ], "tid": "${json-unit.any-string}", "bidder": { "siteId": "10002" From 3882deb85f8fd67dc7861ae7279c0e62fe58b807 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Tue, 14 Jan 2025 18:21:28 +0200 Subject: [PATCH 15/24] Made paa format default to original. --- .../server/auction/BidResponseCreator.java | 8 +-- .../auction/BidResponseCreatorTest.java | 49 ++++++++++++++++++- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 20edcd38256..7bc9f9dae1e 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -898,9 +898,9 @@ private List toExtBidResponseIgi(List bidderResponse private ExtIgi extIgiWithBidder(ExtIgi extIgi, String bidder) { final List extIgiIgs = CollectionUtils.emptyIfNull(extIgi.getIgs()).stream() - .map(igs -> Optional.ofNullable(igs) - .map(ExtIgiIgs::toBuilder) - .orElseGet(ExtIgiIgs::builder) + .filter(Objects::nonNull) + .filter(igs -> StringUtils.isNotEmpty(igs.getImpId())) + .map(igs -> igs.toBuilder() .ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder))) .build()) .toList(); @@ -1229,7 +1229,7 @@ private static PaaFormat resolvePaaFormat(AuctionContext auctionContext) { .or(() -> Optional.ofNullable(auctionContext.getAccount()) .map(Account::getAuction) .map(AccountAuctionConfig::getPaaFormat)) - .orElse(PaaFormat.IAB); + .orElse(PaaFormat.ORIGINAL); } /** diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 2a756324eb2..c00211452e9 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -44,6 +44,7 @@ import org.prebid.server.auction.model.CachedDebugLog; import org.prebid.server.auction.model.CategoryMappingResult; import org.prebid.server.auction.model.MultiBidConfig; +import org.prebid.server.auction.model.PaaFormat; import org.prebid.server.auction.model.TargetingInfo; import org.prebid.server.auction.model.TimeoutContext; import org.prebid.server.auction.model.debug.DebugContext; @@ -91,6 +92,7 @@ import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponseFledge; import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidderError; import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace; @@ -3520,7 +3522,7 @@ public void shouldAddExtIgiIfAvailable() { final Imp imp = givenImp("i1").toBuilder() .ext(mapper.createObjectNode().put("ae", 1)) .build(); - final BidRequest bidRequest = givenBidRequest(identity(), identity(), imp); + final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); final ExtIgi igi = ExtIgi.builder() .impid("impId") .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) @@ -3554,6 +3556,51 @@ public void shouldAddExtIgiIfAvailable() { .build()); } + @Test + public void shouldDefaultToOriginalPaaFormat() { + // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); + final Imp imp = givenImp("i1").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), identity(), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("i1").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getPrebid) + .extracting(ExtBidResponsePrebid::getFledge) + .extracting(ExtBidResponseFledge::getAuctionConfigs) + .asList() + .containsExactly( + FledgeAuctionConfig.builder() + .impId("impId") + .config(mapper.createObjectNode()) + .bidder("bidder1") + .adapter("adapter1") + .build()); + } + @Test public void shouldAddExtPrebidFledgeIfAvailableEvenIfBidsEmpty() { // given From 0841723ea48d22f3de9154cda3e31fb25e52adaf Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Tue, 14 Jan 2025 19:47:53 +0200 Subject: [PATCH 16/24] Added missing validations. --- .../server/auction/BidResponseCreator.java | 123 ++++++--- .../spring/config/ServiceConfiguration.java | 2 + .../auction/BidResponseCreatorTest.java | 259 +++++++++++++++++- 3 files changed, 336 insertions(+), 48 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 7bc9f9dae1e..cbb63000c5c 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -62,6 +62,9 @@ import org.prebid.server.identity.IdGeneratorType; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.log.ConditionalLogger; +import org.prebid.server.log.Logger; +import org.prebid.server.log.LoggerFactory; import org.prebid.server.proto.openrtb.ext.request.ExtImp; import org.prebid.server.proto.openrtb.ext.request.ExtImpAuctionEnvironment; import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid; @@ -122,6 +125,9 @@ public class BidResponseCreator { + private static final Logger logger = LoggerFactory.getLogger(BidResponseCreator.class); + private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger); + private static final String CACHE = "cache"; private static final String PREBID_EXT = "prebid"; private static final Integer DEFAULT_BID_LIMIT_MIN = 1; @@ -131,6 +137,7 @@ public class BidResponseCreator { private static final String TARGETING_ENV_APP_VALUE = "mobile-app"; private static final String TARGETING_ENV_AMP_VALUE = "amp"; + private final double logSamplingRate; private final CoreCacheService coreCacheService; private final BidderCatalog bidderCatalog; private final VastModifier vastModifier; @@ -150,7 +157,8 @@ public class BidResponseCreator { private final String cachePath; private final String cacheAssetUrlTemplate; - public BidResponseCreator(CoreCacheService coreCacheService, + public BidResponseCreator(double logSamplingRate, + CoreCacheService coreCacheService, BidderCatalog bidderCatalog, VastModifier vastModifier, EventsService eventsService, @@ -180,9 +188,11 @@ public BidResponseCreator(CoreCacheService coreCacheService, this.mediaTypeCacheTtl = Objects.requireNonNull(mediaTypeCacheTtl); this.cacheDefaultProperties = Objects.requireNonNull(cacheDefaultProperties); + this.logSamplingRate = logSamplingRate; + + cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate()); cacheHost = Objects.requireNonNull(coreCacheService.getEndpointHost()); cachePath = Objects.requireNonNull(coreCacheService.getEndpointPath()); - cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate()); } private static int validateTruncateAttrChars(int truncateAttrChars) { @@ -820,21 +830,20 @@ private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp, private PaaResult toPaaOutput(List bidderResponseInfos, AuctionContext auctionContext) { final PaaFormat paaFormat = resolvePaaFormat(auctionContext); - final List extIgi = paaFormat == PaaFormat.IAB ? toExtBidResponseIgi(bidderResponseInfos) : null; + final List igis = extractIgis(bidderResponseInfos); + final List extIgi = paaFormat == PaaFormat.IAB && !igis.isEmpty() ? igis : null; - final List imps = auctionContext.getBidRequest().getImp(); + final List fledgeConfigs = paaFormat == PaaFormat.ORIGINAL + ? toOriginalFledgeFormat(igis) + : Collections.emptyList(); // TODO: Remove after transition period - final Stream deprecatedFledgeConfigs = bidderResponseInfos.stream() - .flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps)); - - final Stream fledgeConfigs = paaFormat == PaaFormat.ORIGINAL - ? bidderResponseInfos.stream().flatMap(this::toOriginalFledgeFormat) - : Stream.empty(); - - final List combinedFledgeConfigs = Stream.concat(deprecatedFledgeConfigs, fledgeConfigs) + final List imps = auctionContext.getBidRequest().getImp(); + final List deprecatedFledgeConfigs = bidderResponseInfos.stream() + .flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps)) .toList(); + final List combinedFledgeConfigs = ListUtils.union(deprecatedFledgeConfigs, fledgeConfigs); final ExtBidResponseFledge extBidResponseFledge = combinedFledgeConfigs.isEmpty() ? null : ExtBidResponseFledge.of(combinedFledgeConfigs); @@ -842,20 +851,71 @@ private PaaResult toPaaOutput(List bidderResponseInfos, Auct return new PaaResult(extIgi, extBidResponseFledge); } - private Stream toOriginalFledgeFormat(BidderResponseInfo bidderResponseInfo) { - return Optional.ofNullable(bidderResponseInfo.getSeatBid().getIgi()).stream() - .flatMap(Collection::stream) + private List extractIgis(List bidderResponseInfos) { + return bidderResponseInfos.stream() + .flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream() + .map(igi -> prepareExtIgi(igi, responseInfo.getBidder()))) .filter(Objects::nonNull) + .toList(); + } + + private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) { + if (igi == null) { + return null; + } + + if (StringUtils.isEmpty(igi.getImpid())) { + conditionalLogger.warn("ExtIgi with absent impId", logSamplingRate); + return null; + } + + final List preparedIgs = prepareExtIgiIgs(igi.getIgs(), bidder); + return igi.toBuilder().igs(preparedIgs.isEmpty() ? null : preparedIgs).build(); + } + + private List prepareExtIgiIgs(List igiIgs, String bidder) { + if (igiIgs == null) { + return Collections.emptyList(); + } + + final List preparedIgiIgs = new ArrayList<>(); + for (ExtIgiIgs extIgiIgs : igiIgs) { + if (extIgiIgs == null) { + continue; + } + + if (StringUtils.isEmpty(extIgiIgs.getImpId())) { + conditionalLogger.warn("ExtIgiIgs with absent impId", logSamplingRate); + continue; + } + + if (extIgiIgs.getConfig() == null) { + conditionalLogger.warn("ExtIgiIgs with absent config", logSamplingRate); + continue; + } + + final ExtIgiIgs preparedExtIgiIgs = extIgiIgs.toBuilder() + .ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder))) + .build(); + + preparedIgiIgs.add(preparedExtIgiIgs); + } + + return preparedIgiIgs; + } + + private List toOriginalFledgeFormat(List igis) { + return igis.stream() .map(ExtIgi::getIgs) - .filter(Objects::nonNull) .flatMap(Collection::stream) - .map(extIgiIgs -> extIgiIgsToFledgeConfig(extIgiIgs, bidderResponseInfo.getBidder())); + .map(BidResponseCreator::extIgiIgsToFledgeConfig) + .toList(); } - private FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs, String bidder) { + private static FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs) { return FledgeAuctionConfig.builder() - .bidder(bidder) - .adapter(bidderCatalog.resolveBaseBidder(bidder)) + .bidder(extIgiIgs.getExt().getBidder()) + .adapter(extIgiIgs.getExt().getAdapter()) .impId(extIgiIgs.getImpId()) .config(extIgiIgs.getConfig()) .build(); @@ -887,29 +947,6 @@ private FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeCon .build(); } - private List toExtBidResponseIgi(List bidderResponseInfos) { - final List extIgi = bidderResponseInfos.stream() - .flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream() - .map(igi -> extIgiWithBidder(igi, responseInfo.getBidder()))) - .toList(); - - return extIgi.isEmpty() ? null : extIgi; - } - - private ExtIgi extIgiWithBidder(ExtIgi extIgi, String bidder) { - final List extIgiIgs = CollectionUtils.emptyIfNull(extIgi.getIgs()).stream() - .filter(Objects::nonNull) - .filter(igs -> StringUtils.isNotEmpty(igs.getImpId())) - .map(igs -> igs.toBuilder() - .ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder))) - .build()) - .toList(); - - return extIgiIgs.isEmpty() - ? extIgi - : extIgi.toBuilder().igs(extIgiIgs).build(); - } - private static ExtResponseDebug toExtResponseDebug(List bidderResponseInfos, AuctionContext auctionContext, CacheServiceResult cacheResult, 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 deaa768320c..fa7cc267457 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -807,6 +807,7 @@ CacheDefaultTtlProperties cacheDefaultTtlProperties( @Bean BidResponseCreator bidResponseCreator( + @Value("${logging.sampling-rate:0.01}") double logSamplingRate, CoreCacheService coreCacheService, BidderCatalog bidderCatalog, VastModifier vastModifier, @@ -824,6 +825,7 @@ BidResponseCreator bidResponseCreator( CacheDefaultTtlProperties cacheDefaultTtlProperties) { return new BidResponseCreator( + logSamplingRate, coreCacheService, bidderCatalog, vastModifier, diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index c00211452e9..c3b19bcc491 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -1640,6 +1640,7 @@ public void shouldTruncateTargetingKeywordsByGlobalConfig() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); target = new BidResponseCreator( + 0, coreCacheService, bidderCatalog, vastModifier, @@ -3516,7 +3517,7 @@ public void shouldAddExtPrebidFledgeIfAvailable() { } @Test - public void shouldAddExtIgiIfAvailable() { + public void shouldAddExtIgiIfAvailableAndExtRequestPrebidPaaFormatIsIab() { // given given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); final Imp imp = givenImp("i1").toBuilder() @@ -3525,7 +3526,7 @@ public void shouldAddExtIgiIfAvailable() { final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); final ExtIgi igi = ExtIgi.builder() .impid("impId") - .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) + .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) .build(); final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("i1").build(); @@ -3550,26 +3551,167 @@ public void shouldAddExtIgiIfAvailable() { ExtIgi.builder() .impid("impId") .igs(singletonList(ExtIgiIgs.builder() + .impId("impId") .config(mapper.createObjectNode()) .ext(ExtIgiIgsExt.of("bidder1", "adapter1")) .build())) .build()); } + @Test + public void shouldAddExtPrebidFledgeIfAvailableAndExtRequestPrebidPaaFormatIsOriginal() { + // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.ORIGINAL), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getPrebid) + .extracting(ExtBidResponsePrebid::getFledge) + .extracting(ExtBidResponseFledge::getAuctionConfigs) + .asList() + .containsExactly( + FledgeAuctionConfig.builder() + .impId("impId") + .config(mapper.createObjectNode()) + .bidder("bidder1") + .adapter("adapter1") + .build()); + } + + @Test + public void shouldAddExtIgiIfAvailableAndExtRequestPrebidPaaFormatIsAbsentAndAccountConfigPaaFormatSetToIab() { + // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), identity(), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder + .auctionParticipations(toAuctionParticipant(bidderResponses)) + .account(Account.builder() + .auction(AccountAuctionConfig.builder().paaFormat(PaaFormat.IAB).build()) + .build())); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt().getIgi()).containsExactly( + ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder() + .impId("impId") + .config(mapper.createObjectNode()) + .ext(ExtIgiIgsExt.of("bidder1", "adapter1")) + .build())) + .build()); + } + + @Test + public void shouldAddExtPrebidFledgeIfAvailableAndRequestPaaFormatIsAbsentAndAccountConfigPaaFormatSetToOriginal() { + // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), identity(), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder + .auctionParticipations(toAuctionParticipant(bidderResponses)) + .account(Account.builder() + .auction(AccountAuctionConfig.builder().paaFormat(PaaFormat.ORIGINAL).build()) + .build())); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getPrebid) + .extracting(ExtBidResponsePrebid::getFledge) + .extracting(ExtBidResponseFledge::getAuctionConfigs) + .asList() + .containsExactly( + FledgeAuctionConfig.builder() + .impId("impId") + .config(mapper.createObjectNode()) + .bidder("bidder1") + .adapter("adapter1") + .build()); + } + @Test public void shouldDefaultToOriginalPaaFormat() { // given given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); - final Imp imp = givenImp("i1").toBuilder() + final Imp imp = givenImp("impId").toBuilder() .ext(mapper.createObjectNode().put("ae", 1)) .build(); final BidRequest bidRequest = givenBidRequest(identity(), identity(), imp); final ExtIgi igi = ExtIgi.builder() .impid("impId") - .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) + .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) .build(); - final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("i1").build(); + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); final List bidderResponses = singletonList( BidderResponse.of("bidder1", BidderSeatBid.builder() @@ -3601,6 +3743,112 @@ public void shouldDefaultToOriginalPaaFormat() { .build()); } + @Test + public void shouldDropExtIgiIfAvailableAndExtIgiImpIdIsAbsent() { + // given + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); + final ExtIgi igi = ExtIgi.builder() + .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getIgi) + .isNull(); + } + + @Test + public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { + // given + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getIgi) + .asList() + .containsExactly(ExtIgi.builder().impid("impId").build()); + } + + @Test + public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { + // given + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .igs(singletonList(ExtIgiIgs.builder().impId("impId").build())) + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getIgi) + .asList() + .containsExactly(ExtIgi.builder().impid("impId").build()); + } + @Test public void shouldAddExtPrebidFledgeIfAvailableEvenIfBidsEmpty() { // given @@ -5114,6 +5362,7 @@ private static ExtBidPrebid toExtBidPrebid(ObjectNode ext) { private BidResponseCreator givenBidResponseCreator(int truncateAttrChars) { return new BidResponseCreator( + 0, coreCacheService, bidderCatalog, vastModifier, From 032f15f7a6552744dedf05b41c823527273edd0b Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Tue, 14 Jan 2025 20:04:11 +0200 Subject: [PATCH 17/24] Fixed inconsistent unit test. --- src/main/java/org/prebid/server/handler/SetuidHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/prebid/server/handler/SetuidHandler.java b/src/main/java/org/prebid/server/handler/SetuidHandler.java index 1f6bed55e5f..f440c940a74 100644 --- a/src/main/java/org/prebid/server/handler/SetuidHandler.java +++ b/src/main/java/org/prebid/server/handler/SetuidHandler.java @@ -152,6 +152,7 @@ private static void validateUsersyncers(Stream usersyncers) { .filter(name -> name.getValue() > 1) .map(Map.Entry::getKey) .distinct() + .sorted() .toList(); if (CollectionUtils.isNotEmpty(cookieFamilyNameDuplicates)) { throw new IllegalArgumentException( From 7fd613ecc9b91718cf048d993804a0bc0e670679 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Wed, 15 Jan 2025 14:53:06 +0200 Subject: [PATCH 18/24] Fixed igi validations. --- .../server/auction/BidResponseCreator.java | 20 ++++-- .../auction/BidResponseCreatorTest.java | 64 +++++++++++++++++-- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index cbb63000c5c..0ae43405432 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -87,6 +87,7 @@ import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgb; import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgsExt; import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; @@ -864,13 +865,18 @@ private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) { return null; } - if (StringUtils.isEmpty(igi.getImpid())) { - conditionalLogger.warn("ExtIgi with absent impId", logSamplingRate); - return null; + boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); + if (shouldDropIgb) { + conditionalLogger.warn("ExtIgi with absent impId from bidder: " + bidder, logSamplingRate); } - final List preparedIgs = prepareExtIgiIgs(igi.getIgs(), bidder); - return igi.toBuilder().igs(preparedIgs.isEmpty() ? null : preparedIgs).build(); + final List updatedIgs = prepareExtIgiIgs(igi.getIgs(), bidder); + final List preparedIgs = updatedIgs.isEmpty() ? null : updatedIgs; + final List preparedIgb = shouldDropIgb ? null : igi.getIgb(); + + return ObjectUtils.anyNotNull(preparedIgs, preparedIgb) + ? igi.toBuilder().igs(preparedIgs).igb(preparedIgb).build() + : null; } private List prepareExtIgiIgs(List igiIgs, String bidder) { @@ -885,12 +891,12 @@ private List prepareExtIgiIgs(List igiIgs, String bidder) } if (StringUtils.isEmpty(extIgiIgs.getImpId())) { - conditionalLogger.warn("ExtIgiIgs with absent impId", logSamplingRate); + conditionalLogger.warn("ExtIgiIgs with absent impId from bidder: " + bidder, logSamplingRate); continue; } if (extIgiIgs.getConfig() == null) { - conditionalLogger.warn("ExtIgiIgs with absent config", logSamplingRate); + conditionalLogger.warn("ExtIgiIgs with absent config from bidder: " + bidder, logSamplingRate); continue; } diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index c3b19bcc491..0b6d4b67b9f 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -98,6 +98,7 @@ import org.prebid.server.proto.openrtb.ext.response.ExtDebugTrace; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; import org.prebid.server.proto.openrtb.ext.response.ExtIgi; +import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgb; import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs; import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgsExt; import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; @@ -3744,14 +3745,16 @@ public void shouldDefaultToOriginalPaaFormat() { } @Test - public void shouldDropExtIgiIfAvailableAndExtIgiImpIdIsAbsent() { + public void shouldDropExtIgiIgbIfAvailableAndExtIgiImpIdIsAbsent() { // given + given(bidderCatalog.resolveBaseBidder("bidder1")).willReturn("adapter1"); final Imp imp = givenImp("impId").toBuilder() .ext(mapper.createObjectNode().put("ae", 1)) .build(); final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); final ExtIgi igi = ExtIgi.builder() .igs(singletonList(ExtIgiIgs.builder().impId("impId").config(mapper.createObjectNode()).build())) + .igb(singletonList(ExtIgiIgb.builder().build())) .build(); final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); @@ -3774,7 +3777,16 @@ public void shouldDropExtIgiIfAvailableAndExtIgiImpIdIsAbsent() { // then assertThat(bidResponse.getExt()) .extracting(ExtBidResponse::getIgi) - .isNull(); + .asList() + .containsExactly( + ExtIgi.builder() + .igs(singletonList( + ExtIgiIgs.builder() + .impId("impId") + .config(mapper.createObjectNode()) + .ext(ExtIgiIgsExt.of("bidder1", "adapter1")) + .build())) + .build()); } @Test @@ -3787,6 +3799,7 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { final ExtIgi igi = ExtIgi.builder() .impid("impId") .igs(singletonList(ExtIgiIgs.builder().config(mapper.createObjectNode()).build())) + .igb(singletonList(ExtIgiIgb.builder().build())) .build(); final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); @@ -3810,7 +3823,11 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { assertThat(bidResponse.getExt()) .extracting(ExtBidResponse::getIgi) .asList() - .containsExactly(ExtIgi.builder().impid("impId").build()); + .containsExactly( + ExtIgi.builder() + .impid("impId") + .igb(singletonList(ExtIgiIgb.builder().build())) + .build()); } @Test @@ -3823,6 +3840,7 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { final ExtIgi igi = ExtIgi.builder() .impid("impId") .igs(singletonList(ExtIgiIgs.builder().impId("impId").build())) + .igb(singletonList(ExtIgiIgb.builder().build())) .build(); final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); @@ -3846,7 +3864,45 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { assertThat(bidResponse.getExt()) .extracting(ExtBidResponse::getIgi) .asList() - .containsExactly(ExtIgi.builder().impid("impId").build()); + .containsExactly( + ExtIgi.builder() + .impid("impId") + .igb(singletonList(ExtIgiIgb.builder().build())) + .build()); + } + + @Test + public void shouldDropExtIgiIfAvailableAndExtIgiIgsAndExtIgiIgbAreAbsent() { + // given + final Imp imp = givenImp("impId").toBuilder() + .ext(mapper.createObjectNode().put("ae", 1)) + .build(); + final BidRequest bidRequest = givenBidRequest(identity(), ext -> ext.paaFormat(PaaFormat.IAB), imp); + final ExtIgi igi = ExtIgi.builder() + .impid("impId") + .build(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(2.37)).impid("impId").build(); + final List bidderResponses = singletonList( + BidderResponse.of("bidder1", + BidderSeatBid.builder() + .bids(List.of(BidderBid.of(bid, banner, "USD"))) + .igi(singletonList(igi)) + .build(), 100)); + + final AuctionContext auctionContext = givenAuctionContext( + bidRequest, + contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + + // when + final BidResponse bidResponse = target + .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .result(); + + // then + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getIgi) + .isNull(); } @Test From bfffd2ffe0efd3e3a773172bcccd28d8eca48924 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Wed, 15 Jan 2025 14:55:04 +0200 Subject: [PATCH 19/24] Fixed styling. --- src/main/java/org/prebid/server/auction/BidResponseCreator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 0ae43405432..2b2bc898374 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -865,7 +865,7 @@ private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) { return null; } - boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); + final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); if (shouldDropIgb) { conditionalLogger.warn("ExtIgi with absent impId from bidder: " + bidder, logSamplingRate); } From d5d45c330d15ccc04bce0a4762b10795c5bce5d7 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 24 Jan 2025 16:53:46 +0200 Subject: [PATCH 20/24] Added bidRequest level alias resolving and response level debug warnings. --- .../server/auction/BidResponseCreator.java | 70 +++-- .../server/auction/ExchangeService.java | 2 +- .../auction/BidResponseCreatorTest.java | 262 ++++++++++-------- .../server/auction/ExchangeServiceTest.java | 37 +-- 4 files changed, 217 insertions(+), 154 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 2b2bc898374..0b4dd4fea30 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -224,16 +224,19 @@ Future createOnSkippedAuction(AuctionContext auctionContext, List create(AuctionContext auctionContext, BidRequestCacheInfo cacheInfo, + BidderAliases aliases, Map bidderToMultiBids) { return videoStoredDataResult(auctionContext) - .compose(videoStoredData -> create(videoStoredData, auctionContext, cacheInfo, bidderToMultiBids)) + .compose(videoStoredData -> + create(videoStoredData, auctionContext, cacheInfo, aliases, bidderToMultiBids)) .map(bidResponse -> populateSeatNonBid(auctionContext, bidResponse)); } private Future create(VideoStoredDataResult videoStoredDataResult, AuctionContext auctionContext, BidRequestCacheInfo cacheInfo, + BidderAliases aliases, Map bidderToMultiBids) { final EventsContext eventsContext = createEventsContext(auctionContext); @@ -251,6 +254,7 @@ private Future create(VideoStoredDataResult videoStoredDataResult, toBidderResponseInfos(categoryMappingResult, cacheInfo, auctionContext), auctionContext, cacheInfo, + aliases, bidderToMultiBids, videoStoredDataResult, eventsContext)); @@ -569,6 +573,7 @@ private static CategoryMappingResult addCategoryMappingErrors(CategoryMappingRes private Future cacheBidsAndCreateResponse(List bidderResponses, AuctionContext auctionContext, BidRequestCacheInfo cacheInfo, + BidderAliases aliases, Map bidderToMultiBids, VideoStoredDataResult videoStoredDataResult, EventsContext eventsContext) { @@ -579,6 +584,7 @@ private Future cacheBidsAndCreateResponse(List final ExtBidResponse extBidResponse = toExtBidResponse( bidderResponses, auctionContext, + aliases, CacheServiceResult.empty(), VideoStoredDataResult.empty(), eventsContext.getAuctionTimestamp(), @@ -622,6 +628,7 @@ private Future cacheBidsAndCreateResponse(List .map(cacheResult -> toBidResponse( bidderResponseInfos, auctionContext, + aliases, targeting, cacheInfo, cacheResult, @@ -776,6 +783,7 @@ private static List injectTargeting(List bidderImpIdBidInfos, */ private ExtBidResponse toExtBidResponse(List bidderResponseInfos, AuctionContext auctionContext, + BidderAliases aliases, CacheServiceResult cacheResult, VideoStoredDataResult videoStoredDataResult, long auctionTimestamp, @@ -785,6 +793,10 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI final DebugContext debugContext = auctionContext.getDebugContext(); final boolean debugEnabled = debugContext.isDebugEnabled(); + final PaaResult paaResult = toPaaOutput(bidderResponseInfos, auctionContext, aliases); + final List igi = paaResult.igis(); + final ExtBidResponseFledge fledge = paaResult.fledge(); + final ExtResponseDebug extResponseDebug = toExtResponseDebug( bidderResponseInfos, auctionContext, cacheResult, debugEnabled); final Map> errors = toExtBidderErrors( @@ -794,10 +806,6 @@ private ExtBidResponse toExtBidResponse(List bidderResponseI final Map responseTimeMillis = toResponseTimes(bidderResponseInfos, cacheResult); - final PaaResult paaResult = toPaaOutput(bidderResponseInfos, auctionContext); - final List igi = paaResult.igis(); - final ExtBidResponseFledge fledge = paaResult.fledge(); - final ExtBidResponsePrebid prebid = toExtBidResponsePrebid( auctionTimestamp, auctionContext.getBidRequest(), fledge); @@ -829,9 +837,12 @@ private ExtBidResponsePrebid toExtBidResponsePrebid(long auctionTimestamp, .build(); } - private PaaResult toPaaOutput(List bidderResponseInfos, AuctionContext auctionContext) { + private PaaResult toPaaOutput(List bidderResponseInfos, + AuctionContext auctionContext, + BidderAliases aliases) { + final PaaFormat paaFormat = resolvePaaFormat(auctionContext); - final List igis = extractIgis(bidderResponseInfos); + final List igis = extractIgis(bidderResponseInfos, auctionContext, aliases); final List extIgi = paaFormat == PaaFormat.IAB && !igis.isEmpty() ? igis : null; final List fledgeConfigs = paaFormat == PaaFormat.ORIGINAL @@ -841,7 +852,7 @@ private PaaResult toPaaOutput(List bidderResponseInfos, Auct // TODO: Remove after transition period final List imps = auctionContext.getBidRequest().getImp(); final List deprecatedFledgeConfigs = bidderResponseInfos.stream() - .flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, imps)) + .flatMap(bidderResponseInfo -> toDeprecatedFledgeConfigs(bidderResponseInfo, aliases, imps)) .toList(); final List combinedFledgeConfigs = ListUtils.union(deprecatedFledgeConfigs, fledgeConfigs); @@ -852,25 +863,30 @@ private PaaResult toPaaOutput(List bidderResponseInfos, Auct return new PaaResult(extIgi, extBidResponseFledge); } - private List extractIgis(List bidderResponseInfos) { + private List extractIgis(List bidderResponseInfos, + AuctionContext auctionContext, + BidderAliases aliases) { + return bidderResponseInfos.stream() .flatMap(responseInfo -> responseInfo.getSeatBid().getIgi().stream() - .map(igi -> prepareExtIgi(igi, responseInfo.getBidder()))) + .map(igi -> prepareExtIgi(igi, responseInfo.getBidder(), auctionContext, aliases))) .filter(Objects::nonNull) .toList(); } - private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) { + private ExtIgi prepareExtIgi(ExtIgi igi, String bidder, AuctionContext auctionContext, BidderAliases aliases) { if (igi == null) { return null; } final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); if (shouldDropIgb) { - conditionalLogger.warn("ExtIgi with absent impId from bidder: " + bidder, logSamplingRate); + final String warning = "ExtIgi with absent impId from bidder: " + bidder; + auctionContext.getDebugWarnings().add(warning); + conditionalLogger.warn(warning, logSamplingRate); } - final List updatedIgs = prepareExtIgiIgs(igi.getIgs(), bidder); + final List updatedIgs = prepareExtIgiIgs(igi.getIgs(), bidder, auctionContext, aliases); final List preparedIgs = updatedIgs.isEmpty() ? null : updatedIgs; final List preparedIgb = shouldDropIgb ? null : igi.getIgb(); @@ -879,7 +895,11 @@ private ExtIgi prepareExtIgi(ExtIgi igi, String bidder) { : null; } - private List prepareExtIgiIgs(List igiIgs, String bidder) { + private List prepareExtIgiIgs(List igiIgs, + String bidder, + AuctionContext auctionContext, + BidderAliases aliases) { + if (igiIgs == null) { return Collections.emptyList(); } @@ -891,17 +911,21 @@ private List prepareExtIgiIgs(List igiIgs, String bidder) } if (StringUtils.isEmpty(extIgiIgs.getImpId())) { - conditionalLogger.warn("ExtIgiIgs with absent impId from bidder: " + bidder, logSamplingRate); + final String warning = "ExtIgiIgs with absent impId from bidder: " + bidder; + auctionContext.getDebugWarnings().add(warning); + conditionalLogger.warn(warning, logSamplingRate); continue; } if (extIgiIgs.getConfig() == null) { - conditionalLogger.warn("ExtIgiIgs with absent config from bidder: " + bidder, logSamplingRate); + final String warning = "ExtIgiIgs with absent config from bidder: " + bidder; + auctionContext.getDebugWarnings().add(warning); + conditionalLogger.warn(warning, logSamplingRate); continue; } final ExtIgiIgs preparedExtIgiIgs = extIgiIgs.toBuilder() - .ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(bidder))) + .ext(ExtIgiIgsExt.of(bidder, bidderCatalog.resolveBaseBidder(aliases.resolveBidder(bidder)))) .build(); preparedIgiIgs.add(preparedExtIgiIgs); @@ -928,13 +952,14 @@ private static FledgeAuctionConfig extIgiIgsToFledgeConfig(ExtIgiIgs extIgiIgs) } private Stream toDeprecatedFledgeConfigs(BidderResponseInfo bidderResponseInfo, + BidderAliases aliases, List imps) { return Optional.ofNullable(bidderResponseInfo.getSeatBid().getFledgeAuctionConfigs()) .stream() .flatMap(Collection::stream) .filter(fledgeConfig -> validateFledgeConfig(fledgeConfig, imps)) - .map(fledgeConfig -> fledgeConfigWithBidder(fledgeConfig, bidderResponseInfo.getBidder())); + .map(fledgeConfig -> fledgeConfigWithBidder(fledgeConfig, bidderResponseInfo.getBidder(), aliases)); } private boolean validateFledgeConfig(FledgeAuctionConfig fledgeAuctionConfig, List imps) { @@ -946,10 +971,13 @@ private boolean validateFledgeConfig(FledgeAuctionConfig fledgeAuctionConfig, Li return fledgeEnabled == ExtImpAuctionEnvironment.ON_DEVICE_IG_AUCTION_FLEDGE; } - private FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, String bidder) { + private FledgeAuctionConfig fledgeConfigWithBidder(FledgeAuctionConfig fledgeConfig, + String bidder, + BidderAliases aliases) { + return fledgeConfig.toBuilder() .bidder(bidder) - .adapter(bidderCatalog.resolveBaseBidder(bidder)) + .adapter(bidderCatalog.resolveBaseBidder(aliases.resolveBidder(bidder))) .build(); } @@ -1280,6 +1308,7 @@ private static PaaFormat resolvePaaFormat(AuctionContext auctionContext) { */ private BidResponse toBidResponse(List bidderResponseInfos, AuctionContext auctionContext, + BidderAliases aliases, ExtRequestTargeting targeting, BidRequestCacheInfo requestCacheInfo, CacheServiceResult cacheResult, @@ -1310,6 +1339,7 @@ private BidResponse toBidResponse(List bidderResponseInfos, final ExtBidResponse extBidResponse = toExtBidResponse( bidderResponseInfos, auctionContext, + aliases, cacheResult, videoStoredDataResult, auctionTimestamp, diff --git a/src/main/java/org/prebid/server/auction/ExchangeService.java b/src/main/java/org/prebid/server/auction/ExchangeService.java index 40c8ff86bde..f7b97ca5157 100644 --- a/src/main/java/org/prebid/server/auction/ExchangeService.java +++ b/src/main/java/org/prebid/server/auction/ExchangeService.java @@ -275,7 +275,7 @@ private Future runAuction(AuctionContext receivedContext) { .map(auctionParticipations -> updateResponsesMetrics(auctionParticipations, account, aliases)) .map(context::with)) // produce response from bidder results - .compose(context -> bidResponseCreator.create(context, cacheInfo, bidderToMultiBid) + .compose(context -> bidResponseCreator.create(context, cacheInfo, aliases, bidderToMultiBid) .map(bidResponse -> criteriaLogManager.traceResponse( logger, bidResponse, diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 0b6d4b67b9f..8acd38740c6 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -175,6 +175,7 @@ public class BidResponseCreatorTest extends VertxTest { private static final String IMP_ID = "impId1"; private static final String BID_ADM = "adm"; private static final String BID_NURL = "nurl"; + private static final String PREBID = "prebid"; @Mock private CoreCacheService coreCacheService; @@ -198,6 +199,8 @@ public class BidResponseCreatorTest extends VertxTest { private CacheTtl mediaTypeCacheTtl; @Mock(strictness = LENIENT) private CacheDefaultTtlProperties cacheDefaultProperties; + @Mock(strictness = LENIENT) + private BidderAliases aliases; @Spy private WinningBidComparatorFactory winningBidComparatorFactory; @@ -222,6 +225,8 @@ public void setUp() { given(cacheDefaultProperties.getAudioTtl()).willReturn(null); given(cacheDefaultProperties.getNativeTtl()).willReturn(null); + given(aliases.resolveBidder(any())).willAnswer(request -> request.getArgument(0)); + given(categoryMappingService.createCategoryMapping(any(), any(), any())) .willAnswer(invocationOnMock -> Future.succeededFuture( CategoryMappingResult.of(emptyMap(), emptyMap(), invocationOnMock.getArgument(0), null))); @@ -285,7 +290,7 @@ public void shouldPassBidWithGeneratedIdAndPreserveExtFieldsWhenIdGeneratorTypeU givenCacheServiceResult(singletonList(CacheInfo.empty())); // when - target.create(auctionContext, cacheInfo, MULTI_BIDS); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ExtBidPrebid extBidPrebid = ExtBidPrebid.builder() @@ -320,7 +325,7 @@ public void shouldSkipBidderWhenRejectedByProcessedBidderResponseHooks() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -355,7 +360,7 @@ public void shouldPassRequestModifiedByBidderRequestHooks() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -384,7 +389,7 @@ public void shouldPassOriginalTimeoutToCacheServiceIfCachingIsRequested() { givenCacheServiceResult(singletonList(CacheInfo.empty())); // when - target.create(auctionContext, cacheInfo, MULTI_BIDS); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then verify(coreCacheService).cacheBidsOpenrtb(anyList(), any(), any(), any()); @@ -437,8 +442,7 @@ public void shouldRequestCacheServiceWithExpectedArguments() { givenCacheServiceResult(singletonList(CacheInfo.empty())); // when - target.create(auctionContext, cacheInfo, - MULTI_BIDS); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -500,8 +504,7 @@ imp1, imp2, givenImp("impId3"), givenImp("impId4"))) givenCacheServiceResult(singletonList(CacheInfo.empty())); // when - target.create(auctionContext, cacheInfo, - MULTI_BIDS); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor> bidsArgumentCaptor = ArgumentCaptor.forClass(List.class); @@ -567,7 +570,7 @@ public void shouldRequestCacheServiceWithVideoBidsToModify() { givenCacheServiceResult(singletonList(CacheInfo.empty())); // when - target.create(auctionContext, cacheInfo, MULTI_BIDS); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final EventsContext expectedEventContext = EventsContext.builder() @@ -628,7 +631,7 @@ public void shouldModifyBidAdmWhenBidVideoAndVastModifierReturnValue() { .willReturn(modifiedVast); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -656,7 +659,7 @@ public void shouldCallCacheServiceEvenRoundedCpmIsZero() { givenCacheServiceResult(singletonList(CacheInfo.empty())); // when - target.create(auctionContext, cacheInfo, MULTI_BIDS); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor> bidsArgumentCaptor = ArgumentCaptor.forClass(List.class); @@ -679,7 +682,7 @@ public void shouldSetExpectedConstantResponseFields() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, null, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, null, aliases, MULTI_BIDS).result(); // then final BidResponse responseWithExpectedFields = BidResponse.builder() @@ -706,7 +709,7 @@ public void shouldSetNbrValueTwoAndEmptySeatbidWhenIncomingBidResponsesAreEmpty( final AuctionContext auctionContext = givenAuctionContext(givenBidRequest(givenImp())); // when - final BidResponse bidResponse = target.create(auctionContext, null, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, null, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse).returns(0, BidResponse::getNbr); @@ -724,7 +727,7 @@ public void shouldSetNbrValueTwoAndEmptySeatbidWhenIncomingBidResponsesDoNotCont contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, null, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, null, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse).returns(0, BidResponse::getNbr); @@ -745,7 +748,7 @@ public void shouldSetNbrNullAndPopulateSeatbidWhenAtLeastOneBidIsPresent() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getNbr()).isNull(); @@ -767,7 +770,7 @@ public void shouldSkipBidderResponsesWhereSeatBidContainEmptyBids() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1); @@ -795,7 +798,7 @@ public void shouldOverrideBidIdWhenIdGeneratorIsUUID() { given(idGenerator.generateId()).willReturn("de7fc739-0a6e-41ad-8961-701c30c82166"); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -857,7 +860,7 @@ public void shouldUseGeneratedBidIdForEventAndCacheWhenIdGeneratorIsUUIDAndEvent .willReturn(events); // when - target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ExtBidPrebid extBidPrebid = ExtBidPrebid.builder() @@ -902,7 +905,7 @@ public void shouldSetExpectedResponseSeatBidAndBidFields() { givenCacheServiceResult(emptyList()); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ObjectNode expectedBidExt = mapper.createObjectNode(); @@ -947,7 +950,7 @@ public void shouldUpdateCacheDebugLogWithExtBidResponseWhenEnabledAndBidsReturne .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(auctionContext.getCachedDebugLog().buildCacheBody()) @@ -963,7 +966,7 @@ public void shouldUpdateCacheDebugLogWithExtBidResponseWhenEnabledAndNoBidsRetur contextBuilder -> contextBuilder.cachedDebugLog(new CachedDebugLog(true, 100, null, jacksonMapper))); // when - target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(auctionContext.getCachedDebugLog().buildCacheBody()) @@ -997,7 +1000,7 @@ public void shouldUseBidsReturnedInCategoryMapperResultAndUpdateErrors() { singletonList("Filtered bid 2")))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1023,7 +1026,7 @@ public void shouldThrowExceptionWhenCategoryMappingThrowsPrebidException() { .willReturn(Future.failedFuture(new InvalidRequestException("category exception"))); // when - final Future result = target.create(auctionContext, CACHE_INFO, MULTI_BIDS); + final Future result = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS); // then assertThat(result.failed()).isTrue(); @@ -1059,7 +1062,7 @@ public void shouldNotWriteSkadnAttributeToBidderSection() { givenCacheServiceResult(emptyList()); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ObjectNode expectedBidExt = mapper.createObjectNode(); @@ -1118,7 +1121,7 @@ public void shouldAddTypeToNativeBidAdm() throws JsonProcessingException { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -1179,7 +1182,7 @@ public void shouldReturnEmptyAssetIfImageTypeIsEmpty() throws JsonProcessingExce contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -1234,7 +1237,7 @@ public void shouldReturnEmptyAssetIfNoRelatedNativeAssetFound() throws JsonProce contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -1293,7 +1296,7 @@ public void shouldReturnEmptyAssetIfIdIsNotPresentRelatedNativeAssetFound() thro contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -1351,7 +1354,7 @@ public void shouldReturnEmptyAssetIfDataTypeIsEmpty() throws JsonProcessingExcep contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -1386,7 +1389,7 @@ public void shouldSetBidAdmToNullIfCacheIdIsPresentAndReturnCreativeBidsIsFalse( final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder().doCaching(true).build(); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1416,7 +1419,7 @@ public void shouldSetBidAdmToNullIfVideoCacheIdIsPresentAndReturnCreativeVideoBi givenCacheServiceResult(singletonList(CacheInfo.of("id", null, null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1446,7 +1449,7 @@ public void shouldSetBidExpWhenCacheIdIsMatched() { final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder().doCaching(true).build(); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1476,7 +1479,7 @@ public void shouldSetBidExpMaxTtlWhenCacheIdIsMatchedAndBothTtlIsSet() { final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder().doCaching(true).build(); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1499,7 +1502,7 @@ public void shouldTolerateMissingExtInSeatBidAndBid() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then final ObjectNode expectedBidExt = mapper.createObjectNode(); @@ -1530,7 +1533,7 @@ public void shouldPassPreferDealsToWinningComparatorFactoryWhenBidRequestTrue() contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then verify(winningBidComparatorFactory, times(2)).create(eq(true)); @@ -1550,7 +1553,7 @@ public void shouldPassPreferDealsFalseWhenBidRequestPreferDealsIsNotDefined() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then verify(winningBidComparatorFactory, times(2)).create(eq(false)); @@ -1571,7 +1574,7 @@ public void shouldPopulateTargetingKeywords() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1607,7 +1610,7 @@ public void shouldPopulateTargetingKeywordsForAmpRequest() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1658,7 +1661,7 @@ public void shouldTruncateTargetingKeywordsByGlobalConfig() { cacheDefaultProperties); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1699,7 +1702,7 @@ public void shouldTruncateTargetingKeywordsByAccountConfig() { .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1748,7 +1751,7 @@ public void shouldTruncateTargetingKeywordsByRequestPassedValue() { .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -1793,7 +1796,7 @@ public void shouldReduceAndNotPopulateTargetingKeywordsForExtraBidsWhenCodePrefi contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse result = target.create(auctionContext, CACHE_INFO, multiBidMap).result(); + final BidResponse result = target.create(auctionContext, CACHE_INFO, aliases, multiBidMap).result(); // then assertThat(result.getSeatbid()) @@ -1847,7 +1850,7 @@ public void shouldNotPopulateTargetingKeywordsForExtraBidsWhenCodePrefixIsDefine contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse result = target.create(auctionContext, CACHE_INFO, multiBidMap).result(); + final BidResponse result = target.create(auctionContext, CACHE_INFO, aliases, multiBidMap).result(); final Map expectedWinningBidTargetingMap = new HashMap<>(); expectedWinningBidTargetingMap.put("hb_pb", "4.50"); @@ -1897,7 +1900,7 @@ public void shouldReduceAndPopulateTargetingKeywordsForExtraBidsWhenCodePrefixIs contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse result = target.create(auctionContext, CACHE_INFO, multiBidMap).result(); + final BidResponse result = target.create(auctionContext, CACHE_INFO, aliases, multiBidMap).result(); // then final Map bidder1Bid4Targeting = new HashMap<>(); @@ -1958,7 +1961,7 @@ public void shouldPopulateTargetingKeywordsForWinningBidsAndWinningBidsByBidder( contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -2009,7 +2012,7 @@ public void shouldPopulateTargetingKeywordsFromMediaTypePriceGranularities() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -2045,7 +2048,7 @@ public void shouldPopulateCacheIdHostPathAndUuidTargetingKeywords() { givenCacheServiceResult(singletonList(CacheInfo.of("cacheId", "videoId", null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -2090,7 +2093,7 @@ public void shouldPopulateTargetingKeywordsWithAdditionalValuesFromRequest() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -2123,7 +2126,7 @@ public void shouldPopulateTargetingKeywordsIfBidWasCachedAndAdmWasRemoved() { givenCacheServiceResult(singletonList(CacheInfo.of("cacheId", null, null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // Check if you didn't lost any bids because of bid change in winningBids set // then @@ -2171,7 +2174,7 @@ public void shouldAddExtPrebidEventsIfEventsAreEnabledAndExtRequestPrebidEventPr givenCacheServiceResult(emptyList()); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ArgumentCaptor> bidsArgumentCaptor = ArgumentCaptor.forClass(List.class); @@ -2225,7 +2228,7 @@ public void shouldAddExtPrebidEventsIfEventsAreEnabledAndAccountSupportEventsFor .willReturn(events); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -2275,7 +2278,7 @@ public void shouldAddExtPrebidEventsIfEventsAreEnabledAndDefaultAccountAnalytics .willReturn(events); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -2308,7 +2311,7 @@ public void shouldAddExtPrebidVideoToExtBidPrebidWhenVideoBids() { givenCacheServiceResult(emptyList()); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ArgumentCaptor> bidsArgumentCaptor = ArgumentCaptor.forClass(List.class); @@ -2343,7 +2346,7 @@ public void shouldAddDealTierSatisfiedToExtBidPrebidWhenBidsPrioritySatisfiedMin bidderResponses, emptyList()))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -2379,7 +2382,7 @@ public void shouldNotAddExtPrebidEventsIfEventsAreNotEnabled() { .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -2413,7 +2416,7 @@ public void shouldNotAddExtPrebidEventsIfExtRequestPrebidEventsNull() { .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -2454,7 +2457,7 @@ public void shouldNotAddExtPrebidEventsIfAccountDoesNotSupportEventsForChannel() .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -2486,7 +2489,7 @@ public void shouldReturnCacheEntityInExt() { givenCacheServiceResult(singletonList(CacheInfo.of("cacheId", "videoId", null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -2532,7 +2535,7 @@ public void shouldNotPopulateWinningBidTargetingIfIncludeWinnersFlagIsFalse() { givenCacheServiceResult(singletonList(CacheInfo.of("cacheId", "videoId", null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).flatExtracting(SeatBid::getBid) @@ -2578,7 +2581,7 @@ public void shouldNotPopulateBidderKeysTargetingIfIncludeBidderKeysFlagIsFalse() givenCacheServiceResult(singletonList(CacheInfo.of("cacheId", "videoId", null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).flatExtracting(SeatBid::getBid) @@ -2616,7 +2619,7 @@ public void shouldNotPopulateCacheIdTargetingKeywordsIfBidCpmIsZero() { givenCacheServiceResult(singletonList(CacheInfo.of("cacheId2", null, null, null))); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()).flatExtracting(SeatBid::getBid).hasSize(2) @@ -2653,7 +2656,7 @@ public void shouldNotCacheNonDealBidWithCpmIsZeroAndCacheDealBidWithZeroCpm() { givenCacheServiceResult(singletonList(CacheInfo.of("cacheId2", null, null, null))); // when - target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ArgumentCaptor> bidsArgumentCaptor = ArgumentCaptor.forClass(List.class); @@ -2694,7 +2697,7 @@ public void shouldPopulateBidResponseExtension() { new RuntimeException("cacheError"), emptyMap())); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ExtBidResponse responseExt = bidResponse.getExt(); @@ -2756,7 +2759,7 @@ public void shouldPopulateBidExpBasedOnCachedResult() { given(mediaTypeCacheTtl.getBannerCacheTtl()).willReturn(50); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -2808,7 +2811,7 @@ public void impToStoredVideoJsonShouldTolerateWhenStoredVideoFetchIsFailed() { Future.failedFuture("Fetch failed")); // when - final Future result = target.create(auctionContext, CACHE_INFO, MULTI_BIDS); + final Future result = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS); // then verify(storedRequestProcessor).videoStoredDataResult(any(), eq(singletonList(imp)), anyList(), eq(timeout)); @@ -2865,7 +2868,7 @@ public void impToStoredVideoJsonShouldInjectStoredVideoWhenExtOptionsIsTrueAndVi givenCacheServiceResult(emptyList()); // when - final Future result = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future result = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then verify(storedRequestProcessor).videoStoredDataResult(any(), eq(asList(imp1, imp3)), anyList(), @@ -2910,7 +2913,7 @@ public void impToStoredVideoJsonShouldAddErrorsWithPrebidBidderWhenStoredVideoRe .willReturn(Future.failedFuture("Bad timeout")); // when - final Future result = target.create(auctionContext, CACHE_INFO, MULTI_BIDS); + final Future result = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS); // then verify(storedRequestProcessor).videoStoredDataResult(any(), eq(singletonList(imp1)), anyList(), eq(timeout)); @@ -2949,7 +2952,7 @@ public void shouldProcessRequestAndAddErrorAboutDeprecatedBidder() { "invalid has been deprecated and is no longer available. Use valid instead."); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getExt()).isEqualTo( @@ -2980,7 +2983,7 @@ public void shouldProcessRequestAndAddErrorFromAuctionContext() { .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final Future result = target.create(auctionContext, CACHE_INFO, MULTI_BIDS); + final Future result = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS); // then assertThat(result.result().getExt()).isEqualTo( @@ -3035,7 +3038,7 @@ public void shouldPopulateResponseDebugExtensionAndWarningsIfDebugIsEnabled() { .build())); // when - final BidResponse bidResponse = target.create(auctionContext, cacheInfo, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS).result(); // then final ExtBidResponse responseExt = bidResponse.getExt(); @@ -3097,7 +3100,7 @@ public void shouldPassIntegrationToCacheServiceAndBidEvents() { "http://imp-url?param=value&int=integration")); // when - final Future result = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future result = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then verify(coreCacheService).cacheBidsOpenrtb(anyList(), any(), any(), @@ -3139,7 +3142,7 @@ public void shouldPopulateActivityInfrastructureTraceLogOnSpecifiedTraceLevel() .auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse) @@ -3173,7 +3176,7 @@ public void shouldPopulateBidResponseExtErrorIfImpExtIsInvalid() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getExt().getErrors().get("prebid").getFirst().getMessage()).isEqualTo(errorMessage); @@ -3193,7 +3196,7 @@ public void shouldThrowErrorIfBidIdAndCorrespondingImpIdNotEquals() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final Future bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS); + final Future bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS); // when assertThat(bidResponse.failed()).isTrue(); @@ -3222,7 +3225,7 @@ public void shouldThrowExceptionWhenBidAdmIsParsedButImpNativeNotFound() throws contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getExt()) @@ -3263,7 +3266,7 @@ public void shouldThrowExceptionWhenNativeRequestIsInvalid() throws JsonProcessi contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getExt()) @@ -3302,7 +3305,7 @@ public void shouldPopulateBidAdmIfResponseAssetsIsNull() throws JsonProcessingEx contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse) @@ -3349,7 +3352,7 @@ public void shouldPopulateEventsContextForRequestIfEventsEnabledForRequest() { .willReturn(givenEvents); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -3378,7 +3381,7 @@ public void shouldNotPopulateBidExtTargetingWhenExtRequestTargetingPricegranular contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then final ObjectNode givenDefaultBidExt = @@ -3413,7 +3416,7 @@ public void shouldNotPopulateBidExtTargetingWhenExtRequestTargetingSettingsIsFal contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then final ObjectNode givenDefaultBidExt = @@ -3439,7 +3442,7 @@ public void shouldCopyRequestExtPrebidPassThroughToResponseExtPrebidPassThroughW contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getExt()) @@ -3470,7 +3473,7 @@ public void shouldCopyImpExtPrebidPassThroughToResponseBidExtPrebidPassThroughWh contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -3503,7 +3506,7 @@ public void shouldAddExtPrebidFledgeIfAvailable() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3544,7 +3547,7 @@ public void shouldAddExtIgiIfAvailableAndExtRequestPrebidPaaFormatIsIab() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3586,7 +3589,7 @@ public void shouldAddExtPrebidFledgeIfAvailableAndExtRequestPrebidPaaFormatIsOri // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3635,7 +3638,7 @@ public void shouldAddExtIgiIfAvailableAndExtRequestPrebidPaaFormatIsAbsentAndAcc // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3681,7 +3684,7 @@ public void shouldAddExtPrebidFledgeIfAvailableAndRequestPaaFormatIsAbsentAndAcc // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3726,7 +3729,7 @@ public void shouldDefaultToOriginalPaaFormat() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3771,7 +3774,7 @@ public void shouldDropExtIgiIgbIfAvailableAndExtIgiImpIdIsAbsent() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3787,6 +3790,15 @@ public void shouldDropExtIgiIgbIfAvailableAndExtIgiImpIdIsAbsent() { .ext(ExtIgiIgsExt.of("bidder1", "adapter1")) .build())) .build()); + + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getWarnings) + .extracting(warnings -> warnings.get(PREBID)) + .asList() + .containsExactly( + ExtBidderError.of( + BidderError.Type.generic.getCode(), + "ExtIgi with absent impId from bidder: bidder1")); } @Test @@ -3816,7 +3828,7 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3828,6 +3840,15 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { .impid("impId") .igb(singletonList(ExtIgiIgb.builder().build())) .build()); + + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getWarnings) + .extracting(warnings -> warnings.get(PREBID)) + .asList() + .containsExactly( + ExtBidderError.of( + BidderError.Type.generic.getCode(), + "ExtIgiIgs with absent impId from bidder: bidder1")); } @Test @@ -3857,7 +3878,7 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3869,6 +3890,15 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { .impid("impId") .igb(singletonList(ExtIgiIgb.builder().build())) .build()); + + assertThat(bidResponse.getExt()) + .extracting(ExtBidResponse::getWarnings) + .extracting(warnings -> warnings.get(PREBID)) + .asList() + .containsExactly( + ExtBidderError.of( + BidderError.Type.generic.getCode(), + "ExtIgiIgs with absent config from bidder: bidder1")); } @Test @@ -3896,7 +3926,7 @@ public void shouldDropExtIgiIfAvailableAndExtIgiIgsAndExtIgiIgbAreAbsent() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3927,7 +3957,7 @@ public void shouldAddExtPrebidFledgeIfAvailableEvenIfBidsEmpty() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3960,7 +3990,7 @@ public void shouldDropFledgeResponsesReferencingUnknownImps() { // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -3992,7 +4022,7 @@ public void shouldPopulateExtPrebidSeatNonBidWhenReturnAllBidStatusFlagIsTrue() // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -4027,7 +4057,7 @@ public void shouldNotPopulateExtPrebidSeatNonBidWhenReturnAllBidStatusFlagIsFals // when final BidResponse bidResponse = target - .create(auctionContext, CACHE_INFO, MULTI_BIDS) + .create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS) .result(); // then @@ -4069,7 +4099,7 @@ public void shouldPopulateBidExtWhenExtMediaTypePriceGranularityHasValidVideoExt contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -4112,7 +4142,7 @@ public void shouldPopulateBidExtWhenExtMediaTypePriceGranularityHasValidxNativeE context -> context.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -4158,7 +4188,7 @@ public void shouldThrowErrorIfExtMediaTypePriceGranularityCannotBeParsed() { contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final Future bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS); + final Future bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS); // then assertThat(bidResponse.failed()).isTrue(); @@ -4183,7 +4213,7 @@ public void shouldPopulateTargetingKeywordsWithDefaultPrefixAndRelatedWarning() contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); // when - final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, MULTI_BIDS).result(); + final BidResponse bidResponse = target.create(auctionContext, CACHE_INFO, aliases, MULTI_BIDS).result(); // then assertThat(bidResponse.getSeatbid()) @@ -4247,7 +4277,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromBid() { given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4316,7 +4346,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromImp() { given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4385,7 +4415,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromRequest() { given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4454,7 +4484,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromAccountBanne given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4523,7 +4553,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromAccountVideo given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4592,7 +4622,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromMediaTypeTtl given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4661,7 +4691,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetTtlFromMediaTypeTtl given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4730,7 +4760,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetDefaultTtlForBanner given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4799,7 +4829,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetDefaultTtlForVideoB given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4868,7 +4898,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetDefaultTtlForAudioB given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4937,7 +4967,7 @@ public void createShouldSendCacheRequestWithExpectedTtlAndSetDefaultTtlForNative given(cacheDefaultProperties.getNativeTtl()).willReturn(63); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -4996,7 +5026,7 @@ public void createShouldSendCacheRequestWithTtlFromMediaTypeWhenAccountIsEmpty() given(mediaTypeCacheTtl.getBannerCacheTtl()).willReturn(50); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -5054,7 +5084,7 @@ public void createShouldSendCacheRequestWithNoTtlAndSetEmptyTtl() { given(mediaTypeCacheTtl.getBannerCacheTtl()).willReturn(null); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(CacheContext.class); @@ -5112,7 +5142,7 @@ public void createShouldSendCacheRequestWithVideoBidWithTtlMaxOfTtlAndVideoTtl() given(mediaTypeCacheTtl.getBannerCacheTtl()).willReturn(null); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then assertThat(response.succeeded()).isTrue(); @@ -5171,7 +5201,7 @@ public void createShouldSendCacheRequestWithBannerBidWithTtlMaxOfTtlAndVideoTtl( given(mediaTypeCacheTtl.getBannerCacheTtl()).willReturn(null); // when - final Future response = target.create(auctionContext, cacheInfo, MULTI_BIDS); + final Future response = target.create(auctionContext, cacheInfo, aliases, MULTI_BIDS); // then assertThat(response.succeeded()).isTrue(); @@ -5262,7 +5292,7 @@ private AuctionContext givenAuctionContext(BidRequest bidRequest, .timeoutContext(TimeoutContext.of(0, timeout, 0)) .debugContext(DebugContext.empty()) .debugHttpCalls(new HashMap<>()) - .debugWarnings(emptyList()) + .debugWarnings(new ArrayList<>()) .auctionParticipations(emptyList()) .bidRejectionTrackers(new HashMap<>()) .prebidErrors(new ArrayList<>()); diff --git a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java index 11346bc5957..fbff0d9fd0c 100644 --- a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java +++ b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java @@ -287,7 +287,7 @@ public class ExchangeServiceTest extends VertxTest { @SuppressWarnings("unchecked") @BeforeEach public void setUp() { - given(bidResponseCreator.create(any(), any(), any())) + given(bidResponseCreator.create(any(), any(), any(), any())) .willReturn(Future.succeededFuture(givenBidResponseWithBids(singletonList(givenBid(identity()))))); given(bidderCatalog.isValidName(anyString())).willReturn(true); @@ -1269,7 +1269,7 @@ public void shouldReturnSeparateSeatBidsForTheSameBidderIfBiddersAliasAndBidderW .auctiontimestamp(1000L) .build()))); - given(bidResponseCreator.create(any(), any(), any())) + given(bidResponseCreator.create(any(), any(), any(), any())) .willReturn(Future.succeededFuture(BidResponse.builder() .seatbid(asList( givenSeatBid(singletonList(givenBid(identity())), identity()), @@ -1350,7 +1350,7 @@ public void shouldOverrideDebugEnabledFlag() { .httpCalls(singletonList(ExtHttpCall.builder().build())) .build())); - given(bidResponseCreator.create(any(), any(), any())) + given(bidResponseCreator.create(any(), any(), any(), any())) .willReturn(Future.succeededFuture( BidResponse.builder() .ext(ExtBidResponse.builder() @@ -1365,7 +1365,7 @@ public void shouldOverrideDebugEnabledFlag() { verify(httpBidderRequester).requestBids(any(), any(), any(), any(), any(), any(), eq(true)); final ArgumentCaptor captor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(captor.capture(), any(), anyMap()); + verify(bidResponseCreator).create(captor.capture(), any(), any(), anyMap()); assertThat(captor.getValue().getDebugContext()).isEqualTo(DebugContext.of(true, true, null)); assertThat(result.getBidResponse().getExt().getDebug()).isNotNull(); @@ -1380,7 +1380,7 @@ public void shouldAddDebugInfoIfDebugEnabledAndPublisherAndBidderAllowedDebug() given(httpBidderRequester.requestBids(any(), any(), any(), any(), any(), any(), eq(true))) .willReturn(Future.succeededFuture(bidderSeatBid)); - given(bidResponseCreator.create(any(), any(), any())) + given(bidResponseCreator.create(any(), any(), any(), any())) .willReturn(Future.succeededFuture( BidResponse.builder() .ext(ExtBidResponse.builder() @@ -1402,7 +1402,7 @@ public void shouldAddDebugInfoIfDebugEnabledAndPublisherAndBidderAllowedDebug() verify(httpBidderRequester).requestBids(any(), any(), any(), any(), any(), any(), eq(true)); final ArgumentCaptor captor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(captor.capture(), any(), anyMap()); + verify(bidResponseCreator).create(captor.capture(), any(), any(), anyMap()); assertThat(captor.getValue().getDebugContext()) .isEqualTo(DebugContext.of(true, true, null)); @@ -1423,7 +1423,7 @@ public void shouldNotAddDebugInfoIfPublisherIsNotAllowedToDebug() { given(debugResolver.resolveDebugForBidder(any(), eq("bidder"))) .willReturn(false); - given(bidResponseCreator.create(any(), any(), any())).willReturn( + given(bidResponseCreator.create(any(), any(), any(), any())).willReturn( Future.succeededFuture(BidResponse.builder().ext(ExtBidResponse.builder().build()).build())); // when @@ -1433,7 +1433,7 @@ public void shouldNotAddDebugInfoIfPublisherIsNotAllowedToDebug() { verify(httpBidderRequester).requestBids(any(), any(), any(), any(), any(), any(), eq(false)); final ArgumentCaptor captor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(captor.capture(), any(), anyMap()); + verify(bidResponseCreator).create(captor.capture(), any(), any(), anyMap()); assertThat(captor.getValue().getDebugContext()).isEqualTo( DebugContext.of(false, false, null)); @@ -1454,7 +1454,7 @@ public void shouldNotAddDebugInfoIfBidderDisabledDebug() { given(debugResolver.resolveDebugForBidder(any(), eq("bidder"))) .willReturn(false); - given(bidResponseCreator.create(any(), any(), any())).willReturn( + given(bidResponseCreator.create(any(), any(), any(), any())).willReturn( Future.succeededFuture(BidResponse.builder().ext(ExtBidResponse.builder().build()).build())); // when @@ -1464,7 +1464,7 @@ public void shouldNotAddDebugInfoIfBidderDisabledDebug() { verify(httpBidderRequester).requestBids(any(), any(), any(), any(), any(), any(), eq(false)); final ArgumentCaptor captor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(captor.capture(), any(), anyMap()); + verify(bidResponseCreator).create(captor.capture(), any(), any(), anyMap()); assertThat(captor.getValue().getDebugContext()).isEqualTo( DebugContext.of(true, true, null)); @@ -1543,7 +1543,7 @@ public void shouldCallBidResponseCreatorWithExpectedParamsAndUpdateDebugErrors() final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(AuctionContext.class); verify(bidResponseCreator) - .create(contextArgumentCaptor.capture(), eq(expectedCacheInfo), eq(expectedMultiBidMap)); + .create(contextArgumentCaptor.capture(), eq(expectedCacheInfo), any(), eq(expectedMultiBidMap)); final Bid expectedThirdBid = Bid.builder() .id("bidId3") @@ -1610,6 +1610,7 @@ public void shouldCallBidResponseCreatorWithWinningOnlyTrueWhenIncludeBidderKeys verify(bidResponseCreator).create( auctionContextArgumentCaptor.capture(), eq(BidRequestCacheInfo.builder().doCaching(true).shouldCacheWinningBidsOnly(true).build()), + any(), eq(emptyMap())); assertThat(singletonList(auctionContextArgumentCaptor.getValue().getBidRequest())) @@ -1644,7 +1645,7 @@ public void shouldCallBidResponseCreatorWithWinningOnlyFalseWhenWinningOnlyIsNul target.holdAuction(givenRequestContext(bidRequest)); // then - verify(bidResponseCreator).create(any(), eq(BidRequestCacheInfo.builder().build()), eq(emptyMap())); + verify(bidResponseCreator).create(any(), eq(BidRequestCacheInfo.builder().build()), any(), eq(emptyMap())); } @Test @@ -3742,7 +3743,7 @@ public void shouldReduceBidsHavingDealIdWithSameImpIdByBidderWithToleratingNotOb // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any()); + verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any(), any()); assertThat(contextArgumentCaptor.getValue().getAuctionParticipations()).hasSize(1) .extracting(AuctionParticipation::getBidderResponse) .extracting(BidderResponse::getSeatBid) @@ -3774,7 +3775,7 @@ public void shouldReduceBidsHavingDealIdWithSameImpIdByBidderWithToleratingNotOb // then final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any()); + verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any(), any()); assertThat(contextArgumentCaptor.getValue().getAuctionParticipations()).hasSize(1) .extracting(AuctionParticipation::getBidderResponse) @@ -3803,6 +3804,7 @@ public void shouldResponseWithEmptySeatBidIfBidderNotSupportProvidedMediaTypes() .build(), 0))), any(), + any(), any())) .willReturn(Future.succeededFuture(BidResponse.builder().id("uniqId").build())); @@ -3855,6 +3857,7 @@ public void shouldResponseWithEmptySeatBidIfBidderNotSupportRequestCurrency() { .build(), 0))), any(), + any(), any())) .willReturn(Future.succeededFuture(BidResponse.builder().id("uniqId").build())); @@ -4076,7 +4079,7 @@ private BidRequest captureBidRequest() { private List captureAuctionParticipations() { final ArgumentCaptor contextArgumentCaptor = ArgumentCaptor.forClass(AuctionContext.class); - verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any()); + verify(bidResponseCreator).create(contextArgumentCaptor.capture(), any(), any(), any()); return contextArgumentCaptor.getValue().getAuctionParticipations(); } @@ -4187,12 +4190,12 @@ private static ExtRequestTargeting givenTargeting(boolean includebidderkeys) { } private void givenBidResponseCreator(List bids) { - given(bidResponseCreator.create(any(), any(), any())) + given(bidResponseCreator.create(any(), any(), any(), any())) .willReturn(Future.succeededFuture(givenBidResponseWithBids(bids))); } private void givenBidResponseCreator(Map> errors) { - given(bidResponseCreator.create(any(), any(), any())) + given(bidResponseCreator.create(any(), any(), any(), any())) .willReturn(Future.succeededFuture(givenBidResponseWithError(errors))); } From c466359ee4c6fc5f599fddaf4a1474d936c98821 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 24 Jan 2025 16:56:54 +0200 Subject: [PATCH 21/24] Refactored ImpAdjuster. --- src/main/java/org/prebid/server/auction/ImpAdjuster.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/ImpAdjuster.java b/src/main/java/org/prebid/server/auction/ImpAdjuster.java index 6b03d006079..26cbee95358 100644 --- a/src/main/java/org/prebid/server/auction/ImpAdjuster.java +++ b/src/main/java/org/prebid/server/auction/ImpAdjuster.java @@ -7,14 +7,13 @@ import com.iab.openrtb.request.Imp; import org.prebid.server.json.JacksonMapper; import org.prebid.server.json.JsonMerger; +import org.prebid.server.util.StreamUtil; import org.prebid.server.validation.ImpValidator; -import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Optional; -import java.util.stream.StreamSupport; public class ImpAdjuster { @@ -83,9 +82,8 @@ private void setAeParams(ObjectNode ext) { final boolean extIgsAePresent = Optional.ofNullable(ext) .map(extNode -> extNode.get(EXT_IGS)) .filter(JsonNode::isArray) - .map(extNode -> StreamSupport.stream(extNode.spliterator(), false).toList()) .stream() - .flatMap(Collection::stream) + .flatMap(extNode -> StreamUtil.asStream(extNode.spliterator())) .filter(Objects::nonNull) .anyMatch(igsElementNode -> igsElementNode.has(EXT_AE)); From ce1d57f94013221ab7a03252cdd5bbcc7c6e62ed Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Fri, 24 Jan 2025 17:14:25 +0200 Subject: [PATCH 22/24] Now paa debug warnings utilize debugEnabled flag. --- .../server/auction/BidResponseCreator.java | 13 ++++++++++--- .../server/auction/BidResponseCreatorTest.java | 16 ++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 0b4dd4fea30..583ffb9a938 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -882,7 +882,9 @@ private ExtIgi prepareExtIgi(ExtIgi igi, String bidder, AuctionContext auctionCo final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); if (shouldDropIgb) { final String warning = "ExtIgi with absent impId from bidder: " + bidder; - auctionContext.getDebugWarnings().add(warning); + if (auctionContext.getDebugContext().isDebugEnabled()) { + auctionContext.getDebugWarnings().add(warning); + } conditionalLogger.warn(warning, logSamplingRate); } @@ -904,6 +906,7 @@ private List prepareExtIgiIgs(List igiIgs, return Collections.emptyList(); } + final boolean debugEnabled = auctionContext.getDebugContext().isDebugEnabled(); final List preparedIgiIgs = new ArrayList<>(); for (ExtIgiIgs extIgiIgs : igiIgs) { if (extIgiIgs == null) { @@ -912,14 +915,18 @@ private List prepareExtIgiIgs(List igiIgs, if (StringUtils.isEmpty(extIgiIgs.getImpId())) { final String warning = "ExtIgiIgs with absent impId from bidder: " + bidder; - auctionContext.getDebugWarnings().add(warning); + if (debugEnabled) { + auctionContext.getDebugWarnings().add(warning); + } conditionalLogger.warn(warning, logSamplingRate); continue; } if (extIgiIgs.getConfig() == null) { final String warning = "ExtIgiIgs with absent config from bidder: " + bidder; - auctionContext.getDebugWarnings().add(warning); + if (debugEnabled) { + auctionContext.getDebugWarnings().add(warning); + } conditionalLogger.warn(warning, logSamplingRate); continue; } diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 8acd38740c6..f0848b65c55 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -3770,7 +3770,9 @@ public void shouldDropExtIgiIgbIfAvailableAndExtIgiImpIdIsAbsent() { final AuctionContext auctionContext = givenAuctionContext( bidRequest, - contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + contextBuilder -> contextBuilder + .debugContext(DebugContext.of(true, false, null)) + .auctionParticipations(toAuctionParticipant(bidderResponses))); // when final BidResponse bidResponse = target @@ -3824,7 +3826,9 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { final AuctionContext auctionContext = givenAuctionContext( bidRequest, - contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + contextBuilder -> contextBuilder + .debugContext(DebugContext.of(true, false, null)) + .auctionParticipations(toAuctionParticipant(bidderResponses))); // when final BidResponse bidResponse = target @@ -3874,7 +3878,9 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { final AuctionContext auctionContext = givenAuctionContext( bidRequest, - contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + contextBuilder -> contextBuilder + .debugContext(DebugContext.of(true, false, null)) + .auctionParticipations(toAuctionParticipant(bidderResponses))); // when final BidResponse bidResponse = target @@ -3922,7 +3928,9 @@ public void shouldDropExtIgiIfAvailableAndExtIgiIgsAndExtIgiIgbAreAbsent() { final AuctionContext auctionContext = givenAuctionContext( bidRequest, - contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses))); + contextBuilder -> contextBuilder + .debugContext(DebugContext.of(true, false, null)) + .auctionParticipations(toAuctionParticipant(bidderResponses))); // when final BidResponse bidResponse = target From d16a64bf854141b962ea5e1c9d48cf8da8c3b1a1 Mon Sep 17 00:00:00 2001 From: Alex Maltsev Date: Mon, 27 Jan 2025 13:20:56 +0200 Subject: [PATCH 23/24] Added metrics. --- .../org/prebid/server/auction/BidResponseCreator.java | 10 +++++++++- .../server/spring/config/ServiceConfiguration.java | 2 ++ .../prebid/server/auction/BidResponseCreatorTest.java | 9 +++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 583ffb9a938..4242281a5dd 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -65,6 +65,8 @@ import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; +import org.prebid.server.metric.MetricName; +import org.prebid.server.metric.Metrics; import org.prebid.server.proto.openrtb.ext.request.ExtImp; import org.prebid.server.proto.openrtb.ext.request.ExtImpAuctionEnvironment; import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid; @@ -151,6 +153,7 @@ public class BidResponseCreator { private final int truncateAttrChars; private final Clock clock; private final JacksonMapper mapper; + private final Metrics metrics; private final CacheTtl mediaTypeCacheTtl; private final CacheDefaultTtlProperties cacheDefaultProperties; @@ -171,6 +174,7 @@ public BidResponseCreator(double logSamplingRate, int truncateAttrChars, Clock clock, JacksonMapper mapper, + Metrics metrics, CacheTtl mediaTypeCacheTtl, CacheDefaultTtlProperties cacheDefaultProperties) { @@ -188,6 +192,7 @@ public BidResponseCreator(double logSamplingRate, this.mapper = Objects.requireNonNull(mapper); this.mediaTypeCacheTtl = Objects.requireNonNull(mediaTypeCacheTtl); this.cacheDefaultProperties = Objects.requireNonNull(cacheDefaultProperties); + this.metrics = Objects.requireNonNull(metrics); this.logSamplingRate = logSamplingRate; @@ -879,13 +884,14 @@ private ExtIgi prepareExtIgi(ExtIgi igi, String bidder, AuctionContext auctionCo return null; } - final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()); + final boolean shouldDropIgb = StringUtils.isEmpty(igi.getImpid()) && CollectionUtils.isNotEmpty(igi.getIgb()); if (shouldDropIgb) { final String warning = "ExtIgi with absent impId from bidder: " + bidder; if (auctionContext.getDebugContext().isDebugEnabled()) { auctionContext.getDebugWarnings().add(warning); } conditionalLogger.warn(warning, logSamplingRate); + metrics.updateAlertsMetrics(MetricName.general); } final List updatedIgs = prepareExtIgiIgs(igi.getIgs(), bidder, auctionContext, aliases); @@ -919,6 +925,7 @@ private List prepareExtIgiIgs(List igiIgs, auctionContext.getDebugWarnings().add(warning); } conditionalLogger.warn(warning, logSamplingRate); + metrics.updateAlertsMetrics(MetricName.general); continue; } @@ -928,6 +935,7 @@ private List prepareExtIgiIgs(List igiIgs, auctionContext.getDebugWarnings().add(warning); } conditionalLogger.warn(warning, logSamplingRate); + metrics.updateAlertsMetrics(MetricName.general); continue; } 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 fa7cc267457..bc7352f5a51 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -820,6 +820,7 @@ BidResponseCreator bidResponseCreator( @Value("${settings.targeting.truncate-attr-chars}") int truncateAttrChars, Clock clock, JacksonMapper mapper, + Metrics metrics, @Value("${cache.banner-ttl-seconds:#{null}}") Integer bannerCacheTtl, @Value("${cache.video-ttl-seconds:#{null}}") Integer videoCacheTtl, CacheDefaultTtlProperties cacheDefaultTtlProperties) { @@ -838,6 +839,7 @@ BidResponseCreator bidResponseCreator( truncateAttrChars, clock, mapper, + metrics, CacheTtl.of(bannerCacheTtl, videoCacheTtl), cacheDefaultTtlProperties); } diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index f0848b65c55..04b7d279956 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -69,6 +69,8 @@ import org.prebid.server.hooks.execution.v1.bidder.BidderResponsePayloadImpl; import org.prebid.server.identity.IdGenerator; import org.prebid.server.identity.IdGeneratorType; +import org.prebid.server.metric.MetricName; +import org.prebid.server.metric.Metrics; import org.prebid.server.proto.openrtb.ext.ExtIncludeBrandCategory; import org.prebid.server.proto.openrtb.ext.request.ExtDeal; import org.prebid.server.proto.openrtb.ext.request.ExtDealLine; @@ -201,6 +203,8 @@ public class BidResponseCreatorTest extends VertxTest { private CacheDefaultTtlProperties cacheDefaultProperties; @Mock(strictness = LENIENT) private BidderAliases aliases; + @Mock(strictness = LENIENT) + private Metrics metrics; @Spy private WinningBidComparatorFactory winningBidComparatorFactory; @@ -1657,6 +1661,7 @@ public void shouldTruncateTargetingKeywordsByGlobalConfig() { 20, clock, jacksonMapper, + metrics, mediaTypeCacheTtl, cacheDefaultProperties); @@ -3801,6 +3806,7 @@ public void shouldDropExtIgiIgbIfAvailableAndExtIgiImpIdIsAbsent() { ExtBidderError.of( BidderError.Type.generic.getCode(), "ExtIgi with absent impId from bidder: bidder1")); + verify(metrics).updateAlertsMetrics(MetricName.general); } @Test @@ -3853,6 +3859,7 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsImpIdIsAbsent() { ExtBidderError.of( BidderError.Type.generic.getCode(), "ExtIgiIgs with absent impId from bidder: bidder1")); + verify(metrics).updateAlertsMetrics(MetricName.general); } @Test @@ -3905,6 +3912,7 @@ public void shouldDropExtIgiIgsIfAvailableAndExtIgiIgsConfigIsAbsent() { ExtBidderError.of( BidderError.Type.generic.getCode(), "ExtIgiIgs with absent config from bidder: bidder1")); + verify(metrics).updateAlertsMetrics(MetricName.general); } @Test @@ -5469,6 +5477,7 @@ private BidResponseCreator givenBidResponseCreator(int truncateAttrChars) { truncateAttrChars, clock, jacksonMapper, + metrics, mediaTypeCacheTtl, cacheDefaultProperties); } From 7ea648e3b65f0ec517d8e153695358c5ed4c1d16 Mon Sep 17 00:00:00 2001 From: Markiyan Mykush <95693607+marki1an@users.noreply.github.com> Date: Mon, 27 Jan 2025 15:40:00 +0200 Subject: [PATCH 24/24] Test: `Transition PAAPI parameters` (#3634) * Add functional tests for Transition PAAPI parameters to updated IAB conventions. --- .../functional/model/bidder/BidderName.groovy | 1 + .../model/config/AccountAuctionConfig.groovy | 2 + .../request/auction/AuctionEnvironment.groovy | 19 + .../model/request/auction/Bidder.groovy | 2 + .../model/request/auction/ImpExt.groovy | 5 +- .../InterestGroupAuctionSupport.groovy | 11 + .../model/request/auction/PaaFormat.groovy | 13 + .../model/request/auction/Prebid.groovy | 1 + .../response/auction/BidResponseExt.groovy | 3 + .../auction/InterestGroupAuctionBuyer.groovy | 17 + .../InterestGroupAuctionBuyerExt.groovy | 10 + .../auction/InterestGroupAuctionIntent.groovy | 18 + .../InterestGroupAuctionIntentExt.groovy | 11 + .../auction/InterestGroupAuctionSeller.groovy | 14 + .../InterestGroupAuctionSellerExt.groovy | 10 + .../response/auction/OpenxBidResponse.groovy | 1 - .../functional/tests/BidderParamsSpec.groovy | 78 ++- .../tests/bidder/openx/OpenxSpec.groovy | 450 +++++++++++++++++- 18 files changed, 652 insertions(+), 14 deletions(-) create mode 100644 src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/request/auction/InterestGroupAuctionSupport.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/request/auction/PaaFormat.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyer.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyerExt.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntent.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntentExt.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSeller.groovy create mode 100644 src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSellerExt.groovy diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy index 352080844ab..54e0a451fc6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy @@ -18,6 +18,7 @@ enum BidderName { APPNEXUS("appnexus"), RUBICON_ALIAS("rubiconAlias"), OPENX("openx"), + OPENX_ALIAS("openxalias"), ACEEX("aceex"), ACUITYADS("acuityads"), AAX("aax"), diff --git a/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy b/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy index 4e423c03312..8dc9831e3fa 100644 --- a/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/config/AccountAuctionConfig.groovy @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming import groovy.transform.ToString import org.prebid.server.functional.model.bidder.BidderName import org.prebid.server.functional.model.request.auction.BidAdjustment +import org.prebid.server.functional.model.request.auction.PaaFormat import org.prebid.server.functional.model.request.auction.Targeting import org.prebid.server.functional.model.response.auction.MediaType @@ -23,6 +24,7 @@ class AccountAuctionConfig { AccountEventsConfig events AccountPriceFloorsConfig priceFloors Targeting targeting + PaaFormat paaformat @JsonProperty("preferredmediatype") Map preferredMediaType @JsonProperty("privacysandbox") diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy new file mode 100644 index 00000000000..f880b7bc634 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy @@ -0,0 +1,19 @@ +package org.prebid.server.functional.model.request.auction + +import com.fasterxml.jackson.annotation.JsonValue +import org.prebid.server.functional.util.PBSUtils + +enum AuctionEnvironment { + + NOT_SUPPORTED(0), + DEVICE_ORCHESTRATED(1), + SERVER_ORCHESTRATED(3), + UNKNOWN(Integer.MAX_VALUE), + + @JsonValue + private int value + + AuctionEnvironment(Integer value) { + this.value = value + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy index 605f286c803..05a43bbb528 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Bidder.groovy @@ -22,6 +22,8 @@ class Bidder { AppNexus appNexus Openx openx Ix ix + @JsonProperty("openxalias") + Openx openxAlias static Bidder getDefaultBidder() { new Bidder().tap { diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy index e817a4540a0..55c626d7bd6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy @@ -23,10 +23,13 @@ class ImpExt { String tid String gpid String sid - Integer ae + @JsonProperty("ae") + AuctionEnvironment auctionEnvironment String all String skadn String general + @JsonProperty("igs") + List interestGroupAuctionSupports AnyUnsupportedBidder anyUnsupportedBidder static ImpExt getDefaultImpExt() { diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/InterestGroupAuctionSupport.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/InterestGroupAuctionSupport.groovy new file mode 100644 index 00000000000..31d3628587d --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/InterestGroupAuctionSupport.groovy @@ -0,0 +1,11 @@ +package org.prebid.server.functional.model.request.auction + +import com.fasterxml.jackson.annotation.JsonProperty +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class InterestGroupAuctionSupport { + + @JsonProperty("ae") + AuctionEnvironment auctionEnvironment +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/PaaFormat.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/PaaFormat.groovy new file mode 100644 index 00000000000..79f41e953fe --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/PaaFormat.groovy @@ -0,0 +1,13 @@ +package org.prebid.server.functional.model.request.auction + +import com.fasterxml.jackson.annotation.JsonValue + +enum PaaFormat { + + ORIGINAL, IAB, INVALID + + @JsonValue + String getValue() { + name().toLowerCase() + } +} diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy index ba89f5680fa..0e021bb4598 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/Prebid.groovy @@ -40,6 +40,7 @@ class Prebid { PrebidModulesConfig modules PrebidAnalytics analytics StoredAuctionResponse storedAuctionResponse + PaaFormat paaFormat static class Channel { diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/BidResponseExt.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/BidResponseExt.groovy index 3ccb3384e89..d1d282d663a 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/BidResponseExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/BidResponseExt.groovy @@ -1,5 +1,6 @@ package org.prebid.server.functional.model.response.auction +import com.fasterxml.jackson.annotation.JsonProperty import groovy.transform.ToString import org.prebid.server.functional.model.response.BidderError import org.prebid.server.functional.model.response.Debug @@ -15,4 +16,6 @@ class BidResponseExt { Map usersync BidResponsePrebid prebid Map> warnings + @JsonProperty("igi") + List interestGroupAuctionIntent } diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyer.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyer.groovy new file mode 100644 index 00000000000..b8d1bf80d38 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyer.groovy @@ -0,0 +1,17 @@ +package org.prebid.server.functional.model.response.auction + +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import groovy.transform.ToString +import org.prebid.server.functional.model.Currency + +@ToString(includeNames = true, ignoreNulls = true) +@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) +class InterestGroupAuctionBuyer { + + String origin + BigDecimal maxBid + Currency cur + Map pbs + InterestGroupAuctionBuyerExt ext +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyerExt.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyerExt.groovy new file mode 100644 index 00000000000..4404491246c --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionBuyerExt.groovy @@ -0,0 +1,10 @@ +package org.prebid.server.functional.model.response.auction + +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class InterestGroupAuctionBuyerExt { + + String bidder + String adapter +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntent.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntent.groovy new file mode 100644 index 00000000000..29ff15d4eeb --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntent.groovy @@ -0,0 +1,18 @@ +package org.prebid.server.functional.model.response.auction + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) +class InterestGroupAuctionIntent { + + String impId + @JsonProperty("igb") + List interestGroupAuctionBuyer + @JsonProperty("igs") + List interestGroupAuctionSeller + InterestGroupAuctionIntentExt ext +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntentExt.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntentExt.groovy new file mode 100644 index 00000000000..29aeaf980da --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionIntentExt.groovy @@ -0,0 +1,11 @@ +package org.prebid.server.functional.model.response.auction + +import groovy.transform.ToString +import org.prebid.server.functional.model.bidder.BidderName + +@ToString(includeNames = true, ignoreNulls = true) +class InterestGroupAuctionIntentExt { + + BidderName bidder + BidderName adapter +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSeller.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSeller.groovy new file mode 100644 index 00000000000..192f5c2f611 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSeller.groovy @@ -0,0 +1,14 @@ +package org.prebid.server.functional.model.response.auction + +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +@JsonNaming(PropertyNamingStrategies.LowerCaseStrategy) +class InterestGroupAuctionSeller { + + String impId + Map config + InterestGroupAuctionSellerExt ext +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSellerExt.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSellerExt.groovy new file mode 100644 index 00000000000..fcecf1b5480 --- /dev/null +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/InterestGroupAuctionSellerExt.groovy @@ -0,0 +1,10 @@ +package org.prebid.server.functional.model.response.auction + +import groovy.transform.ToString + +@ToString(includeNames = true, ignoreNulls = true) +class InterestGroupAuctionSellerExt { + + String bidder + String adapter +} diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/OpenxBidResponse.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/OpenxBidResponse.groovy index 2ba60b226c1..b5d5289d5a6 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/OpenxBidResponse.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/OpenxBidResponse.groovy @@ -1,6 +1,5 @@ package org.prebid.server.functional.model.response.auction - import groovy.transform.ToString import org.prebid.server.functional.model.request.auction.BidRequest diff --git a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy index cab50bd816b..61774594b1f 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BidderParamsSpec.groovy @@ -6,6 +6,7 @@ import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.db.StoredImp import org.prebid.server.functional.model.db.StoredRequest import org.prebid.server.functional.model.request.amp.AmpRequest +import org.prebid.server.functional.model.request.auction.AuctionEnvironment import org.prebid.server.functional.model.request.auction.Banner import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Device @@ -15,6 +16,7 @@ import org.prebid.server.functional.model.request.auction.Imp import org.prebid.server.functional.model.request.auction.ImpExt import org.prebid.server.functional.model.request.auction.ImpExtContext import org.prebid.server.functional.model.request.auction.ImpExtContextData +import org.prebid.server.functional.model.request.auction.InterestGroupAuctionSupport import org.prebid.server.functional.model.request.auction.Native import org.prebid.server.functional.model.request.auction.PrebidStoredRequest import org.prebid.server.functional.model.request.auction.Site @@ -34,6 +36,10 @@ import static org.prebid.server.functional.model.bidder.BidderName.APPNEXUS import static org.prebid.server.functional.model.bidder.CompressionType.GZIP import static org.prebid.server.functional.model.bidder.CompressionType.NONE import static org.prebid.server.functional.model.request.auction.Asset.titleAsset +import static org.prebid.server.functional.model.request.auction.AuctionEnvironment.DEVICE_ORCHESTRATED +import static org.prebid.server.functional.model.request.auction.AuctionEnvironment.NOT_SUPPORTED +import static org.prebid.server.functional.model.request.auction.AuctionEnvironment.SERVER_ORCHESTRATED +import static org.prebid.server.functional.model.request.auction.AuctionEnvironment.UNKNOWN import static org.prebid.server.functional.model.request.auction.DistributionChannel.APP import static org.prebid.server.functional.model.request.auction.DistributionChannel.DOOH import static org.prebid.server.functional.model.request.auction.DistributionChannel.SITE @@ -781,7 +787,7 @@ class BidderParamsSpec extends BaseSpec { def impExt = ImpExt.getDefaultImpExt().tap { prebid.bidder.generic = null generic = new Generic() - ae = PBSUtils.randomNumber + auctionEnvironment = PBSUtils.getRandomEnum(AuctionEnvironment) all = PBSUtils.randomNumber context = new ImpExtContext(data: new ImpExtContextData()) data = new ImpExtContextData(pbAdSlot: PBSUtils.randomString) @@ -801,7 +807,7 @@ class BidderParamsSpec extends BaseSpec { def bidderRequest = bidder.getBidderRequest(bidRequest.id) verifyAll(bidderRequest.imp[0].ext) { bidder == impExt.generic - ae == impExt.ae + auctionEnvironment == impExt.auctionEnvironment all == impExt.all context == impExt.context data == impExt.data @@ -847,7 +853,7 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted not specified"() { given: "PBS with adapter configuration" def pbsService = pbsServiceFactory.getService( - "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.enabled": "true", "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "") @@ -955,7 +961,7 @@ class BidderParamsSpec extends BaseSpec { def "PBS should send request to bidder when adapters.bidder.aliases.bidder.meta-info.currency-accepted intersect with requested currency"() { given: "PBS with adapter configuration" def pbsService = pbsServiceFactory.getService( - "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.enabled": "true", "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "${USD},${EUR}".toString()) @@ -996,7 +1002,7 @@ class BidderParamsSpec extends BaseSpec { def "PBS shouldn't send request to bidder and emit warning when adapters.bidder.aliases.bidder.meta-info.currency-accepted not intersect with requested currency"() { given: "PBS with adapter configuration" def pbsService = pbsServiceFactory.getService( - "adapters.generic.aliases.alias.enabled" : "true", + "adapters.generic.aliases.alias.enabled": "true", "adapters.generic.aliases.alias.endpoint": "$networkServiceContainer.rootUri/auction".toString(), "adapters.generic.aliases.alias.meta-info.currency-accepted": "${JPY},${CHF}".toString()) @@ -1040,4 +1046,66 @@ class BidderParamsSpec extends BaseSpec { assert seatNonBid.nonBid[0].impId == bidRequest.imp[0].id assert seatNonBid.nonBid[0].statusCode == REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY } + + def "PBS should add auction environment to imp.ext.igs when it is present in imp.ext and imp.ext.igs is empty"() { + given: "Default bid request with populated imp.ext" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.tap { + auctionEnvironment = requestedAuctionEnvironment + interestGroupAuctionSupports = [new InterestGroupAuctionSupport(auctionEnvironment: null)] + } + } + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should imp[].{ae/ext.igs.ae} same value as requested" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].ext.auctionEnvironment == requestedAuctionEnvironment + assert bidderRequest.imp[0].ext.interestGroupAuctionSupports[0].auctionEnvironment == requestedAuctionEnvironment + + where: + requestedAuctionEnvironment << [NOT_SUPPORTED, DEVICE_ORCHESTRATED] + } + + def "PBS shouldn't add unsupported auction environment to imp.ext.igs when it is present in imp.ext and imp.ext.igs is empty"() { + given: "Default bid request with populated imp.ext" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.tap { + auctionEnvironment = requestedAuctionEnvironment + interestGroupAuctionSupports = [new InterestGroupAuctionSupport(auctionEnvironment: null)] + } + } + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should imp[].ae same value as requested" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].ext.auctionEnvironment == requestedAuctionEnvironment + assert !bidderRequest.imp[0].ext.interestGroupAuctionSupports[0].auctionEnvironment + + where: + requestedAuctionEnvironment << [SERVER_ORCHESTRATED, UNKNOWN] + } + + def "PBS shouldn't change auction environment in imp.ext.igs when it is present in both imp.ext and imp.ext.igs"() { + given: "Default bid request with populated imp.ext" + def extAuctionEnv = PBSUtils.getRandomEnum(AuctionEnvironment) + def extIgsAuctionEnv = PBSUtils.getRandomEnum(AuctionEnvironment) + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.tap { + auctionEnvironment = extAuctionEnv + interestGroupAuctionSupports = [new InterestGroupAuctionSupport(auctionEnvironment: extIgsAuctionEnv)] + } + } + + when: "PBS processes auction request" + defaultPbsService.sendAuctionRequest(bidRequest) + + then: "Bidder request should imp[].{ae/ext.igs.ae} same value as requested" + def bidderRequest = bidder.getBidderRequest(bidRequest.id) + assert bidderRequest.imp[0].ext.auctionEnvironment == extAuctionEnv + assert bidderRequest.imp[0].ext.interestGroupAuctionSupports[0].auctionEnvironment == extIgsAuctionEnv + } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy index 45540134252..1adf84c32fd 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/bidder/openx/OpenxSpec.groovy @@ -1,35 +1,95 @@ package org.prebid.server.functional.tests.bidder.openx +import org.prebid.server.functional.model.Currency import org.prebid.server.functional.model.bidder.Openx +import org.prebid.server.functional.model.config.AccountAuctionConfig +import org.prebid.server.functional.model.config.AccountConfig +import org.prebid.server.functional.model.db.Account import org.prebid.server.functional.model.request.auction.BidRequest +import org.prebid.server.functional.model.request.auction.PaaFormat +import org.prebid.server.functional.model.response.auction.InterestGroupAuctionBuyer +import org.prebid.server.functional.model.response.auction.InterestGroupAuctionBuyerExt +import org.prebid.server.functional.model.response.auction.InterestGroupAuctionIntent +import org.prebid.server.functional.model.response.auction.InterestGroupAuctionSeller import org.prebid.server.functional.model.response.auction.OpenxBidResponse import org.prebid.server.functional.model.response.auction.OpenxBidResponseExt +import org.prebid.server.functional.service.PrebidServerException import org.prebid.server.functional.service.PrebidServerService import org.prebid.server.functional.tests.BaseSpec import org.prebid.server.functional.util.PBSUtils import spock.lang.Shared +import java.time.Instant + +import static org.prebid.server.functional.model.bidder.BidderName.OPENX +import static org.prebid.server.functional.model.bidder.BidderName.OPENX_ALIAS +import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD +import static org.prebid.server.functional.model.request.auction.AuctionEnvironment.DEVICE_ORCHESTRATED +import static org.prebid.server.functional.model.request.auction.AuctionEnvironment.NOT_SUPPORTED +import static org.prebid.server.functional.model.request.auction.PaaFormat.IAB +import static org.prebid.server.functional.model.request.auction.PaaFormat.ORIGINAL +import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID import static org.prebid.server.functional.testcontainers.Dependencies.networkServiceContainer class OpenxSpec extends BaseSpec { private static final Map OPENX_CONFIG = ["adapters.openx.enabled" : "true", "adapters.openx.endpoint": "$networkServiceContainer.rootUri/auction".toString()] + private static final Map OPENX_ALIAS_CONFIG = ["adapters.openx.aliases.openxalias.enabled" : "true", + "adapters.openx.aliases.openxalias.endpoint": "$networkServiceContainer.rootUri/auction".toString()] @Shared PrebidServerService pbsService = pbsServiceFactory.getService(OPENX_CONFIG) - def "PBS should populate fledge config when bid response with fledge and imp[0].ext.ae = 1"() { + def "PBS should populate fledge config by default when bid response with fledge"() { given: "Default basic BidRequest with ae and openx bidder" def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.ae = 1 + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx } and: "Default bid response with fledge config" def impId = bidRequest.imp[0].id def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] - def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest).tap { + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(impId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response should contain fledge config" + def auctionConfigs = response.ext?.prebid?.fledge?.auctionConfigs + assert auctionConfigs?.size() == 1 + assert auctionConfigs[0].impId == impId + assert auctionConfigs[0].bidder == bidResponse.seatbid[0].seat.value + assert auctionConfigs[0].adapter == bidResponse.seatbid[0].seat.value + assert auctionConfigs[0].config == fledgeConfig + + and: "PBS response shouldn't contain igb config" + assert !response.ext?.interestGroupAuctionIntent?.interestGroupAuctionBuyer + + and: "PBS response shouldn't contain igs config" + assert !response.ext?.interestGroupAuctionIntent?.interestGroupAuctionSeller + } + + def "PBS should populate fledge config when bid response with fledge and ext.prebid.paaFormat = ORIGINAL"() { + given: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = ORIGINAL + } + + and: "Default bid response with fledge config" + def impId = bidRequest.imp[0].id + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { ext = new OpenxBidResponseExt().tap { fledgeAuctionConfigs = [(impId): fledgeConfig] } @@ -48,13 +108,61 @@ class OpenxSpec extends BaseSpec { assert auctionConfigs[0].bidder == bidResponse.seatbid[0].seat.value assert auctionConfigs[0].adapter == bidResponse.seatbid[0].seat.value assert auctionConfigs[0].config == fledgeConfig + + and: "PBS response shouldn't contain igb config" + assert !response.ext?.interestGroupAuctionIntent?.interestGroupAuctionBuyer + + and: "PBS response shouldn't contain igs config" + assert !response.ext?.interestGroupAuctionIntent?.interestGroupAuctionSeller } - def "PBS shouldn't populate fledge config when imp[0].ext.ae = 0"() { + def "PBS should take precedence request paa format over account value when both specified"() { + given: "Default bid request with openx" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = IAB + } + + and: "Default bid response with fledge config" + def impId = bidRequest.imp[0].id + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(impId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Save account in the DB" + def accountConfig = new AccountConfig(auction: new AccountAuctionConfig(paaformat: ORIGINAL)) + def account = new Account(uuid: bidRequest.site.publisher.id, config: accountConfig) + accountDao.save(account) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response shouldn't contain fledge config" + assert !response.ext?.prebid?.fledge?.auctionConfigs + + and: "PBS response should contain igs config" + def interestGroupAuctionSeller = response.ext.interestGroupAuctionIntent[0].interestGroupAuctionSeller[0] + assert interestGroupAuctionSeller.impId == impId + assert interestGroupAuctionSeller.config == fledgeConfig + assert interestGroupAuctionSeller.ext.bidder == bidResponse.seatbid[0].seat.value + assert interestGroupAuctionSeller.ext.adapter == bidResponse.seatbid[0].seat.value + + and: "PBS response shouldn't contain igb config" + assert !response.ext?.interestGroupAuctionIntent?[0]?.interestGroupAuctionBuyer + } + + def "PBS shouldn't populate fledge config when bid response with fledge and ext.prebid.paaFormat = IAB"() { given: "Default basic BidRequest without ae" def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.ae = 0 + imp[0].ext.auctionEnvironment = NOT_SUPPORTED imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = IAB } and: "Default bid response" @@ -73,12 +181,21 @@ class OpenxSpec extends BaseSpec { then: "PBS response shouldn't contain fledge config" assert !response.ext.prebid.fledge + + and: "PBS response shouldn't contain igb config" + assert !response.ext?.interestGroupAuctionIntent?[0]?.interestGroupAuctionBuyer + + and: "PBS response should contain igs config" + def interestGroupAuctionSeller = response.ext.interestGroupAuctionIntent[0].interestGroupAuctionSeller[0] + assert interestGroupAuctionSeller.impId == impId + assert interestGroupAuctionSeller.config + assert interestGroupAuctionSeller.ext.bidder == bidResponse.seatbid[0].seat.value + assert interestGroupAuctionSeller.ext.adapter == OPENX.value } - def "PBS shouldn't populate fledge config when imp[0].ext.ae = 1 and bid response didn't return fledge config"() { + def "PBS shouldn't populate fledge config when bid response didn't return fledge config"() { given: "Default basic BidRequest without ae" def bidRequest = BidRequest.defaultBidRequest.tap { - imp[0].ext.ae = 1 imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx } @@ -97,5 +214,324 @@ class OpenxSpec extends BaseSpec { then: "PBS response shouldn't contain fledge config" assert !response.ext.prebid.fledge + + and: "PBS response shouldn't contain igi config" + assert !response?.ext?.interestGroupAuctionIntent + } + + def "PBS should populate fledge and iab output config when bid response with fledge and paa formant IAB"() { + given: "Default bid request with openx" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = requestPaaFormant + } + + and: "Default bid response with fledge config" + def impId = bidRequest.imp[0].id + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(impId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Save account in the DB" + def accountConfig = new AccountConfig(auction: new AccountAuctionConfig(paaformat: accountPaaFormat)) + def account = new Account(uuid: bidRequest.site.publisher.id, config: accountConfig) + accountDao.save(account) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response shouldn't contain fledge config" + assert !response.ext?.prebid?.fledge?.auctionConfigs + + and: "PBS response should contain igs config" + def interestGroupAuctionSeller = response.ext.interestGroupAuctionIntent[0].interestGroupAuctionSeller[0] + assert interestGroupAuctionSeller.impId == impId + assert interestGroupAuctionSeller.config == fledgeConfig + assert interestGroupAuctionSeller.ext.bidder == bidResponse.seatbid[0].seat.value + assert interestGroupAuctionSeller.ext.adapter == bidResponse.seatbid[0].seat.value + + and: "PBS response shouldn't contain igb config" + assert !response.ext?.interestGroupAuctionIntent?[0]?.interestGroupAuctionBuyer + + where: + accountPaaFormat | requestPaaFormant + IAB | IAB + null | IAB + IAB | null + } + + def "PBS should populate fledge config by default when bid response with fledge and requested aliases"() { + given: "PBS config with alias config" + def pbsService = pbsServiceFactory.getService(OPENX_CONFIG + OPENX_ALIAS_CONFIG) + + and: "Default basic BidRequest with ae and bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.openxAlias = Openx.defaultOpenx + ext.prebid.aliases = [(OPENX_ALIAS.value): OPENX] + } + + and: "Default bid response with fledge config" + def impId = bidRequest.imp[0].id + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX_ALIAS).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(impId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response should contain fledge config" + def auctionConfigs = response.ext?.prebid?.fledge?.auctionConfigs + assert auctionConfigs?.size() == 1 + assert auctionConfigs[0].impId == impId + assert auctionConfigs[0].bidder == OPENX_ALIAS.value + assert auctionConfigs[0].adapter == OPENX.value + assert auctionConfigs[0].config == fledgeConfig + + and: "PBS response shouldn't contain igi config" + assert !response.ext?.interestGroupAuctionIntent + } + + def "PBS should populate iab config when bid response with fledge and requested aliases"() { + given: "PBS config" + def pbsService = pbsServiceFactory.getService(OPENX_CONFIG + OPENX_ALIAS_CONFIG) + + and: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.generic = null + imp[0].ext.prebid.bidder.openxAlias = Openx.defaultOpenx + ext.prebid.aliases = [(OPENX_ALIAS.value): OPENX] + ext.prebid.paaFormat = IAB + } + + and: "Default bid response with fledge config" + def impId = bidRequest.imp[0].id + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX_ALIAS).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(impId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response shouldn't contain fledge config" + assert !response.ext?.prebid?.fledge?.auctionConfigs + + and: "PBS response should contain igs config" + def interestGroupAuctionSeller = response.ext.interestGroupAuctionIntent[0].interestGroupAuctionSeller[0] + assert interestGroupAuctionSeller.impId == impId + assert interestGroupAuctionSeller.config == fledgeConfig + assert interestGroupAuctionSeller.ext.bidder == OPENX_ALIAS.value + assert interestGroupAuctionSeller.ext.adapter == OPENX.value + + and: "PBS response shouldn't contain igi config" + assert !response.ext?.interestGroupAuctionIntent?[0].interestGroupAuctionBuyer + } + + def "PBS should populate fledge config by default when bid response with fledge and imp mismatched"() { + given: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + } + + and: "Default bid response with fledge config" + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(fledgeImpId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response should contain fledge config" + def auctionConfigs = response.ext?.prebid?.fledge?.auctionConfigs + assert auctionConfigs?.size() == 1 + assert auctionConfigs[0].impId == fledgeImpId + assert auctionConfigs[0].bidder == bidResponse.seatbid[0].seat.value + assert auctionConfigs[0].adapter == bidResponse.seatbid[0].seat.value + assert auctionConfigs[0].config == fledgeConfig + + and: "PBS response shouldn't contain igi config" + assert !response.ext?.interestGroupAuctionIntent + + where: + fledgeImpId << [PBSUtils.randomString, PBSUtils.randomNumber as String, WILDCARD.value] + } + + def "PBS should log error and not populated fledge impId when bidder respond with not empty config, but an empty impid"() { + given: "Start time" + def startTime = Instant.now() + + and: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = IAB + } + + and: "Default bid response with fledge config without imp" + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(""): fledgeConfig] as Map + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + and: "Flush metrics" + flushMetrics(pbsService) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response shouldn't contain fledge config" + assert !response.ext?.prebid?.fledge?.auctionConfigs + + and: "PBS response shouldn't contain igi config" + assert !response.ext?.interestGroupAuctionIntent + + and: "PBS log should contain error" + def logs = pbsService.getLogsByTime(startTime) + assert getLogsByText(logs, "ExtIgiIgs with absent impId from bidder: ${OPENX.value}") + + and: "Bid response should contain warning" + assert response.ext.warnings[PREBID]?.code == [999] + assert response.ext.warnings[PREBID]?.message == + ["ExtIgiIgs with absent impId from bidder: ${OPENX.value}" as String] + + and: "Alert.general metric should be updated" + def metrics = pbsService.sendCollectedMetricsRequest() + assert metrics["alerts.general" as String] == 1 + } + + def "PBS shouldn't populate fledge or igi config when bidder respond with igb"() { + given: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + } + + and: "Default bid response with igb config" + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { + ext = new OpenxBidResponseExt().tap { + interestGroupAuctionIntent = [new InterestGroupAuctionIntent( + interestGroupAuctionBuyer: [new InterestGroupAuctionBuyer( + origin: PBSUtils.randomString, + maxBid: PBSUtils.randomDecimal, + cur: PBSUtils.getRandomEnum(Currency), + pbs: [(PBSUtils.randomString): PBSUtils.randomString], + ext: new InterestGroupAuctionBuyerExt( + bidder: PBSUtils.randomString, + adapter: PBSUtils.randomString + ) + )]) + ] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response should contain fledge config" + assert !response.ext?.prebid?.fledge?.auctionConfigs + + and: "PBS response shouldn't contain igi config" + assert !response.ext?.interestGroupAuctionIntent + } + + def "PBS should throw error when requested unknown paa format"() { + given: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = PaaFormat.INVALID + } + + and: "Default bid response with fledge config" + def impId = bidRequest.imp[0].id + def fledgeConfig = [(PBSUtils.randomString): PBSUtils.randomString] + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { + ext = new OpenxBidResponseExt().tap { + fledgeAuctionConfigs = [(impId): fledgeConfig] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + pbsService.sendAuctionRequest(bidRequest) + + then: "Request should fail with error" + def exception = thrown(PrebidServerException) + assert exception.responseBody.startsWith("Invalid request format: Error decoding bidRequest: " + + "Cannot deserialize value of type `org.prebid.server.auction.model.PaaFormat` " + + "from String \"invalid\": not one of the values accepted for Enum class: [original, iab]") + } + + def "PBS shouldn't cause error when igs and igb empty array"() { + given: "Default basic BidRequest with ae and openx bidder" + def bidRequest = BidRequest.defaultBidRequest.tap { + imp[0].ext.auctionEnvironment = DEVICE_ORCHESTRATED + imp[0].ext.prebid.bidder.openx = Openx.defaultOpenx + ext.prebid.paaFormat = paaFormat + } + + and: "Default bid response with igs config" + def bidResponse = OpenxBidResponse.getDefaultBidResponse(bidRequest, OPENX).tap { + ext = new OpenxBidResponseExt().tap { + interestGroupAuctionIntent = [new InterestGroupAuctionIntent( + interestGroupAuctionSeller: interestGroupAuctionSeller, + interestGroupAuctionBuyer: interestGroupAuctionBuyer + )] + } + } + + and: "Set bidder response" + bidder.setResponse(bidRequest.id, bidResponse) + + when: "PBS processes auction request" + def response = pbsService.sendAuctionRequest(bidRequest) + + then: "PBS response should contain fledge config" + assert !response.ext?.prebid?.fledge?.auctionConfigs + + and: "PBS response shouldn't contain igi config" + assert !response.ext?.interestGroupAuctionIntent + + where: + paaFormat | interestGroupAuctionSeller | interestGroupAuctionBuyer + IAB | [new InterestGroupAuctionSeller()] | [new InterestGroupAuctionBuyer()] + ORIGINAL | [] | [] } }