From 20b181abaa3810fbd981043dee2be60e1151c421 Mon Sep 17 00:00:00 2001 From: Shawn He Date: Tue, 27 Oct 2026 17:55:50 -0700 Subject: [PATCH 1/2] ADS-10178: Label each bid with the format the Nativo exchange returned in mtype. --- .../server/bidder/nativo/NativoBidder.java | 13 ++- .../bidder/nativo/NativoBidderTest.java | 107 ++++++++++++++++++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/bidder/nativo/NativoBidder.java b/src/main/java/org/prebid/server/bidder/nativo/NativoBidder.java index 394279fff83..c3de985ce30 100644 --- a/src/main/java/org/prebid/server/bidder/nativo/NativoBidder.java +++ b/src/main/java/org/prebid/server/bidder/nativo/NativoBidder.java @@ -22,6 +22,7 @@ import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidSdk; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidSdkRenderer; +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; @@ -88,10 +89,20 @@ private List bidsFromResponse(BidRequest bidRequest, BidResponse bidR .flatMap(Collection::stream) .filter(Objects::nonNull) .map(bid -> updateBid(bid, rendererVersion, errors)) - .map(bid -> BidderBid.of(bid, BidderUtil.getBidType(bid, impMap), bidResponse.getCur())) + .map(bid -> BidderBid.of(bid, getBidType(bid, impMap), bidResponse.getCur())) .toList(); } + private static BidType getBidType(Bid bid, Map impMap) { + return switch (bid.getMtype()) { + case 1 -> BidType.banner; + case 2 -> BidType.video; + case 3 -> BidType.audio; + case 4 -> BidType.xNative; + case null, default -> BidderUtil.getBidType(bid, impMap); + }; + } + private String getNativoRendererVersion(BidRequest bidRequest) { return Optional.ofNullable(bidRequest.getExt()) .map(ExtRequest::getPrebid) diff --git a/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java b/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java index 8fa090c5a7c..42b86ad62a2 100644 --- a/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java @@ -264,6 +264,108 @@ public void makeBidsShouldReturnErrorAndOriginalBidWhenBidExtCannotBeParsed() assertThat(result.getValue().getFirst().getBid().getExt()).isEqualTo(invalidExt); } + @Test + public void makeBidsShouldReturnNativeBidWhenMtypeIsNativeOnBannerAndNativeImp() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") + .banner(Banner.builder().build()) + .xNative(Native.builder().build())); + final Bid bid = givenBid("bid1", "imp1", 4); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.xNative, "USD")); + } + + @Test + public void makeBidsShouldReturnBannerBidWhenMtypeIsBannerOnBannerAndVideoImp() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") + .banner(Banner.builder().build()) + .video(Video.builder().build())); + final Bid bid = givenBid("bid1", "imp1", 1); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.banner, "USD")); + } + + @Test + public void makeBidsShouldReturnVideoBidWhenMtypeIsVideoOnVideoAndNativeImp() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") + .video(Video.builder().build()) + .xNative(Native.builder().build())); + final Bid bid = givenBid("bid1", "imp1", 2); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.video, "USD")); + } + + @Test + public void makeBidsShouldReturnNativeBidWhenMtypeIsNativeOnBannerVideoAndNativeImp() + throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") + .banner(Banner.builder().build()) + .video(Video.builder().build()) + .xNative(Native.builder().build())); + final Bid bid = givenBid("bid1", "imp1", 4); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.xNative, "USD")); + } + + @Test + public void makeBidsShouldReturnAudioBidWhenMtypeIsAudio() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1").banner(Banner.builder().build())); + final Bid bid = givenBid("bid1", "imp1", 3); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.audio, "USD")); + } + + @Test + public void makeBidsShouldReturnBidTypeFromImpWhenMtypeIsUnrecognized() throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") + .banner(Banner.builder().build()) + .xNative(Native.builder().build())); + final Bid bid = givenBid("bid1", "imp1", 7); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); + + // when + final Result> result = target.makeBids(httpCall, bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.banner, "USD")); + } + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { return BidRequest.builder() .imp(singletonList(impCustomizer.apply(Imp.builder().id("imp1")).build())) @@ -282,11 +384,16 @@ private static BidRequest givenBidRequestWithRenderer(UnaryOperator Date: Thu, 29 Oct 2026 09:05:19 -0700 Subject: [PATCH 2/2] the native, banner and video mtype tests in NativoBidderTest are renamed to makeBidsShouldReturn{Native,Banner,Video}BidWhenMtypeIs{Native,Banner,Video}, all mtype tests now use an imp with no formats (including audio, which loses its banner), and the redundant all-format native test is removed. --- .../bidder/nativo/NativoBidderTest.java | 39 ++++--------------- 1 file changed, 7 insertions(+), 32 deletions(-) diff --git a/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java b/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java index 42b86ad62a2..f9eea0c0f31 100644 --- a/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/nativo/NativoBidderTest.java @@ -265,11 +265,9 @@ public void makeBidsShouldReturnErrorAndOriginalBidWhenBidExtCannotBeParsed() } @Test - public void makeBidsShouldReturnNativeBidWhenMtypeIsNativeOnBannerAndNativeImp() throws JsonProcessingException { + public void makeBidsShouldReturnNativeBidWhenMtypeIsNative() throws JsonProcessingException { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") - .banner(Banner.builder().build()) - .xNative(Native.builder().build())); + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1")); final Bid bid = givenBid("bid1", "imp1", 4); final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); @@ -282,11 +280,9 @@ public void makeBidsShouldReturnNativeBidWhenMtypeIsNativeOnBannerAndNativeImp() } @Test - public void makeBidsShouldReturnBannerBidWhenMtypeIsBannerOnBannerAndVideoImp() throws JsonProcessingException { + public void makeBidsShouldReturnBannerBidWhenMtypeIsBanner() throws JsonProcessingException { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") - .banner(Banner.builder().build()) - .video(Video.builder().build())); + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1")); final Bid bid = givenBid("bid1", "imp1", 1); final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); @@ -299,11 +295,9 @@ public void makeBidsShouldReturnBannerBidWhenMtypeIsBannerOnBannerAndVideoImp() } @Test - public void makeBidsShouldReturnVideoBidWhenMtypeIsVideoOnVideoAndNativeImp() throws JsonProcessingException { + public void makeBidsShouldReturnVideoBidWhenMtypeIsVideo() throws JsonProcessingException { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") - .video(Video.builder().build()) - .xNative(Native.builder().build())); + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1")); final Bid bid = givenBid("bid1", "imp1", 2); final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); @@ -315,29 +309,10 @@ public void makeBidsShouldReturnVideoBidWhenMtypeIsVideoOnVideoAndNativeImp() th assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.video, "USD")); } - @Test - public void makeBidsShouldReturnNativeBidWhenMtypeIsNativeOnBannerVideoAndNativeImp() - throws JsonProcessingException { - // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1") - .banner(Banner.builder().build()) - .video(Video.builder().build()) - .xNative(Native.builder().build())); - final Bid bid = givenBid("bid1", "imp1", 4); - final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid))); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).containsExactly(BidderBid.of(bid, BidType.xNative, "USD")); - } - @Test public void makeBidsShouldReturnAudioBidWhenMtypeIsAudio() throws JsonProcessingException { // given - final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1").banner(Banner.builder().build())); + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("imp1")); final Bid bid = givenBid("bid1", "imp1", 3); final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(singletonList(bid)));