diff --git a/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java b/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java index 675d5f65bc7..199637f6001 100644 --- a/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java +++ b/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java @@ -68,6 +68,7 @@ import org.prebid.server.bidder.rubicon.proto.request.RubiconUserExt; import org.prebid.server.bidder.rubicon.proto.request.RubiconUserExtRp; import org.prebid.server.bidder.rubicon.proto.request.RubiconVideoExt; +import org.prebid.server.bidder.rubicon.proto.request.RubiconVideoExtRp; import org.prebid.server.bidder.rubicon.proto.response.RubiconBid; import org.prebid.server.bidder.rubicon.proto.response.RubiconBidResponse; import org.prebid.server.bidder.rubicon.proto.response.RubiconSeatBid; @@ -78,12 +79,14 @@ import org.prebid.server.floors.model.PriceFloorRules; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.log.ConditionalLogger; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.FlexibleExtension; import org.prebid.server.proto.openrtb.ext.request.ExtApp; import org.prebid.server.proto.openrtb.ext.request.ExtDeal; import org.prebid.server.proto.openrtb.ext.request.ExtDealLine; import org.prebid.server.proto.openrtb.ext.request.ExtDevice; +import org.prebid.server.proto.openrtb.ext.request.ExtImpContext; import org.prebid.server.proto.openrtb.ext.request.ExtImpContextDataAdserver; import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebidFloors; @@ -130,6 +133,8 @@ public class RubiconBidder implements Bidder { private static final Logger logger = LoggerFactory.getLogger(RubiconBidder.class); + private static final ConditionalLogger MISSING_VIDEO_SIZE_LOGGER = + new ConditionalLogger("missing_video_size", logger); private static final String TK_XINT_QUERY_PARAMETER = "tk_xint"; private static final String PREBID_SERVER_USER_AGENT = "prebid-server/1.0"; @@ -138,6 +143,12 @@ public class RubiconBidder implements Bidder { private static final String FPD_GPID_FIELD = "gpid"; private static final String FPD_SKADN_FIELD = "skadn"; + private static final String FPD_SECTIONCAT_FIELD = "sectioncat"; + private static final String FPD_PAGECAT_FIELD = "pagecat"; + private static final String FPD_PAGE_FIELD = "page"; + private static final String FPD_REF_FIELD = "ref"; + private static final String FPD_SEARCH_FIELD = "search"; + private static final String FPD_CONTEXT_FIELD = "context"; private static final String FPD_DATA_FIELD = "data"; private static final String FPD_DATA_PBADSLOT_FIELD = "pbadslot"; private static final String FPD_ADSERVER_FIELD = "adserver"; @@ -148,14 +159,13 @@ public class RubiconBidder implements Bidder { private static final String PREBID_EXT = "prebid"; private static final String PPUID_STYPE = "ppuid"; + private static final String OTHER_STYPE = "other"; private static final String SHA256EMAIL_STYPE = "sha256email"; private static final String DMP_STYPE = "dmp"; - private static final String XAPI_CURRENCY = "USD"; private static final Set USER_SEGTAXES = Set.of(4); private static final Set SITE_SEGTAXES = Set.of(1, 2, 5, 6); - private static final String SEGTAX_BLAH_ATTRIBUTE = "segtaxBLAH"; private static final Set STYPE_TO_REMOVE = new HashSet<>(Arrays.asList(PPUID_STYPE, SHA256EMAIL_STYPE, DMP_STYPE)); @@ -166,7 +176,6 @@ public class RubiconBidder implements Bidder { new TypeReference<>() { }; private static final boolean DEFAULT_MULTIFORMAT_VALUE = false; - private static final int SEGTAX_BLAH_MAX_SIZE = 100; private final String endpointUrl; private final Set supportedVendors; @@ -654,6 +663,7 @@ private RubiconImpExt makeImpExt(Imp imp, String ipfResolvedCurrency, PriceFloorResult priceFloorResult) { + final ExtImpContext context = extImpContext(imp); final RubiconImpExtPrebid rubiconImpExtPrebid = priceFloorResult != null ? makeRubiconExtPrebid(priceFloorResult, ipfResolvedCurrency, imp, bidRequest) : null; @@ -664,7 +674,7 @@ private RubiconImpExt makeImpExt(Imp imp, final RubiconImpExtRp rubiconImpExtRp = RubiconImpExtRp.of( rubiconImpExt.getZoneId(), - makeTarget(imp, rubiconImpExt, site, app), + makeTarget(imp, rubiconImpExt, site, app, context), RubiconImpExtRpTrack.of("", ""), rubiconImpExtRpRtb); @@ -678,14 +688,26 @@ private RubiconImpExt makeImpExt(Imp imp, .build(); } - private JsonNode makeTarget(Imp imp, ExtImpRubicon rubiconImpExt, Site site, App app) { + private ExtImpContext extImpContext(Imp imp) { + final JsonNode context = imp.getExt().get(FPD_CONTEXT_FIELD); + if (context == null || context.isNull()) { + return null; + } + try { + return mapper.mapper().convertValue(context, ExtImpContext.class); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage(), e); + } + } + + private JsonNode makeTarget(Imp imp, ExtImpRubicon rubiconImpExt, Site site, App app, ExtImpContext context) { final ObjectNode result = mapper.mapper().createObjectNode(); populateFirstPartyDataAttributes(rubiconImpExt.getInventory(), result); mergeFirstPartyDataFromSite(site, result); mergeFirstPartyDataFromApp(app, result); - mergeFirstPartyDataFromImp(imp, rubiconImpExt, result); + mergeFirstPartyDataFromImp(imp, rubiconImpExt, context, result); return result.size() > 0 ? result : null; } @@ -720,6 +742,17 @@ private void mergeFirstPartyDataFromSite(Site site, ObjectNode result) { if (siteExt != null) { populateFirstPartyDataAttributes(siteExt.getData(), result); } + + // merge OPENRTB.site.sectioncat to every impression XAPI.imp[].ext.rp.target.sectioncat + mergeCollectionAttributeIntoArray(result, site, Site::getSectioncat, FPD_SECTIONCAT_FIELD); + // merge OPENRTB.site.pagecat to every impression XAPI.imp[].ext.rp.target.pagecat + mergeCollectionAttributeIntoArray(result, site, Site::getPagecat, FPD_PAGECAT_FIELD); + // merge OPENRTB.site.page to every impression XAPI.imp[].ext.rp.target.page + mergeStringAttributeIntoArray(result, site, Site::getPage, FPD_PAGE_FIELD); + // merge OPENRTB.site.ref to every impression XAPI.imp[].ext.rp.target.ref + mergeStringAttributeIntoArray(result, site, Site::getRef, FPD_REF_FIELD); + // merge OPENRTB.site.search to every impression XAPI.imp[].ext.rp.target.search + mergeStringAttributeIntoArray(result, site, Site::getSearch, FPD_SEARCH_FIELD); } private void mergeFirstPartyDataFromApp(App app, ObjectNode result) { @@ -728,41 +761,72 @@ private void mergeFirstPartyDataFromApp(App app, ObjectNode result) { if (appExt != null) { populateFirstPartyDataAttributes(appExt.getData(), result); } + + // merge OPENRTB.app.sectioncat to every impression XAPI.imp[].ext.rp.target.sectioncat + mergeCollectionAttributeIntoArray(result, app, App::getSectioncat, FPD_SECTIONCAT_FIELD); + // merge OPENRTB.app.pagecat to every impression XAPI.imp[].ext.rp.target.pagecat + mergeCollectionAttributeIntoArray(result, app, App::getPagecat, FPD_PAGECAT_FIELD); } private void mergeFirstPartyDataFromImp(Imp imp, ExtImpRubicon rubiconImpExt, + ExtImpContext context, ObjectNode result) { - mergeFirstPartyDataKeywords(imp, result); - mergeFirstPartyDataFromData(imp, result); + + mergeFirstPartyDataFromData(imp, context, result); + mergeFirstPartyDataKeywords(imp, context, result); // merge OPENRTB.imp[].ext.rubicon.keywords to XAPI.imp[].ext.rp.target.keywords mergeCollectionAttributeIntoArray(result, rubiconImpExt, ExtImpRubicon::getKeywords, FPD_KEYWORDS_FIELD); - } + // merge OPENRTB.imp[].ext.context.search to XAPI.imp[].ext.rp.target.search + mergeStringAttributeIntoArray( + result, + context, + extContext -> getTextValueFromNode(extContext.getProperty(FPD_SEARCH_FIELD)), + FPD_SEARCH_FIELD); + // merge OPENRTB.imp[].ext.data.search to XAPI.imp[].ext.rp.target.search + mergeStringAttributeIntoArray( + result, + imp.getExt().get(FPD_DATA_FIELD), + node -> getTextValueFromNodeByPath(node, FPD_SEARCH_FIELD), + FPD_SEARCH_FIELD); + } + + private void mergeFirstPartyDataFromData(Imp imp, ExtImpContext context, ObjectNode result) { + final ObjectNode contextDataNode = toObjectNode( + ObjectUtil.getIfNotNull(context, ExtImpContext::getData)); + // merge OPENRTB.imp[].ext.context.data.* to XAPI.imp[].ext.rp.target.* + populateFirstPartyDataAttributes(contextDataNode, result); - private void mergeFirstPartyDataFromData(Imp imp, ObjectNode result) { final ObjectNode dataNode = toObjectNode(imp.getExt().get(FPD_DATA_FIELD)); // merge OPENRTB.imp[].ext.data.* to XAPI.imp[].ext.rp.target.* populateFirstPartyDataAttributes(dataNode, result); // override XAPI.imp[].ext.rp.target.* with OPENRTB.imp[].ext.data.* - overrideFirstPartyDataAttributes(dataNode, result); + overrideFirstPartyDataAttributes(contextDataNode, dataNode, result); } - private void overrideFirstPartyDataAttributes(ObjectNode dataNode, ObjectNode result) { + private void overrideFirstPartyDataAttributes(ObjectNode contextDataNode, ObjectNode dataNode, ObjectNode result) { final JsonNode pbadslotNode = dataNode.get(FPD_DATA_PBADSLOT_FIELD); if (pbadslotNode != null && pbadslotNode.isTextual()) { // copy imp[].ext.data.pbadslot to XAPI.imp[].ext.rp.target.pbadslot result.set(FPD_DATA_PBADSLOT_FIELD, pbadslotNode); } else { // copy adserver.adslot value to XAPI field imp[].ext.rp.target.dfp_ad_unit_code - final String resolvedDfpAdUnitCode = getAdSlotFromAdServer(dataNode); + final String resolvedDfpAdUnitCode = getAdSlot(contextDataNode, dataNode); if (resolvedDfpAdUnitCode != null) { result.set(DFP_ADUNIT_CODE_FIELD, TextNode.valueOf(resolvedDfpAdUnitCode)); } } } - private void mergeFirstPartyDataKeywords(Imp imp, ObjectNode result) { + private void mergeFirstPartyDataKeywords(Imp imp, ExtImpContext context, ObjectNode result) { + // merge OPENRTB.imp[].ext.context.keywords to XAPI.imp[].ext.rp.target.keywords + final JsonNode keywordsNode = context != null ? context.getProperty("keywords") : null; + final String keywords = getTextValueFromNode(keywordsNode); + if (StringUtils.isNotBlank(keywords)) { + mergeIntoArray(result, FPD_KEYWORDS_FIELD, keywords.split(",")); + } + // merge OPENRTB.imp[].ext.data.keywords to XAPI.imp[].ext.rp.target.keywords final String dataKeywords = getTextValueFromNodeByPath(imp.getExt().get(FPD_DATA_FIELD), FPD_KEYWORDS_FIELD); if (StringUtils.isNotBlank(dataKeywords)) { @@ -912,10 +976,19 @@ private ObjectNode getSkadn(ObjectNode impExt) { return skadnNode != null && skadnNode.isObject() ? (ObjectNode) skadnNode : null; } - private String getAdSlot(Imp imp) { + private String getAdSlot(Imp imp, ExtImpContext context) { + final ObjectNode contextDataNode = context != null ? context.getData() : null; final ObjectNode dataNode = toObjectNode(imp.getExt().get(FPD_DATA_FIELD)); - return getAdSlotFromAdServer(dataNode); + return getAdSlot(contextDataNode, dataNode); + } + + private String getAdSlot(ObjectNode contextDataNode, ObjectNode dataNode) { + return ObjectUtils.firstNonNull( + // or imp[].ext.context.data.adserver.adslot + getAdSlotFromAdServer(contextDataNode), + // or imp[].ext.data.adserver.adslot + getAdSlotFromAdServer(dataNode)); } private String getAdSlotFromAdServer(JsonNode dataNode) { @@ -968,20 +1041,54 @@ private Video makeVideo(Imp imp, RubiconVideoParams rubiconVideoParams, String r final Integer skip = rubiconVideoParams != null ? rubiconVideoParams.getSkip() : null; final Integer skipDelay = rubiconVideoParams != null ? rubiconVideoParams.getSkipdelay() : null; + final Integer sizeId = rubiconVideoParams != null ? rubiconVideoParams.getSizeId() : null; + + final Integer resolvedSizeId = BidderUtil.isNullOrZero(sizeId) + ? resolveVideoSizeId(video.getPlacement(), imp.getInstl()) + : sizeId; + validateVideoSizeId(resolvedSizeId, referer, imp.getId()); final Integer rewarded = imp.getRwdd(); final String videoType = rewarded != null && rewarded == 1 ? "rewarded" : null; // optimization for empty ext params - if (skip == null && skipDelay == null && videoType == null) { + if (skip == null && skipDelay == null && resolvedSizeId == null && videoType == null) { return video; } return video.toBuilder() - .ext(mapper.mapper().valueToTree(RubiconVideoExt.of(skip, skipDelay, videoType))) + .ext(mapper.mapper().valueToTree( + RubiconVideoExt.of(skip, skipDelay, RubiconVideoExtRp.of(resolvedSizeId), videoType))) .build(); } + private static void validateVideoSizeId(Integer resolvedSizeId, String referer, String impId) { + // log only 1% of cases to monitor how often video impressions does not have size id + if (resolvedSizeId == null) { + MISSING_VIDEO_SIZE_LOGGER.warn( + "RP adapter: video request with no size_id. Referrer URL = %s, impId = %s" + .formatted(referer, impId), + 0.01d); + } + } + + private static Integer resolveVideoSizeId(Integer placement, Integer instl) { + if (placement != null) { + if (placement == 1) { + return 201; + } + if (placement == 3) { + return 203; + } + } + + if (instl != null && instl == 1) { + return 202; + } + + return null; + } + private Banner makeBanner(Imp imp) { final Banner banner = imp.getBanner(); final Integer width = banner.getW(); @@ -1082,7 +1189,6 @@ private User makeUser(User user, ExtImpRubicon rubiconImpExt) { final ExtUser userExt = ExtUser.builder() .eids(resolvedUserEids) - .fcapIds(extUser != null ? extUser.getFcapIds() : null) .build(); final RubiconUserExt rubiconUserExt = RubiconUserExt.builder() @@ -1223,7 +1329,6 @@ private JsonNode rubiconUserExtRpTarget(ObjectNode visitor, User user) { mergeFirstPartyDataFromUser(user.getExt(), result); enrichWithIabAttribute(result, user.getData(), USER_SEGTAXES); - enrichWithSegtaxBlahAttribute(result, user.getData(), USER_SEGTAXES); } return !result.isEmpty() ? result : null; @@ -1264,63 +1369,6 @@ private static void enrichWithIabAttribute(ObjectNode target, List data, S } } - private static void enrichWithSegtaxBlahAttribute(ObjectNode target, List data, Set segtaxValues) { - final List> validDataSegments = getValidDataSegments( - CollectionUtils.emptyIfNull(data).stream() - .filter(Objects::nonNull) - .filter(dataRecord -> !containsSegtaxValue(dataRecord.getExt(), segtaxValues)) - .map(Data::getSegment) - .filter(CollectionUtils::isNotEmpty) - .collect(Collectors.toCollection(ArrayList::new))); - - if (CollectionUtils.isEmpty(validDataSegments)) { - return; - } - - final List values = resolveSegtaxBlahValues(validDataSegments); - final ArrayNode segtaxBlah = target.putArray(SEGTAX_BLAH_ATTRIBUTE); - values.forEach(segtaxBlah::add); - } - - private static List> getValidDataSegments(List> dataSegments) { - return dataSegments.stream() - .map(RubiconBidder::getValidOnlySegments) - .filter(CollectionUtils::isNotEmpty) - .collect(Collectors.toCollection(ArrayList::new)); - } - - private static List getValidOnlySegments(List segments) { - return segments.stream() - .filter(segment -> StringUtils.isNotBlank(segment.getId())) - .collect(Collectors.toCollection(ArrayList::new)); - } - - private static List resolveSegtaxBlahValues(final List> segments) { - final List values = new ArrayList<>(); - for (int i = 0; i < SEGTAX_BLAH_MAX_SIZE; i++) { - final int segmentsIndex = i % segments.size(); - final List currentSegments = segments.get(segmentsIndex); - values.add(getAndRemoveLastSegment(currentSegments).getId()); - - if (CollectionUtils.isEmpty(currentSegments)) { - segments.remove(segmentsIndex); - if (CollectionUtils.isEmpty(segments)) { - break; - } - } - } - - return values; - } - - private static Segment getAndRemoveLastSegment(List list) { - final int lastElementIndex = list.size() - 1; - final Segment lastSegment = list.get(lastElementIndex); - list.remove(lastElementIndex); - - return lastSegment; - } - private static boolean containsSegtaxValue(ObjectNode ext, Set segtaxValues) { final JsonNode taxonomyName = ext != null ? ext.get("segtax") : null; @@ -1397,7 +1445,6 @@ private ExtSite makeSiteExt(Site site, ExtImpRubicon rubiconImpExt) { if (CollectionUtils.isNotEmpty(siteContentData)) { target = existingRubiconSiteExtRpTargetOrEmptyNode(extSite); enrichWithIabAttribute(target, siteContentData, SITE_SEGTAXES); - enrichWithSegtaxBlahAttribute(target, siteContentData, SITE_SEGTAXES); } return mapper.fillExtension( @@ -1509,7 +1556,7 @@ private BidRequest createLineItemBidRequest(ExtDealLine lineItem, BidRequest bid final Imp dealsImp = imp.toBuilder() .banner(modifyBanner(imp.getBanner(), lineItem.getSizes())) .ext(modifyRubiconImpExt(imp.getExt(), bidRequest.getExt(), lineItem.getExtLineItemId(), - getAdSlot(imp))) + getAdSlot(imp, extImpContext(imp)))) .build(); return bidRequest.toBuilder() diff --git a/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExt.java b/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExt.java index 9f32e9124cf..1d545488b4e 100644 --- a/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExt.java +++ b/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExt.java @@ -11,5 +11,7 @@ public class RubiconVideoExt { Integer skipdelay; + RubiconVideoExtRp rp; + String videotype; } diff --git a/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExtRp.java b/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExtRp.java new file mode 100644 index 00000000000..88b81e54932 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/rubicon/proto/request/RubiconVideoExtRp.java @@ -0,0 +1,11 @@ +package org.prebid.server.bidder.rubicon.proto.request; + +import lombok.AllArgsConstructor; +import lombok.Value; + +@AllArgsConstructor(staticName = "of") +@Value +public class RubiconVideoExtRp { + + Integer sizeId; +} diff --git a/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java b/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java index 129ebf9eeba..747ae3e583d 100644 --- a/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java @@ -69,6 +69,7 @@ import org.prebid.server.bidder.rubicon.proto.request.RubiconUserExt; import org.prebid.server.bidder.rubicon.proto.request.RubiconUserExtRp; import org.prebid.server.bidder.rubicon.proto.request.RubiconVideoExt; +import org.prebid.server.bidder.rubicon.proto.request.RubiconVideoExtRp; import org.prebid.server.bidder.rubicon.proto.response.RubiconBid; import org.prebid.server.bidder.rubicon.proto.response.RubiconBidResponse; import org.prebid.server.bidder.rubicon.proto.response.RubiconSeatBid; @@ -116,7 +117,6 @@ import java.util.Set; import java.util.function.Function; import java.util.function.UnaryOperator; -import java.util.stream.IntStream; import static java.math.BigDecimal.ONE; import static java.math.BigDecimal.TEN; @@ -808,6 +808,75 @@ public void makeHttpRequestsShouldIgnoreBidRequestIfCurrencyServiceThrowsAnExcep + " for imp `impId` with a reason: failed", BidderError.Type.bad_input)); } + @Test + public void shouldSetSizeIdTo201IfPlacementIs1AndSizeIdIsNotPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + builder -> builder.instl(1).video(Video.builder().placement(1).build()), + builder -> builder.video(RubiconVideoParams.builder().sizeId(null).build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).doesNotContainNull() + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getVideo).doesNotContainNull() + .extracting(Video::getExt).doesNotContainNull() + .extracting(ext -> mapper.treeToValue(ext, RubiconVideoExt.class)) + .extracting(RubiconVideoExt::getRp) + .extracting(RubiconVideoExtRp::getSizeId) + .containsOnly(201); + } + + @Test + public void shouldSetSizeIdTo203IfPlacementIs3AndSizeIdIsNotPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + builder -> builder.instl(1).video(Video.builder().placement(3).build()), + builder -> builder.video(RubiconVideoParams.builder().sizeId(null).build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).doesNotContainNull() + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getVideo).doesNotContainNull() + .extracting(Video::getExt).doesNotContainNull() + .extracting(ext -> mapper.treeToValue(ext, RubiconVideoExt.class)) + .extracting(RubiconVideoExt::getRp) + .extracting(RubiconVideoExtRp::getSizeId) + .containsOnly(203); + } + + @Test + public void shouldSetSizeIdTo202UsingInstlFlagIfPlacementAndSizeIdAreNotPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + builder -> builder.instl(1).video(Video.builder().placement(null).build()), + builder -> builder.video(RubiconVideoParams.builder().sizeId(null).build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).doesNotContainNull() + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getVideo).doesNotContainNull() + .extracting(Video::getExt).doesNotContainNull() + .extracting(ext -> mapper.treeToValue(ext, RubiconVideoExt.class)) + .extracting(RubiconVideoExt::getRp) + .extracting(RubiconVideoExtRp::getSizeId) + .containsOnly(202); + } + @Test public void makeHttpRequestsShouldFillVideoExt() { // given @@ -826,7 +895,7 @@ public void makeHttpRequestsShouldFillVideoExt() { .extracting(Imp::getVideo).doesNotContainNull() .extracting(Video::getExt).doesNotContainNull() .extracting(ext -> mapper.treeToValue(ext, RubiconVideoExt.class)) - .containsOnly(RubiconVideoExt.of(5, 10, null)); + .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); } @Test @@ -854,8 +923,7 @@ public void makeHttpRequestsShouldTransferRewardedVideoFlagIntoRewardedVideoObje .extracting(Imp::getVideo).doesNotContainNull() .extracting(Video::getExt).doesNotContainNull() .extracting(ex -> mapper.treeToValue(ex, RubiconVideoExt.class)) - .extracting(RubiconVideoExt::getVideotype) - .containsOnly("rewarded"); + .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), "rewarded")); } @Test @@ -882,8 +950,7 @@ public void makeHttpRequestsShouldIgnoreRewardedVideoLogic() { .extracting(Imp::getVideo).doesNotContainNull() .extracting(Video::getExt).doesNotContainNull() .extracting(ex -> mapper.treeToValue(ex, RubiconVideoExt.class)) - .extracting(RubiconVideoExt::getVideotype) - .containsOnlyNulls(); + .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); } @Test @@ -910,8 +977,7 @@ public void makeHttpRequestsShouldIgnoreRewardedVideoLogicIfRewardedInventoryIsN .extracting(Imp::getVideo).doesNotContainNull() .extracting(Video::getExt).doesNotContainNull() .extracting(ex -> mapper.treeToValue(ex, RubiconVideoExt.class)) - .extracting(RubiconVideoExt::getVideotype) - .containsOnlyNulls(); + .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); } @Test @@ -959,7 +1025,7 @@ public void makeHttpRequestsShouldIgnoreRewardedVideoFlag() { .extracting(Imp::getVideo).doesNotContainNull() .extracting(Video::getExt).doesNotContainNull() .extracting(ex -> mapper.treeToValue(ex, RubiconVideoExt.class)) - .containsOnly(RubiconVideoExt.of(5, 10, null)); + .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); } @Test @@ -989,70 +1055,6 @@ public void makeHttpRequestsShouldFillUserExtIfUserAndVisitorPresent() { .build()); } - @Test - public void makeHttpRequestsShouldFillUserExtRpWithSegtaxBlahWithNoMoreThanHundredAttributes() { - // given - final List segments = IntStream.range(0, 150) - .mapToObj(index -> givenDataWithSegmentEntry(3, "SegmentId_" + index)) - .toList(); - - final BidRequest bidRequest = givenBidRequest( - builder -> builder.user(User.builder().data(segments).build()), - builder -> builder.video(Video.builder().build()), - identity()); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - final ObjectNode expectedTarget = mapper.createObjectNode(); - final ArrayNode expectedIabAttribute = expectedTarget.putArray("iab"); - expectedIabAttribute.add("segmentId"); - - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1).doesNotContainNull() - .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) - .extracting(BidRequest::getUser).doesNotContainNull() - .extracting(User::getExt) - .extracting(userExt -> userExt.getProperty("rp")) - .extracting(rp -> rp.get("target")) - .extracting(target -> target.get("segtaxBLAH")) - .extracting(JsonNode::size) - .containsExactly(100); - } - - @Test - public void makeHttpRequestsShouldFillUserExtRpWithSegtaxBlahWithSegtaxesFromEachData() { - // given - final List dataWithSegments = asList(givenTestDataWithSegmentEntries(3), - givenDataWithSegmentEntry(3, "Included_SegmentId_1"), - givenDataWithSegmentEntry(3, "Included_SegmentId_2")); - - final BidRequest bidRequest = givenBidRequest( - builder -> builder.user(User.builder().data(dataWithSegments).build()), - builder -> builder.video(Video.builder().build()), - identity()); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - final ObjectNode expectedTarget = mapper.createObjectNode(); - final ArrayNode expectedIabAttribute = expectedTarget.putArray("iab"); - expectedIabAttribute.add("segmentId"); - - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1).doesNotContainNull() - .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) - .extracting(BidRequest::getUser).doesNotContainNull() - .extracting(User::getExt) - .extracting(userExt -> userExt.getProperty("rp")) - .extracting(rp -> rp.get("target")) - .extracting(target -> target.get("segtaxBLAH")) - .flatExtracting(blah -> mapper.convertValue(blah, List.class)) - .contains("Included_SegmentId_1", "Included_SegmentId_2"); - } - @Test public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeIfSegtaxEqualsFour() { // given @@ -1107,7 +1109,7 @@ public void makeHttpRequestsShouldRemoveUserDataObject() { } @Test - public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeAndSegtaxBlahIfSegtaxIsEqualFour() { + public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeOnlyIfSegtaxIsEqualFour() { // given final BidRequest bidRequest = givenBidRequest( builder -> builder.user(User.builder() @@ -1125,8 +1127,6 @@ public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeAndSegtaxBlahIfSe final ObjectNode expectedTarget = mapper.createObjectNode(); final ArrayNode expectedIabAttribute = expectedTarget.putArray("iab"); expectedIabAttribute.add("segmentId"); - final ArrayNode expectedSegtaxBLAHAttribute = expectedTarget.putArray("segtaxBLAH"); - expectedSegtaxBLAHAttribute.add("secondSegmentId"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).doesNotContainNull() @@ -1141,7 +1141,7 @@ public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeAndSegtaxBlahIfSe } @Test - public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxBlahAndIabAttributeIfSegtaxEqualsOneOrTwoOrFiveOrSix() { + public void makeHttpRequestsShouldFillSiteExtRpWithIabAttributeIfSegtaxEqualsOneOrTwoOrFiveOrSix() { // given final BidRequest bidRequest = givenBidRequest( builder -> builder.site(Site.builder() @@ -1167,8 +1167,6 @@ public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxBlahAndIabAttributeIfSe expectedIabAttribute.add("secondSegmentId"); expectedIabAttribute.add("fifthSegmentId"); expectedIabAttribute.add("sixthSegmentId"); - final ArrayNode expectedSegtaxBLAHAttribute = expectedTarget.putArray("segtaxBLAH"); - expectedSegtaxBLAHAttribute.add("thirdSegmentId"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).doesNotContainNull() @@ -1180,38 +1178,6 @@ public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxBlahAndIabAttributeIfSe .containsExactly(expectedTarget); } - @Test - public void makeHttpRequestsShouldFillSiteExtRpWithSegtaxBlahWithNoMoreThanHundredEntries() { - // given - final List segments = IntStream.range(0, 150) - .mapToObj(index -> givenDataWithSegmentEntry(3, "SegmentId_" + index)) - .toList(); - - final BidRequest bidRequest = givenBidRequest( - builder -> builder.site(Site.builder() - .content(Content.builder() - .data(segments) - .build()) - .build()), - builder -> builder.video(Video.builder().build()), - identity()); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1).doesNotContainNull() - .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) - .extracting(BidRequest::getSite).doesNotContainNull() - .extracting(Site::getExt) - .extracting(ext -> ext.getProperty("rp")) - .extracting(rp -> rp.get("target")) - .extracting(rp -> rp.get("segtaxBLAH")) - .extracting(JsonNode::size) - .containsExactly(100); - } - @Test public void makeHttpRequestsShouldRemoveSiteContentDataObject() { // given @@ -1242,7 +1208,7 @@ public void makeHttpRequestsShouldRemoveSiteContentDataObject() { } @Test - public void makeHttpRequestsShouldSetSegtaxBlahProperty() { + public void makeHttpRequestsShouldIgnoreNotIntSegtaxProperty() { // given final ObjectNode userNode = mapper.createObjectNode(); userNode.put("segtax", "3"); @@ -1258,17 +1224,12 @@ public void makeHttpRequestsShouldSetSegtaxBlahProperty() { final Result>> result = target.makeHttpRequests(bidRequest); // then - final ObjectNode expectedTarget = mapper.createObjectNode(); - final ArrayNode expectedSegtaxBLAHAttribute = expectedTarget.putArray("segtaxBLAH"); - expectedSegtaxBLAHAttribute.add("segmentId"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).doesNotContainNull() .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .extracting(BidRequest::getUser).doesNotContainNull() .extracting(User::getExt) - .extracting(ext -> ext.getProperty("rp")) - .extracting(rp -> rp.get("target")) - .containsExactly(expectedTarget); + .containsNull(); } @Test @@ -2410,7 +2371,7 @@ public void makeHttpRequestsShouldCreateRequestPerImp() { } @Test - public void makeHttpRequestsShouldCopyAndModifyDataFieldToRubiconImpExtRpTarget() { + public void makeHttpRequestsShouldCopyAndModifyImpExtContextDataAndDataFieldsToRubiconImpExtRpTarget() { // given final BidRequest bidRequest = givenBidRequest( identity(), @@ -2437,6 +2398,7 @@ public void makeHttpRequestsShouldCopyAndModifyDataFieldToRubiconImpExtRpTarget( .extracting(RubiconImpExt::getRp) .extracting(RubiconImpExtRp::getTarget) .containsOnly(mapper.createObjectNode() + .set("property1", mapper.createArrayNode().add("value1")) .set("property2", mapper.createArrayNode().add("value2"))); } @@ -2461,6 +2423,66 @@ public void makeHttpRequestsShouldPassThroughImpExtGpid() { .containsExactly(TextNode.valueOf("gpidvalue")); } + @Test + public void makeHttpRequestsShouldNotCopyAdSlotFromAdServerWhenAdServerNameIsNotGam() { + // given + final BidRequest bidRequest = givenBidRequest( + identity(), + impBuilder -> impBuilder.video(Video.builder().build()), + identity()); + + bidRequest.getImp().get(0).getExt() + .set("context", mapper.createObjectNode() + .set("data", mapper.createObjectNode() + .put("property", "value") + .set("adserver", mapper.createObjectNode() + .put("name", "not-gam") + .put("adslot", "/test-adserver")))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) + .extracting(RubiconImpExt::getRp) + .extracting(RubiconImpExtRp::getTarget) + .containsOnly(mapper.createObjectNode() + .set("property", mapper.createArrayNode().add("value"))); + } + + @Test + public void makeHttpRequestsShouldNotCopyAndModifyImpExtContextDataAdslotToRubiconImpExtRpTargetDfpAdUnitCode() { + // given + final BidRequest bidRequest = givenBidRequest( + identity(), + impBuilder -> impBuilder.video(Video.builder().build()), + identity()); + + final ObjectNode impExt = bidRequest.getImp().get(0).getExt(); + final ObjectNode impExtContextDataNode = mapper.createObjectNode() + .set("adslot", mapper.createArrayNode().add("123")); + impExt.set("context", mapper.valueToTree(ExtImpContext.of(impExtContextDataNode))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) + .extracting(RubiconImpExt::getRp) + .extracting(RubiconImpExtRp::getTarget) + .containsOnly(mapper.createObjectNode().set("adslot", mapper.createArrayNode().add("123"))); + } + @Test public void makeHttpRequestsShouldCopySiteExtDataFieldsToRubiconImpExtRpTarget() { // given @@ -2514,11 +2536,13 @@ public void makeHttpRequestsShouldCopyAppExtDataFieldsToRubiconImpExtRpTarget() } @Test - public void makeHttpRequestsShouldCopySiteExtDataFieldToRubiconImpExtRpTarget() + public void makeHttpRequestsShouldCopySiteExtDataAndImpExtContextDataFieldsToRubiconImpExtRpTarget() throws IOException { // given final ObjectNode siteExtDataNode = mapper.createObjectNode() .set("site", mapper.createArrayNode().add("value1")); + final ObjectNode impExtContextDataNode = mapper.createObjectNode() + .set("imp_ext", mapper.createArrayNode().add("value2")); final BidRequest bidRequest = givenBidRequest( requestBuilder -> requestBuilder @@ -2526,6 +2550,9 @@ public void makeHttpRequestsShouldCopySiteExtDataFieldToRubiconImpExtRpTarget() impBuilder -> impBuilder.video(Video.builder().build()), identity()); + final ObjectNode impExt = bidRequest.getImp().get(0).getExt(); + impExt.set("context", mapper.valueToTree(ExtImpContext.of(impExtContextDataNode))); + // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -2538,11 +2565,11 @@ public void makeHttpRequestsShouldCopySiteExtDataFieldToRubiconImpExtRpTarget() .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) .extracting(RubiconImpExt::getRp) .extracting(RubiconImpExtRp::getTarget) - .containsOnly(mapper.readTree("{\"site\":[\"value1\"]}")); + .containsOnly(mapper.readTree("{\"imp_ext\":[\"value2\"],\"site\":[\"value1\"]}")); } @Test - public void makeHttpRequestsShouldCopyAppExtDataFieldToRubiconImpExtRpTarget() + public void makeHttpRequestsShouldCopyAppExtDataAndImpExtContextDataFieldsToRubiconImpExtRpTarget() throws IOException { // given final ObjectNode appExtDataNode = mapper.createObjectNode() @@ -2571,11 +2598,11 @@ public void makeHttpRequestsShouldCopyAppExtDataFieldToRubiconImpExtRpTarget() .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) .extracting(RubiconImpExt::getRp) .extracting(RubiconImpExtRp::getTarget) - .containsOnly(mapper.readTree("{\"app\":[\"value1\"]}")); + .containsOnly(mapper.readTree("{\"imp_ext\":[\"value2\"],\"app\":[\"value1\"]}")); } @Test - public void makeHttpRequestsShouldMergeImpExtRubiconKeywordsToRubiconImpExtRpTargetKeywords() + public void makeHttpRequestsShouldMergeImpExtRubiconAndContextAndDataKeywordsToRubiconImpExtRpTargetKeywords() throws IOException { // given @@ -2585,6 +2612,9 @@ public void makeHttpRequestsShouldMergeImpExtRubiconKeywordsToRubiconImpExtRpTar identity()); final ObjectNode impExt = bidRequest.getImp().get(0).getExt(); + final ExtImpContext extImpContext = ExtImpContext.of(null); + extImpContext.addProperty("keywords", new TextNode("imp,ext,context,keywords")); + impExt.set("context", mapper.valueToTree(extImpContext)); impExt.set("data", mapper.createObjectNode() .put("keywords", "imp,ext,data,keywords")); impExt.set( @@ -2606,11 +2636,12 @@ public void makeHttpRequestsShouldMergeImpExtRubiconKeywordsToRubiconImpExtRpTar .extracting(RubiconImpExt::getRp) .extracting(RubiconImpExtRp::getTarget) .containsOnly(mapper.readTree("{\"keywords\":[" + + "\"imp,ext,data,keywords\"," + " \"imp\"," + " \"ext\"," - + " \"data\"," + + " \"context\"," + " \"keywords\"," - + "\"imp,ext,data,keywords\"," + + " \"data\"," + " \"rubicon\"" + "]}")); } @@ -2641,7 +2672,7 @@ public void makeHttpRequestsShouldCopyImpExtContextAndDataSearchToRubiconImpExtR .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) .extracting(RubiconImpExt::getRp) .extracting(RubiconImpExtRp::getTarget) - .containsOnly(mapper.readTree("{\"search\":[\"imp ext data search\"]}")); + .containsOnly(mapper.readTree("{\"search\":[\"imp ext data search\", \"imp ext context search\"]}")); } @Test @@ -2664,6 +2695,89 @@ public void makeHttpRequestsShouldCopyImpExtVideoLanguageToSiteContentLanguage() .containsOnly("ua"); } + @Test + public void makeHttpRequestsShouldMergeImpExtContextSearchAndSiteSearchAndCopyToRubiconImpExtRpTarget() + throws JsonProcessingException { + // given + final BidRequest bidRequest = givenBidRequest( + requestBuilder -> requestBuilder.site(Site.builder().search("site search").build()), + impBuilder -> impBuilder.video(Video.builder().build()), + identity()); + + final ObjectNode impExt = bidRequest.getImp().get(0).getExt(); + final ExtImpContext extImpContext = ExtImpContext.of(null); + extImpContext.addProperty("search", new TextNode("imp ext search")); + impExt.set("context", mapper.valueToTree(extImpContext)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) + .extracting(RubiconImpExt::getRp) + .extracting(RubiconImpExtRp::getTarget) + .containsOnly(mapper.readTree("{\"search\":[\"site search\", \"imp ext search\"]}")); + } + + @Test + public void makeHttpRequestsShouldMergeImpExtContextDataAndSiteAttributesAndCopyToRubiconImpExtRpTarget() { + // given + final BidRequest bidRequest = givenBidRequest( + requestBuilder -> requestBuilder.site(Site.builder() + .sectioncat(singletonList("site sectioncat")) + .pagecat(singletonList("site pagecat")) + .page("site page") + .ref("site ref") + .search("site search") + .build()), + impBuilder -> impBuilder.video(Video.builder().build()), + identity()); + + final ObjectNode impExtContextData = mapper.createObjectNode() + .set("sectioncat", mapper.createArrayNode().add("imp ext sectioncat")) + .set("pagecat", mapper.createArrayNode().add("imp ext pagecat")) + .put("page", "imp ext page") + .put("ref", "imp ext ref") + .put("search", "imp ext search"); + + final ObjectNode impExt = bidRequest.getImp().get(0).getExt(); + impExt.set("context", mapper.valueToTree(ExtImpContext.of(impExtContextData))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) + .extracting(RubiconImpExt::getRp) + .extracting(RubiconImpExtRp::getTarget) + .containsOnly(mapper.createObjectNode() + .set("sectioncat", mapper.createArrayNode() + .add("site sectioncat") + .add("imp ext sectioncat")) + .set("pagecat", mapper.createArrayNode() + .add("site pagecat") + .add("imp ext pagecat")) + .set("page", mapper.createArrayNode() + .add("site page") + .add("imp ext page")) + .set("ref", mapper.createArrayNode() + .add("site ref") + .add("imp ext ref")) + .set("search", mapper.createArrayNode() + .add("site search") + .add("imp ext search"))); + } + @Test public void makeHttpRequestsShouldOverridePbadslotIfPresentInRequestImpExt() { // given @@ -2715,6 +2829,73 @@ public void makeHttpRequestsShouldOverrideDfpAdunitCodeIfAdslotPresentInImpExtDa .containsExactly(TextNode.valueOf("adslotvalue")); } + @Test + public void makeHttpRequestsShouldOverrideDfpAdunitCodeIfAdslotPresentInImpExtContextDataAndAndAdserverNameIsGam() { + // given + final BidRequest bidRequest = givenBidRequest( + identity(), impBuilder -> impBuilder.video(Video.builder().build()), identity()); + + final ObjectNode dataNode = + mapper.createObjectNode() + .set("adserver", mapper.createObjectNode() + .put("adslot", "adslotvalue") + .put("name", "gam")); + + bidRequest.getImp().get(0).getExt() + .set("context", mapper.createObjectNode().set("data", dataNode)); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .extracting(ext -> ext.at("/rp/target/dfp_ad_unit_code")) + .containsExactly(TextNode.valueOf("adslotvalue")); + } + + @Test + public void makeHttpRequestsShouldMergeImpExtContextDataAndAppAttributesAndCopyToRubiconImpExtRpTarget() { + // given + final BidRequest bidRequest = givenBidRequest( + requestBuilder -> requestBuilder.app(App.builder() + .sectioncat(singletonList("app sectioncat")) + .pagecat(singletonList("app pagecat")) + .build()), + impBuilder -> impBuilder.video(Video.builder().build()), + identity()); + + final ObjectNode impExtContextData = mapper.createObjectNode() + .set("sectioncat", mapper.createArrayNode().add("imp ext sectioncat")) + .set("pagecat", mapper.createArrayNode().add("imp ext pagecat")); + + final ObjectNode impExt = bidRequest.getImp().get(0).getExt(); + impExt.set("context", mapper.valueToTree(ExtImpContext.of(impExtContextData))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getExt) + .extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class)) + .extracting(RubiconImpExt::getRp) + .extracting(RubiconImpExtRp::getTarget) + .containsOnly(mapper.createObjectNode() + .set("sectioncat", mapper.createArrayNode() + .add("app sectioncat") + .add("imp ext sectioncat")) + .set("pagecat", mapper.createArrayNode() + .add("app pagecat") + .add("imp ext pagecat"))); + } + @Test public void makeHttpRequestsShouldCopySiteKeywords() { // given @@ -3782,16 +3963,6 @@ private static Data givenDataWithSegmentEntry(Integer segtax, String segmentId) .build(); } - private static Data givenTestDataWithSegmentEntries(Integer segtax) { - final List segments = IntStream.range(0, 1000) - .mapToObj(index -> Segment.builder().id("segmentId_" + index).build()) - .toList(); - return Data.builder() - .segment(segments) - .ext(mapper.createObjectNode().put("segtax", segtax)) - .build(); - } - private static PriceFloorRules givenFloors( UnaryOperator floorsCustomizer) { diff --git a/src/test/resources/org/prebid/server/it/hooks/reject/test-rubicon-bid-request-1.json b/src/test/resources/org/prebid/server/it/hooks/reject/test-rubicon-bid-request-1.json index e53c80ad46a..5637a0f0026 100644 --- a/src/test/resources/org/prebid/server/it/hooks/reject/test-rubicon-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/hooks/reject/test-rubicon-bid-request-1.json @@ -24,6 +24,11 @@ "ext": { "rp": { "zone_id": 4001, + "target": { + "page": [ + "http://www.example.com" + ] + }, "track": { "mint": "", "mint_version": "" diff --git a/src/test/resources/org/prebid/server/it/hooks/sample-module/test-rubicon-bid-request-1.json b/src/test/resources/org/prebid/server/it/hooks/sample-module/test-rubicon-bid-request-1.json index 3af3db2ec3a..89d2ac57bcb 100644 --- a/src/test/resources/org/prebid/server/it/hooks/sample-module/test-rubicon-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/hooks/sample-module/test-rubicon-bid-request-1.json @@ -25,6 +25,11 @@ "ext": { "rp": { "zone_id": 4001, + "target": { + "page": [ + "http://www.example.com" + ] + }, "track": { "mint": "", "mint_version": "" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/magnite/test-magnite-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/magnite/test-magnite-bid-request.json index 541f4302b67..15584c3d343 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/magnite/test-magnite-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/magnite/test-magnite-bid-request.json @@ -14,6 +14,11 @@ "ext": { "rp": { "zone_id": 4001, + "target": { + "page": [ + "http://www.example.com" + ] + }, "track": { "mint": "", "mint_version": "" diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon/test-rubicon-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon/test-rubicon-bid-request.json index 541f4302b67..15584c3d343 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon/test-rubicon-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon/test-rubicon-bid-request.json @@ -14,6 +14,11 @@ "ext": { "rp": { "zone_id": 4001, + "target": { + "page": [ + "http://www.example.com" + ] + }, "track": { "mint": "", "mint_version": ""