Skip to content

Commit 19e3285

Browse files
authored
OpenX Adapter: Set buyer exts fields in bid.ext.prebid.meta (prebid#4171)
1 parent 2383a14 commit 19e3285

3 files changed

Lines changed: 216 additions & 4 deletions

File tree

src/main/java/org/prebid/server/bidder/openx/OpenxBidder.java

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.prebid.server.bidder.model.HttpRequest;
1818
import org.prebid.server.bidder.model.Result;
1919
import org.prebid.server.bidder.openx.model.OpenxImpType;
20+
import org.prebid.server.bidder.openx.proto.OpenxBidExt;
2021
import org.prebid.server.bidder.openx.proto.OpenxBidResponse;
2122
import org.prebid.server.bidder.openx.proto.OpenxBidResponseExt;
2223
import org.prebid.server.bidder.openx.proto.OpenxRequestExt;
@@ -29,6 +30,8 @@
2930
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
3031
import org.prebid.server.proto.openrtb.ext.request.openx.ExtImpOpenx;
3132
import org.prebid.server.proto.openrtb.ext.response.BidType;
33+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid;
34+
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidMeta;
3235
import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo;
3336
import org.prebid.server.proto.openrtb.ext.response.ExtIgi;
3437
import org.prebid.server.proto.openrtb.ext.response.ExtIgiIgs;
@@ -270,13 +273,13 @@ private ObjectNode makeImpExt(ObjectNode impExt, boolean addCustomParams) {
270273
return openxImpExt;
271274
}
272275

273-
private static List<BidderBid> extractBids(BidRequest bidRequest, OpenxBidResponse bidResponse) {
276+
private List<BidderBid> extractBids(BidRequest bidRequest, OpenxBidResponse bidResponse) {
274277
return bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())
275278
? Collections.emptyList()
276279
: bidsFromResponse(bidRequest, bidResponse);
277280
}
278281

279-
private static List<BidderBid> bidsFromResponse(BidRequest bidRequest, OpenxBidResponse bidResponse) {
282+
private List<BidderBid> bidsFromResponse(BidRequest bidRequest, OpenxBidResponse bidResponse) {
280283
final Map<String, BidType> impIdToBidType = impIdToBidType(bidRequest);
281284

282285
final String bidCurrency = StringUtils.isNotBlank(bidResponse.getCur())
@@ -292,11 +295,11 @@ private static List<BidderBid> bidsFromResponse(BidRequest bidRequest, OpenxBidR
292295
.toList();
293296
}
294297

295-
private static BidderBid toBidderBid(Bid bid, Map<String, BidType> impIdToBidType, String bidCurrency) {
298+
private BidderBid toBidderBid(Bid bid, Map<String, BidType> impIdToBidType, String bidCurrency) {
296299
final BidType bidType = getBidType(bid, impIdToBidType);
297300
final ExtBidPrebidVideo videoInfo = bidType == BidType.video ? getVideoInfo(bid) : null;
298301
return BidderBid.builder()
299-
.bid(bid)
302+
.bid(bid.toBuilder().ext(getBidExt(bid)).build())
300303
.type(bidType)
301304
.bidCurrency(bidCurrency)
302305
.videoInfo(videoInfo)
@@ -334,4 +337,48 @@ private static List<ExtIgi> extractIgi(OpenxBidResponse bidResponse) {
334337

335338
return igs.isEmpty() ? null : Collections.singletonList(ExtIgi.builder().igs(igs).build());
336339
}
340+
341+
private ObjectNode getBidExt(Bid bid) {
342+
final ObjectNode ext = bid.getExt();
343+
if (ext == null) {
344+
return null;
345+
}
346+
347+
final OpenxBidExt openxBidExt = parseOpenxBidExt(ext);
348+
final Integer buyerId = parseStringToInt(openxBidExt.getBuyerId());
349+
final Integer dspId = parseStringToInt(openxBidExt.getDspId());
350+
final Integer brandId = parseStringToInt(openxBidExt.getBrandId());
351+
352+
if (buyerId == null && dspId == null && brandId == null) {
353+
return ext;
354+
}
355+
356+
final ExtBidPrebidMeta meta = ExtBidPrebidMeta.builder()
357+
.networkId(dspId)
358+
.advertiserId(buyerId)
359+
.brandId(brandId)
360+
.build();
361+
362+
final ExtBidPrebid extBidPrebid = ExtBidPrebid.builder().meta(meta).build();
363+
364+
ext.set(PREBID_EXT, mapper.mapper().valueToTree(extBidPrebid));
365+
366+
return ext;
367+
}
368+
369+
private OpenxBidExt parseOpenxBidExt(ObjectNode ext) {
370+
try {
371+
return mapper.mapper().convertValue(ext, OpenxBidExt.class);
372+
} catch (IllegalArgumentException e) {
373+
return OpenxBidExt.builder().build();
374+
}
375+
}
376+
377+
private static Integer parseStringToInt(String value) {
378+
try {
379+
return Integer.parseInt(value);
380+
} catch (NumberFormatException e) {
381+
return null;
382+
}
383+
}
337384
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.prebid.server.bidder.openx.proto;
2+
3+
import lombok.Builder;
4+
import lombok.Value;
5+
6+
@Builder
7+
@Value
8+
public class OpenxBidExt {
9+
10+
String dspId;
11+
12+
String buyerId;
13+
14+
String brandId;
15+
}

src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.prebid.server.bidder.model.HttpRequest;
2424
import org.prebid.server.bidder.model.HttpResponse;
2525
import org.prebid.server.bidder.model.Result;
26+
import org.prebid.server.bidder.openx.proto.OpenxBidExt;
2627
import org.prebid.server.bidder.openx.proto.OpenxBidResponse;
2728
import org.prebid.server.bidder.openx.proto.OpenxBidResponseExt;
2829
import org.prebid.server.bidder.openx.proto.OpenxRequestExt;
@@ -983,6 +984,155 @@ public void makeBidsShouldReturnResultContainingEmptyValueAndErrorsWhenSeatBidEm
983984
.containsOnly(Collections.emptyList(), Collections.emptyList());
984985
}
985986

987+
@Test
988+
public void makeBidShouldReturnBidWithExtPrebidMetaContainingAllFieldsFromBidExt() throws JsonProcessingException {
989+
// given
990+
final ObjectNode bidExt = mapper.valueToTree(OpenxBidExt.builder()
991+
.dspId("1")
992+
.buyerId("2")
993+
.brandId("3")
994+
.build());
995+
final BidderCall<BidRequest> httpCall = givenHttpCall(mapper.writeValueAsString(
996+
BidResponse.builder()
997+
.seatbid(singletonList(SeatBid.builder()
998+
.bid(List.of(
999+
Bid.builder()
1000+
.w(200)
1001+
.h(150)
1002+
.price(BigDecimal.ONE)
1003+
.impid("impId1")
1004+
.dealid("dealid")
1005+
.adm("<div>This is an Ad</div>")
1006+
.ext(bidExt)
1007+
.build()))
1008+
.build()))
1009+
.build()));
1010+
1011+
final BidRequest bidRequest = BidRequest.builder()
1012+
.id("bidRequestId")
1013+
.imp(List.of(
1014+
Imp.builder()
1015+
.id("impId1")
1016+
.banner(Banner.builder().build())
1017+
.build()))
1018+
.build();
1019+
1020+
// when
1021+
final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest);
1022+
1023+
// then
1024+
final ObjectNode expectedExtWithBidMeta = mapper.createObjectNode()
1025+
.put("dsp_id", "1")
1026+
.put("buyer_id", "2")
1027+
.put("brand_id", "3")
1028+
.set("prebid", mapper.createObjectNode()
1029+
.set("meta", mapper.createObjectNode()
1030+
.put("advertiserId", 2)
1031+
.put("brandId", 3)
1032+
.put("networkId", 1)));
1033+
assertThat(result.getErrors()).isEmpty();
1034+
assertThat(result.getBids()).hasSize(1)
1035+
.extracting(BidderBid::getBid)
1036+
.extracting(Bid::getExt)
1037+
.containsExactly(expectedExtWithBidMeta);
1038+
}
1039+
1040+
@Test
1041+
public void makeBidShouldReturnBidWithExtPrebidMetaContainingBrandIdFieldOnly() throws JsonProcessingException {
1042+
// given
1043+
final ObjectNode bidExt = mapper.valueToTree(OpenxBidExt.builder()
1044+
.brandId("4")
1045+
.build());
1046+
final BidderCall<BidRequest> httpCall = givenHttpCall(mapper.writeValueAsString(
1047+
BidResponse.builder()
1048+
.seatbid(singletonList(SeatBid.builder()
1049+
.bid(List.of(
1050+
Bid.builder()
1051+
.w(200)
1052+
.h(150)
1053+
.price(BigDecimal.ONE)
1054+
.impid("impId1")
1055+
.dealid("dealid")
1056+
.adm("<div>This is an Ad</div>")
1057+
.ext(bidExt)
1058+
.build()))
1059+
.build()))
1060+
.build()));
1061+
1062+
final BidRequest bidRequest = BidRequest.builder()
1063+
.id("bidRequestId")
1064+
.imp(List.of(
1065+
Imp.builder()
1066+
.id("impId1")
1067+
.banner(Banner.builder().build())
1068+
.build()))
1069+
.build();
1070+
1071+
// when
1072+
final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest);
1073+
1074+
// then
1075+
final ObjectNode expectedExtWithBidMeta = mapper.createObjectNode()
1076+
.put("brand_id", "4")
1077+
.set("prebid", mapper.createObjectNode()
1078+
.set("meta", mapper.createObjectNode()
1079+
.put("brandId", 4)));
1080+
assertThat(result.getErrors()).isEmpty();
1081+
assertThat(result.getBids()).hasSize(1)
1082+
.extracting(BidderBid::getBid)
1083+
.extracting(Bid::getExt)
1084+
.containsExactly(expectedExtWithBidMeta);
1085+
}
1086+
1087+
@Test
1088+
public void makeBidShouldReturnBidWithExtPrebidMetaNotContainingFieldsWithInvalidValues()
1089+
throws JsonProcessingException {
1090+
// given
1091+
final ObjectNode bidExt = mapper.valueToTree(OpenxBidExt.builder()
1092+
.dspId("abc")
1093+
.buyerId("xyz")
1094+
.brandId("cba")
1095+
.build());
1096+
final BidderCall<BidRequest> httpCall = givenHttpCall(mapper.writeValueAsString(
1097+
BidResponse.builder()
1098+
.seatbid(singletonList(SeatBid.builder()
1099+
.bid(List.of(
1100+
Bid.builder()
1101+
.w(200)
1102+
.h(150)
1103+
.price(BigDecimal.ONE)
1104+
.impid("impId1")
1105+
.dealid("dealid")
1106+
.adm("<div>This is an Ad</div>")
1107+
.ext(bidExt)
1108+
.build()))
1109+
.build()))
1110+
.build()));
1111+
1112+
final BidRequest bidRequest = BidRequest.builder()
1113+
.id("bidRequestId")
1114+
.imp(List.of(
1115+
Imp.builder()
1116+
.id("impId1")
1117+
.banner(Banner.builder().build())
1118+
.build()))
1119+
.build();
1120+
1121+
// when
1122+
final CompositeBidderResponse result = target.makeBidderResponse(httpCall, bidRequest);
1123+
1124+
// then
1125+
final ObjectNode expectedExtWithBidMeta = mapper.createObjectNode()
1126+
.put("dsp_id", "abc")
1127+
.put("buyer_id", "xyz")
1128+
.put("brand_id", "cba");
1129+
assertThat(result.getErrors()).isEmpty();
1130+
assertThat(result.getBids()).hasSize(1)
1131+
.extracting(BidderBid::getBid)
1132+
.extracting(Bid::getExt)
1133+
.containsExactly(expectedExtWithBidMeta);
1134+
}
1135+
9861136
private static Map<String, JsonNode> givenCustomParams(String key, Object values) {
9871137
return singletonMap(key, mapper.valueToTree(values));
9881138
}

0 commit comments

Comments
 (0)