From d87670e8e81341d254d6bfa859928520a34afd28 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Mon, 24 Feb 2025 14:37:57 +0100 Subject: [PATCH 1/7] OMS: Video support #3770 --- .../prebid/server/bidder/oms/OmsBidder.java | 48 +++++- .../openrtb/ext/request/omx/ExtImpOms.java | 11 ++ src/main/resources/bidder-config/oms.yaml | 2 + .../resources/static/bidder-params/oms.json | 20 ++- .../server/bidder/oms/OmsBidderTest.java | 147 ++++++++++++++++-- .../oms/test-auction-oms-response.json | 1 + .../openrtb2/oms/test-oms-bid-response.json | 3 +- 7 files changed, 208 insertions(+), 24 deletions(-) create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index 9dfc6d158e3..fd7ceda06bf 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -1,6 +1,8 @@ package org.prebid.server.bidder.oms; +import com.fasterxml.jackson.core.type.TypeReference; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; @@ -10,8 +12,11 @@ import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.Result; +import org.prebid.server.exception.PreBidException; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.omx.ExtImpOms; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; @@ -23,6 +28,8 @@ public class OmsBidder implements Bidder { + private static final TypeReference> EXT_TYPE_REFERENCE = new TypeReference<>() { + }; private final String endpointUrl; private final JacksonMapper mapper; @@ -32,8 +39,33 @@ public OmsBidder(String endpointUrl, JacksonMapper mapper) { } @Override - public final Result>> makeHttpRequests(BidRequest bidRequest) { - return Result.withValue(BidderUtil.defaultRequest(bidRequest, endpointUrl, mapper)); + public Result>> makeHttpRequests(BidRequest request) { + String uri = endpointUrl; + + if (!request.getImp().isEmpty()) { + try { + final ExtImpOms impExt = parseImpExt(request.getImp().get(0)); + if (impExt != null) { + if (impExt.getPid() != null && !impExt.getPid().isEmpty()) { + uri = String.format("%s?publisherId=%s", endpointUrl, impExt.getPid()); + } else if (impExt.getPublisherId() != null && impExt.getPublisherId() > 0) { + uri = String.format("%s?publisherId=%d", endpointUrl, impExt.getPublisherId()); + } + } + } catch (PreBidException e) { + return Result.withError(BidderError.badInput(e.getMessage())); + } + } + + return Result.withValue(BidderUtil.defaultRequest(request, uri, mapper)); + } + + private ExtImpOms parseImpExt(Imp imp) throws PreBidException { + try { + return mapper.mapper().convertValue(imp.getExt(), EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException("Invalid ext. Imp.Id: " + imp.getId()); + } } @Override @@ -41,7 +73,7 @@ public final Result> makeBids(BidderCall httpCall, B try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); return Result.withValues(extractBids(bidResponse)); - } catch (DecodeException e) { + } catch (DecodeException | PreBidException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); } } @@ -59,7 +91,15 @@ private static List bidsFromResponse(BidResponse bidResponse) { .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) - .map(bid -> BidderBid.of(bid, BidType.banner, bidResponse.getCur())) + .map(bid -> BidderBid.of(bid, getBidType(bid.getMtype()), bidResponse.getCur())) .toList(); } + + private static BidType getBidType(Integer mType) { + return switch (mType) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + case null, default -> throw new PreBidException("Unsupported mType " + mType); + }; + } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java new file mode 100644 index 00000000000..608af97b4dd --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java @@ -0,0 +1,11 @@ +package org.prebid.server.proto.openrtb.ext.request.omx; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtImpOms { + + String pid; + + Integer publisherId; +} diff --git a/src/main/resources/bidder-config/oms.yaml b/src/main/resources/bidder-config/oms.yaml index 0b46d3e01ed..16c4a4cac08 100644 --- a/src/main/resources/bidder-config/oms.yaml +++ b/src/main/resources/bidder-config/oms.yaml @@ -5,7 +5,9 @@ adapters: maintainer-email: prebid@onlinemediasolutions.com app-media-types: - banner + - video site-media-types: - banner + - video supported-vendors: vendor-id: 0 diff --git a/src/main/resources/static/bidder-params/oms.json b/src/main/resources/static/bidder-params/oms.json index 1ab7e25eb7f..fa9dec36f61 100644 --- a/src/main/resources/static/bidder-params/oms.json +++ b/src/main/resources/static/bidder-params/oms.json @@ -6,11 +6,25 @@ "properties": { "pid": { "type": "string", - "description": "An id used to identify OMS publisher.", + "description": "Deprecated: An id used to identify OMS publisher.", "minLength": 5 + }, + "publisherId": { + "type": "integer", + "description": "An ID used to identify OMS publisher.", + "minimum": 10000 } }, - "required": [ - "pid" + "oneOf": [ + { + "required": [ + "pid" + ] + }, + { + "required": [ + "publisherId" + ] + } ] } diff --git a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java index 7d9f4e84e06..89b669e0f6a 100644 --- a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java @@ -1,6 +1,7 @@ package org.prebid.server.bidder.oms; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; @@ -15,7 +16,12 @@ import org.prebid.server.bidder.model.HttpRequest; 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.request.omx.ExtImpOms; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.function.UnaryOperator; @@ -24,7 +30,7 @@ import static java.util.function.UnaryOperator.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; +import static org.prebid.server.bidder.model.BidderError.badInput; public class OmsBidderTest extends VertxTest { @@ -37,10 +43,40 @@ public void creationShouldFailOnInvalidEndpointUrl() { assertThatIllegalArgumentException().isThrownBy(() -> new OmsBidder("invalid_url", jacksonMapper)); } + @Test + public void makeHttpRequestsShouldReturnErrorWhenRequestHasInvalidImpression() { + // given + final ObjectNode invalidExt = mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())); + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(invalidExt)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1).first().isEqualTo(badInput("Invalid ext. Imp.Id: 123")); + } + @Test public void makeHttpRequestsShouldCreateExpectedUrl() { // given - final BidRequest bidRequest = givenBidRequest(identity()); + final ExtImpOms impExt = ExtImpOms.of("otherTagId", 12345); + final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://randomurl.com?publisherId=otherTagId"); + } + + @Test + public void makeHttpRequestsShouldCreateExpectedUrlWithPublisherId() { + // given + final ExtImpOms impExt = ExtImpOms.of(null, 12345); + final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -49,7 +85,43 @@ public void makeHttpRequestsShouldCreateExpectedUrl() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) - .containsExactly("https://randomurl.com"); + .containsExactly("https://randomurl.com?publisherId=12345"); + } + + @Test + public void makeHttpRequestsShouldIncludePidInRequestWhenPresent() { + // given + final ObjectNode impExt = mapper.createObjectNode().put("pid", "examplePid"); + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(impExt)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .containsExactly(impExt); + } + + @Test + public void makeHttpRequestsShouldIncludePublisherIdInRequestWhenPresent() { + // given + final ObjectNode impExt = mapper.createObjectNode().put("publisherId", 12345); + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(impExt)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .containsExactly(impExt); } @Test @@ -101,32 +173,75 @@ public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall( givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), - mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123")))); + mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123").mtype(1)))); // when final Result> result = target.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(givenBid(), banner, null)); + assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.banner); } @Test - public void makeBidsShouldReturnBannerBidIfBannerAndVideoAndAudioAndNativeIsAbsentInRequestImp() - throws JsonProcessingException { + public void makeBidsShouldReturnVideoBid() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall( - givenBidRequest(identity()), - mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123")))); + givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), + mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123").mtype(2)))); // when final Result> result = target.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsExactly(BidderBid.of(givenBid(), banner, null)); + assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.video); + } + + @Test + public void makeBidsShouldReturnErrorWhenMTypeIsUnsupported() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), + mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123").mtype(99)))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().get(0).getMessage()).contains("Unsupported mType 99"); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldExtractAllBidsFromMultipleSeatBids() throws JsonProcessingException { + // given + final Bid bid1 = Bid.builder().impid("bid1").mtype(1).build(); + final Bid bid2 = Bid.builder().impid("bid2").mtype(1).build(); + final Bid bid3 = Bid.builder().impid("bid3").mtype(2).build(); + + final SeatBid seatBid1 = SeatBid.builder().bid(Arrays.asList(bid1, bid2)).build(); + final SeatBid seatBid2 = SeatBid.builder().bid(Collections.singletonList(bid3)).build(); + + final BidResponse bidResponse = BidResponse.builder() + .seatbid(Arrays.asList(seatBid1, seatBid2)) + .cur("USD") + .build(); + final String bidResponseJson = mapper.writeValueAsString(bidResponse); + + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())); + final BidderCall httpCall = givenHttpCall(bidRequest, bidResponseJson); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(3) + .extracting(BidderBid::getType) + .containsExactly(BidType.banner, BidType.banner, BidType.video); + assertThat(result.getValue()).extracting(BidderBid::getBidCurrency).containsOnly("USD"); } private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { @@ -148,14 +263,14 @@ private static BidResponse givenBidResponse(Function givenHttpCall(BidRequest bidRequest, String body) { return BidderCall.succeededHttp( HttpRequest.builder().payload(bidRequest).build(), HttpResponse.of(200, null, body), null); } + + private ObjectNode givenImpExt(ExtImpOms impExt) { + return mapper.valueToTree(ExtPrebid.of(null, impExt)); + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-response.json b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-response.json index 315114b4f75..52f16380f34 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-response.json @@ -9,6 +9,7 @@ "exp": 300, "price": 3.33, "crid": "creativeId", + "mtype": 1, "ext": { "origbidcpm": 3.33, "prebid": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-response.json index 04d26e04318..6922c116b46 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-response.json @@ -7,7 +7,8 @@ "id": "bid_id", "impid": "imp_id", "price": 3.33, - "crid": "creativeId" + "crid": "creativeId", + "mtype": 1 } ] } From 6459db50d3855cc4ff1aaf32caabbb2a1d285a1e Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 5 Mar 2025 13:26:33 +0100 Subject: [PATCH 2/7] fix comments --- .../prebid/server/bidder/oms/OmsBidder.java | 52 +++++++++++++------ .../openrtb/ext/request/omx/ExtImpOms.java | 3 +- .../server/bidder/oms/OmsBidderTest.java | 37 ++++++++++--- .../oms/test-auction-oms-request.json | 2 +- .../it/openrtb2/oms/test-oms-bid-request.json | 2 +- 5 files changed, 72 insertions(+), 24 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index fd7ceda06bf..8900c801cf0 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; @@ -18,6 +19,7 @@ import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.omx.ExtImpOms; import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; @@ -40,24 +42,22 @@ public OmsBidder(String endpointUrl, JacksonMapper mapper) { @Override public Result>> makeHttpRequests(BidRequest request) { - String uri = endpointUrl; - if (!request.getImp().isEmpty()) { try { - final ExtImpOms impExt = parseImpExt(request.getImp().get(0)); - if (impExt != null) { - if (impExt.getPid() != null && !impExt.getPid().isEmpty()) { - uri = String.format("%s?publisherId=%s", endpointUrl, impExt.getPid()); - } else if (impExt.getPublisherId() != null && impExt.getPublisherId() > 0) { - uri = String.format("%s?publisherId=%d", endpointUrl, impExt.getPublisherId()); - } - } + final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); + final String publisherId = impExt.getPid() == null + && impExt.getPublisherId() != null + && impExt.getPublisherId() > 0 + ? String.valueOf(impExt.getPublisherId()) + : impExt.getPid(); + final String url = "%s?publisherId=%s".formatted(endpointUrl, publisherId); + return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); } catch (PreBidException e) { return Result.withError(BidderError.badInput(e.getMessage())); } } - return Result.withValue(BidderUtil.defaultRequest(request, uri, mapper)); + return Result.withValue(BidderUtil.defaultRequest(request, endpointUrl, mapper)); } private ExtImpOms parseImpExt(Imp imp) throws PreBidException { @@ -91,15 +91,37 @@ private static List bidsFromResponse(BidResponse bidResponse) { .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) - .map(bid -> BidderBid.of(bid, getBidType(bid.getMtype()), bidResponse.getCur())) + .map(bid -> BidderBid.builder() + .bid(bid) + .type(getBidType(bid)) + .bidCurrency(bidResponse.getCur()) + .videoInfo(videoInfo(bid)) + .build()) .toList(); } - private static BidType getBidType(Integer mType) { - return switch (mType) { + private static BidType getBidType(Bid bid) { + final Integer markupType = bid.getMtype(); + return switch (markupType) { case 1 -> BidType.banner; case 2 -> BidType.video; - case null, default -> throw new PreBidException("Unsupported mType " + mType); + case null, default -> BidType.banner; }; } + + private static ExtBidPrebidVideo videoInfo(Bid bid) { + if (!Integer.valueOf(2).equals(bid.getMtype())) { + return null; + } + final List cat = bid.getCat(); + final Integer duration = bid.getDur(); + + final boolean catNotEmpty = CollectionUtils.isNotEmpty(cat); + final boolean durationValid = duration != null && duration > 0; + return catNotEmpty || durationValid + ? ExtBidPrebidVideo.of( + durationValid ? duration : null, + catNotEmpty ? cat.getFirst() : null) + : null; + } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java index 608af97b4dd..246b278202b 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java @@ -1,11 +1,12 @@ package org.prebid.server.proto.openrtb.ext.request.omx; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Value; @Value(staticConstructor = "of") public class ExtImpOms { String pid; - + @JsonProperty("publisherId") Integer publisherId; } diff --git a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java index 89b669e0f6a..81b3186bc71 100644 --- a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java @@ -19,6 +19,7 @@ import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.omx.ExtImpOms; import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; import java.util.Arrays; import java.util.Collections; @@ -91,7 +92,8 @@ public void makeHttpRequestsShouldCreateExpectedUrlWithPublisherId() { @Test public void makeHttpRequestsShouldIncludePidInRequestWhenPresent() { // given - final ObjectNode impExt = mapper.createObjectNode().put("pid", "examplePid"); + final ObjectNode bidderExt = mapper.createObjectNode().put("pid", "examplePid"); + final ObjectNode impExt = mapper.createObjectNode().set("bidder", bidderExt); final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(impExt)); // when @@ -109,7 +111,8 @@ public void makeHttpRequestsShouldIncludePidInRequestWhenPresent() { @Test public void makeHttpRequestsShouldIncludePublisherIdInRequestWhenPresent() { // given - final ObjectNode impExt = mapper.createObjectNode().put("publisherId", 12345); + final ObjectNode bidderExt = mapper.createObjectNode().put("publisherId", 12345); + final ObjectNode impExt = mapper.createObjectNode().set("bidder", bidderExt); final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(impExt)); // when @@ -199,7 +202,7 @@ public void makeBidsShouldReturnVideoBid() throws JsonProcessingException { } @Test - public void makeBidsShouldReturnErrorWhenMTypeIsUnsupported() throws JsonProcessingException { + public void makeBidsShouldReturnBannerWhenMTypeIsUnsupported() throws JsonProcessingException { // given final BidderCall httpCall = givenHttpCall( givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), @@ -209,9 +212,8 @@ public void makeBidsShouldReturnErrorWhenMTypeIsUnsupported() throws JsonProcess final Result> result = target.makeBids(httpCall, null); // then - assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().get(0).getMessage()).contains("Unsupported mType 99"); - assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.banner); } @Test @@ -244,6 +246,29 @@ public void makeBidsShouldExtractAllBidsFromMultipleSeatBids() throws JsonProces assertThat(result.getValue()).extracting(BidderBid::getBidCurrency).containsOnly("USD"); } + @Test + public void makeBidsShouldReturnVideoBidWithVideoInfo() throws JsonProcessingException { + // given + final Bid videoBid = Bid.builder() + .mtype(2) + .dur(30) + .cat(List.of("IAB1")) + .build(); + final BidResponse bidResponse = BidResponse.builder() + .seatbid(List.of(SeatBid.builder().bid(List.of(videoBid)).build())) + .cur("USD") + .build(); + final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(bidResponse)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getValue()) + .extracting(BidderBid::getVideoInfo) + .containsExactly(ExtBidPrebidVideo.of(30, "IAB1")); + } + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { return givenBidRequest(identity(), impCustomizer); } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-request.json b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-request.json index 777f07481d7..38808efff2a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-auction-oms-request.json @@ -9,7 +9,7 @@ }, "ext": { "oms": { - "pid": "exampleProperty" + "publisherId": 12345 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-request.json index 1eb99acd606..d0020c7c009 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/oms/test-oms-bid-request.json @@ -11,7 +11,7 @@ "ext": { "tid": "${json-unit.any-string}", "bidder": { - "pid": "exampleProperty" + "publisherId": 12345 } } } From f32d6565afeb4d1c54ae4a6e7d312e24397b21b3 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Mon, 10 Mar 2025 16:08:16 +0100 Subject: [PATCH 3/7] fix comments --- .../prebid/server/bidder/oms/OmsBidder.java | 44 ++++++++----------- .../openrtb/ext/request/omx/ExtImpOms.java | 1 - .../server/bidder/oms/OmsBidderTest.java | 18 +------- 3 files changed, 19 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index 8900c801cf0..b3892435daf 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -45,11 +45,8 @@ public Result>> makeHttpRequests(BidRequest request if (!request.getImp().isEmpty()) { try { final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); - final String publisherId = impExt.getPid() == null - && impExt.getPublisherId() != null - && impExt.getPublisherId() > 0 - ? String.valueOf(impExt.getPublisherId()) - : impExt.getPid(); + final String publisherId = impExt.getPublisherId() != null && impExt.getPublisherId() > 0 + ? String.valueOf(impExt.getPublisherId()) : null; final String url = "%s?publisherId=%s".formatted(endpointUrl, publisherId); return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); } catch (PreBidException e) { @@ -91,37 +88,32 @@ private static List bidsFromResponse(BidResponse bidResponse) { .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) - .map(bid -> BidderBid.builder() - .bid(bid) - .type(getBidType(bid)) - .bidCurrency(bidResponse.getCur()) - .videoInfo(videoInfo(bid)) - .build()) + .map(bid -> { + final BidType bidType = getBidType(bid); + return BidderBid.builder() + .bid(bid) + .type(bidType) + .bidCurrency(bidResponse.getCur()) + .videoInfo(videoInfo(bidType, bid)) + .build(); + }) .toList(); } private static BidType getBidType(Bid bid) { - final Integer markupType = bid.getMtype(); - return switch (markupType) { - case 1 -> BidType.banner; - case 2 -> BidType.video; - case null, default -> BidType.banner; - }; + return Objects.equals(bid.getMtype(), 2) ? BidType.video : BidType.banner; } - private static ExtBidPrebidVideo videoInfo(Bid bid) { - if (!Integer.valueOf(2).equals(bid.getMtype())) { + private static ExtBidPrebidVideo videoInfo(BidType bidType, Bid bid) { + if (bidType != BidType.video) { return null; } final List cat = bid.getCat(); final Integer duration = bid.getDur(); - final boolean catNotEmpty = CollectionUtils.isNotEmpty(cat); - final boolean durationValid = duration != null && duration > 0; - return catNotEmpty || durationValid - ? ExtBidPrebidVideo.of( - durationValid ? duration : null, - catNotEmpty ? cat.getFirst() : null) - : null; + return ExtBidPrebidVideo.of( + duration != null ? duration : 0, + CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : "" + ); } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java index 246b278202b..2ba78019a6f 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java @@ -6,7 +6,6 @@ @Value(staticConstructor = "of") public class ExtImpOms { - String pid; @JsonProperty("publisherId") Integer publisherId; } diff --git a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java index 81b3186bc71..6d85251b2d0 100644 --- a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java @@ -57,26 +57,10 @@ public void makeHttpRequestsShouldReturnErrorWhenRequestHasInvalidImpression() { assertThat(result.getErrors()).hasSize(1).first().isEqualTo(badInput("Invalid ext. Imp.Id: 123")); } - @Test - public void makeHttpRequestsShouldCreateExpectedUrl() { - // given - final ExtImpOms impExt = ExtImpOms.of("otherTagId", 12345); - final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1) - .extracting(HttpRequest::getUri) - .containsExactly("https://randomurl.com?publisherId=otherTagId"); - } - @Test public void makeHttpRequestsShouldCreateExpectedUrlWithPublisherId() { // given - final ExtImpOms impExt = ExtImpOms.of(null, 12345); + final ExtImpOms impExt = ExtImpOms.of(12345); final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); // when From ed5230cf5625abf5bd6b895a7d6938aabc0e43f1 Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Tue, 11 Mar 2025 12:46:30 +0100 Subject: [PATCH 4/7] fix comments --- .../prebid/server/bidder/oms/OmsBidder.java | 10 +++++++--- .../openrtb/ext/request/omx/ExtImpOms.java | 2 ++ .../server/bidder/oms/OmsBidderTest.java | 18 +++++++++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index b3892435daf..2726b0e7709 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -7,6 +7,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -45,8 +46,11 @@ public Result>> makeHttpRequests(BidRequest request if (!request.getImp().isEmpty()) { try { final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); - final String publisherId = impExt.getPublisherId() != null && impExt.getPublisherId() > 0 - ? String.valueOf(impExt.getPublisherId()) : null; + final String publisherId = impExt.getPid() == null + && impExt.getPublisherId() != null + && impExt.getPublisherId() > 0 + ? String.valueOf(impExt.getPublisherId()) + : impExt.getPid(); final String url = "%s?publisherId=%s".formatted(endpointUrl, publisherId); return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); } catch (PreBidException e) { @@ -113,7 +117,7 @@ private static ExtBidPrebidVideo videoInfo(BidType bidType, Bid bid) { return ExtBidPrebidVideo.of( duration != null ? duration : 0, - CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : "" + CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : StringUtils.EMPTY ); } } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java index 2ba78019a6f..f6a96821d44 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/omx/ExtImpOms.java @@ -6,6 +6,8 @@ @Value(staticConstructor = "of") public class ExtImpOms { + String pid; + @JsonProperty("publisherId") Integer publisherId; } diff --git a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java index 6d85251b2d0..81b3186bc71 100644 --- a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java @@ -57,10 +57,26 @@ public void makeHttpRequestsShouldReturnErrorWhenRequestHasInvalidImpression() { assertThat(result.getErrors()).hasSize(1).first().isEqualTo(badInput("Invalid ext. Imp.Id: 123")); } + @Test + public void makeHttpRequestsShouldCreateExpectedUrl() { + // given + final ExtImpOms impExt = ExtImpOms.of("otherTagId", 12345); + final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactly("https://randomurl.com?publisherId=otherTagId"); + } + @Test public void makeHttpRequestsShouldCreateExpectedUrlWithPublisherId() { // given - final ExtImpOms impExt = ExtImpOms.of(12345); + final ExtImpOms impExt = ExtImpOms.of(null, 12345); final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); // when From 057d34369c072d050249e5df281f6cf7570667dd Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 12 Mar 2025 12:05:32 +0100 Subject: [PATCH 5/7] fix comments --- src/main/java/org/prebid/server/bidder/oms/OmsBidder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index 2726b0e7709..ea6ef43d8f8 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -7,6 +7,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; @@ -74,7 +75,7 @@ public final Result> makeBids(BidderCall httpCall, B try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); return Result.withValues(extractBids(bidResponse)); - } catch (DecodeException | PreBidException e) { + } catch (DecodeException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); } } @@ -116,7 +117,7 @@ private static ExtBidPrebidVideo videoInfo(BidType bidType, Bid bid) { final Integer duration = bid.getDur(); return ExtBidPrebidVideo.of( - duration != null ? duration : 0, + ObjectUtils.defaultIfNull(duration, 0), CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : StringUtils.EMPTY ); } From 2d95af32d96798677d3ebb06ab52033aaf45f9da Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Wed, 19 Mar 2025 11:56:14 +0100 Subject: [PATCH 6/7] fix comments --- .../prebid/server/bidder/oms/OmsBidder.java | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index ea6ef43d8f8..d4af940da63 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -47,12 +47,9 @@ public Result>> makeHttpRequests(BidRequest request if (!request.getImp().isEmpty()) { try { final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); - final String publisherId = impExt.getPid() == null - && impExt.getPublisherId() != null - && impExt.getPublisherId() > 0 - ? String.valueOf(impExt.getPublisherId()) - : impExt.getPid(); - final String url = "%s?publisherId=%s".formatted(endpointUrl, publisherId); + final String publisherId = resolverPublisherId(impExt.getPid(), impExt.getPublisherId()); + final String encodedPublisherId = HttpUtil.encodeUrl(publisherId); + final String url = "%s?publisherId=%s".formatted(endpointUrl, encodedPublisherId); return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); } catch (PreBidException e) { return Result.withError(BidderError.badInput(e.getMessage())); @@ -70,6 +67,13 @@ private ExtImpOms parseImpExt(Imp imp) throws PreBidException { } } + private String resolverPublisherId(String pid, Integer publisherId) { + if (StringUtils.isEmpty(pid) && publisherId != null && publisherId > 0) { + return String.valueOf(publisherId); + } + return pid; + } + @Override public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { @@ -93,18 +97,20 @@ private static List bidsFromResponse(BidResponse bidResponse) { .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) - .map(bid -> { - final BidType bidType = getBidType(bid); - return BidderBid.builder() - .bid(bid) - .type(bidType) - .bidCurrency(bidResponse.getCur()) - .videoInfo(videoInfo(bidType, bid)) - .build(); - }) + .map(bid -> createBidderBid(bid, bidResponse.getCur())) .toList(); } + private static BidderBid createBidderBid(Bid bid, String currency) { + final BidType bidType = getBidType(bid); + return BidderBid.builder() + .bid(bid) + .type(bidType) + .bidCurrency(currency) + .videoInfo(videoInfo(bidType, bid)) + .build(); + } + private static BidType getBidType(Bid bid) { return Objects.equals(bid.getMtype(), 2) ? BidType.video : BidType.banner; } @@ -118,7 +124,6 @@ private static ExtBidPrebidVideo videoInfo(BidType bidType, Bid bid) { return ExtBidPrebidVideo.of( ObjectUtils.defaultIfNull(duration, 0), - CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : StringUtils.EMPTY - ); + CollectionUtils.isNotEmpty(cat) ? cat.getFirst() : StringUtils.EMPTY); } } From cef4cb6844d157efc02d7084c8d9f106f7684edc Mon Sep 17 00:00:00 2001 From: pkaczmarek Date: Tue, 1 Apr 2025 13:19:04 +0200 Subject: [PATCH 7/7] fix comments --- .../prebid/server/bidder/oms/OmsBidder.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index d4af940da63..81e1c8091f5 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -44,19 +44,15 @@ public OmsBidder(String endpointUrl, JacksonMapper mapper) { @Override public Result>> makeHttpRequests(BidRequest request) { - if (!request.getImp().isEmpty()) { - try { - final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); - final String publisherId = resolverPublisherId(impExt.getPid(), impExt.getPublisherId()); - final String encodedPublisherId = HttpUtil.encodeUrl(publisherId); - final String url = "%s?publisherId=%s".formatted(endpointUrl, encodedPublisherId); - return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); - } catch (PreBidException e) { - return Result.withError(BidderError.badInput(e.getMessage())); - } + try { + final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); + final String publisherId = resolverPublisherId(impExt.getPid(), impExt.getPublisherId()); + final String encodedPublisherId = HttpUtil.encodeUrl(publisherId); + final String url = "%s?publisherId=%s".formatted(endpointUrl, encodedPublisherId); + return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); + } catch (PreBidException e) { + return Result.withError(BidderError.badInput(e.getMessage())); } - - return Result.withValue(BidderUtil.defaultRequest(request, endpointUrl, mapper)); } private ExtImpOms parseImpExt(Imp imp) throws PreBidException {