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 a820a52890c..9843eedca9e 100644 --- a/src/main/java/org/prebid/server/bidder/ix/IxBidder.java +++ b/src/main/java/org/prebid/server/bidder/ix/IxBidder.java @@ -15,7 +15,6 @@ import com.iab.openrtb.request.ntv.EventTrackingMethod; import com.iab.openrtb.request.ntv.EventType; import com.iab.openrtb.response.Bid; -import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.EventTracker; import com.iab.openrtb.response.Response; import com.iab.openrtb.response.SeatBid; @@ -23,10 +22,13 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.ix.model.request.IxDiag; +import org.prebid.server.bidder.ix.model.response.IxBidResponse; +import org.prebid.server.bidder.ix.model.response.IxExtBidResponse; import org.prebid.server.bidder.ix.model.response.NativeV11Wrapper; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.CompositeBidderResponse; import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.Result; import org.prebid.server.exception.PreBidException; @@ -41,6 +43,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.ExtBidPrebidVideo; +import org.prebid.server.proto.openrtb.ext.response.FledgeAuctionConfig; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; @@ -104,6 +107,21 @@ public Result>> makeHttpRequests(BidRequest bidRequ return Result.of(httpRequests, errors); } + @Override + public CompositeBidderResponse makeBidderResponse(BidderCall httpCall, BidRequest bidRequest) { + try { + final IxBidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), IxBidResponse.class); + final List bidderErrors = new ArrayList<>(); + return CompositeBidderResponse.builder() + .bids(extractIxBids(bidRequest, bidResponse, bidderErrors)) + .fledgeAuctionConfigs(extractFledge(bidResponse)) + .errors(bidderErrors) + .build(); + } catch (DecodeException e) { + return CompositeBidderResponse.withError(BidderError.badServerResponse(e.getMessage())); + } + } + private ExtImpIx parseImpExt(Imp imp) { try { return mapper.mapper().convertValue(imp.getExt(), IX_EXT_TYPE_REFERENCE).getBidder(); @@ -226,24 +244,14 @@ private static Publisher modifyPublisher(Publisher publisher, String id) { } @Override + @Deprecated(since = "Not used, since Bidder.makeBidderResponse(...) was overridden.") public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { - try { - final List errors = new ArrayList<>(); - final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - final BidRequest payload = httpCall.getRequest().getPayload(); - return Result.of(extractBids(bidResponse, payload, errors), errors); - } catch (DecodeException e) { - return Result.withError(BidderError.badServerResponse(e.getMessage())); - } - } - - private List extractBids(BidResponse bidResponse, BidRequest bidRequest, List errors) { - return bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid()) - ? Collections.emptyList() - : bidsFromResponse(bidResponse, bidRequest, errors); + return Result.withError(BidderError.generic("Invalid method call")); } - private List bidsFromResponse(BidResponse bidResponse, BidRequest bidRequest, List errors) { + private List bidsFromResponse(IxBidResponse bidResponse, + BidRequest bidRequest, + List errors) { return bidResponse.getSeatbid().stream() .filter(Objects::nonNull) .map(SeatBid::getBid) @@ -254,7 +262,7 @@ private List bidsFromResponse(BidResponse bidResponse, BidRequest bid .toList(); } - private BidderBid toBidderBid(Bid bid, BidRequest bidRequest, BidResponse bidResponse, List errors) { + private BidderBid toBidderBid(Bid bid, BidRequest bidRequest, IxBidResponse bidResponse, List errors) { final BidType bidType; try { bidType = getBidType(bid, bidRequest.getImp()); @@ -384,4 +392,23 @@ private ObjectNode resolveBidExt(Integer duration) { .video(ExtBidPrebidVideo.of(duration, null)) .build()); } + + private List extractIxBids(BidRequest bidRequest, + IxBidResponse bidResponse, + List bidderErrors) { + return bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid()) + ? Collections.emptyList() + : bidsFromResponse(bidResponse, bidRequest, bidderErrors); + } + + private List extractFledge(IxBidResponse bidResponse) { + return Optional.ofNullable(bidResponse) + .map(IxBidResponse::getExt) + .map(IxExtBidResponse::getFledgeAuctionConfigs) + .orElse(Collections.emptyMap()) + .entrySet() + .stream() + .map(e -> FledgeAuctionConfig.builder().impId(e.getKey()).config(e.getValue()).build()) + .toList(); + } } diff --git a/src/main/java/org/prebid/server/bidder/ix/model/response/IxBidResponse.java b/src/main/java/org/prebid/server/bidder/ix/model/response/IxBidResponse.java new file mode 100644 index 00000000000..0bbbace5f81 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/ix/model/response/IxBidResponse.java @@ -0,0 +1,26 @@ +package org.prebid.server.bidder.ix.model.response; + +import com.iab.openrtb.response.SeatBid; +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +@Builder(toBuilder = true) +@Value +public class IxBidResponse { + + String id; + + List seatbid; + + String bidid; + + String cur; + + String customdata; + + Integer nbr; + + IxExtBidResponse ext; +} diff --git a/src/main/java/org/prebid/server/bidder/ix/model/response/IxExtBidResponse.java b/src/main/java/org/prebid/server/bidder/ix/model/response/IxExtBidResponse.java new file mode 100644 index 00000000000..c292317d22c --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/ix/model/response/IxExtBidResponse.java @@ -0,0 +1,15 @@ +package org.prebid.server.bidder.ix.model.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.Value; + +import java.util.Map; + +@Value(staticConstructor = "of") +public class IxExtBidResponse { + + @JsonProperty("fledge_auction_configs") + Map fledgeAuctionConfigs; + +} 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 a8fd6cf5722..cd0147f0270 100644 --- a/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java @@ -28,10 +28,13 @@ import org.mockito.junit.MockitoRule; import org.prebid.server.VertxTest; import org.prebid.server.bidder.ix.model.request.IxDiag; +import org.prebid.server.bidder.ix.model.response.IxBidResponse; +import org.prebid.server.bidder.ix.model.response.IxExtBidResponse; import org.prebid.server.bidder.ix.model.response.NativeV11Wrapper; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.CompositeBidderResponse; import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; @@ -43,9 +46,11 @@ 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.version.PrebidVersionProvider; import java.util.List; +import java.util.Map; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -56,6 +61,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.BDDMockito.given; +import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; public class IxBidderTest extends VertxTest { @@ -305,131 +311,136 @@ public void makeHttpRequestsShouldNotCreateRequestAppWhenImpExtSiteIdPresentAndS } @Test - public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + public void makeBidderResponseShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given final BidderCall httpCall = givenHttpCall(null, "invalid"); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, null); // then assertThat(result.getErrors()).hasSize(1); assertThat(result.getErrors().get(0).getMessage()).startsWith("Failed to decode: Unrecognized token"); assertThat(result.getErrors().get(0).getType()).isEqualTo(BidderError.Type.bad_server_response); - assertThat(result.getValue()).isEmpty(); + assertThat(result.getBids()).isEmpty(); } @Test - public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { + public void makeBidderResponseShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).isEmpty(); + assertThat(result.getBids()).isEmpty(); } @Test - public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { + public void makeBidderResponseShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(BidResponse.builder().build())); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).isEmpty(); + assertThat(result.getBids()).isEmpty(); } @Test - public void makeBidsShouldReturnBannerBidIfBannerIsPresent() throws JsonProcessingException { + public void makeBidderResponseShouldReturnBannerBidIfBannerIsPresent() throws JsonProcessingException { // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), BidType.banner, "EUR")); } @Test - public void makeBidsShouldReturnNativeBidIfNativeIsPresent() throws JsonProcessingException { + public void makeBidderResponseShouldReturnNativeBidIfNativeIsPresent() throws JsonProcessingException { // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), BidType.xNative, "EUR")); } @Test - public void makeBidsShouldReturnAudioBidIfAudioIsPresent() throws JsonProcessingException { + public void makeBidderResponseShouldReturnAudioBidIfAudioIsPresent() throws JsonProcessingException { // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").audio(Audio.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").audio(Audio.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), BidType.audio, "EUR")); } @Test - public void makeBidsShouldReturnErrorIfImpNotMatched() throws JsonProcessingException { + public void makeBidderResponseShouldReturnErrorIfImpNotMatched() throws JsonProcessingException { // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse(bidBuilder -> bidBuilder.impid("489")))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then - assertThat(result.getValue()).isEmpty(); + assertThat(result.getBids()).isEmpty(); assertThat(result.getErrors()).containsExactly(BidderError.badServerResponse("Unmatched impression id 489")); } @Test - public void makeBidsShouldReturnBidWithVideoExt() throws JsonProcessingException { + public void makeBidderResponseShouldReturnBidWithVideoExt() throws JsonProcessingException { // given final Video video = Video.builder().build(); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").video(video).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").video(video).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse( bidBuilder -> bidBuilder @@ -439,11 +450,11 @@ public void makeBidsShouldReturnBidWithVideoExt() throws JsonProcessingException .build()))))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getBid) .extracting(Bid::getExt) .extracting(node -> mapper.treeToValue(node, ExtBidPrebid.class)) @@ -453,7 +464,7 @@ public void makeBidsShouldReturnBidWithVideoExt() throws JsonProcessingException } @Test - public void makeBidsShouldReturnAdmContainingImageTrackersUrls() throws JsonProcessingException { + public void makeBidderResponseShouldReturnAdmContainingImageTrackersUrls() throws JsonProcessingException { // given final String adm = mapper.writeValueAsString( Response.builder() @@ -464,16 +475,17 @@ public void makeBidsShouldReturnAdmContainingImageTrackersUrls() throws JsonProc .url("eventUrl") .build())) .build()); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder .impid("123") .adm(adm)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then final Response expectedNativeResponse = Response.builder() @@ -485,14 +497,15 @@ public void makeBidsShouldReturnAdmContainingImageTrackersUrls() throws JsonProc .build(); assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getBid) .extracting(Bid::getAdm) .containsExactly(mapper.writeValueAsString(expectedNativeResponse)); } @Test - public void makeBidsShouldReturnAdmContainingImpTrackersAndEventImpTrackersUrls() throws JsonProcessingException { + public void makeBidderResponseShouldReturnAdmContainingImpTrackersAndEventImpTrackersUrls() + throws JsonProcessingException { // given final String adm = mapper.writeValueAsString( Response.builder() @@ -503,16 +516,17 @@ public void makeBidsShouldReturnAdmContainingImpTrackersAndEventImpTrackersUrls( .url("eventUrl") .build())) .build()); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder .impid("123") .adm(adm)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then final Response expectedNativeResponse = Response.builder() @@ -524,14 +538,14 @@ public void makeBidsShouldReturnAdmContainingImpTrackersAndEventImpTrackersUrls( .build(); assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getBid) .extracting(Bid::getAdm) .containsExactly(mapper.writeValueAsString(expectedNativeResponse)); } @Test - public void makeBidsShouldReturnAdmContainingOnlyUniqueImpTrackersUrls() throws JsonProcessingException { + public void makeBidderResponseShouldReturnAdmContainingOnlyUniqueImpTrackersUrls() throws JsonProcessingException { // given final String adm = mapper.writeValueAsString( Response.builder() @@ -546,20 +560,21 @@ public void makeBidsShouldReturnAdmContainingOnlyUniqueImpTrackersUrls() throws .url("someTracker") .build())) .build()); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder .impid("123") .adm(adm)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getBid) .extracting(Bid::getAdm) .extracting(bidAdm -> mapper.readValue(bidAdm, Response.class)) @@ -568,7 +583,7 @@ public void makeBidsShouldReturnAdmContainingOnlyUniqueImpTrackersUrls() throws } @Test - public void makeBidsShouldReturnValidAdmIfNativeIsPresentInImpAndAdm12() throws JsonProcessingException { + public void makeBidderResponseShouldReturnValidAdmIfNativeIsPresentInImpAndAdm12() throws JsonProcessingException { // given final String adm = mapper.writeValueAsString(NativeV11Wrapper.of( Response.builder() @@ -580,16 +595,17 @@ public void makeBidsShouldReturnValidAdmIfNativeIsPresentInImpAndAdm12() throws .url("EventUrl") .build())) .build())); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").xNative(Native.builder().build()).build())) - .build(), + bidRequest, mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder .impid("123") .adm(adm)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then final NativeV11Wrapper expectedNativeResponse = NativeV11Wrapper.of(Response.builder() @@ -602,24 +618,25 @@ public void makeBidsShouldReturnValidAdmIfNativeIsPresentInImpAndAdm12() throws .build()); assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getBid) .extracting(Bid::getAdm) .containsExactly(mapper.writeValueAsString(expectedNativeResponse)); } @Test - public void makeBidsShouldReturnBannerBidIfMTypeIsOne() throws JsonProcessingException { + public void makeBidderResponseShouldReturnBannerBidIfMTypeIsOne() throws JsonProcessingException { // given final Banner banner = Banner.builder().w(300).h(200).build(); final Video video = Video.builder().build(); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("123") + .banner(banner) + .video(video).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder() - .id("123") - .banner(banner) - .video(video).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse( bidBuilder -> bidBuilder @@ -627,27 +644,28 @@ public void makeBidsShouldReturnBannerBidIfMTypeIsOne() throws JsonProcessingExc .mtype(1)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getType) .containsExactly(BidType.banner); } @Test - public void makeBidsShouldReturnVideoBidIfMTypeIsTwo() throws JsonProcessingException { + public void makeBidderResponseShouldReturnVideoBidIfMTypeIsTwo() throws JsonProcessingException { // given final Banner banner = Banner.builder().w(300).h(200).build(); final Video video = Video.builder().build(); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("123") + .banner(banner) + .video(video).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder() - .id("123") - .banner(banner) - .video(video).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse( bidBuilder -> bidBuilder @@ -655,27 +673,28 @@ public void makeBidsShouldReturnVideoBidIfMTypeIsTwo() throws JsonProcessingExce .mtype(2)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getType) .containsExactly(BidType.video); } @Test - public void makeBidsShouldReturnAudioBidIfMTypeIsThree() throws JsonProcessingException { + public void makeBidderResponseShouldReturnAudioBidIfMTypeIsThree() throws JsonProcessingException { // given final Banner banner = Banner.builder().w(300).h(200).build(); final Video video = Video.builder().build(); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("123") + .banner(banner) + .video(video).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder() - .id("123") - .banner(banner) - .video(video).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse( bidBuilder -> bidBuilder @@ -683,27 +702,28 @@ public void makeBidsShouldReturnAudioBidIfMTypeIsThree() throws JsonProcessingEx .mtype(3)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getType) .containsExactly(BidType.audio); } @Test - public void makeBidsShouldReturnNativeBidIfMTypeIsFour() throws JsonProcessingException { + public void makeBidderResponseShouldReturnNativeBidIfMTypeIsFour() throws JsonProcessingException { // given final Banner banner = Banner.builder().w(300).h(200).build(); final Video video = Video.builder().build(); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("123") + .banner(banner) + .video(video).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder() - .id("123") - .banner(banner) - .video(video).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse( bidBuilder -> bidBuilder @@ -711,27 +731,28 @@ public void makeBidsShouldReturnNativeBidIfMTypeIsFour() throws JsonProcessingEx .mtype(4)))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getType) .containsExactly(BidType.xNative); } @Test - public void makeBidsShouldReturnCorrectTypeExtPrebidTypeInResponse() throws JsonProcessingException { + public void makeBidderResponseShouldReturnCorrectTypeExtPrebidTypeInResponse() throws JsonProcessingException { // given final Banner banner = Banner.builder().w(300).h(200).build(); final Video video = Video.builder().build(); + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .id("123") + .banner(banner) + .video(video).build())) + .build(); final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder() - .id("123") - .banner(banner) - .video(video).build())) - .build(), + bidRequest, mapper.writeValueAsString( givenBidResponse( bidBuilder -> bidBuilder @@ -740,15 +761,46 @@ public void makeBidsShouldReturnCorrectTypeExtPrebidTypeInResponse() throws Json .set("prebid", mapper.createObjectNode().put("type", "video")))))); // when - final Result> result = target.makeBids(httpCall, null); + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getBids()) .extracting(BidderBid::getType) .containsExactly(BidType.video); } + @Test + public void makeBidderResponseShouldReturnFledgeAuctionConfig() throws JsonProcessingException { + // given + final String impId = "imp_id"; + final BidResponse bidResponse = givenBidResponse(bidBuilder -> bidBuilder.impid(impId).mtype(1)); + final ObjectNode fledgeAuctionConfig = 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(Map.of(impId, fledgeAuctionConfig))) + .build(); + final BidderCall httpCall = + givenHttpCall(bidRequest, mapper.writeValueAsString(bidResponseWithFledge)); + + // when + final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest); + + // then + 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); + } + private static ExtRequest givenExtRequest(String pbjsv) { return ExtRequest.of(ExtRequestPrebid.builder() .channel(ExtRequestPrebidChannel.of("pbjs", pbjsv))