Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/main/java/org/prebid/server/auction/BidResponseCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -1565,7 +1565,15 @@ private Bid toBid(BidInfo bidInfo,
final String categoryDuration = bidInfo.getCategory();
targetingKeywords = keywordsCreator != null
? keywordsCreator.makeFor(
bid, seat, isWinningBid, cacheId, bidType.getName(), videoCacheId, categoryDuration, account)
bid,
seat,
isWinningBid,
cacheId,
bidType.getName(),
videoCacheId,
categoryDuration,
account,
bidWarnings)
: null;
} else {
targetingKeywords = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import com.iab.openrtb.response.Bid;
import org.apache.commons.lang3.StringUtils;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity;
import org.prebid.server.proto.openrtb.ext.response.ExtBidderError;
import org.prebid.server.settings.model.Account;

import java.math.BigDecimal;
Expand All @@ -12,7 +14,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
* Used throughout Prebid to create targeting keys as keys which can be used in an ad server like DFP.
Expand Down Expand Up @@ -154,7 +155,8 @@ Map<String, String> makeFor(Bid bid,
String format,
String vastCacheId,
String categoryDuration,
Account account) {
Account account,
Map<String, List<ExtBidderError>> bidWarnings) {

final Map<String, String> keywords = makeFor(
bidder,
Expand All @@ -170,13 +172,13 @@ Map<String, String> makeFor(Bid bid,
account);

if (resolver == null) {
return truncateKeys(keywords);
return truncateKeys(keywords, bidWarnings);
}

final Map<String, String> augmentedKeywords = new HashMap<>(keywords);
augmentedKeywords.putAll(resolver.resolve(bid, bidder));

return truncateKeys(augmentedKeywords);
return truncateKeys(augmentedKeywords, bidWarnings);
}

/**
Expand Down Expand Up @@ -261,12 +263,33 @@ private static String sizeFrom(Integer width, Integer height) {
: null;
}

private Map<String, String> truncateKeys(Map<String, String> keyValues) {
return truncateAttrChars > 0
? keyValues.entrySet().stream()
.collect(Collectors
.toMap(keyValue -> truncateKey(keyValue.getKey()), Map.Entry::getValue, (key1, key2) -> key1))
: keyValues;
private Map<String, String> truncateKeys(Map<String, String> keyValues,
Map<String, List<ExtBidderError>> bidWarnings) {

if (truncateAttrChars <= 0) {
return keyValues;
}

final Map<String, String> keys = new HashMap<>();
final List<String> truncatedKeys = new ArrayList<>();
for (Map.Entry<String, String> entry : keyValues.entrySet()) {
final String key = entry.getKey();
final String truncatedKey = truncateKey(key);
keys.putIfAbsent(truncatedKey, entry.getValue());

if (truncatedKey.length() != key.length()) {
truncatedKeys.add(key);
}
}

if (!truncatedKeys.isEmpty()) {
final String errorMessage = "The following keys have been truncated: %s"
.formatted(String.join(", ", truncatedKeys));
bidWarnings.computeIfAbsent("targeting", ignored -> new ArrayList<>())
.add(ExtBidderError.of(BidderError.Type.bad_input.getCode(), errorMessage));
}

return keys;
}

private String truncateKey(String key) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package org.prebid.server.auction;

import com.iab.openrtb.response.Bid;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.prebid.server.proto.openrtb.ext.request.ExtGranularityRange;
import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity;
import org.prebid.server.proto.openrtb.ext.response.ExtBidderError;
import org.prebid.server.settings.model.Account;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.util.Collections.singletonList;
Expand Down Expand Up @@ -46,7 +50,7 @@ public void shouldReturnTargetingKeywordsForOrdinaryBidOpenrtb() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", false, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", false, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).containsOnly(
Expand Down Expand Up @@ -77,7 +81,8 @@ public void shouldReturnTargetingKeywordsWithEntireKeysOpenrtb() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "veryververyverylongbidder1", false, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "veryververyverylongbidder1", false, null, null,
null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).containsOnly(
Expand Down Expand Up @@ -113,7 +118,7 @@ public void shouldReturnTargetingKeywordsForWinningBidOpenrtb() {
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, "cacheId1", "banner",
"videoCacheId1", "categoryDuration", Account.empty("accountId"));
"videoCacheId1", "categoryDuration", Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).containsOnly(
Expand Down Expand Up @@ -156,7 +161,7 @@ public void shouldIncludeFormatOpenrtb() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "", true, null, "banner", null, null, Account.empty("accountId"));
.makeFor(bid, "", true, null, "banner", null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).contains(entry("hb_format", "banner"));
Expand All @@ -182,7 +187,7 @@ public void shouldNotIncludeCacheIdAndDealIdAndSizeOpenrtb() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).doesNotContainKeys("hb_cache_id_bidder", "hb_deal_bidder", "hb_size_bidder",
Expand All @@ -209,7 +214,7 @@ public void shouldReturnEnvKeyForAppRequestOpenrtb() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).contains(
Expand Down Expand Up @@ -237,7 +242,7 @@ public void shouldNotIncludeWinningBidTargetingIfIncludeWinnersFlagIsFalse() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).doesNotContainKeys("hb_bidder", "hb_pb");
Expand All @@ -263,7 +268,7 @@ public void shouldIncludeWinningBidTargetingIfIncludeWinnersFlagIsTrue() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).containsKeys("hb_bidder", "hb_pb");
Expand All @@ -289,7 +294,7 @@ public void shouldNotIncludeBidderKeysTargetingIfIncludeBidderKeysFlagIsFalse()
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).doesNotContainKeys("hb_bidder_bidder1", "hb_pb_bidder1");
Expand All @@ -315,7 +320,7 @@ public void shouldIncludeBidderKeysTargetingIfIncludeBidderKeysFlagIsTrue() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).containsKeys("hb_bidder_bidder1", "hb_pb_bidder1");
Expand All @@ -325,6 +330,7 @@ public void shouldIncludeBidderKeysTargetingIfIncludeBidderKeysFlagIsTrue() {
public void shouldTruncateTargetingBidderKeywordsIfTruncateAttrCharsIsDefined() {
// given
final Bid bid = Bid.builder().price(BigDecimal.ONE).build();
final Map<String, List<ExtBidderError>> bidWarnings = new HashMap<>();

// when
final Map<String, String> keywords = TargetingKeywordsCreator.create(
Expand All @@ -341,17 +347,24 @@ public void shouldTruncateTargetingBidderKeywordsIfTruncateAttrCharsIsDefined()
null,
null,
defaultKeyPrefix)
.makeFor(bid, "someVeryLongBidderName", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "someVeryLongBidderName", true, null, null,
null, null, Account.empty("accountId"), bidWarnings);

// then
assertThat(keywords).hasSize(2)
.containsKeys("hb_bidder_someVeryLo", "hb_pb_someVeryLongBi");
assertThat(bidWarnings)
.extracting(warnings -> warnings.get("targeting"))
.asInstanceOf(InstanceOfAssertFactories.LIST)
.containsOnly(ExtBidderError.of(2, "The following keys have been truncated: "
+ "hb_pb_someVeryLongBidderName, hb_bidder_someVeryLongBidderName"));
}

@Test
public void shouldTruncateTargetingWithoutBidderSuffixKeywordsIfTruncateAttrCharsIsDefined() {
// given
final Bid bid = Bid.builder().price(BigDecimal.ONE).build();
final Map<String, List<ExtBidderError>> bidWarnings = new HashMap<>();

// when
final Map<String, String> keywords = TargetingKeywordsCreator.create(
Expand All @@ -368,17 +381,23 @@ public void shouldTruncateTargetingWithoutBidderSuffixKeywordsIfTruncateAttrChar
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"), bidWarnings);

// then
assertThat(keywords).hasSize(2)
.containsKeys("hb_bidd", "hb_pb");

assertThat(bidWarnings)
.extracting(warnings -> warnings.get("targeting"))
.asInstanceOf(InstanceOfAssertFactories.LIST)
.containsOnly(ExtBidderError.of(2, "The following keys have been truncated: hb_bidder"));
}

@Test
public void shouldTruncateTargetingAndDropDuplicatedWhenTruncateIsTooShort() {
// given
final Bid bid = Bid.builder().price(BigDecimal.ONE).build();
final Map<String, List<ExtBidderError>> bidWarnings = new HashMap<>();

// when
final Map<String, String> keywords = TargetingKeywordsCreator.create(
Expand All @@ -395,18 +414,24 @@ public void shouldTruncateTargetingAndDropDuplicatedWhenTruncateIsTooShort() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder", true, null, null, null, null, Account.empty("accountId"), bidWarnings);

// then
// Without truncating: "hb_bidder", "hb_bidder_bidder", "hb_env", "hb_env_bidder", "hb_pb", "hb_pb_bidder"
assertThat(keywords).hasSize(4)
.containsKeys("hb_bid", "hb_env", "hb_pb", "hb_pb_");

assertThat(bidWarnings)
.extracting(warnings -> warnings.get("targeting"))
.asInstanceOf(InstanceOfAssertFactories.LIST)
.containsOnly(ExtBidderError.of(2, "The following keys have been truncated: "
+ "hb_pb_bidder, hb_bidder, hb_bidder_bidder, hb_env_bidder"));
}

@Test
public void shouldNotTruncateTargetingKeywordsIfTruncateAttrCharsIsNotDefined() {
// given
final Bid bid = Bid.builder().price(BigDecimal.ONE).build();
final Map<String, List<ExtBidderError>> bidWarnings = new HashMap<>();

// when
final Map<String, String> keywords = TargetingKeywordsCreator.create(
Expand All @@ -423,11 +448,13 @@ public void shouldNotTruncateTargetingKeywordsIfTruncateAttrCharsIsNotDefined()
null,
null,
defaultKeyPrefix)
.makeFor(bid, "someVeryLongBidderName", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "someVeryLongBidderName", true, null, null,
null, null, Account.empty("accountId"), bidWarnings);

// then
assertThat(keywords).hasSize(2)
.containsKeys("hb_bidder_someVeryLongBidderName", "hb_pb_someVeryLongBidderName");
assertThat(bidWarnings).isEmpty();
}

@Test
Expand All @@ -440,6 +467,7 @@ public void shouldTruncateKeysFromResolver() {

final TargetingKeywordsResolver resolver = mock(TargetingKeywordsResolver.class);
given(resolver.resolve(any(), anyString())).willReturn(singletonMap("key_longer_than_twenty", "value1"));
final Map<String, List<ExtBidderError>> bidWarnings = new HashMap<>();

// when
final Map<String, String> keywords = TargetingKeywordsCreator.create(
Expand All @@ -456,10 +484,15 @@ public void shouldTruncateKeysFromResolver() {
null,
resolver,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"), bidWarnings);

// then
assertThat(keywords).contains(entry("key_longer_than_twen", "value1"));

assertThat(bidWarnings)
.extracting(warnings -> warnings.get("targeting"))
.asInstanceOf(InstanceOfAssertFactories.LIST)
.containsOnly(ExtBidderError.of(2, "The following keys have been truncated: key_longer_than_twenty"));
}

@Test
Expand Down Expand Up @@ -488,7 +521,7 @@ public void shouldIncludeKeywordsFromResolver() {
null,
resolver,
defaultKeyPrefix)
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", true, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).contains(entry("keyword1", "value1"));
Expand All @@ -514,7 +547,7 @@ public void shouldIncludeDealBidTargetingIfAlwaysIncludeDealsFlagIsTrue() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", false, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", false, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).containsOnlyKeys("hb_bidder_bidder1", "hb_deal_bidder1", "hb_pb_bidder1");
Expand All @@ -540,7 +573,7 @@ public void shouldNotIncludeDealBidTargetingIfAlwaysIncludeDealsFlagIsFalse() {
null,
null,
defaultKeyPrefix)
.makeFor(bid, "bidder1", false, null, null, null, null, Account.empty("accountId"));
.makeFor(bid, "bidder1", false, null, null, null, null, Account.empty("accountId"), new HashMap<>());

// then
assertThat(keywords).doesNotContainKeys("hb_bidder_bidder1", "hb_deal_bidder1", "hb_pb_bidder1");
Expand Down
Loading