Skip to content

Commit

Permalink
RP adapter: update segment logic (#1260)
Browse files Browse the repository at this point in the history
  • Loading branch information
SerhiiNahornyi authored and nickluck8 committed Aug 10, 2021
1 parent cf207ed commit 69b4e8c
Show file tree
Hide file tree
Showing 16 changed files with 481 additions and 49 deletions.
41 changes: 32 additions & 9 deletions src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.collect.ImmutableSet;
import com.iab.openrtb.request.App;
import com.iab.openrtb.request.Banner;
import com.iab.openrtb.request.BidRequest;
Expand Down Expand Up @@ -141,6 +142,9 @@ public class RubiconBidder implements Bidder<BidRequest> {
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<Integer> USER_SEGTAXES = ImmutableSet.of(3);
private static final Set<Integer> SITE_SEGTAXES = ImmutableSet.of(1, 2);

private static final Set<String> STYPE_TO_REMOVE = new HashSet<>(Arrays.asList(PPUID_STYPE, SHA256EMAIL_STYPE,
DMP_STYPE));
private static final TypeReference<ExtPrebid<ExtImpPrebid, ExtImpRubicon>> RUBICON_EXT_TYPE_REFERENCE =
Expand Down Expand Up @@ -1073,7 +1077,7 @@ private JsonNode rubiconUserExtRpTarget(Map<String, List<ExtUserEid>> sourceToUs
if (user != null) {
mergeFirstPartyDataFromUser(user.getExt(), result);

enrichWithIabAttribute(result, user.getData());
enrichWithIabAttribute(result, user.getData(), USER_SEGTAXES);
}

return result.size() > 0 ? result : null;
Expand Down Expand Up @@ -1108,10 +1112,10 @@ private void mergeFirstPartyDataFromUser(ExtUser userExt, ObjectNode result) {
}
}

private void enrichWithIabAttribute(ObjectNode target, List<Data> data) {
private static void enrichWithIabAttribute(ObjectNode target, List<Data> data, Set<Integer> segtaxValues) {
final List<String> iabValue = CollectionUtils.emptyIfNull(data).stream()
.filter(Objects::nonNull)
.filter(dataRecord -> containsIabTaxonomyName(dataRecord.getExt()))
.filter(dataRecord -> containsSegtaxValue(dataRecord.getExt(), segtaxValues))
.map(Data::getSegment)
.filter(Objects::nonNull)
.flatMap(segments -> segments.stream()
Expand All @@ -1125,10 +1129,10 @@ private void enrichWithIabAttribute(ObjectNode target, List<Data> data) {
}
}

private boolean containsIabTaxonomyName(ObjectNode ext) {
final JsonNode taxonomyName = ext != null ? ext.get("taxonomyname") : null;
return taxonomyName != null && taxonomyName.isTextual()
&& StringUtils.containsIgnoreCase(taxonomyName.textValue(), "iab");
private static boolean containsSegtaxValue(ObjectNode ext, Set<Integer> segtaxValues) {
final JsonNode taxonomyName = ext != null ? ext.get("segtax") : null;

return taxonomyName != null && taxonomyName.isInt() && segtaxValues.contains(taxonomyName.intValue());
}

private static String extractLiverampId(Map<String, List<ExtUserEid>> sourceToUserEidExt) {
Expand Down Expand Up @@ -1195,10 +1199,29 @@ private ExtPublisher makePublisherExt(ExtImpRubicon rubiconImpExt) {
private ExtSite makeSiteExt(Site site, ExtImpRubicon rubiconImpExt) {
final ExtSite extSite = site != null ? site.getExt() : null;
final Integer siteExtAmp = extSite != null ? extSite.getAmp() : null;
final Content siteContent = site != null ? site.getContent() : null;
final List<Data> siteContentData = siteContent != null ? siteContent.getData() : null;
ObjectNode target = null;

if (CollectionUtils.isNotEmpty(siteContentData)) {
target = existingRubiconSiteExtRpTargetOrEmptyNode(extSite);
enrichWithIabAttribute(target, siteContentData, SITE_SEGTAXES);
}

return mapper.fillExtension(
ExtSite.of(siteExtAmp, null),
RubiconSiteExt.of(RubiconSiteExtRp.of(rubiconImpExt.getSiteId())));
RubiconSiteExt.of(RubiconSiteExtRp.of(rubiconImpExt.getSiteId(),
target != null && !target.isEmpty() ? target : null)));
}

private ObjectNode existingRubiconSiteExtRpTargetOrEmptyNode(ExtSite siteExt) {
final RubiconSiteExt rubiconSiteExt = siteExt != null
? mapper.mapper().convertValue(siteExt, RubiconSiteExt.class)
: null;
final RubiconSiteExtRp rubiconSiteExtRp = rubiconSiteExt != null ? rubiconSiteExt.getRp() : null;
final JsonNode target = rubiconSiteExtRp != null ? rubiconSiteExtRp.getTarget() : null;

return target != null && target.isObject() ? (ObjectNode) target : mapper.mapper().createObjectNode();
}

private App makeApp(App app, ExtImpRubicon rubiconImpExt) {
Expand All @@ -1210,7 +1233,7 @@ private App makeApp(App app, ExtImpRubicon rubiconImpExt) {

private ExtApp makeAppExt(ExtImpRubicon rubiconImpExt) {
return mapper.fillExtension(ExtApp.of(null, null),
RubiconAppExt.of(RubiconSiteExtRp.of(rubiconImpExt.getSiteId())));
RubiconAppExt.of(RubiconSiteExtRp.of(rubiconImpExt.getSiteId(), null)));
}

private static Source makeSource(Source source, String pchain) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.bidder.rubicon.proto;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.AllArgsConstructor;
import lombok.Value;

Expand All @@ -8,4 +9,6 @@
public class RubiconSiteExtRp {

Integer siteId;

JsonNode target;
}
Original file line number Diff line number Diff line change
Expand Up @@ -814,15 +814,13 @@ public void makeHttpRequestsShouldFillUserExtIfUserAndVisitorPresent() {
}

@Test
public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeIfTaxonomynameContainsIab() {
public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeIfSegtaxEqualsThree() {
// given
final ObjectNode userNode = mapper.createObjectNode();
userNode.put("taxonomyname", "contains IaB");
final BidRequest bidRequest = givenBidRequest(
builder -> builder.user(User.builder().data(singletonList(Data.builder()
.segment(singletonList(Segment.builder().id("segmentId")
.build()))
.ext(userNode).build())).build()),
builder -> builder.user(User.builder()
.data(singletonList(
givenDataWithSegmentEntry(3, "segmentId")
)).build()),
builder -> builder.video(Video.builder().build()),
identity());

Expand All @@ -847,21 +845,14 @@ public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeIfTaxonomynameCon
}

@Test
public void makeHttpRequestsShouldFillWithIabAttributeOnlyIfContainsIabInTaxonomynameAttribute() {
public void makeHttpRequestsShouldFillUserExtRpWithIabAttributeOnlyIfSegtaxIsEqualThree() {
// given
final ObjectNode firstUserDataNode = mapper.createObjectNode();
firstUserDataNode.put("taxonomyname", "contains IaB");
final ObjectNode secondUserDataNode = mapper.createObjectNode();
secondUserDataNode.put("taxonomyname", "not contain");
final BidRequest bidRequest = givenBidRequest(
builder -> builder.user(User.builder().data(asList(Data.builder()
.segment(singletonList(Segment.builder().id("segmentId")
.build()))
.ext(firstUserDataNode).build(),
Data.builder()
.segment(singletonList(Segment.builder().id("secondSegmentId")
.build()))
.ext(secondUserDataNode).build())).build()),
builder -> builder.user(User.builder()
.data(asList(
givenDataWithSegmentEntry(3, "segmentId"),
givenDataWithSegmentEntry(2, "secondSegmentId")))
.build()),
builder -> builder.video(Video.builder().build()),
identity());

Expand All @@ -886,12 +877,44 @@ public void makeHttpRequestsShouldFillWithIabAttributeOnlyIfContainsIabInTaxonom
}

@Test
public void makeHttpRequestsShouldIgnoreNotTextualTaxonomynameProperty() {
public void makeHttpRequestsShouldFillSiteExtRpWithIabAttributeIfSegtaxEqualsOneOrTwo() {
// given
final ObjectNode userNode = mapper.createObjectNode();
final ArrayNode wrongTaxonomyAttributeType = userNode.putArray("taxonomyname");
wrongTaxonomyAttributeType.add("contains IaB value");
final BidRequest bidRequest = givenBidRequest(
builder -> builder.site(Site.builder()
.content(Content.builder()
.data(asList(
givenDataWithSegmentEntry(1, "firstSegmentId"),
givenDataWithSegmentEntry(2, "secondSegmentId"),
givenDataWithSegmentEntry(3, "thirdSegmentId")))
.build())
.build()),
builder -> builder.video(Video.builder().build()),
identity());

// when
final Result<List<HttpRequest<BidRequest>>> result = rubiconBidder.makeHttpRequests(bidRequest);

// then
final ObjectNode expectedTarget = mapper.createObjectNode();
final ArrayNode expectedIabAttribute = expectedTarget.putArray("iab");
expectedIabAttribute.add("firstSegmentId");
expectedIabAttribute.add("secondSegmentId");

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"))
.containsExactly(expectedTarget);
}

@Test
public void makeHttpRequestsShouldIgnoreNotIntSegtaxProperty() {
// given
final ObjectNode userNode = mapper.createObjectNode();
userNode.put("segtax", "3");
final BidRequest bidRequest = givenBidRequest(
builder -> builder.user(User.builder().data(singletonList(Data.builder()
.segment(singletonList(Segment.builder().id("segmentId")
Expand All @@ -909,7 +932,6 @@ public void makeHttpRequestsShouldIgnoreNotTextualTaxonomynameProperty() {
.extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class))
.extracting(BidRequest::getUser).doesNotContainNull()
.extracting(User::getExt)
.hasSize(1)
.containsNull();
}

Expand Down Expand Up @@ -1564,7 +1586,7 @@ public void makeHttpRequestsShouldFillSiteExtIfSitePresent() {
RubiconPubExt.of(RubiconPubExtRp.of(2001))))
.build())
.ext(jacksonMapper.fillExtension(
ExtSite.of(null, null), RubiconSiteExt.of(RubiconSiteExtRp.of(3001))))
ExtSite.of(null, null), RubiconSiteExt.of(RubiconSiteExtRp.of(3001, null))))
.build());
}

Expand All @@ -1591,7 +1613,7 @@ public void makeHttpRequestsShouldPassSiteExtAmpIfPresent() {
RubiconPubExt.of(RubiconPubExtRp.of(2001))))
.build())
.ext(jacksonMapper.fillExtension(
ExtSite.of(1, null), RubiconSiteExt.of(RubiconSiteExtRp.of(3001))))
ExtSite.of(1, null), RubiconSiteExt.of(RubiconSiteExtRp.of(3001, null))))
.build());
}

Expand All @@ -1613,7 +1635,7 @@ public void makeHttpRequestsShouldRemoveSiteExtData() {
.extracting(Site::getExt)
.containsOnly(jacksonMapper.fillExtension(
ExtSite.of(null, null),
RubiconSiteExt.of(RubiconSiteExtRp.of(3001))));
RubiconSiteExt.of(RubiconSiteExtRp.of(3001, null))));
}

@Test
Expand All @@ -1640,7 +1662,7 @@ public void makeHttpRequestsShouldFillAppExtIfAppPresent() {
.build())
.ext(jacksonMapper.fillExtension(
ExtApp.of(null, null),
RubiconAppExt.of(RubiconSiteExtRp.of(3001))))
RubiconAppExt.of(RubiconSiteExtRp.of(3001, null))))
.build());
}

Expand All @@ -1662,7 +1684,7 @@ public void makeHttpRequestsShouldRemoveAppExtData() {
.extracting(App::getExt)
.containsOnly(jacksonMapper.fillExtension(
ExtApp.of(null, null),
RubiconAppExt.of(RubiconSiteExtRp.of(3001))));
RubiconAppExt.of(RubiconSiteExtRp.of(3001, null))));
}

@Test
Expand Down Expand Up @@ -2891,6 +2913,13 @@ private static Imp givenImp(Function<ImpBuilder, ImpBuilder> impCustomizer) {
return givenImp(impCustomizer, identity());
}

private static Data givenDataWithSegmentEntry(Integer segtax, String segmentId) {
return Data.builder()
.segment(singletonList(Segment.builder().id(segmentId).build()))
.ext(mapper.createObjectNode().put("segtax", segtax))
.build();
}

private static HttpCall<BidRequest> givenHttpCall(BidRequest bidRequest, String body) {
return HttpCall.success(
HttpRequest.<BidRequest>builder().payload(bidRequest).build(),
Expand Down
61 changes: 61 additions & 0 deletions src/test/java/org/prebid/server/it/RubiconTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.prebid.server.it;

import io.restassured.response.Response;
import org.json.JSONException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.skyscreamer.jsonassert.JSONAssert;
import org.skyscreamer.jsonassert.JSONCompareMode;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
import static com.github.tomakehurst.wiremock.client.WireMock.post;
import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
import static io.restassured.RestAssured.given;
import static java.util.Collections.singletonList;

@RunWith(SpringRunner.class)
public class RubiconTest extends IntegrationTest {

@Test
public void testOpenrtb2AuctionCoreFunctionality() throws IOException, JSONException {
// given
WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange"))
.withHeader("Accept", equalTo("application/json"))
.withHeader("Content-Type", equalTo("application/json;charset=UTF-8"))
.withQueryParam("tk_xint", equalTo("rp-pbs"))
.withRequestBody(equalToJson(
jsonFrom("openrtb2/rubicon/test-rubicon-bid-request.json")))
.willReturn(aResponse().withBody(
jsonFrom("openrtb2/rubicon/test-rubicon-bid-response.json"))));

// pre-bid cache
WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache"))
.withRequestBody(equalToJson(
jsonFrom("openrtb2/rubicon/test-cache-rubicon-request.json")))
.willReturn(aResponse().withBody(
jsonFrom("openrtb2/rubicon/test-cache-rubicon-response.json"))));

// when
final Response response = given(SPEC)
.header("Referer", "http://www.example.com")
.header("X-Forwarded-For", "193.168.244.1")
.header("User-Agent", "userAgent")
.header("Origin", "http://www.example.com")
// this uids cookie value stands for {"uids":{"rubicon":"RUB-UID"}}
.cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJSVUItVUlEIn19")
.body(jsonFrom("openrtb2/rubicon/test-auction-rubicon-request.json"))
.post("/openrtb2/auction");

// then
final String expectedAuctionResponse = openrtbAuctionResponseFrom(
"openrtb2/rubicon/test-auction-rubicon-response.json",
response, singletonList("rubicon"));

JSONAssert.assertEquals(expectedAuctionResponse, response.asString(), JSONCompareMode.NON_EXTENSIBLE);
}
}
Loading

0 comments on commit 69b4e8c

Please sign in to comment.