From a397bcf495057dcd83e6ee1e763463e2f0448214 Mon Sep 17 00:00:00 2001 From: Andre Gielow Date: Fri, 15 Aug 2025 17:12:59 -0400 Subject: [PATCH] TheTradeDesk adapter should resolve burl if not resolved --- .../thetradedesk/TheTradeDeskBidder.java | 1 + .../thetradedesk/TheTradeDeskBidderTest.java | 101 +++++++++++++----- 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidder.java b/src/main/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidder.java index d83274e4852..a2853b26d72 100644 --- a/src/main/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidder.java +++ b/src/main/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidder.java @@ -231,6 +231,7 @@ private static Bid resolvePriceMacros(Bid bid) { return bid.toBuilder() .nurl(StringUtils.replace(bid.getNurl(), PRICE_MACRO, priceAsString)) .adm(StringUtils.replace(bid.getAdm(), PRICE_MACRO, priceAsString)) + .burl(StringUtils.replace(bid.getBurl(), PRICE_MACRO, priceAsString)) .build(); } } diff --git a/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java b/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java index 8c167590e4f..033b8236d34 100644 --- a/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/thetradedesk/TheTradeDeskBidderTest.java @@ -512,7 +512,8 @@ public void makeBidsShouldReplacePriceMacroInNurlAndAdmWithBidPrice() throws Jso .impid("123") .price(BigDecimal.valueOf(1.23)) .nurl("http://example.com/nurl?price=${AUCTION_PRICE}") - .adm("
Price: ${AUCTION_PRICE}
"))); + .adm("
Price: ${AUCTION_PRICE}
") + .burl("https://adsrvr.org/feedback/xxx?wp=${AUCTION_PRICE}¶m2=xyz"))); // when final Result> result = target.makeBids(httpCall, null); @@ -521,8 +522,9 @@ public void makeBidsShouldReplacePriceMacroInNurlAndAdmWithBidPrice() throws Jso assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm, Bid::getPrice) - .containsOnly(tuple("http://example.com/nurl?price=1.23", "
Price: 1.23
", BigDecimal.valueOf(1.23))); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl, Bid::getPrice) + .containsOnly(tuple("http://example.com/nurl?price=1.23", "
Price: 1.23
", + "https://adsrvr.org/feedback/xxx?wp=1.23¶m2=xyz", BigDecimal.valueOf(1.23))); } @Test @@ -534,7 +536,8 @@ public void makeBidsShouldReplacePriceMacroWithZeroWhenBidPriceIsNull() throws J .impid("123") .price(null) .nurl("http://example.com/nurl?price=${AUCTION_PRICE}") - .adm("
Price: ${AUCTION_PRICE}
"))); + .adm("
Price: ${AUCTION_PRICE}
") + .burl("https://adsrvr.org/feedback/xxx?wp=${AUCTION_PRICE}¶m2=xyz"))); // when final Result> result = target.makeBids(httpCall, null); @@ -543,8 +546,9 @@ public void makeBidsShouldReplacePriceMacroWithZeroWhenBidPriceIsNull() throws J assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl?price=0", "
Price: 0
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple("http://example.com/nurl?price=0", "
Price: 0
", + "https://adsrvr.org/feedback/xxx?wp=0¶m2=xyz")); } @Test @@ -556,7 +560,8 @@ public void makeBidsShouldReplacePriceMacroWithZeroWhenBidPriceIsZero() throws J .impid("123") .price(BigDecimal.ZERO) .nurl("http://example.com/nurl?price=${AUCTION_PRICE}") - .adm("
Price: ${AUCTION_PRICE}
"))); + .adm("
Price: ${AUCTION_PRICE}
") + .burl("https://adsrvr.org/feedback/xxx?wp=${AUCTION_PRICE}¶m2=xyz"))); // when final Result> result = target.makeBids(httpCall, null); @@ -565,8 +570,9 @@ public void makeBidsShouldReplacePriceMacroWithZeroWhenBidPriceIsZero() throws J assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl?price=0", "
Price: 0
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple("http://example.com/nurl?price=0", "
Price: 0
", + "https://adsrvr.org/feedback/xxx?wp=0¶m2=xyz")); } @Test @@ -578,7 +584,8 @@ public void makeBidsShouldReplacePriceMacroInNurlOnlyWhenAdmDoesNotContainMacro( .impid("123") .price(BigDecimal.valueOf(5.67)) .nurl("http://example.com/nurl?price=${AUCTION_PRICE}") - .adm("
No macro here
"))); + .adm("
No macro here
") + .burl("http://example.com/burl"))); // when final Result> result = target.makeBids(httpCall, null); @@ -587,8 +594,9 @@ public void makeBidsShouldReplacePriceMacroInNurlOnlyWhenAdmDoesNotContainMacro( assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl?price=5.67", "
No macro here
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple("http://example.com/nurl?price=5.67", "
No macro here
", + "http://example.com/burl")); } @Test @@ -600,7 +608,8 @@ public void makeBidsShouldReplacePriceMacroInAdmOnlyWhenNurlDoesNotContainMacro( .impid("123") .price(BigDecimal.valueOf(8.90)) .nurl("http://example.com/nurl") - .adm("
Price: ${AUCTION_PRICE}
"))); + .adm("
Price: ${AUCTION_PRICE}
") + .burl("http://example.com/burl"))); // when final Result> result = target.makeBids(httpCall, null); @@ -609,8 +618,9 @@ public void makeBidsShouldReplacePriceMacroInAdmOnlyWhenNurlDoesNotContainMacro( assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl", "
Price: 8.9
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple("http://example.com/nurl", "
Price: 8.9
", + "http://example.com/burl")); } @Test @@ -622,7 +632,8 @@ public void makeBidsShouldNotReplacePriceMacroWhenNurlAndAdmDoNotContainMacro() .impid("123") .price(BigDecimal.valueOf(12.34)) .nurl("http://example.com/nurl") - .adm("
No macro
"))); + .adm("
No macro
") + .burl("http://example.com/burl"))); // when final Result> result = target.makeBids(httpCall, null); @@ -631,8 +642,9 @@ public void makeBidsShouldNotReplacePriceMacroWhenNurlAndAdmDoNotContainMacro() assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl", "
No macro
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple("http://example.com/nurl", "
No macro
", + "http://example.com/burl")); } @Test @@ -644,7 +656,8 @@ public void makeBidsShouldHandleNullNurlAndAdm() throws JsonProcessingException .impid("123") .price(BigDecimal.valueOf(15.00)) .nurl(null) - .adm(null))); + .adm(null) + .burl(null))); // when final Result> result = target.makeBids(httpCall, null); @@ -653,8 +666,8 @@ public void makeBidsShouldHandleNullNurlAndAdm() throws JsonProcessingException assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple(null, null)); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple(null, null, null)); } @Test @@ -666,7 +679,8 @@ public void makeBidsShouldReplaceMultiplePriceMacrosInSameField() throws JsonPro .impid("123") .price(BigDecimal.valueOf(9.99)) .nurl("http://example.com/nurl?price=${AUCTION_PRICE}&backup_price=${AUCTION_PRICE}") - .adm("
Price: ${AUCTION_PRICE}, Fallback: ${AUCTION_PRICE}
"))); + .adm("
Price: ${AUCTION_PRICE}, Fallback: ${AUCTION_PRICE}
") + .burl("https://adsrvr.org/feedback/xxx?wp=${AUCTION_PRICE}&backup_wp=${AUCTION_PRICE}¶m2=xyz"))); // when final Result> result = target.makeBids(httpCall, null); @@ -675,8 +689,11 @@ public void makeBidsShouldReplaceMultiplePriceMacrosInSameField() throws JsonPro assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl?price=9.99&backup_price=9.99", "
Price: 9.99, Fallback: 9.99
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple( + "http://example.com/nurl?price=9.99&backup_price=9.99", + "
Price: 9.99, Fallback: 9.99
", + "https://adsrvr.org/feedback/xxx?wp=9.99&backup_wp=9.99¶m2=xyz")); } @Test @@ -688,7 +705,8 @@ public void makeBidsShouldHandleLargeDecimalPrices() throws JsonProcessingExcept .impid("123") .price(new BigDecimal("123456789.123456789")) .nurl("http://example.com/nurl?price=${AUCTION_PRICE}") - .adm("
Price: ${AUCTION_PRICE}
"))); + .adm("
Price: ${AUCTION_PRICE}
") + .burl("https://adsrvr.org/feedback/xxx?wp=${AUCTION_PRICE}¶m2=xyz"))); // when final Result> result = target.makeBids(httpCall, null); @@ -697,8 +715,37 @@ public void makeBidsShouldHandleLargeDecimalPrices() throws JsonProcessingExcept assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(BidderBid::getBid) - .extracting(Bid::getNurl, Bid::getAdm) - .containsOnly(tuple("http://example.com/nurl?price=123456789.123456789", "
Price: 123456789.123456789
")); + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple( + "http://example.com/nurl?price=123456789.123456789", + "
Price: 123456789.123456789
", + "https://adsrvr.org/feedback/xxx?wp=123456789.123456789¶m2=xyz")); + } + + @Test + public void makeBidsShouldReplacePriceMacroInBurlIfNurlAndAdmDoNotContainMacro() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall( + givenBidResponse(bidBuilder -> bidBuilder + .mtype(1) + .impid("123") + .price(BigDecimal.valueOf(7.77)) + .nurl("http://example.com/nurl") + .adm("
No macro
") + .burl("https://adsrvr.org/feedback/xxx?wp=${AUCTION_PRICE}¶m2=xyz"))); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(BidderBid::getBid) + .extracting(Bid::getNurl, Bid::getAdm, Bid::getBurl) + .containsOnly(tuple( + "http://example.com/nurl", + "
No macro
", + "https://adsrvr.org/feedback/xxx?wp=7.77¶m2=xyz")); } private String givenBidResponse(UnaryOperator bidCustomizer) throws JsonProcessingException {