Skip to content

Commit e056b48

Browse files
authored
Rubicon: Updated xapi integration (#3377)
1 parent 344cb98 commit e056b48

10 files changed

Lines changed: 131 additions & 31 deletions

File tree

src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
import org.prebid.server.util.HttpUtil;
111111
import org.prebid.server.util.ListUtil;
112112
import org.prebid.server.util.ObjectUtil;
113+
import org.prebid.server.version.PrebidVersionProvider;
113114

114115
import java.math.BigDecimal;
115116
import java.net.URISyntaxException;
@@ -154,6 +155,9 @@ public class RubiconBidder implements Bidder<BidRequest> {
154155
private static final String DFP_ADUNIT_CODE_FIELD = "dfp_ad_unit_code";
155156
private static final String STYPE_FIELD = "stype";
156157
private static final String PREBID_EXT = "prebid";
158+
private static final String PBS_LOGIN = "pbs_login";
159+
private static final String PBS_VERSION = "pbs_version";
160+
private static final String PBS_URL = "pbs_url";
157161

158162
private static final String PPUID_STYPE = "ppuid";
159163
private static final String SHA256EMAIL_STYPE = "sha256email";
@@ -180,33 +184,41 @@ public class RubiconBidder implements Bidder<BidRequest> {
180184

181185
private final String bidderName;
182186
private final String endpointUrl;
187+
private final String externalUrl;
188+
private final String xapiUsername;
183189
private final Set<String> supportedVendors;
184190
private final boolean generateBidId;
185191
private final boolean useVideoSizeLogic;
186192
private final CurrencyConversionService currencyConversionService;
187193
private final PriceFloorResolver floorResolver;
194+
private final PrebidVersionProvider versionProvider;
188195
private final JacksonMapper mapper;
189196

190197
private final MultiMap headers;
191198

192199
public RubiconBidder(String bidderName,
193200
String endpoint,
201+
String externalUrl,
194202
String xapiUsername,
195203
String xapiPassword,
196204
List<String> supportedVendors,
197205
boolean generateBidId,
198206
boolean useVideoSizeLogic,
199207
CurrencyConversionService currencyConversionService,
200208
PriceFloorResolver floorResolver,
209+
PrebidVersionProvider versionProvider,
201210
JacksonMapper mapper) {
202211

203212
this.bidderName = Objects.requireNonNull(bidderName);
204213
this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpoint));
214+
this.externalUrl = HttpUtil.validateUrl(Objects.requireNonNull(externalUrl));
215+
this.xapiUsername = Objects.requireNonNull(xapiUsername);
205216
this.supportedVendors = Set.copyOf(Objects.requireNonNull(supportedVendors));
206217
this.generateBidId = generateBidId;
207218
this.useVideoSizeLogic = useVideoSizeLogic;
208219
this.currencyConversionService = Objects.requireNonNull(currencyConversionService);
209220
this.floorResolver = Objects.requireNonNull(floorResolver);
221+
this.versionProvider = Objects.requireNonNull(versionProvider);
210222
this.mapper = Objects.requireNonNull(mapper);
211223

212224
headers = headers(Objects.requireNonNull(xapiUsername), Objects.requireNonNull(xapiPassword));
@@ -704,7 +716,11 @@ private JsonNode makeTarget(Imp imp, ExtImpRubicon rubiconImpExt, Site site, App
704716
mergeFirstPartyDataFromApp(app, result);
705717
mergeFirstPartyDataFromImp(imp, rubiconImpExt, result);
706718

707-
return !result.isEmpty() ? result : null;
719+
result.put(PBS_LOGIN, xapiUsername);
720+
result.put(PBS_VERSION, versionProvider.getNameVersionRecord());
721+
result.put(PBS_URL, externalUrl);
722+
723+
return result;
708724
}
709725

710726
private RubiconImpExtPrebid makeRubiconExtPrebid(PriceFloorResult priceFloorResult,

src/main/java/org/prebid/server/spring/config/bidder/RubiconConfiguration.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler;
1313
import org.prebid.server.spring.config.bidder.util.UsersyncerCreator;
1414
import org.prebid.server.spring.env.YamlPropertySourceFactory;
15+
import org.prebid.server.version.PrebidVersionProvider;
1516
import org.springframework.beans.factory.annotation.Value;
1617
import org.springframework.boot.context.properties.ConfigurationProperties;
1718
import org.springframework.context.annotation.Bean;
@@ -40,6 +41,7 @@ BidderDeps rubiconBidderDeps(RubiconConfigurationProperties rubiconConfiguration
4041
@NotBlank @Value("${external-url}") String externalUrl,
4142
CurrencyConversionService currencyConversionService,
4243
PriceFloorResolver floorResolver,
44+
PrebidVersionProvider versionProvider,
4345
JacksonMapper mapper) {
4446

4547
return BidderDepsAssembler.<RubiconConfigurationProperties>forBidder(BIDDER_NAME)
@@ -49,13 +51,15 @@ BidderDeps rubiconBidderDeps(RubiconConfigurationProperties rubiconConfiguration
4951
new RubiconBidder(
5052
BIDDER_NAME,
5153
config.getEndpoint(),
54+
externalUrl,
5255
config.getXapi().getUsername(),
5356
config.getXapi().getPassword(),
5457
config.getMetaInfo().getSupportedVendors(),
5558
config.getGenerateBidId(),
5659
config.getUseVideoSizeIdLogic(),
5760
currencyConversionService,
5861
floorResolver,
62+
versionProvider,
5963
mapper))
6064
.assemble();
6165
}

src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
109109
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
110110
import org.prebid.server.util.HttpUtil;
111+
import org.prebid.server.version.PrebidVersionProvider;
111112

112113
import java.io.IOException;
113114
import java.math.BigDecimal;
@@ -147,8 +148,10 @@ public class RubiconBidderTest extends VertxTest {
147148

148149
private static final String BIDDER_NAME = "bidderName";
149150
private static final String ENDPOINT_URL = "http://rubiconproject.com/exchange.json?tk_xint=prebid";
151+
private static final String EXTERNAL_URL = "http://localhost:8080";
150152
private static final String USERNAME = "username";
151153
private static final String PASSWORD = "password";
154+
private static final String PBS_VERSION = "pbs_version";
152155
private static final List<String> SUPPORTED_VENDORS = Arrays.asList("activeview", "comscore",
153156
"doubleverify", "integralads", "moat", "sizmek", "whiteops");
154157

@@ -158,34 +161,44 @@ public class RubiconBidderTest extends VertxTest {
158161
@Mock(strictness = LENIENT)
159162
private CurrencyConversionService currencyConversionService;
160163

164+
@Mock(strictness = LENIENT)
165+
private PrebidVersionProvider versionProvider;
166+
161167
private RubiconBidder target;
162168

163169
@BeforeEach
164170
public void setUp() {
165-
target = new RubiconBidder(BIDDER_NAME,
171+
target = new RubiconBidder(
172+
BIDDER_NAME,
166173
ENDPOINT_URL,
174+
EXTERNAL_URL,
167175
USERNAME,
168176
PASSWORD,
169177
SUPPORTED_VENDORS,
170178
false,
171179
true,
172180
currencyConversionService,
173181
priceFloorResolver,
182+
versionProvider,
174183
jacksonMapper);
184+
185+
given(versionProvider.getNameVersionRecord()).willReturn("pbs_version");
175186
}
176187

177188
@Test
178189
public void creationShouldFailOnInvalidEndpointUrl() {
179190
assertThatIllegalArgumentException().isThrownBy(
180191
() -> new RubiconBidder(BIDDER_NAME,
181192
"invalid_url",
193+
EXTERNAL_URL,
182194
USERNAME,
183195
PASSWORD,
184196
SUPPORTED_VENDORS,
185197
false,
186198
true,
187199
currencyConversionService,
188200
priceFloorResolver,
201+
versionProvider,
189202
jacksonMapper));
190203
}
191204

@@ -623,17 +636,17 @@ public void makeHttpRequestsShouldFillImpExt() {
623636
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
624637

625638
// then
639+
final ObjectNode expectedTarget = givenImpExtRpTarget().setAll(
640+
(ObjectNode) mapper.valueToTree(Inventory.of(singletonList("5-star"), singletonList("tech"))));
641+
626642
assertThat(result.getErrors()).isEmpty();
627643
assertThat(result.getValue()).hasSize(1).doesNotContainNull()
628644
.extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class))
629645
.flatExtracting(BidRequest::getImp).doesNotContainNull()
630646
.extracting(Imp::getExt).doesNotContainNull()
631647
.extracting(ext -> mapper.treeToValue(ext, RubiconImpExt.class))
632-
.containsOnly(RubiconImpExt.builder()
633-
.rp(RubiconImpExtRp.of(4001,
634-
mapper.valueToTree(Inventory.of(singletonList("5-star"), singletonList("tech"))),
635-
RubiconImpExtRpTrack.of("", ""),
636-
null))
648+
.containsExactly(RubiconImpExt.builder()
649+
.rp(RubiconImpExtRp.of(4001, expectedTarget, RubiconImpExtRpTrack.of("", ""), null))
637650
.skadn(givenSkadn)
638651
.maxbids(1)
639652
.build());
@@ -832,13 +845,15 @@ public void shouldNotSetSizeIfVideoSizeProcessingLogicIsDisabledAndBidderParamsI
832845
target = new RubiconBidder(
833846
BIDDER_NAME,
834847
ENDPOINT_URL,
848+
EXTERNAL_URL,
835849
USERNAME,
836850
PASSWORD,
837851
SUPPORTED_VENDORS,
838852
true,
839853
false,
840854
currencyConversionService,
841855
priceFloorResolver,
856+
versionProvider,
842857
jacksonMapper);
843858
final BidRequest bidRequest = givenBidRequest(
844859
builder -> builder.instl(1).video(Video.builder().placement(1).build()),
@@ -863,13 +878,15 @@ public void shouldSetSizeFromBidderParamsWhenVideoSizeProcessingLogicIsDisabled(
863878
target = new RubiconBidder(
864879
BIDDER_NAME,
865880
ENDPOINT_URL,
881+
EXTERNAL_URL,
866882
USERNAME,
867883
PASSWORD,
868884
SUPPORTED_VENDORS,
869885
true,
870886
false,
871887
currencyConversionService,
872888
priceFloorResolver,
889+
versionProvider,
873890
jacksonMapper);
874891
final BidRequest bidRequest = givenBidRequest(
875892
builder -> builder.instl(1).video(Video.builder().placement(1).build()),
@@ -2493,11 +2510,14 @@ public void makeHttpRequestsShouldCreateRequestPerImp() {
24932510
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
24942511

24952512
// then
2513+
final RubiconImpExtRp expectedImpExtRp = RubiconImpExtRp.of(
2514+
null, givenImpExtRpTarget(), RubiconImpExtRpTrack.of("", ""), null);
2515+
24962516
final BidRequest expectedBidRequest1 = BidRequest.builder()
24972517
.imp(singletonList(Imp.builder()
24982518
.video(Video.builder().build())
24992519
.ext(mapper.valueToTree(RubiconImpExt.builder()
2500-
.rp(RubiconImpExtRp.of(null, null, RubiconImpExtRpTrack.of("", ""), null))
2520+
.rp(expectedImpExtRp)
25012521
.maxbids(1)
25022522
.build()))
25032523
.build()))
@@ -2508,7 +2528,7 @@ public void makeHttpRequestsShouldCreateRequestPerImp() {
25082528
.video(Video.builder().build())
25092529
.ext(mapper.valueToTree(
25102530
RubiconImpExt.builder()
2511-
.rp(RubiconImpExtRp.of(null, null, RubiconImpExtRpTrack.of("", ""), null))
2531+
.rp(expectedImpExtRp)
25122532
.maxbids(1)
25132533
.build()))
25142534
.build()))
@@ -2544,8 +2564,7 @@ public void makeHttpRequestsShouldCopyAndModifyDataFieldsToRubiconImpExtRpTarget
25442564
.extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class))
25452565
.extracting(RubiconImpExt::getRp)
25462566
.extracting(RubiconImpExtRp::getTarget)
2547-
.containsOnly(mapper.createObjectNode()
2548-
.<ObjectNode>set("property2", mapper.createArrayNode().add("value2")));
2567+
.containsExactly(givenImpExtRpTarget().set("property2", mapper.createArrayNode().add("value2")));
25492568
}
25502569

25512570
@Test
@@ -2592,7 +2611,7 @@ public void makeHttpRequestsShouldCopySiteExtDataFieldsToRubiconImpExtRpTarget()
25922611
.extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class))
25932612
.extracting(RubiconImpExt::getRp)
25942613
.extracting(RubiconImpExtRp::getTarget)
2595-
.containsOnly(mapper.createObjectNode().set("property", mapper.createArrayNode().add("value")));
2614+
.containsExactly(givenImpExtRpTarget().set("property", mapper.createArrayNode().add("value")));
25962615
}
25972616

25982617
@Test
@@ -2618,7 +2637,27 @@ public void makeHttpRequestsShouldCopyAppExtDataFieldsToRubiconImpExtRpTarget()
26182637
.extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class))
26192638
.extracting(RubiconImpExt::getRp)
26202639
.extracting(RubiconImpExtRp::getTarget)
2621-
.containsOnly(mapper.createObjectNode().set("property", mapper.createArrayNode().add("value")));
2640+
.containsOnly(givenImpExtRpTarget().set("property", mapper.createArrayNode().add("value")));
2641+
}
2642+
2643+
@Test
2644+
public void makeHttpRequestsShouldSetXapiFieldsToRubiconImpExtRpTarget() {
2645+
// given
2646+
final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.video(Video.builder().build()));
2647+
2648+
// when
2649+
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
2650+
2651+
// then
2652+
assertThat(result.getErrors()).isEmpty();
2653+
assertThat(result.getValue())
2654+
.extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class))
2655+
.flatExtracting(BidRequest::getImp)
2656+
.extracting(Imp::getExt)
2657+
.extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class))
2658+
.extracting(RubiconImpExt::getRp)
2659+
.extracting(RubiconImpExtRp::getTarget)
2660+
.containsExactly(givenImpExtRpTarget());
26222661
}
26232662

26242663
@Test
@@ -2737,6 +2776,9 @@ public void makeHttpRequestsShouldCopyDataSearchToRubiconImpExtRpTargetSearch()
27372776
final Result<List<HttpRequest<BidRequest>>> result = target.makeHttpRequests(bidRequest);
27382777

27392778
// then
2779+
final ObjectNode expectedTarget = givenImpExtRpTarget()
2780+
.set("search", mapper.createArrayNode().add("imp ext data search"));
2781+
27402782
assertThat(result.getErrors()).isEmpty();
27412783
assertThat(result.getValue())
27422784
.extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class))
@@ -2745,7 +2787,7 @@ public void makeHttpRequestsShouldCopyDataSearchToRubiconImpExtRpTargetSearch()
27452787
.extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class))
27462788
.extracting(RubiconImpExt::getRp)
27472789
.extracting(RubiconImpExtRp::getTarget)
2748-
.containsOnly(mapper.readTree("{\"search\":[\"imp ext data search\"]}"));
2790+
.containsExactly(expectedTarget);
27492791
}
27502792

27512793
@Test
@@ -2794,8 +2836,7 @@ public void makeHttpRequestsShouldMergeSiteAttributesAndCopyToRubiconImpExtRpTar
27942836
.extracting(objectNode -> mapper.convertValue(objectNode, RubiconImpExt.class))
27952837
.extracting(RubiconImpExt::getRp)
27962838
.extracting(RubiconImpExtRp::getTarget)
2797-
.containsOnly(mapper.createObjectNode()
2798-
.<ObjectNode>set("page", mapper.createArrayNode().add("site page")));
2839+
.containsExactly(givenImpExtRpTarget().set("page", mapper.createArrayNode().add("site page")));
27992840
}
28002841

28012842
@Test
@@ -3002,8 +3043,8 @@ public void makeHttpRequestsShouldReturnOnlyLineItemRequestsWithExpectedFieldsWh
30023043
.flatExtracting(BidRequest::getImp)
30033044
.extracting(imp -> mapper.treeToValue(imp.getExt(), RubiconImpExt.class).getRp().getTarget())
30043045
.containsOnly(
3005-
mapper.readTree("{\"line_item\":\"123\"}"),
3006-
mapper.readTree("{\"line_item\":\"234\"}"));
3046+
givenImpExtRpTarget().put("line_item", "123"),
3047+
givenImpExtRpTarget().put("line_item", "234"));
30073048
}
30083049

30093050
@Test
@@ -3719,8 +3760,8 @@ public void makeBidsShouldReturnNativeBidIfNativeIsPresent() throws JsonProcessi
37193760
public void makeBidsShouldReturnBidWithRandomlyGeneratedId() throws JsonProcessingException {
37203761
// given
37213762
target = new RubiconBidder(
3722-
BIDDER_NAME, ENDPOINT_URL, USERNAME, PASSWORD, SUPPORTED_VENDORS, true, true,
3723-
currencyConversionService, priceFloorResolver, jacksonMapper);
3763+
BIDDER_NAME, ENDPOINT_URL, ENDPOINT_URL, USERNAME, PASSWORD, SUPPORTED_VENDORS, true, true,
3764+
currencyConversionService, priceFloorResolver, versionProvider, jacksonMapper);
37243765

37253766
final BidderCall<BidRequest> httpCall = givenHttpCall(givenBidRequest(identity()),
37263767
mapper.writeValueAsString(RubiconBidResponse.builder()
@@ -3745,8 +3786,8 @@ public void makeBidsShouldReturnBidWithRandomlyGeneratedId() throws JsonProcessi
37453786
public void makeBidsShouldReturnBidWithCurrencyFromBidResponse() throws JsonProcessingException {
37463787
// given
37473788
target = new RubiconBidder(
3748-
BIDDER_NAME, ENDPOINT_URL, USERNAME, PASSWORD, SUPPORTED_VENDORS, true, true,
3749-
currencyConversionService, priceFloorResolver, jacksonMapper);
3789+
BIDDER_NAME, ENDPOINT_URL, EXTERNAL_URL, USERNAME, PASSWORD, SUPPORTED_VENDORS, true, true,
3790+
currencyConversionService, priceFloorResolver, versionProvider, jacksonMapper);
37503791

37513792
final BidderCall<BidRequest> httpCall = givenHttpCall(givenBidRequest(identity()),
37523793
mapper.writeValueAsString(RubiconBidResponse.builder()
@@ -3942,6 +3983,13 @@ private static Data givenTestDataWithSegmentEntries(Integer segtax) {
39423983
.build();
39433984
}
39443985

3986+
private static ObjectNode givenImpExtRpTarget() {
3987+
return mapper.createObjectNode()
3988+
.put("pbs_login", USERNAME)
3989+
.put("pbs_version", PBS_VERSION)
3990+
.put("pbs_url", EXTERNAL_URL);
3991+
}
3992+
39453993
@AllArgsConstructor(staticName = "of")
39463994
@Value
39473995
private static class Inventory {

src/test/java/org/prebid/server/it/MagniteTest.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import org.json.JSONException;
55
import org.junit.jupiter.api.Test;
66
import org.prebid.server.model.Endpoint;
7+
import org.prebid.server.version.PrebidVersionProvider;
8+
import org.springframework.beans.factory.annotation.Autowired;
79

810
import java.io.IOException;
911

@@ -15,11 +17,15 @@
1517

1618
public class MagniteTest extends IntegrationTest {
1719

20+
@Autowired
21+
private PrebidVersionProvider versionProvider;
22+
1823
@Test
1924
public void testOpenrtb2AuctionCoreFunctionality() throws IOException, JSONException {
2025
// given
2126
WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/magnite-exchange"))
22-
.withRequestBody(equalToJson(jsonFrom("openrtb2/magnite/test-magnite-bid-request.json")))
27+
.withRequestBody(equalToJson(
28+
jsonFrom("openrtb2/magnite/test-magnite-bid-request.json", versionProvider)))
2329
.willReturn(aResponse().withBody(jsonFrom("openrtb2/magnite/test-magnite-bid-response.json"))));
2430

2531
// when

0 commit comments

Comments
 (0)