Skip to content

Commit

Permalink
Telaria: add pod support (#1763)
Browse files Browse the repository at this point in the history
  • Loading branch information
marki1an authored Mar 22, 2022
1 parent 91bac30 commit 0d8eaf9
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 83 deletions.
83 changes: 51 additions & 32 deletions src/main/java/org/prebid/server/bidder/telaria/TelariaBidder.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
import org.prebid.server.proto.openrtb.ext.response.BidType;
import org.prebid.server.util.HttpUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class TelariaBidder implements Bidder<BidRequest> {

Expand All @@ -53,7 +53,6 @@ public TelariaBidder(String endpointUrl, JacksonMapper mapper) {

@Override
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest bidRequest) {
final List<Imp> validImps = new ArrayList<>();
try {
validateImp(bidRequest.getImp());
} catch (PreBidException e) {
Expand All @@ -62,37 +61,43 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest bidRequ

final String publisherId = getPublisherId(bidRequest);
String seatCode = null;
final BidRequest.BidRequestBuilder requestBuilder = bidRequest.toBuilder();
ExtImpTelaria extImp = null;
for (Imp imp : bidRequest.getImp()) {
try {
extImp = parseImpExt(imp);
seatCode = extImp.getSeatCode();
validImps.add(updateImp(imp, extImp, publisherId));
} catch (PreBidException e) {
return Result.withError(BidderError.badInput(e.getMessage()));
}
}
Imp modifyImp = bidRequest.getImp().get(0);

if (extImp != null && extImp.getExtra() != null) {
requestBuilder.ext(mapper.fillExtension(ExtRequest.empty(), TelariaRequestExt.of(extImp.getExtra())));
try {
extImp = parseImpExt(modifyImp);
seatCode = extImp.getSeatCode();
modifyImp = updateImp(modifyImp, extImp, publisherId);
} catch (PreBidException e) {
return Result.withError(BidderError.badInput(e.getMessage()));
}
final BidRequest outgoingRequest = updateBidRequest(bidRequest, extImp, seatCode, modifyImp);
return Result.withValue(makeHttpRequest(outgoingRequest));
}

private HttpRequest<BidRequest> makeHttpRequest(BidRequest bidRequest) {
return HttpRequest.<BidRequest>builder()
.method(HttpMethod.POST)
.uri(endpointUrl)
.headers(headers(bidRequest))
.payload(bidRequest)
.body(mapper.encodeToBytes(bidRequest))
.build();
}

private BidRequest updateBidRequest(BidRequest bidRequest, ExtImpTelaria extImp, String seatCode, Imp modifyImp) {
final BidRequest.BidRequestBuilder bidRequestBuilder = bidRequest.toBuilder();

if (bidRequest.getSite() != null) {
requestBuilder.site(modifySite(bidRequest.getSite(), seatCode));
bidRequestBuilder.site(modifySite(bidRequest.getSite(), seatCode));
} else if (bidRequest.getApp() != null) {
requestBuilder.app(modifyApp(bidRequest.getApp(), seatCode));
bidRequestBuilder.app(modifyApp(bidRequest.getApp(), seatCode));
}

final BidRequest outgoingRequest = requestBuilder.imp(validImps).build();

return Result.withValue(HttpRequest.<BidRequest>builder()
.method(HttpMethod.POST)
.uri(endpointUrl)
.headers(headers(bidRequest))
.payload(outgoingRequest)
.body(mapper.encodeToBytes(outgoingRequest))
.build());
return bidRequestBuilder
.ext(modifyExt(extImp))
.imp(Collections.singletonList(modifyImp))
.build();
}

private static void validateImp(List<Imp> imps) {
Expand Down Expand Up @@ -136,6 +141,12 @@ private Imp updateImp(Imp imp, ExtImpTelaria extImp, String publisherId) {
.build();
}

private ExtRequest modifyExt(ExtImpTelaria extImp) {
return extImp != null
? mapper.fillExtension(ExtRequest.empty(), TelariaRequestExt.of(extImp.getExtra()))
: null;
}

private static Site modifySite(Site site, String seatCode) {
return site.toBuilder().publisher(createPublisher(site.getPublisher(), seatCode)).build();
}
Expand Down Expand Up @@ -169,29 +180,37 @@ private static MultiMap headers(BidRequest bidRequest) {
public Result<List<BidderBid>> makeBids(HttpCall<BidRequest> httpCall, BidRequest bidRequest) {
try {
final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class);
return Result.withValues(extractBids(bidResponse));
return Result.withValues(extractBids(bidResponse, bidRequest));
} catch (PreBidException | DecodeException e) {
return Result.withError(BidderError.badServerResponse(e.getMessage()));
}
}

private List<BidderBid> extractBids(BidResponse bidResponse) {
private List<BidderBid> extractBids(BidResponse bidResponse, BidRequest bidRequest) {
if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) {
return Collections.emptyList();
}
return bidsFromResponse(bidResponse);
return bidsFromResponse(bidResponse, bidRequest);
}

private static List<BidderBid> bidsFromResponse(BidResponse bidResponse) {
private static List<BidderBid> bidsFromResponse(BidResponse bidResponse, BidRequest bidRequest) {
final SeatBid firstSeatBid = bidResponse.getSeatbid().get(0);
final List<Bid> bids = firstSeatBid.getBid();
final List<Imp> imps = bidRequest.getImp();

if (CollectionUtils.isEmpty(bids)) {
return Collections.emptyList();
}
return bids.stream()
.filter(Objects::nonNull)
.map(bid -> BidderBid.of(bid, BidType.video, bidResponse.getCur()))

return IntStream.range(0, bids.size())
.filter(i -> bids.get(i) != null)
.filter(i -> i < imps.size())
.mapToObj(i -> makeBidderBid(bids.get(i), bidResponse, imps.get(i)))
.collect(Collectors.toList());
}

private static BidderBid makeBidderBid(Bid bid, BidResponse bidResponse, Imp imp) {
final Bid modifyBid = bid.toBuilder().impid(imp.getId()).build();
return BidderBid.of(modifyBid, BidType.video, bidResponse.getCur());
}
}
129 changes: 78 additions & 51 deletions src/test/java/org/prebid/server/bidder/telaria/TelariaBidderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.UnaryOperator;

import static java.util.Collections.singletonList;
import static java.util.function.Function.identity;
import static java.util.function.UnaryOperator.identity;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.tuple;
Expand Down Expand Up @@ -225,38 +225,6 @@ public void makeHttpRequestsShouldSetSitePublisherIdIfSiteIsPresent() {
.containsExactly("seatCode");
}

@Test
public void makeBidsShouldReturnEmptyBidderBidsFromSecondSeatBid() throws JsonProcessingException {
// given
final SeatBid firstSeatBId = SeatBid.builder()
.bid(singletonList(Bid.builder()
.impid("123")
.build()))
.build();

final SeatBid secondSeatBid = SeatBid.builder()
.bid(singletonList(Bid.builder()
.impid("456")
.build()))
.build();

final HttpCall<BidRequest> httpCall = givenHttpCall(
BidRequest.builder()
.imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build()))
.build(),
mapper.writeValueAsString(BidResponse.builder()
.seatbid(Arrays.asList(firstSeatBId, secondSeatBid))
.build()));

// when
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, null);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.containsExactly(BidderBid.of(Bid.builder().impid("123").build(), video, null));
}

@Test
public void makeHttpRequestsShouldReturnResultWithHttpRequestsContainingExpectedHeaders() {
// given
Expand Down Expand Up @@ -287,6 +255,40 @@ public void makeHttpRequestsShouldReturnResultWithHttpRequestsContainingExpected
tuple("DNT", "0"));
}

@Test
public void makeBidsShouldReturnEmptyBidderBidsFromSecondSeatBid() throws JsonProcessingException {
// given
final SeatBid firstSeatBId = SeatBid.builder()
.bid(singletonList(Bid.builder()
.impid("123")
.build()))
.build();

final SeatBid secondSeatBid = SeatBid.builder()
.bid(singletonList(Bid.builder()
.impid("456")
.build()))
.build();

final BidRequest bidRequest = BidRequest.builder()
.imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build()))
.build();

final HttpCall<BidRequest> httpCall = givenHttpCall(
bidRequest,
mapper.writeValueAsString(BidResponse.builder()
.seatbid(Arrays.asList(firstSeatBId, secondSeatBid))
.build()));

// when
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.containsExactly(BidderBid.of(Bid.builder().impid("123").build(), video, null));
}

@Test
public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() {
// given
Expand Down Expand Up @@ -319,14 +321,15 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso
}

@Test
public void makeBidsShouldReturnErrorIfNoBidsFromSeatArePresent() throws JsonProcessingException {
public void makeBidsShouldReturnEmptyListIfNoBidsFromSeatArePresent() throws JsonProcessingException {
// given
final HttpCall<BidRequest> httpCall = givenHttpCall(null,
final BidRequest bidRequest = BidRequest.builder().build();
final HttpCall<BidRequest> httpCall = givenHttpCall(bidRequest,
mapper.writeValueAsString(BidResponse.builder()
.seatbid(singletonList(SeatBid.builder().build())).build()));

// when
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, null);
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
Expand All @@ -336,45 +339,69 @@ public void makeBidsShouldReturnErrorIfNoBidsFromSeatArePresent() throws JsonPro
@Test
public void makeBidsShouldReturnVideoBidIfVideoIsPresentInRequestImp() throws JsonProcessingException {
// given
final BidRequest bidRequest = BidRequest.builder()
.imp(singletonList(Imp.builder().id("123").video(Video.builder().build()).build()))
.build();

final HttpCall<BidRequest> httpCall = givenHttpCall(
BidRequest.builder()
.imp(singletonList(Imp.builder().id("123").video(Video.builder().build()).build()))
.build(),
bidRequest,
mapper.writeValueAsString(
givenBidResponse(bidBuilder -> bidBuilder.impid("123"))));

// when
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, null);
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.containsExactly(BidderBid.of(Bid.builder().impid("123").build(), video, "USD"));
}

@Test
public void makeBidsShouldReturnProperImpidFromBidRequestImpId() throws JsonProcessingException {
// given
final BidRequest bidRequest = BidRequest.builder()
.imp(singletonList(Imp.builder().id("312").video(Video.builder().build()).build()))
.build();

final HttpCall<BidRequest> httpCall = givenHttpCall(
bidRequest,
mapper.writeValueAsString(givenBidResponse(identity())));

// when
final Result<List<BidderBid>> result = telariaBidder.makeBids(httpCall, bidRequest);

// then
assertThat(result.getErrors()).isEmpty();
assertThat(result.getValue())
.extracting(BidderBid::getBid)
.extracting(Bid::getImpid)
.containsExactly("312");
}

private static BidRequest givenBidRequest(
Function<BidRequest.BidRequestBuilder, BidRequest.BidRequestBuilder> bidRequestCustomizer,
Function<Imp.ImpBuilder, Imp.ImpBuilder> impCustomizer) {
UnaryOperator<BidRequest.BidRequestBuilder> bidRequestCustomizer,
UnaryOperator<Imp.ImpBuilder> impCustomizer) {

return bidRequestCustomizer.apply(BidRequest.builder()
.imp(singletonList(givenImp(impCustomizer))))
.imp(singletonList(givenImp(impCustomizer))))
.build();
}

private static BidRequest givenBidRequest(Function<Imp.ImpBuilder, Imp.ImpBuilder> impCustomizer) {
private static BidRequest givenBidRequest(UnaryOperator<Imp.ImpBuilder> impCustomizer) {
return givenBidRequest(identity(), impCustomizer);
}

private static Imp givenImp(Function<Imp.ImpBuilder, Imp.ImpBuilder> impCustomizer) {
private static Imp givenImp(UnaryOperator<Imp.ImpBuilder> impCustomizer) {
return impCustomizer.apply(Imp.builder()
.id("123")
.video(Video.builder().build())
.ext(mapper.valueToTree(ExtPrebid.of(null,
ExtImpTelaria.of("adCode", "seatCode", null)))))
.id("123")
.video(Video.builder().build())
.ext(mapper.valueToTree(ExtPrebid.of(null,
ExtImpTelaria.of("adCode", "seatCode", null)))))
.build();
}

private static BidResponse givenBidResponse(Function<Bid.BidBuilder, Bid.BidBuilder> bidCustomizer) {
private static BidResponse givenBidResponse(UnaryOperator<Bid.BidBuilder> bidCustomizer) {
return BidResponse.builder()
.cur("USD")
.seatbid(singletonList(SeatBid.builder().bid(singletonList(bidCustomizer.apply(Bid.builder()).build()))
Expand Down

0 comments on commit 0d8eaf9

Please sign in to comment.