diff --git a/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java b/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java index 39c269b163b..f2228778feb 100644 --- a/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java +++ b/src/main/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidder.java @@ -3,8 +3,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Publisher; +import com.iab.openrtb.request.Site; import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; @@ -22,6 +25,7 @@ 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.ExtPublisher; import org.prebid.server.proto.openrtb.ext.request.rtbhouse.ExtImpRtbhouse; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; @@ -34,6 +38,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; public class RtbhouseBidder implements Bidder { @@ -60,6 +65,7 @@ public Result>> makeHttpRequests(BidRequest bidRequ final List modifiedImps = new ArrayList<>(); final List errors = new ArrayList<>(); + String publisherId = null; for (Imp imp : bidRequest.getImp()) { try { @@ -67,6 +73,9 @@ public Result>> makeHttpRequests(BidRequest bidRequ final Price bidFloorPrice = resolveBidFloor(imp, impExt, bidRequest); modifiedImps.add(modifyImp(imp, bidFloorPrice)); + if (publisherId == null) { + publisherId = impExt.getPublisherId(); + } } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } @@ -78,6 +87,7 @@ public Result>> makeHttpRequests(BidRequest bidRequ final BidRequest outgoingRequest = bidRequest.toBuilder() .cur(Collections.singletonList(BIDDER_CURRENCY)) + .site(modifySite(bidRequest.getSite(), publisherId)) .imp(modifiedImps) .build(); @@ -175,10 +185,10 @@ private ExtImpRtbhouse parseImpExt(Imp imp) { } private static Imp modifyImp(Imp imp, Price bidFloorPrice) { - return imp.toBuilder() .bidfloorcur(ObjectUtil.getIfNotNull(bidFloorPrice, Price::getCurrency)) .bidfloor(ObjectUtil.getIfNotNull(bidFloorPrice, Price::getValue)) + .pmp(null) .build(); } @@ -223,4 +233,24 @@ private static Bid resolveMacros(Bid bid) { .build(); } + private Site modifySite(Site site, String publisherId) { + final ObjectNode prebidNode = mapper.mapper().createObjectNode(); + prebidNode.put("publisherId", publisherId); + + final ExtPublisher extPublisher = ExtPublisher.empty(); + extPublisher.addProperty("prebid", prebidNode); + + final Publisher publisher = Optional.ofNullable(site) + .map(Site::getPublisher) + .map(Publisher::toBuilder) + .orElseGet(Publisher::builder) + .ext(extPublisher) + .build(); + + return Optional.ofNullable(site) + .map(Site::toBuilder) + .orElseGet(Site::builder) + .publisher(publisher) + .build(); + } } diff --git a/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java b/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java index e6429a971d1..fe10dad45e3 100644 --- a/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/rtbhouse/RtbhouseBidderTest.java @@ -1,11 +1,16 @@ package org.prebid.server.bidder.rtbhouse; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Deal; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Native; +import com.iab.openrtb.request.Pmp; +import com.iab.openrtb.request.Publisher; +import com.iab.openrtb.request.Site; import com.iab.openrtb.request.Video; import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; @@ -321,6 +326,198 @@ public void makeBidsShouldReturnBidWithResolvedMacros() throws JsonProcessingExc .containsExactly(tuple("nurl:12.34", "adm:12.34")); } + @Test + public void makeHttpRequestsShouldCreateSiteAndPublisherWhenBidRequestHasNoSite() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.site(null), + identity(), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .allSatisfy(site -> { + assertThat(site).isNotNull(); + assertThat(site.getPublisher()).isNotNull(); + assertThat(site.getPublisher().getExt()).isNotNull(); + + final JsonNode prebidNode = site.getPublisher().getExt().getProperty("prebid"); + assertThat(prebidNode).isNotNull(); + assertThat(prebidNode.get("publisherId").asText()).isEqualTo("publisherId"); + }); + } + + @Test + public void makeHttpRequestsShouldAddPublisherToExistingSiteWhenNoPublisher() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.site(Site.builder() + .id("site_id") + .name("site_name") + .domain("example.com") + .page("https://example.com/page") + .publisher(null) + .build()), + identity(), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .allSatisfy(site -> { + assertThat(site.getId()).isEqualTo("site_id"); + assertThat(site.getName()).isEqualTo("site_name"); + assertThat(site.getDomain()).isEqualTo("example.com"); + assertThat(site.getPage()).isEqualTo("https://example.com/page"); + assertThat(site.getPublisher()).isNotNull(); + + final JsonNode prebidNode = site.getPublisher().getExt().getProperty("prebid"); + assertThat(prebidNode).isNotNull(); + assertThat(prebidNode.get("publisherId").asText()).isEqualTo("publisherId"); + }); + } + + @Test + public void makeHttpRequestsShouldPreserveOtherPublisherFieldsWhenUpdatingId() { + // given + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.site(Site.builder() + .id("site_id") + .publisher(Publisher.builder() + .id("old_publisher_id") + .name("publisher_name") + .domain("publisher.com") + .build()) + .build()), + identity(), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .allSatisfy(site -> { + final JsonNode prebidNode = site.getPublisher().getExt().getProperty("prebid"); + assertThat(prebidNode).isNotNull(); + assertThat(prebidNode.get("publisherId").asText()).isEqualTo("publisherId"); + assertThat(site.getPublisher().getId()).isEqualTo("old_publisher_id"); + assertThat(site.getPublisher().getName()).isEqualTo("publisher_name"); + assertThat(site.getPublisher().getDomain()).isEqualTo("publisher.com"); + }); + } + + @Test + public void makeHttpRequestsShouldPreserveOtherBidRequestFields() { + // given + final List imps = List.of( + givenImp(imp -> imp.id("imp1"), identity()), + givenImp(imp -> imp.id("imp2"), identity())); + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id") + .test(1) + .tmax(2000L) + .imp(imps) + .cur(List.of("USD", "EUR")) + .site(Site.builder().id("site_id").build()), + identity(), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .allSatisfy(request -> { + assertThat(request.getId()).isEqualTo("request_id"); + assertThat(request.getTest()).isEqualTo(1); + assertThat(request.getTmax()).isEqualTo(2000L); + assertThat(request.getImp()).hasSize(2); + assertThat(request.getImp().get(0).getId()).isEqualTo("imp1"); + assertThat(request.getImp().get(1).getId()).isEqualTo("imp2"); + assertThat(request.getCur()).containsExactly("USD"); + + final JsonNode prebidNode = request.getSite().getPublisher().getExt() + .getProperty("prebid"); + assertThat(prebidNode).isNotNull(); + assertThat(prebidNode.get("publisherId").asText()).isEqualTo("publisherId"); + }); + } + + @Test + public void makeHttpRequestsShouldUsePublisherIdFromFirstImp() { + // given + final List imps = List.of( + givenImp(imp -> imp.id("imp1"), + ext -> ext.publisherId("first_publisher_id")), + givenImp(imp -> imp.id("imp2"), + ext -> ext.publisherId("second_publisher_id"))); + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id") + .imp(imps) + .site(Site.builder().id("site_id").build()), + identity(), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .extracting(BidRequest::getSite) + .allSatisfy(site -> { + final JsonNode prebidNode = site.getPublisher().getExt().getProperty("prebid"); + assertThat(prebidNode).isNotNull(); + assertThat(prebidNode.get("publisherId").asText()) + .isEqualTo("first_publisher_id"); + }); + } + + @Test + public void makeHttpRequestsShouldAlwaysRemovePmpField() { + // given + final List deals = List.of( + Deal.builder().id("deal1").build(), + Deal.builder().id("deal2").build()); + final BidRequest bidRequest = givenBidRequest( + bidReq -> bidReq.id("request_id"), + imp -> imp.id("123") + .pmp(Pmp.builder() + .privateAuction(1) + .deals(deals) + .build()), + identity()); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getPmp) + .containsOnlyNulls(); + } + private static BidResponse givenBidResponse(Function bidCustomizer) { return BidResponse.builder() .cur("USD") diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json index c4922bee672..e63afde3937 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request.json @@ -23,7 +23,12 @@ "domain": "www.example.com", "page": "http://www.example.com", "publisher": { - "domain": "example.com" + "domain": "example.com", + "ext": { + "prebid": { + "publisherId": "publisherId" + } + } }, "ext": { "amp": 0