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 857f212a209..e36c8344504 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -272,7 +272,7 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage final ObjectNode newExt = makeKeywords(impExt); final Imp.ImpBuilder impBuilder = imp.toBuilder() - .banner(banner != null ? assignSizesIfMissing(banner) : null) + .banner(banner != null ? fillBannerSizeFromFormat(banner) : null) .audio(null) .bidfloor(resolveBidFloor(impExtBidder.getKadfloor(), imp.getBidfloor())) .displaymanager(StringUtils.firstNonBlank(imp.getDisplaymanager(), displayManager)) @@ -281,12 +281,24 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage enrichWithAdSlotParameters(impBuilder, impExtBidder.getAdSlot(), banner); - return impBuilder.build(); + final Imp result = impBuilder.build(); + final Banner resultBanner = result.getBanner(); + // Per OpenRTB 2.6 spec, banner sizes are optional for interstitial impressions. + final boolean isInterstitial = Objects.equals(result.getInstl(), 1); + if (resultBanner != null && (resultBanner.getW() == null || resultBanner.getH() == null) && !isInterstitial) { + throw new PreBidException("No sizes provided for Banner"); + } + + return result; } - private static Banner assignSizesIfMissing(Banner banner) { + private static Banner fillBannerSizeFromFormat(Banner banner) { final List format = banner.getFormat(); - if ((banner.getW() != null && banner.getH() != null) || CollectionUtils.isEmpty(format)) { + if (banner.getW() != null && banner.getH() != null) { + return banner; + } + + if (CollectionUtils.isEmpty(format)) { return banner; } 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 0d7b50e89a9..a500c6be8d3 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -587,6 +587,83 @@ public void makeHttpRequestsShouldSetBannerWidthAndHeightFromFormatIfMissedOrigi .containsExactly(100); } + @Test + public void makeHttpRequestsShouldReturnErrorIfBannerHasNoSizesAndNoFormat() { + // given - non-interstitial banner with no W/H and no format: should error + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.banner(Banner.builder().build()), + extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()) + .containsExactly(BidderError.badInput("No sizes provided for Banner")); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldReturnErrorIfBannerHasOnlyOneDimensionAndNoFormat() { + // given - banner with w=300, h=null, no format, adSlot without size: should error + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.banner(Banner.builder().w(300).build()), + extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()) + .containsExactly(BidderError.badInput("No sizes provided for Banner")); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldNotReturnErrorForInterstitialBannerWithNoSizes() { + // given - per OpenRTB 2.6, banner sizes are optional for interstitial imps (instl=1) + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder + .instl(1) + .banner(Banner.builder().build()), + extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1); + } + + @Test + public void makeHttpRequestsShouldAllowBannerWithNoFormatWhenAdSlotProvidesSize() { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.banner(Banner.builder().build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + // Default givenBidRequest adSlot is "slot@300x250", so dimensions come from adSlot + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .extracting(Banner::getW) + .containsExactly(300); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .extracting(Banner::getH) + .containsExactly(250); + } + + + @Test public void makeHttpRequestsShouldSetTagIdForBannerImpsWithSymbolsFromAdSlotBeforeAtSign() { // given