Skip to content

Commit

Permalink
Advangelist bidder review (#1055)
Browse files Browse the repository at this point in the history
  • Loading branch information
SerhiiNahornyi authored and nickluck8 committed Aug 10, 2021
1 parent 007c326 commit 8de097e
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import com.iab.openrtb.request.Format;
import com.iab.openrtb.request.Imp;
import com.iab.openrtb.request.Site;
import com.iab.openrtb.request.Video;
import com.iab.openrtb.response.Bid;
import com.iab.openrtb.response.BidResponse;
import com.iab.openrtb.response.SeatBid;
import io.vertx.core.MultiMap;
Expand All @@ -29,19 +29,22 @@
import org.prebid.server.util.HttpUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
* Advangelists {@link Bidder} implementation.
*/
public class AdvangelistsBidder implements Bidder<BidRequest> {

private static final TypeReference<ExtPrebid<?, ExtImpAdvangelists>> ADVANGELISTS_EXT_TYPE_REFERENCE = new
TypeReference<ExtPrebid<?, ExtImpAdvangelists>>() {
};
private static final String URL_PUBLISHER_ID_MACRO = "{{PublisherID}}";

private final String endpointUrl;
private final JacksonMapper mapper;
Expand All @@ -54,7 +57,7 @@ public AdvangelistsBidder(String endpointUrl, JacksonMapper mapper) {
@Override
public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request) {
final List<BidderError> errors = new ArrayList<>();
List<HttpRequest<BidRequest>> httpRequests = new ArrayList<>();
final List<HttpRequest<BidRequest>> httpRequests = new ArrayList<>();
try {
final Map<ExtImpAdvangelists, List<Imp>> impToExtImp = getImpToExtImp(request, errors);
httpRequests.addAll(buildAdapterRequests(request, impToExtImp));
Expand All @@ -68,8 +71,12 @@ public Result<List<HttpRequest<BidRequest>>> makeHttpRequests(BidRequest request
private Map<ExtImpAdvangelists, List<Imp>> getImpToExtImp(BidRequest request, List<BidderError> errors) {
final Map<ExtImpAdvangelists, List<Imp>> extToListOfUpdatedImp = new HashMap<>();
for (Imp imp : request.getImp()) {
if (imp.getBanner() == null && imp.getVideo() == null) {
errors.add(BidderError.badInput("Unsupported impression has been received"));
continue;
}
try {
final ExtImpAdvangelists extImpEmxDigital = parseAndValidateImpExt(imp);
final ExtImpAdvangelists extImpEmxDigital = parseImpExt(imp);
final Imp updatedImp = updateImp(imp);

extToListOfUpdatedImp.putIfAbsent(extImpEmxDigital, new ArrayList<>());
Expand All @@ -86,80 +93,75 @@ private Map<ExtImpAdvangelists, List<Imp>> getImpToExtImp(BidRequest request, Li
return extToListOfUpdatedImp;
}

private ExtImpAdvangelists parseAndValidateImpExt(Imp imp) {
final ExtImpAdvangelists bidder;
private ExtImpAdvangelists parseImpExt(Imp imp) {
final ExtImpAdvangelists bidderExt;
try {
bidder = mapper.mapper().convertValue(imp.getExt(), ADVANGELISTS_EXT_TYPE_REFERENCE).getBidder();
bidderExt = mapper.mapper().convertValue(imp.getExt(), ADVANGELISTS_EXT_TYPE_REFERENCE).getBidder();
} catch (IllegalArgumentException e) {
throw new PreBidException(e.getMessage(), e);
throw new PreBidException(e.getMessage());
}

if (StringUtils.isBlank(bidder.getPubid())) {
if (StringUtils.isEmpty(bidderExt.getPubid())) {
throw new PreBidException("No pubid value provided");
}

return bidder;
return bidderExt;
}

private static Imp updateImp(Imp imp) {
final Imp.ImpBuilder impBuilder = imp.toBuilder().ext(null);

final Video video = imp.getVideo();
if (video != null) {
return impBuilder.banner(null)
.audio(null)
.xNative(null)
.build();
}
final Imp.ImpBuilder impBuilder = imp.toBuilder()
.audio(null)
.xNative(null)
.ext(null);

final Banner banner = imp.getBanner();
if (banner != null) {
return impBuilder.banner(modifyImpBanner(banner)).build();
}

throw new PreBidException("Unsupported impression has been received");
return impBuilder.build();
}

private static Banner modifyImpBanner(Banner banner) {
if (banner != null && (banner.getW() == null || banner.getH() == null)) {
final Banner.BannerBuilder bannerBuilder = banner.toBuilder();
final List<Format> originalFormat = banner.getFormat();
if (banner.getW() == null || banner.getH() == null) {
final List<Format> bannerFormats = banner.getFormat();

if (CollectionUtils.isEmpty(originalFormat)) {
if (CollectionUtils.isEmpty(bannerFormats)) {
throw new PreBidException("Expected at least one banner.format entry or explicit w/h");
}

final List<Format> formatSkipFirst = originalFormat.subList(1, originalFormat.size());
bannerBuilder.format(formatSkipFirst);

Format firstFormat = originalFormat.get(0);
bannerBuilder.w(firstFormat.getW());
bannerBuilder.h(firstFormat.getH());
final List<Format> formatSkipFirst = bannerFormats.subList(1, bannerFormats.size());
final Format firstFormat = bannerFormats.get(0);

return bannerBuilder.build();
return banner.toBuilder()
.format(formatSkipFirst)
.w(firstFormat.getW())
.h(firstFormat.getH())
.build();
}

return banner;
}

private List<HttpRequest<BidRequest>> buildAdapterRequests(BidRequest bidRequest,
Map<ExtImpAdvangelists, List<Imp>> impExtToListOfImps) {
Map<ExtImpAdvangelists,
List<Imp>> impExtToListOfImps) {
final List<HttpRequest<BidRequest>> httpRequests = new ArrayList<>();

for (Map.Entry<ExtImpAdvangelists, List<Imp>> impExtAndListOfImo : impExtToListOfImps.entrySet()) {
final ExtImpAdvangelists extImpAdvangelists = impExtAndListOfImo.getKey();
final List<Imp> imps = impExtAndListOfImo.getValue();
final BidRequest updatedBidRequest = makeBidRequest(bidRequest, extImpAdvangelists, imps);

final String body = mapper.encode(updatedBidRequest);
final MultiMap headers = HttpUtil.headers()
.add(HttpUtil.X_OPENRTB_VERSION_HEADER, "2.5");
final String createdEndpoint = endpointUrl + extImpAdvangelists.getPubid();

final String createdEndpoint = endpointUrl
.replace(URL_PUBLISHER_ID_MACRO, HttpUtil.encodeUrl(extImpAdvangelists.getPubid()));

final HttpRequest<BidRequest> createdBidRequest = HttpRequest.<BidRequest>builder()
.method(HttpMethod.POST)
.uri(createdEndpoint)
.body(body)
.body(mapper.encode(updatedBidRequest))
.headers(headers)
.payload(bidRequest)
.build();
Expand All @@ -170,22 +172,22 @@ private List<HttpRequest<BidRequest>> buildAdapterRequests(BidRequest bidRequest
return httpRequests;
}

private static BidRequest makeBidRequest(BidRequest preBidRequest, ExtImpAdvangelists extImpAdvangelists,
private static BidRequest makeBidRequest(BidRequest bidRequest,
ExtImpAdvangelists extImpAdvangelists,
List<Imp> imps) {
final BidRequest.BidRequestBuilder bidRequestBuilder = preBidRequest.toBuilder();

final List<Imp> modifiedImps = imps.stream()
.map(imp -> imp.toBuilder().tagid(extImpAdvangelists.getPlacement()).build())
.collect(Collectors.toList());

final BidRequest.BidRequestBuilder bidRequestBuilder = bidRequest.toBuilder();
bidRequestBuilder.imp(modifiedImps);

final Site site = preBidRequest.getSite();
final Site site = bidRequest.getSite();
if (site != null) {
bidRequestBuilder.site(site.toBuilder().publisher(null).domain("").build());
}

final App app = preBidRequest.getApp();
final App app = bidRequest.getApp();
if (app != null) {
bidRequestBuilder.app(app.toBuilder().publisher(null).build());
}
Expand Down Expand Up @@ -213,20 +215,26 @@ private static List<BidderBid> extractBids(BidRequest bidRequest, BidResponse bi
}

private static List<BidderBid> bidsFromResponse(BidRequest bidRequest, BidResponse bidResponse) {
return bidResponse.getSeatbid().stream()
.map(SeatBid::getBid)
.flatMap(Collection::stream)
.map(bid -> BidderBid.of(bid, getType(bid.getImpid(), bidRequest.getImp()), bidResponse.getCur()))
final SeatBid firstSeatBid = bidResponse.getSeatbid().get(0);
final List<Bid> bids = firstSeatBid.getBid();

if (CollectionUtils.isEmpty(bids)) {
throw new PreBidException("Empty bids array");
}

return bids.stream()
.filter(Objects::nonNull)
.map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest.getImp()), bidResponse.getCur()))
.collect(Collectors.toList());
}

/**
* Resolves the media type for the bid.
*/
private static BidType getType(String impId, List<Imp> imps) {
private static BidType getBidType(String impId, List<Imp> imps) {
for (Imp imp : imps) {
if (imp.getId().equals(impId) && imp.getVideo() != null) {
return BidType.video;
if (imp.getId().equals(impId)) {
if (imp.getVideo() != null) {
return BidType.video;
}
return BidType.banner;
}
}
return BidType.banner;
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/bidder-config/advangelists.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
adapters:
advangelists:
enabled: false
endpoint: http://nep.advangelists.com/xp/get?pubid=
endpoint: http://nep.advangelists.com/xp/get?pubid={{PublisherID}}
pbs-enforces-gdpr: true
pbs-enforces-ccpa: true
modifying-vast-xml-allowed: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@

public class AdvangelistsBidderTest extends VertxTest {

private static final String ENDPOINT_URL = "http://test/get?pubid=";
private static final String ENDPOINT_URL = "http://test/get?pubid={{PublisherID}}";

private AdvangelistsBidder advangelistsBidder;

Expand All @@ -62,6 +62,7 @@ public void makeHttpRequestsShouldReturnErrorWhenImpExtCouldNotBeParsed() {
// given
final BidRequest bidRequest = BidRequest.builder()
.imp(singletonList(Imp.builder()
.banner(Banner.builder().build())
.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))
.build()))
.build();
Expand All @@ -71,14 +72,18 @@ public void makeHttpRequestsShouldReturnErrorWhenImpExtCouldNotBeParsed() {

// then
assertThat(result.getErrors()).hasSize(1);
assertThat(result.getErrors().get(0).getMessage()).startsWith("Cannot deserialize instance");
assertThat(result.getErrors()).allSatisfy(error -> {
assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input);
assertThat(error.getMessage()).startsWith("Cannot deserialize instance");
});
assertThat(result.getValue()).isEmpty();
}

@Test
public void makeHttpRequestsShouldReturnErrorWhenExtPubIdIsNull() {
// given
final BidRequest bidRequest = givenBidRequest(identity(), ExtImpAdvangelists.of(null, null));
final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build()),
ExtImpAdvangelists.of(null, null));

// when
final Result<List<HttpRequest<BidRequest>>> result = advangelistsBidder.makeHttpRequests(bidRequest);
Expand All @@ -92,7 +97,8 @@ public void makeHttpRequestsShouldReturnErrorWhenExtPubIdIsNull() {
@Test
public void makeHttpRequestsShouldReturnErrorWhenExtPubIdIsBlank() {
// given
final BidRequest bidRequest = givenBidRequest(identity(), ExtImpAdvangelists.of(" ", null));
final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build()),
ExtImpAdvangelists.of("", null));

// when
final Result<List<HttpRequest<BidRequest>>> result = advangelistsBidder.makeHttpRequests(bidRequest);
Expand Down Expand Up @@ -123,26 +129,21 @@ public void makeHttpRequestShouldReturnAllErrorsWithRequest() {
// given
final Imp impWithoutFormatFirst =
givenImp(impBuilder -> impBuilder.banner(Banner.builder().format(null).build()));
final Imp impWithoutFormatSecond =
givenImp(impBuilder -> impBuilder.banner(Banner.builder().format(null).build()));
final Imp impWithoutType = givenImp(identity());
final Imp impWithoutPubIdFirst = givenImp(identity(), ExtImpAdvangelists.of(" ", null));
final Imp impWithoutPubIdSecond = givenImp(identity(), ExtImpAdvangelists.of(" ", null));
final Imp impWithoutPubIdFirst = givenImp(impBuilder -> impBuilder.banner(Banner.builder().build()),
ExtImpAdvangelists.of("", null));
final Imp normalImp = givenImp(impBuilder -> impBuilder.video(Video.builder().build()));

final BidRequest bidRequest = BidRequest.builder()
.imp(asList(impWithoutFormatFirst, impWithoutPubIdFirst, impWithoutFormatSecond, impWithoutPubIdSecond,
normalImp, impWithoutType))
.imp(asList(impWithoutFormatFirst, impWithoutPubIdFirst, normalImp, impWithoutType))
.build();

// when
final Result<List<HttpRequest<BidRequest>>> result = advangelistsBidder.makeHttpRequests(bidRequest);

// then
assertThat(result.getErrors()).hasSize(5)
.containsOnly(BidderError.badInput("No pubid value provided"),
BidderError.badInput("No pubid value provided"),
BidderError.badInput("Expected at least one banner.format entry or explicit w/h"),
assertThat(result.getErrors()).hasSize(3)
.containsExactlyInAnyOrder(BidderError.badInput("No pubid value provided"),
BidderError.badInput("Expected at least one banner.format entry or explicit w/h"),
BidderError.badInput("Unsupported impression has been received"));
assertThat(result.getValue()).hasSize(1);
Expand Down Expand Up @@ -333,8 +334,10 @@ public void makeBidsShouldReturnErrorWhenResponseBodyCouldNotBeParsed() {

// then
assertThat(result.getErrors()).hasSize(1);
assertThat(result.getErrors().get(0).getMessage()).startsWith("Failed to decode: Unrecognized token");
assertThat(result.getErrors().get(0).getType()).isEqualTo(BidderError.Type.bad_server_response);
assertThat(result.getErrors()).allSatisfy(error -> {
assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response);
assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token");
});
assertThat(result.getValue()).isEmpty();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ adapters.adtelligent.endpoint=http://localhost:8090/adtelligent-exchange
adapters.adtelligent.pbs-enforces-gdpr=true
adapters.adtelligent.usersync.url=//adtelligent-usersync
adapters.advangelists.enabled=true
adapters.advangelists.endpoint=http://localhost:8090/advangelists-exchange?pubid=
adapters.advangelists.endpoint=http://localhost:8090/advangelists-exchange?pubid={{PublisherID}}
adapters.advangelists.pbs-enforces-gdpr=true
adapters.advangelists.usersync.url=//advangelists-usersync
adapters.aja.enabled=true
Expand Down

0 comments on commit 8de097e

Please sign in to comment.