Skip to content

Commit 17ff599

Browse files
committed
Multiple Bidder Codes
1 parent 31a0b05 commit 17ff599

2 files changed

Lines changed: 129 additions & 80 deletions

File tree

src/main/java/org/prebid/server/auction/BidResponseCreator.java

Lines changed: 72 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,6 @@ public BidResponseCreator(double logSamplingRate,
193193
this.mediaTypeCacheTtl = Objects.requireNonNull(mediaTypeCacheTtl);
194194
this.cacheDefaultProperties = Objects.requireNonNull(cacheDefaultProperties);
195195
this.metrics = Objects.requireNonNull(metrics);
196-
197196
this.logSamplingRate = logSamplingRate;
198197

199198
cacheAssetUrlTemplate = Objects.requireNonNull(coreCacheService.getCachedAssetURLTemplate());
@@ -210,7 +209,6 @@ private static int validateTruncateAttrChars(int truncateAttrChars) {
210209

211210
Future<BidResponse> createOnSkippedAuction(AuctionContext auctionContext, List<SeatBid> seatBids) {
212211
final BidRequest bidRequest = auctionContext.getBidRequest();
213-
214212
final ExtBidResponse extBidResponse = ExtBidResponse.builder()
215213
.warnings(extractContextWarnings(auctionContext))
216214
.tmaxrequest(bidRequest.getTmax())
@@ -243,7 +241,6 @@ private Future<BidResponse> create(VideoStoredDataResult videoStoredDataResult,
243241
Map<String, MultiBidConfig> bidderToMultiBids) {
244242

245243
final EventsContext eventsContext = createEventsContext(auctionContext);
246-
247244
final List<BidderResponse> bidderResponses = auctionContext.getAuctionParticipations().stream()
248245
.filter(auctionParticipation -> !auctionParticipation.isRequestBlocked())
249246
.map(AuctionParticipation::getBidderResponse)
@@ -271,7 +268,6 @@ private Future<List<BidderResponse>> updateBids(List<BidderResponse> bidderRespo
271268

272269
for (final BidderResponse bidderResponse : bidderResponses) {
273270
final String bidder = bidderResponse.getBidder();
274-
275271
final List<BidderBid> modifiedBidderBids = new ArrayList<>();
276272
final BidderSeatBid seatBid = bidderResponse.getSeatBid();
277273
for (final BidderBid bidderBid : seatBid.getBids()) {
@@ -299,7 +295,6 @@ private Bid updateBid(Bid bid,
299295

300296
final Account account = auctionContext.getAccount();
301297
final List<String> debugWarnings = auctionContext.getDebugWarnings();
302-
303298
final String generatedBidId = bidIdGenerator.getType() != IdGeneratorType.none
304299
? bidIdGenerator.generateId()
305300
: null;
@@ -365,15 +360,13 @@ private ObjectNode updateBidExt(Bid bid,
365360
generatedBidId,
366361
effectiveBidId);
367362
final ObjectNode existingBidExt = bid.getExt();
368-
369363
final ObjectNode updatedBidExt = mapper.mapper().createObjectNode();
370364

371365
if (existingBidExt != null && !existingBidExt.isEmpty()) {
372366
updatedBidExt.setAll(existingBidExt);
373367
}
374368

375369
updatedBidExt.set(PREBID_EXT, mapper.mapper().valueToTree(updatedExtBidPrebid));
376-
377370
return updatedBidExt;
378371
}
379372

@@ -389,7 +382,6 @@ private ExtBidPrebid updateBidExtPrebid(Bid bid,
389382
final Video storedVideo = videoStoredDataResult.getImpIdToStoredVideo().get(bid.getImpid());
390383
final Events events = createEvents(bidder, account, effectiveBidId, eventsContext);
391384
final ExtBidPrebidVideo extBidPrebidVideo = getExtBidPrebidVideo(bid.getExt()).orElse(null);
392-
393385
final ExtBidPrebid.ExtBidPrebidBuilder extBidPrebidBuilder = getExtPrebid(bid.getExt(), ExtBidPrebid.class)
394386
.map(ExtBidPrebid::toBuilder)
395387
.orElseGet(ExtBidPrebid::builder);
@@ -419,52 +411,77 @@ private List<BidderResponseInfo> toBidderResponseInfos(CategoryMappingResult cat
419411
final List<Imp> imps = auctionContext.getBidRequest().getImp();
420412
final Account account = auctionContext.getAccount();
421413
final List<BidderResponseInfo> result = new ArrayList<>();
422-
423414
final List<BidderResponse> bidderResponses = categoryMappingResult.getBidderResponses();
415+
424416
for (final BidderResponse bidderResponse : bidderResponses) {
425417
final String bidder = bidderResponse.getBidder();
426-
427-
final List<BidInfo> bidInfos = new ArrayList<>();
428418
final BidderSeatBid seatBid = bidderResponse.getSeatBid();
429419

430-
final BidderBid firstBid = CollectionUtils.isEmpty(seatBid.getBids()) ? null : seatBid.getBids().getFirst();
431-
final String seat = firstBid == null ? bidder : firstBid.getSeat();
432-
final String adapterCode = firstBid == null ? bidder : Optional.ofNullable(firstBid.getBid())
433-
.map(Bid::getExt)
434-
.flatMap(ext -> getExtPrebid(ext, ExtBidPrebid.class))
435-
.map(ExtBidPrebid::getMeta)
436-
.map(ExtBidPrebidMeta::getAdapterCode)
437-
.orElse(bidder);
420+
final Map<String, List<BidderBid>> seatToBids = seatBid.getBids().stream()
421+
.filter(bidderBid -> Objects.nonNull(bidderBid.getSeat()))
422+
.collect(Collectors.groupingBy(BidderBid::getSeat));
438423

439-
for (final BidderBid bidderBid : seatBid.getBids()) {
440-
final BidInfo bidInfo = toBidInfo(
441-
bidderBid.getBid(),
442-
bidderBid.getType(),
443-
bidderBid.getSeat(),
444-
imps,
424+
if (seatToBids.isEmpty()) {
425+
final BidderSeatBidInfo bidderSeatBidInfo = BidderSeatBidInfo.of(
426+
Collections.emptyList(),
427+
seatBid.getHttpCalls(),
428+
seatBid.getErrors(),
429+
seatBid.getWarnings(),
430+
seatBid.getFledgeAuctionConfigs(),
431+
seatBid.getIgi());
432+
433+
result.add(BidderResponseInfo.of(
445434
bidder,
446-
categoryMappingResult,
447-
cacheInfo,
448-
account);
449-
bidInfos.add(bidInfo);
435+
bidder,
436+
bidder,
437+
bidderSeatBidInfo,
438+
bidderResponse.getResponseTime()));
439+
440+
continue;
450441
}
451442

452-
final BidderSeatBidInfo bidderSeatBidInfo = BidderSeatBidInfo.of(
453-
bidInfos,
454-
seatBid.getHttpCalls(),
455-
seatBid.getErrors(),
456-
seatBid.getWarnings(),
457-
seatBid.getFledgeAuctionConfigs(),
458-
seatBid.getIgi());
459-
460-
result.add(BidderResponseInfo.of(
461-
bidder,
462-
seat,
463-
adapterCode,
464-
bidderSeatBidInfo,
465-
bidderResponse.getResponseTime()));
466-
}
443+
for (final Map.Entry<String, List<BidderBid>> bidsEntry : seatToBids.entrySet()) {
444+
final List<BidInfo> bidInfos = new ArrayList<>();
445+
final String seat = bidsEntry.getKey();
446+
final List<BidderBid> bids = bidsEntry.getValue();
447+
final BidderBid firstBid = CollectionUtils.isEmpty(bids) ? null : bids.getFirst();
448+
final String adapterCode = Optional.ofNullable(firstBid)
449+
.map(BidderBid::getBid)
450+
.map(Bid::getExt)
451+
.flatMap(ext -> getExtPrebid(ext, ExtBidPrebid.class))
452+
.map(ExtBidPrebid::getMeta)
453+
.map(ExtBidPrebidMeta::getAdapterCode)
454+
.orElse(bidder);
455+
456+
for (final BidderBid bidderBid : bids) {
457+
final BidInfo bidInfo = toBidInfo(
458+
bidderBid.getBid(),
459+
bidderBid.getType(),
460+
bidderBid.getSeat(),
461+
imps,
462+
bidder,
463+
categoryMappingResult,
464+
cacheInfo,
465+
account);
466+
bidInfos.add(bidInfo);
467+
}
467468

469+
final BidderSeatBidInfo bidderSeatBidInfo = BidderSeatBidInfo.of(
470+
bidInfos,
471+
seatBid.getHttpCalls(),
472+
seatBid.getErrors(),
473+
seatBid.getWarnings(),
474+
seatBid.getFledgeAuctionConfigs(),
475+
seatBid.getIgi());
476+
477+
result.add(BidderResponseInfo.of(
478+
bidder,
479+
seat,
480+
adapterCode,
481+
bidderSeatBidInfo,
482+
bidderResponse.getResponseTime()));
483+
}
484+
}
468485
return result;
469486
}
470487

@@ -1156,15 +1173,13 @@ private Map<String, List<ExtBidderError>> toExtBidderErrors(List<BidderResponseI
11561173
Map<String, List<ExtBidderError>> bidErrors) {
11571174

11581175
final Map<String, List<ExtBidderError>> errors = new HashMap<>();
1159-
11601176
errors.putAll(extractBidderErrors(bidderResponses));
11611177
errors.putAll(extractDeprecatedBiddersErrors(auctionContext.getBidRequest()));
11621178
errors.putAll(extractPrebidErrors(videoStoredDataResult, auctionContext));
11631179
errors.putAll(extractCacheErrors(cacheResult));
11641180
if (MapUtils.isNotEmpty(bidErrors)) {
11651181
addBidErrors(errors, bidErrors);
11661182
}
1167-
11681183
return errors.isEmpty() ? null : errors;
11691184
}
11701185

@@ -1177,7 +1192,11 @@ private static Map<String, List<ExtBidderError>> extractBidderErrors(
11771192
return bidderResponses.stream()
11781193
.filter(bidderResponse -> CollectionUtils.isNotEmpty(bidderResponse.getSeatBid().getErrors()))
11791194
.collect(Collectors.toMap(BidderResponseInfo::getSeat,
1180-
bidderResponse -> errorsDetails(bidderResponse.getSeatBid().getErrors())));
1195+
bidderResponse -> errorsDetails(bidderResponse.getSeatBid().getErrors()),
1196+
(errors1, errors2) -> {
1197+
errors1.addAll(errors2);
1198+
return errors1;
1199+
}));
11811200
}
11821201

11831202
/**
@@ -1189,7 +1208,11 @@ private static Map<String, List<ExtBidderError>> extractBidderWarnings(
11891208
return bidderResponses.stream()
11901209
.filter(bidderResponse -> CollectionUtils.isNotEmpty(bidderResponse.getSeatBid().getWarnings()))
11911210
.collect(Collectors.toMap(BidderResponseInfo::getSeat,
1192-
bidderResponse -> errorsDetails(bidderResponse.getSeatBid().getWarnings())));
1211+
bidderResponse -> errorsDetails(bidderResponse.getSeatBid().getWarnings()),
1212+
(warnings1, warnings2) -> {
1213+
warnings1.addAll(warnings2);
1214+
return warnings1;
1215+
}));
11931216
}
11941217

11951218
/**
@@ -1322,7 +1345,7 @@ private static Map<String, Integer> toResponseTimes(Collection<BidderResponseInf
13221345
CacheServiceResult cacheResult) {
13231346

13241347
final Map<String, Integer> responseTimeMillis = bidderResponses.stream()
1325-
.collect(Collectors.toMap(BidderResponseInfo::getSeat, BidderResponseInfo::getResponseTime));
1348+
.collect(Collectors.toMap(BidderResponseInfo::getSeat, BidderResponseInfo::getResponseTime, Math::max));
13261349

13271350
final DebugHttpCall debugHttpCall = cacheResult.getHttpCall();
13281351
final Integer cacheResponseTime = debugHttpCall != null ? debugHttpCall.getResponseTimeMillis() : null;

src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -409,13 +409,13 @@ public void shouldRequestCacheServiceWithExpectedArguments() {
409409
final List<BidderResponse> bidderResponses = asList(
410410
BidderResponse.of("bidder1",
411411
givenSeatBid(
412-
BidderBid.of(bid1, banner, "USD"),
413-
BidderBid.of(bid2, banner, "USD")),
412+
BidderBid.of(bid1, banner, "seat1", "USD"),
413+
BidderBid.of(bid2, banner, "seat1", "USD")),
414414
100),
415415
BidderResponse.of("bidder2",
416416
givenSeatBid(
417-
BidderBid.of(bid3, banner, "USD"),
418-
BidderBid.of(bid4, banner, "USD")),
417+
BidderBid.of(bid3, banner, "seat2", "USD"),
418+
BidderBid.of(bid4, banner, "seat2", "USD")),
419419
100));
420420

421421
final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder()
@@ -481,13 +481,13 @@ public void shouldRequestCacheServiceWithWinningBidsOnlyWhenWinningonlyIsTrue()
481481
final List<BidderResponse> bidderResponses = asList(
482482
BidderResponse.of("bidder1",
483483
givenSeatBid(
484-
BidderBid.of(bid1, banner, "USD"),
485-
BidderBid.of(bid2, banner, "USD")),
484+
BidderBid.of(bid1, banner, "seat1", "USD"),
485+
BidderBid.of(bid2, banner, "seat1", "USD")),
486486
100),
487487
BidderResponse.of("bidder2",
488488
givenSeatBid(
489-
BidderBid.of(bid3, banner, "USD"),
490-
BidderBid.of(bid4, banner, "USD")),
489+
BidderBid.of(bid3, banner, "seat2", "USD"),
490+
BidderBid.of(bid4, banner, "seat2", "USD")),
491491
100));
492492

493493
final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder()
@@ -549,8 +549,8 @@ public void shouldRequestCacheServiceWithVideoBidsToModify() {
549549

550550
final String bidder1 = "bidder1";
551551
final List<BidderResponse> bidderResponses = asList(
552-
BidderResponse.of(bidder1, givenSeatBid(BidderBid.of(bid1, video, "USD")), 100),
553-
BidderResponse.of("bidder2", givenSeatBid(BidderBid.of(bid2, banner, "USD")), 100));
552+
BidderResponse.of(bidder1, givenSeatBid(BidderBid.of(bid1, video, "seat1", "USD")), 100),
553+
BidderResponse.of("bidder2", givenSeatBid(BidderBid.of(bid2, banner, "seat2", "USD")), 100));
554554

555555
final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder()
556556
.doCaching(true)
@@ -652,7 +652,7 @@ public void shouldCallCacheServiceEvenRoundedCpmIsZero() {
652652
// given
653653
final Bid bid1 = Bid.builder().id("bidId1").impid(IMP_ID).price(BigDecimal.valueOf(0.05)).build();
654654
final List<BidderResponse> bidderResponses = singletonList(
655-
BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid1, banner, "USD")), 100));
655+
BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid1, banner, "seat1", "USD")), 100));
656656

657657
final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder().doCaching(true).build();
658658
final AuctionContext auctionContext = givenAuctionContext(givenBidRequest(givenImp()))
@@ -888,20 +888,33 @@ public void shouldSetExpectedResponseSeatBidAndBidFields() {
888888
final ObjectNode bidExt = mapper.createObjectNode()
889889
.put("origbidcpm", BigDecimal.ONE)
890890
.put("origbidcur", "USD");
891-
final Bid bid = Bid.builder()
892-
.id("bidId")
891+
892+
final Bid bid1 = Bid.builder()
893+
.id("bidId1")
893894
.price(BigDecimal.ONE)
894895
.adm(BID_ADM)
895-
.impid(IMP_ID)
896+
.impid("impId1")
897+
.ext(bidExt)
898+
.build();
899+
900+
final Bid bid2 = Bid.builder()
901+
.id("bidId2")
902+
.price(BigDecimal.ONE)
903+
.adm(BID_ADM)
904+
.impid("impId2")
896905
.ext(bidExt)
897906
.build();
898907

899908
final String bidder = "bidder1";
900-
final List<BidderResponse> bidderResponses = singletonList(BidderResponse.of(bidder,
901-
givenSeatBid(BidderBid.of(bid, banner, "seat", "USD")), 100));
909+
final List<BidderResponse> bidderResponses = singletonList(BidderResponse.of(
910+
bidder,
911+
givenSeatBid(
912+
BidderBid.of(bid1, banner, "seat1", "USD"),
913+
BidderBid.of(bid2, banner, "seat2", "USD")),
914+
100));
902915

903916
final AuctionContext auctionContext = givenAuctionContext(
904-
givenBidRequest(givenImp()),
917+
givenBidRequest(givenImp("impId1"), givenImp("impId2")),
905918
contextBuilder -> contextBuilder.auctionParticipations(toAuctionParticipant(bidderResponses)));
906919

907920
final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder().doCaching(true).build();
@@ -919,21 +932,34 @@ public void shouldSetExpectedResponseSeatBidAndBidFields() {
919932
final ArgumentCaptor<List<BidInfo>> bidsArgumentCaptor = ArgumentCaptor.forClass(List.class);
920933
verify(coreCacheService).cacheBidsOpenrtb(bidsArgumentCaptor.capture(), any(), any(), any());
921934

922-
assertThat(bidsArgumentCaptor.getValue()).extracting(bidInfo -> bidInfo.getBid().getExt())
935+
assertThat(bidsArgumentCaptor.getValue())
936+
.extracting(bidInfo -> bidInfo.getBid().getExt())
923937
.containsOnly(expectedBidExt);
924938

925939
assertThat(bidResponse.getSeatbid())
926-
.containsOnly(SeatBid.builder()
927-
.seat("seat")
928-
.group(0)
929-
.bid(singletonList(Bid.builder()
930-
.id("bidId")
931-
.impid(IMP_ID)
932-
.price(BigDecimal.ONE)
933-
.adm(BID_ADM)
934-
.ext(expectedBidExt)
935-
.build()))
936-
.build());
940+
.containsOnly(
941+
SeatBid.builder()
942+
.seat("seat1")
943+
.group(0)
944+
.bid(singletonList(Bid.builder()
945+
.id("bidId1")
946+
.impid("impId1")
947+
.price(BigDecimal.ONE)
948+
.adm(BID_ADM)
949+
.ext(expectedBidExt)
950+
.build()))
951+
.build(),
952+
SeatBid.builder()
953+
.seat("seat2")
954+
.group(0)
955+
.bid(singletonList(Bid.builder()
956+
.id("bidId2")
957+
.impid("impId2")
958+
.price(BigDecimal.ONE)
959+
.adm(BID_ADM)
960+
.ext(expectedBidExt)
961+
.build()))
962+
.build());
937963
}
938964

939965
@Test
@@ -2653,8 +2679,8 @@ public void shouldNotCacheNonDealBidWithCpmIsZeroAndCacheDealBidWithZeroCpm() {
26532679
final Bid bid2 = Bid.builder().id("bidId2").impid("impId2").price(BigDecimal.ZERO).dealid("dealId2").build();
26542680

26552681
final List<BidderResponse> bidderResponses = asList(
2656-
BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid1, banner, null)), 99),
2657-
BidderResponse.of("bidder2", givenSeatBid(BidderBid.of(bid2, banner, null)), 99));
2682+
BidderResponse.of("bidder1", givenSeatBid(BidderBid.of(bid1, banner, "seat1", null)), 99),
2683+
BidderResponse.of("bidder2", givenSeatBid(BidderBid.of(bid2, banner, "seat2", null)), 99));
26582684

26592685
final AuctionContext auctionContext = givenAuctionContext(
26602686
givenBidRequest(imp1, imp2),

0 commit comments

Comments
 (0)