diff --git a/src/main/java/org/prebid/server/bidder/insticator/InsticatorBidder.java b/src/main/java/org/prebid/server/bidder/insticator/InsticatorBidder.java index 4a1bd8b19dd..9cb2367b365 100644 --- a/src/main/java/org/prebid/server/bidder/insticator/InsticatorBidder.java +++ b/src/main/java/org/prebid/server/bidder/insticator/InsticatorBidder.java @@ -1,6 +1,7 @@ package org.prebid.server.bidder.insticator; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.App; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; @@ -10,7 +11,6 @@ import com.iab.openrtb.request.Video; import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; -import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; import org.prebid.server.bidder.Bidder; @@ -28,13 +28,14 @@ import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.insticator.ExtImpInsticator; 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.util.BidderUtil; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -49,6 +50,7 @@ public class InsticatorBidder implements Bidder { private static final String DEFAULT_BIDDER_CURRENCY = "USD"; private static final String INSTICATOR_FIELD = "insticator"; + private static final String PREBID_FIELD = "prebid"; private static final InsticatorExtRequestCaller DEFAULT_INSTICATOR_CALLER = InsticatorExtRequestCaller.of("Prebid-Server", "n/a"); @@ -241,22 +243,41 @@ public Result> makeBids(BidderCall httpCall, BidRequ } } - private static List extractBids(BidResponse bidResponse) { + private List extractBids(BidResponse bidResponse) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); } return bidResponse.getSeatbid().stream() .filter(Objects::nonNull) - .map(SeatBid::getBid) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .filter(Objects::nonNull) - .map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur())) - .filter(Objects::nonNull) + .filter(seatBid -> CollectionUtils.isNotEmpty(seatBid.getBid())) + .flatMap(seatBid -> seatBid.getBid().stream() + .filter(Objects::nonNull) + .map(bid -> { + final BidType bidType = getBidType(bid); + return BidderBid.of( + modifyBidExt(bid, bidType, seatBid.getSeat()), bidType, bidResponse.getCur()); + })) .toList(); } + private Bid modifyBidExt(Bid bid, BidType bidType, String seat) { + final ExtBidPrebidMeta meta = ExtBidPrebidMeta.builder() + .mediaType(bidType.getName()) + .seat(seat) + .build(); + final ExtBidPrebid extBidPrebid = ExtBidPrebid.builder() + .meta(meta) + .build(); + final ObjectNode ext = bid.getExt() != null + ? bid.getExt().deepCopy() + : mapper.mapper().createObjectNode(); + ext.set(PREBID_FIELD, mapper.mapper().valueToTree(extBidPrebid)); + return bid.toBuilder() + .ext(ext) + .build(); + } + private static BidType getBidType(Bid bid) { return switch (bid.getMtype()) { case 2 -> BidType.video; diff --git a/src/test/java/org/prebid/server/bidder/insticator/InsticatorBidderTest.java b/src/test/java/org/prebid/server/bidder/insticator/InsticatorBidderTest.java index aed7e02037a..0c3224f62b7 100644 --- a/src/test/java/org/prebid/server/bidder/insticator/InsticatorBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/insticator/InsticatorBidderTest.java @@ -30,6 +30,8 @@ import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.insticator.ExtImpInsticator; +import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; +import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta; import java.math.BigDecimal; import java.util.Arrays; @@ -501,57 +503,107 @@ public void makeBidsShouldReturnEmptyBidsWhenResponseDoesNotHaveSeatBid() throws @Test public void makeBidsShouldReturnBannerBidSuccessfully() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid.impid("1").mtype(1))); + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bid -> bid.impid("1").mtype(1), "dsp_seat")); // when final Result> result = target.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(Bid.builder().mtype(1).impid("1").build(), banner, "USD")); + assertThat(result.getValue()).hasSize(1) + .allSatisfy(bidderBid -> { + assertThat(bidderBid.getType()).isEqualTo(banner); + assertThat(bidderBid.getBidCurrency()).isEqualTo("USD"); + assertThat(bidderBid.getBid().getImpid()).isEqualTo("1"); + }); + assertThat(result.getValue().getFirst().getBid().getExt()) + .isEqualTo(mapper.createObjectNode().set("prebid", mapper.valueToTree( + ExtBidPrebid.builder() + .meta(ExtBidPrebidMeta.builder() + .mediaType("banner") + .seat("dsp_seat") + .build()) + .build()))); } @Test public void makeBidsShouldReturnVideoBidSuccessfully() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid.impid("2").mtype(2))); + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bid -> bid.impid("2").mtype(2), "video_seat")); // when final Result> result = target.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(Bid.builder().mtype(2).impid("2").build(), video, "USD")); + assertThat(result.getValue()).hasSize(1) + .allSatisfy(bidderBid -> { + assertThat(bidderBid.getType()).isEqualTo(video); + assertThat(bidderBid.getBidCurrency()).isEqualTo("USD"); + assertThat(bidderBid.getBid().getImpid()).isEqualTo("2"); + }); + assertThat(result.getValue().getFirst().getBid().getExt()) + .isEqualTo(mapper.createObjectNode().set("prebid", mapper.valueToTree( + ExtBidPrebid.builder() + .meta(ExtBidPrebidMeta.builder() + .mediaType("video") + .seat("video_seat") + .build()) + .build()))); } @Test public void makeBidsShouldReturnBannerBidWhenMtypeIsUnknown() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid.impid("3").mtype(3))); + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bid -> bid.impid("3").mtype(3), "seat1")); // when final Result> result = target.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(Bid.builder().mtype(3).impid("3").build(), banner, "USD")); + assertThat(result.getValue()).hasSize(1) + .allSatisfy(bidderBid -> { + assertThat(bidderBid.getType()).isEqualTo(banner); + assertThat(bidderBid.getBid().getImpid()).isEqualTo("3"); + }); } @Test public void makeBidsShouldReturnBannerBidWhenMtypeIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid.impid("3").mtype(null))); + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bid -> bid.impid("3").mtype(null), null)); // when final Result> result = target.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(Bid.builder().mtype(null).impid("3").build(), banner, "USD")); + assertThat(result.getValue()).hasSize(1) + .allSatisfy(bidderBid -> { + assertThat(bidderBid.getType()).isEqualTo(banner); + assertThat(bidderBid.getBid().getImpid()).isEqualTo("3"); + }); + } + + @Test + public void makeBidsShouldSetSeatFromSeatBidInMeta() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bid -> bid.impid("1").mtype(1), "pubmatic_54229")); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + final ObjectNode ext = result.getValue().getFirst().getBid().getExt(); + final ExtBidPrebid extBidPrebid = mapper.treeToValue(ext.get("prebid"), ExtBidPrebid.class); + assertThat(extBidPrebid.getMeta().getSeat()).isEqualTo("pubmatic_54229"); } private static BidRequest givenBidRequest(UnaryOperator... impCustomizers) { @@ -595,10 +647,16 @@ private static BidderCall givenHttpCall(String body) { } private String givenBidResponse(UnaryOperator bidCustomizer) throws JsonProcessingException { + return givenBidResponse(bidCustomizer, null); + } + + private String givenBidResponse(UnaryOperator bidCustomizer, String seat) + throws JsonProcessingException { return mapper.writeValueAsString(BidResponse.builder() .cur("USD") .seatbid(singletonList(SeatBid.builder() .bid(singletonList(bidCustomizer.apply(Bid.builder()).build())) + .seat(seat) .build())) .build()); } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-auction-insticator-response.json b/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-auction-insticator-response.json index 71881371150..e5bac51431f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-auction-insticator-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-auction-insticator-response.json @@ -19,7 +19,9 @@ "prebid": { "type": "banner", "meta": { - "adaptercode": "insticator" + "adaptercode": "insticator", + "mediaType": "banner", + "seat": "dsp_seat" } }, "origbidcpm": 3.33 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-response.json index 2769168e6ed..b62d5d5c359 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/insticator/test-insticator-bid-response.json @@ -15,7 +15,8 @@ "h": 250, "w": 300 } - ] + ], + "seat": "dsp_seat" } ] }