diff --git a/src/main/java/org/prebid/server/bidder/ttx/TtxBidder.java b/src/main/java/org/prebid/server/bidder/thirtythreeacross/ThirtyThreeAcrossBidder.java similarity index 53% rename from src/main/java/org/prebid/server/bidder/ttx/TtxBidder.java rename to src/main/java/org/prebid/server/bidder/thirtythreeacross/ThirtyThreeAcrossBidder.java index ec9afe371cf..eb9008680a3 100644 --- a/src/main/java/org/prebid/server/bidder/ttx/TtxBidder.java +++ b/src/main/java/org/prebid/server/bidder/thirtythreeacross/ThirtyThreeAcrossBidder.java @@ -1,8 +1,8 @@ -package org.prebid.server.bidder.ttx; +package org.prebid.server.bidder.thirtythreeacross; +import com.fasterxml.jackson.core.JsonPointer; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Video; @@ -11,6 +11,7 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; @@ -18,17 +19,19 @@ import org.prebid.server.bidder.model.HttpCall; import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.Result; -import org.prebid.server.bidder.ttx.proto.TtxImpExt; -import org.prebid.server.bidder.ttx.proto.TtxImpExtTtx; -import org.prebid.server.bidder.ttx.response.TtxBidExt; -import org.prebid.server.bidder.ttx.response.TtxBidExtTtx; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossExtTtx; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossExtTtxCaller; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossImpExt; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossImpExtTtx; import org.prebid.server.exception.PreBidException; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; -import org.prebid.server.proto.openrtb.ext.request.ttx.ExtImpTtx; +import org.prebid.server.proto.openrtb.ext.request.ExtRequest; +import org.prebid.server.proto.openrtb.ext.request.thirtythreeacross.ExtImpThirtyThreeAcross; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.ObjectUtil; import java.util.ArrayList; import java.util.Collection; @@ -39,16 +42,19 @@ import java.util.Objects; import java.util.stream.Collectors; -public class TtxBidder implements Bidder { +public class ThirtyThreeAcrossBidder implements Bidder { - private static final TypeReference> TTX_EXT_TYPE_REFERENCE = + private static final TypeReference> THIRTY_THREE_ACROSS_EXT_TYPE_REFERENCE = new TypeReference<>() { }; + private static final ThirtyThreeAcrossExtTtxCaller PREBID_CALLER = + ThirtyThreeAcrossExtTtxCaller.of("Prebid-Server-Java", "n/a"); + private static final JsonPointer BID_MEDIA_TYPE_POINTER = JsonPointer.valueOf("/ttx/mediaType"); private final String endpointUrl; private final JacksonMapper mapper; - public TtxBidder(String endpointUrl, JacksonMapper mapper) { + public ThirtyThreeAcrossBidder(String endpointUrl, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); this.mapper = Objects.requireNonNull(mapper); } @@ -59,53 +65,93 @@ public Result>> makeHttpRequests(BidRequest request final Map> impsMap = new HashMap<>(); final List> requests = new ArrayList<>(); - for (Imp imp : request.getImp()) { + final BidRequest modifiedRequest = modifyRequest(request, errors); + for (Imp imp : modifiedRequest.getImp()) { try { validateImp(imp); - final ExtImpTtx extImpTtx = parseImpExt(imp); - final Imp updatedImp = updateImp(imp, extImpTtx); - impsMap.computeIfAbsent(computeKey(updatedImp), k -> new ArrayList<>()).add(updatedImp); + final ExtImpThirtyThreeAcross extImpTtx = parseImpExt(imp); + + final String productId = extImpTtx.getProductId(); + final ThirtyThreeAcrossImpExt modifiedImpExt = createImpExt(productId, extImpTtx); + final Imp updatedImp = updateImp(imp, productId, modifiedImpExt); + + impsMap.computeIfAbsent(getImpGroupName(modifiedImpExt), ignored -> new ArrayList<>()).add(updatedImp); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } } for (List imps : impsMap.values()) { - requests.add(createRequest(request, imps)); + requests.add(createRequest(modifiedRequest, imps)); } return Result.of(requests, errors); } - private void validateImp(Imp imp) throws PreBidException { + private BidRequest modifyRequest(BidRequest request, List errors) { + try { + return request.toBuilder().ext(modifyRequestExt(request.getExt())).build(); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + return request; + } + } + + private ExtRequest modifyRequestExt(ExtRequest ext) throws PreBidException { + final Map extProperties = ObjectUtil.getIfNotNull(ext, ExtRequest::getProperties); + final JsonNode extTtxNode = ObjectUtil.getIfNotNull(extProperties, properties -> properties.get("ttx")); + final ThirtyThreeAcrossExtTtx extTtx; + try { + extTtx = mapper.mapper().convertValue(extTtxNode, ThirtyThreeAcrossExtTtx.class); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage()); + } + + final ExtRequest modifiedExt = ExtRequest.empty(); + if (extProperties != null) { + modifiedExt.addProperties(extProperties); + } + modifiedExt.addProperty("ttx", mapper.mapper().valueToTree(modifyRequestExtTtx(extTtx))); + + return modifiedExt; + } + + private static ThirtyThreeAcrossExtTtx modifyRequestExtTtx(ThirtyThreeAcrossExtTtx extTtx) { + return ThirtyThreeAcrossExtTtx.of(extTtx != null && CollectionUtils.isNotEmpty(extTtx.getCaller()) + ? ListUtils.union(extTtx.getCaller(), Collections.singletonList(PREBID_CALLER)) + : Collections.singletonList(PREBID_CALLER)); + } + + private static void validateImp(Imp imp) { if (imp.getBanner() == null && imp.getVideo() == null) { throw new PreBidException( String.format("Imp ID %s must have at least one of [Banner, Video] defined", imp.getId())); } } - private ExtImpTtx parseImpExt(Imp imp) throws PreBidException { + private ExtImpThirtyThreeAcross parseImpExt(Imp imp) { try { - return mapper.mapper().convertValue(imp.getExt(), TTX_EXT_TYPE_REFERENCE).getBidder(); + return mapper.mapper().convertValue(imp.getExt(), THIRTY_THREE_ACROSS_EXT_TYPE_REFERENCE).getBidder(); } catch (IllegalArgumentException e) { throw new PreBidException(e.getMessage()); } } - private Imp updateImp(Imp imp, ExtImpTtx extImpTtx) throws PreBidException { - final String productId = extImpTtx.getProductId(); + private static ThirtyThreeAcrossImpExt createImpExt(String productId, ExtImpThirtyThreeAcross extImpTtx) { + final String zoneId = extImpTtx.getZoneId(); + + return ThirtyThreeAcrossImpExt.of(ThirtyThreeAcrossImpExtTtx.of( + productId, StringUtils.isNotEmpty(zoneId) ? zoneId : extImpTtx.getSiteId())); + } + + private Imp updateImp(Imp imp, String productId, ThirtyThreeAcrossImpExt impExt) { return imp.toBuilder() .video(updatedVideo(imp.getVideo(), productId)) - .ext(createImpExt(productId, extImpTtx.getZoneId(), extImpTtx.getSiteId())) + .ext(mapper.mapper().valueToTree(impExt)) .build(); } - private String computeKey(Imp imp) { - final JsonNode ttx = imp.getExt().get("ttx"); - return ttx.get("prod").asText() + ttx.get("zoneid").asText(); - } - - private static Video updatedVideo(Video video, String productId) throws PreBidException { + private static Video updatedVideo(Video video, String productId) { if (video == null) { return null; } @@ -117,11 +163,10 @@ private static Video updatedVideo(Video video, String productId) throws PreBidEx throw new PreBidException("One or more invalid or missing video field(s) " + "w, h, protocols, mimes, playbackmethod"); } - final Integer videoPlacement = video.getPlacement(); return video.toBuilder() .startdelay(resolveStartDelay(video.getStartdelay(), productId)) - .placement(resolvePlacement(videoPlacement, productId)) + .placement(resolvePlacement(video.getPlacement(), productId)) .build(); } @@ -143,10 +188,9 @@ private static Integer resolvePlacement(Integer videoPlacement, String productId return videoPlacement; } - private ObjectNode createImpExt(String productId, String zoneId, String siteId) { - final TtxImpExt ttxImpExt = TtxImpExt.of( - TtxImpExtTtx.of(productId, StringUtils.isNotEmpty(zoneId) ? zoneId : siteId)); - return mapper.mapper().valueToTree(ttxImpExt); + private static String getImpGroupName(ThirtyThreeAcrossImpExt impExt) { + final ThirtyThreeAcrossImpExtTtx impExtTtx = impExt.getTtx(); + return impExtTtx.getProd() + impExtTtx.getZoneid(); } private HttpRequest createRequest(BidRequest request, List requestImps) { @@ -167,42 +211,30 @@ private HttpRequest createRequest(BidRequest request, List requ public Result> makeBids(HttpCall httpCall, BidRequest bidRequest) { try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - return Result.of(extractBids(bidResponse), Collections.emptyList()); + return Result.withValues(extractBids(bidResponse)); } catch (DecodeException | PreBidException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); } } - private List extractBids(BidResponse bidResponse) { + private static List extractBids(BidResponse bidResponse) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); } - return bidsFromResponse(bidResponse); - } - private List bidsFromResponse(BidResponse bidResponse) { return bidResponse.getSeatbid().stream() .filter(Objects::nonNull) .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) + .filter(Objects::nonNull) .map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur())) .collect(Collectors.toList()); } - private BidType getBidType(Bid - bid) { - try { - final TtxBidExt ttxBidExt = mapper.mapper().convertValue(bid.getExt(), TtxBidExt.class); - return ttxBidExt != null ? getBidTypeByTtx(ttxBidExt.getTtx()) : BidType.banner; - } catch (IllegalArgumentException e) { - return BidType.banner; - } - } - - private static BidType getBidTypeByTtx(TtxBidExtTtx bidExt) { - return bidExt != null && Objects.equals(bidExt.getMediaType(), "video") - ? BidType.video - : BidType.banner; + private static BidType getBidType(Bid bid) { + final String mediaType = ObjectUtil.getIfNotNull(bid.getExt(), + ext -> ext.at(BID_MEDIA_TYPE_POINTER).asText(null)); + return "video".equals(mediaType) ? BidType.video : BidType.banner; } } diff --git a/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossExtTtx.java b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossExtTtx.java new file mode 100644 index 00000000000..76ca070a4c2 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossExtTtx.java @@ -0,0 +1,11 @@ +package org.prebid.server.bidder.thirtythreeacross.proto; + +import lombok.Value; + +import java.util.List; + +@Value(staticConstructor = "of") +public class ThirtyThreeAcrossExtTtx { + + List caller; +} diff --git a/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossExtTtxCaller.java b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossExtTtxCaller.java new file mode 100644 index 00000000000..ccd5644e22e --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossExtTtxCaller.java @@ -0,0 +1,11 @@ +package org.prebid.server.bidder.thirtythreeacross.proto; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ThirtyThreeAcrossExtTtxCaller { + + String name; + + String version; +} diff --git a/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossImpExt.java b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossImpExt.java new file mode 100644 index 00000000000..2b8c13e7c75 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossImpExt.java @@ -0,0 +1,9 @@ +package org.prebid.server.bidder.thirtythreeacross.proto; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ThirtyThreeAcrossImpExt { + + ThirtyThreeAcrossImpExtTtx ttx; +} diff --git a/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossImpExtTtx.java b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossImpExtTtx.java new file mode 100644 index 00000000000..2dcfcaca618 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/thirtythreeacross/proto/ThirtyThreeAcrossImpExtTtx.java @@ -0,0 +1,11 @@ +package org.prebid.server.bidder.thirtythreeacross.proto; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ThirtyThreeAcrossImpExtTtx { + + String prod; + + String zoneid; +} diff --git a/src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExt.java b/src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExt.java deleted file mode 100644 index 1e20d401040..00000000000 --- a/src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExt.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.prebid.server.bidder.ttx.proto; - -import lombok.AllArgsConstructor; -import lombok.Value; - -@AllArgsConstructor(staticName = "of") -@Value -public class TtxImpExt { - - TtxImpExtTtx ttx; -} diff --git a/src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExtTtx.java b/src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExtTtx.java deleted file mode 100644 index 2d5284b5d1f..00000000000 --- a/src/main/java/org/prebid/server/bidder/ttx/proto/TtxImpExtTtx.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.prebid.server.bidder.ttx.proto; - -import lombok.AllArgsConstructor; -import lombok.Value; - -@AllArgsConstructor(staticName = "of") -@Value -public class TtxImpExtTtx { - - String prod; - - String zoneid; -} diff --git a/src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExt.java b/src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExt.java deleted file mode 100644 index 6f4ba1b5702..00000000000 --- a/src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExt.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.prebid.server.bidder.ttx.response; - -import lombok.AllArgsConstructor; -import lombok.Value; - -@AllArgsConstructor(staticName = "of") -@Value -public class TtxBidExt { - - TtxBidExtTtx ttx; -} diff --git a/src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExtTtx.java b/src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExtTtx.java deleted file mode 100644 index 6a66b3322f7..00000000000 --- a/src/main/java/org/prebid/server/bidder/ttx/response/TtxBidExtTtx.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.prebid.server.bidder.ttx.response; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Value; - -@AllArgsConstructor(staticName = "of") -@Value -public class TtxBidExtTtx { - - @JsonProperty("mediaType") - @JsonInclude(JsonInclude.Include.NON_EMPTY) - String mediaType; -} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ttx/ExtImpTtx.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/thirtythreeacross/ExtImpThirtyThreeAcross.java similarity index 77% rename from src/main/java/org/prebid/server/proto/openrtb/ext/request/ttx/ExtImpTtx.java rename to src/main/java/org/prebid/server/proto/openrtb/ext/request/thirtythreeacross/ExtImpThirtyThreeAcross.java index c01d5b51e54..e18c9fb1583 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ttx/ExtImpTtx.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/thirtythreeacross/ExtImpThirtyThreeAcross.java @@ -1,4 +1,4 @@ -package org.prebid.server.proto.openrtb.ext.request.ttx; +package org.prebid.server.proto.openrtb.ext.request.thirtythreeacross; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -9,7 +9,7 @@ */ @AllArgsConstructor(staticName = "of") @Value -public class ExtImpTtx { +public class ExtImpThirtyThreeAcross { @JsonProperty("siteId") String siteId; diff --git a/src/main/java/org/prebid/server/spring/config/bidder/TtxConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ThirtyThreeAcrossConfiguration.java similarity index 55% rename from src/main/java/org/prebid/server/spring/config/bidder/TtxConfiguration.java rename to src/main/java/org/prebid/server/spring/config/bidder/ThirtyThreeAcrossConfiguration.java index 63dd447f8b4..c114867c505 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/TtxConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/ThirtyThreeAcrossConfiguration.java @@ -1,7 +1,7 @@ package org.prebid.server.spring.config.bidder; import org.prebid.server.bidder.BidderDeps; -import org.prebid.server.bidder.ttx.TtxBidder; +import org.prebid.server.bidder.thirtythreeacross.ThirtyThreeAcrossBidder; import org.prebid.server.json.JacksonMapper; import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; @@ -16,26 +16,26 @@ import javax.validation.constraints.NotBlank; @Configuration -@PropertySource(value = "classpath:/bidder-config/ttx.yaml", factory = YamlPropertySourceFactory.class) -public class TtxConfiguration { +@PropertySource(value = "classpath:/bidder-config/thirtythreeacross.yaml", factory = YamlPropertySourceFactory.class) +public class ThirtyThreeAcrossConfiguration { - private static final String BIDDER_NAME = "ttx"; + private static final String BIDDER_NAME = "thirtythreeacross"; - @Bean("ttxConfigurationProperties") - @ConfigurationProperties("adapters.ttx") + @Bean("thirtyThreeAcrossConfigurationProperties") + @ConfigurationProperties("adapters.thirtythreeacross") BidderConfigurationProperties configurationProperties() { return new BidderConfigurationProperties(); } @Bean - BidderDeps ttxBidderDeps(BidderConfigurationProperties ttxConfigurationProperties, - @NotBlank @Value("${external-url}") String externalUrl, - JacksonMapper mapper) { + BidderDeps thirtythreeacrossBidderDeps(BidderConfigurationProperties thirtyThreeAcrossConfigurationProperties, + @NotBlank @Value("${external-url}") String externalUrl, + JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) - .withConfig(ttxConfigurationProperties) + .withConfig(thirtyThreeAcrossConfigurationProperties) .usersyncerCreator(UsersyncerCreator.create(externalUrl)) - .bidderCreator(config -> new TtxBidder(config.getEndpoint(), mapper)) + .bidderCreator(config -> new ThirtyThreeAcrossBidder(config.getEndpoint(), mapper)) .assemble(); } } diff --git a/src/main/resources/bidder-config/ttx.yaml b/src/main/resources/bidder-config/thirtythreeacross.yaml similarity index 97% rename from src/main/resources/bidder-config/ttx.yaml rename to src/main/resources/bidder-config/thirtythreeacross.yaml index 7dc3142bf5b..0d54ae48f52 100644 --- a/src/main/resources/bidder-config/ttx.yaml +++ b/src/main/resources/bidder-config/thirtythreeacross.yaml @@ -1,5 +1,5 @@ adapters: - ttx: + thirtythreeacross: endpoint: https://ssc.33across.com/api/v1/s2s aliases: '33across': diff --git a/src/main/resources/static/bidder-params/ttx.json b/src/main/resources/static/bidder-params/thirtythreeacross.json similarity index 100% rename from src/main/resources/static/bidder-params/ttx.json rename to src/main/resources/static/bidder-params/thirtythreeacross.json diff --git a/src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java b/src/test/java/org/prebid/server/bidder/thirtythreeacross/ThirtyThreeAcrossBidderTest.java similarity index 56% rename from src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java rename to src/test/java/org/prebid/server/bidder/thirtythreeacross/ThirtyThreeAcrossBidderTest.java index a5e499106f5..f4cd9d03821 100644 --- a/src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/thirtythreeacross/ThirtyThreeAcrossBidderTest.java @@ -1,6 +1,7 @@ -package org.prebid.server.bidder.ttx; +package org.prebid.server.bidder.thirtythreeacross; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; @@ -17,38 +18,97 @@ import org.prebid.server.bidder.model.HttpRequest; import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; -import org.prebid.server.bidder.ttx.proto.TtxImpExt; -import org.prebid.server.bidder.ttx.proto.TtxImpExtTtx; -import org.prebid.server.bidder.ttx.response.TtxBidExt; -import org.prebid.server.bidder.ttx.response.TtxBidExtTtx; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossExtTtx; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossExtTtxCaller; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossImpExt; +import org.prebid.server.bidder.thirtythreeacross.proto.ThirtyThreeAcrossImpExtTtx; import org.prebid.server.proto.openrtb.ext.ExtPrebid; -import org.prebid.server.proto.openrtb.ext.request.ttx.ExtImpTtx; +import org.prebid.server.proto.openrtb.ext.request.ExtRequest; +import org.prebid.server.proto.openrtb.ext.request.thirtythreeacross.ExtImpThirtyThreeAcross; import java.util.List; -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; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; -public class TtxBidderTest extends VertxTest { +public class ThirtyThreeAcrossBidderTest extends VertxTest { private static final String ENDPOINT_URL = "https://test.endpoint.com"; - private TtxBidder ttxBidder; + private ThirtyThreeAcrossBidder thirtyThreeAcrossBidder; @Before public void setUp() { - ttxBidder = new TtxBidder(ENDPOINT_URL, jacksonMapper); + thirtyThreeAcrossBidder = new ThirtyThreeAcrossBidder(ENDPOINT_URL, jacksonMapper); } @Test public void creationShouldFailOnInvalidEndpointUrl() { - assertThatIllegalArgumentException().isThrownBy(() -> new TtxBidder("invalid_url", jacksonMapper)); + assertThatIllegalArgumentException() + .isThrownBy(() -> new ThirtyThreeAcrossBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldAppendErrorIfExtTtxCouldNotBeParsed() { + // given + final ExtRequest ext = ExtRequest.empty(); + ext.addProperty("ttx", mapper.createArrayNode()); + final BidRequest bidRequest = givenBidRequest(request -> request.ext(ext), identity()); + + // when + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); + + // then + assertThat(result.getValue()).hasSize(1); + assertThat(result.getErrors()).hasSize(1) + .extracting(BidderError::getMessage) + .allSatisfy(error -> assertThat(error).startsWith("Cannot deserialize value of")); + } + + @Test + public void makeHttpRequestsShouldAddExtTtxIfNotPresent() { + // given + final BidRequest bidRequest = givenBidRequest(identity()); + + // when + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); + + // then + final ExtRequest ext = ExtRequest.empty(); + ext.addProperty("ttx", mapper.valueToTree(ThirtyThreeAcrossExtTtx.of(singletonList( + ThirtyThreeAcrossExtTtxCaller.of("Prebid-Server-Java", "n/a"))))); + assertThat(result.getValue()).extracting(HttpRequest::getPayload) + .extracting(BidRequest::getExt) + .containsExactly(ext); + assertThat(result.getErrors()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldUpdateExtTtx() { + // given + final ExtRequest ext = ExtRequest.empty(); + ext.addProperty("ttx", mapper.valueToTree(ThirtyThreeAcrossExtTtx.of(singletonList( + ThirtyThreeAcrossExtTtxCaller.of("Caller", "1.0"))))); + final BidRequest bidRequest = givenBidRequest(request -> request.ext(ext), identity()); + + // when + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); + + // then + final ExtRequest updatedExt = ExtRequest.empty(); + updatedExt.addProperty("ttx", mapper.valueToTree(ThirtyThreeAcrossExtTtx.of(List.of( + ThirtyThreeAcrossExtTtxCaller.of("Caller", "1.0"), + ThirtyThreeAcrossExtTtxCaller.of("Prebid-Server-Java", "n/a"))))); + assertThat(result.getValue()).extracting(HttpRequest::getPayload) + .extracting(BidRequest::getExt) + .containsExactly(updatedExt); + assertThat(result.getErrors()).isEmpty(); } @Test @@ -59,7 +119,7 @@ public void makeHttpRequestsShouldAppendErrorIfImpExtCouldNotBeParsed() { .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).hasSize(1); @@ -77,7 +137,7 @@ public void makeHttpRequestsShouldNotUpdateSiteIfSiteNotPresent() { bidRequestBuilder.site(null), identity()); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -93,7 +153,7 @@ public void makeHttpRequestsShouldNotCreateNewSiteIfSiteNotPresentInBidRequest() final BidRequest bidRequest = givenBidRequest(identity()); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -111,7 +171,7 @@ public void makeHttpRequestsShouldChangeOnlyFirstImpExt() { .build(); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -119,22 +179,22 @@ public void makeHttpRequestsShouldChangeOnlyFirstImpExt() { .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .flatExtracting(BidRequest::getImp) .extracting(Imp::getExt) - .containsExactly( - mapper.valueToTree(TtxImpExt.of(TtxImpExtTtx.of("productId", "zoneId")))); + .containsExactly(mapper.valueToTree( + ThirtyThreeAcrossImpExt.of(ThirtyThreeAcrossImpExtTtx.of("productId", "zoneId")))); } @Test public void makeHttpRequestsShouldReturnErrorIfVideoParamsNotPresent() { // given final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList( - givenImp(impBuilder -> impBuilder - .video(Video.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpTtx.of("11", null, "3"))))))) + .imp(singletonList(givenImp(impBuilder -> impBuilder + .video(Video.builder().build()) + .ext(mapper.valueToTree( + ExtPrebid.of(null, ExtImpThirtyThreeAcross.of("11", null, "3"))))))) .build(); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()) @@ -145,15 +205,16 @@ public void makeHttpRequestsShouldReturnErrorIfVideoParamsNotPresent() { @Test public void makeHttpRequestsShouldUpdateNotPresentPlacement() { // given + final ExtPrebid ext = ExtPrebid.of(null, + ExtImpThirtyThreeAcross.of("11", null, "3")); final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList( - givenImp(impBuilder -> impBuilder - .video(validVideo()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpTtx.of("11", null, "3"))))))) + .imp(singletonList(givenImp(impBuilder -> impBuilder + .video(validVideo()) + .ext(mapper.valueToTree(ext))))) .build(); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -168,15 +229,16 @@ public void makeHttpRequestsShouldUpdateNotPresentPlacement() { @Test public void makeHttpRequestsShouldNotUpdatePlacementWhenProductIdIsNotInstreamAndPlacementIsNotZero() { // given + final ExtPrebid ext = ExtPrebid.of(null, + ExtImpThirtyThreeAcross.of("11", null, "3")); final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList( - givenImp(impBuilder -> impBuilder - .video(validVideo().toBuilder().placement(23).build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpTtx.of("11", null, "3"))))))) + .imp(singletonList(givenImp(impBuilder -> impBuilder + .video(validVideo().toBuilder().placement(23).build()) + .ext(mapper.valueToTree(ext))))) .build(); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -191,15 +253,16 @@ public void makeHttpRequestsShouldNotUpdatePlacementWhenProductIdIsNotInstreamAn @Test public void makeHttpRequestsShouldUpdatePlacementAndStartDelayIfProdIsInstream() { // given + final ExtPrebid ext = ExtPrebid.of(null, + ExtImpThirtyThreeAcross.of("11", null, "instream")); final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList( - givenImp(impBuilder -> impBuilder - .video(validVideo()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpTtx.of("11", null, "instream"))))))) + .imp(singletonList(givenImp(impBuilder -> impBuilder + .video(validVideo()) + .ext(mapper.valueToTree(ext))))) .build(); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); @@ -219,7 +282,7 @@ public void makeBidsShouldReturnErrorIfNoBannerOrVideoPresent() { .build(); // when - final Result>> result = ttxBidder.makeHttpRequests(bidRequest); + final Result>> result = thirtyThreeAcrossBidder.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()) @@ -233,7 +296,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { final HttpCall httpCall = givenHttpCall(null, "invalid"); // when - final Result> result = ttxBidder.makeBids(httpCall, null); + final Result> result = thirtyThreeAcrossBidder.makeBids(httpCall, null); // then assertThat(result.getErrors()) @@ -251,7 +314,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces mapper.writeValueAsString(null)); // when - final Result> result = ttxBidder.makeBids(httpCall, null); + final Result> result = thirtyThreeAcrossBidder.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); @@ -265,7 +328,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso mapper.writeValueAsString(BidResponse.builder().build())); // when - final Result> result = ttxBidder.makeBids(httpCall, null); + final Result> result = thirtyThreeAcrossBidder.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); @@ -283,7 +346,7 @@ public void makeBidsShouldReturnBannerBidByDefault() throws JsonProcessingExcept givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); // when - final Result> result = ttxBidder.makeBids(httpCall, null); + final Result> result = thirtyThreeAcrossBidder.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); @@ -294,23 +357,20 @@ public void makeBidsShouldReturnBannerBidByDefault() throws JsonProcessingExcept @Test public void makeBidsShouldReturnVideoBidIfVideoInBidExt() throws JsonProcessingException { // given - final TtxBidExt ttxBidExt = TtxBidExt.of(TtxBidExtTtx.of("video")); + final ObjectNode bidExt = mapper.createObjectNode().set("ttx", + mapper.createObjectNode().put("mediaType", "video")); final HttpCall httpCall = givenHttpCall( BidRequest.builder() .imp(singletonList(Imp.builder().build())) .build(), - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder - .ext(mapper.valueToTree(ttxBidExt))))); + mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(bidExt)))); // when - final Result> result = ttxBidder.makeBids(httpCall, null); + final Result> result = thirtyThreeAcrossBidder.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - final Bid expectedBid = Bid.builder() - .ext(mapper.valueToTree(ttxBidExt)) - .build(); + final Bid expectedBid = Bid.builder().ext(bidExt).build(); assertThat(result.getValue()) .containsOnly(BidderBid.of(expectedBid, video, "USD")); } @@ -318,23 +378,20 @@ public void makeBidsShouldReturnVideoBidIfVideoInBidExt() throws JsonProcessingE @Test public void makeBidsShouldReturnBannerBidIfExtNotContainVideoString() throws JsonProcessingException { // given - final TtxBidExt ttxBidExt = TtxBidExt.of(TtxBidExtTtx.of("notVideo")); + final ObjectNode bidExt = mapper.createObjectNode().set("ttx", + mapper.createObjectNode().put("mediaType", "notVideo")); final HttpCall httpCall = givenHttpCall( BidRequest.builder() .imp(singletonList(Imp.builder().build())) .build(), - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder - .ext(mapper.valueToTree(ttxBidExt))))); + mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.ext(bidExt)))); // when - final Result> result = ttxBidder.makeBids(httpCall, null); + final Result> result = thirtyThreeAcrossBidder.makeBids(httpCall, null); // then assertThat(result.getErrors()).isEmpty(); - final Bid expectedBid = Bid.builder() - .ext(mapper.valueToTree(ttxBidExt)) - .build(); + final Bid expectedBid = Bid.builder().ext(bidExt).build(); assertThat(result.getValue()) .containsOnly(BidderBid.of(expectedBid, banner, "USD")); } @@ -350,27 +407,29 @@ private static Video validVideo() { } private static BidRequest givenBidRequest( - Function bidRequestCustomizer, - Function impCustomizer) { + UnaryOperator bidRequestCustomizer, + UnaryOperator impCustomizer) { - return bidRequestCustomizer.apply(BidRequest.builder() - .imp(singletonList(givenImp(impCustomizer)))) - .build(); + final List imps = singletonList(givenImp(impCustomizer)); + return bidRequestCustomizer.apply(BidRequest.builder().imp(imps)).build(); } - private static BidRequest givenBidRequest(Function impCustomizer) { + private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { return givenBidRequest(identity(), impCustomizer); } - private static Imp givenImp(Function impCustomizer) { - return impCustomizer.apply(Imp.builder() + private static Imp givenImp(UnaryOperator impCustomizer) { + final ExtPrebid ext = ExtPrebid.of(null, + ExtImpThirtyThreeAcross.of("siteId", "zoneId", "productId")); + final Imp.ImpBuilder builder = Imp.builder() .id("123") .banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpTtx.of("siteId", "zoneId", "productId"))))) - .build(); + .ext(mapper.valueToTree(ext)); + + return impCustomizer.apply(builder).build(); } - private static BidResponse givenBidResponse(Function bidCustomizer) { + private static BidResponse givenBidResponse(UnaryOperator bidCustomizer) { return BidResponse.builder() .cur("USD") .seatbid(singletonList(SeatBid.builder() diff --git a/src/test/java/org/prebid/server/it/TtxTest.java b/src/test/java/org/prebid/server/it/ThirtyThreeAcrossTest.java similarity index 54% rename from src/test/java/org/prebid/server/it/TtxTest.java rename to src/test/java/org/prebid/server/it/ThirtyThreeAcrossTest.java index 0e9a2d8aa0f..10a891e9647 100644 --- a/src/test/java/org/prebid/server/it/TtxTest.java +++ b/src/test/java/org/prebid/server/it/ThirtyThreeAcrossTest.java @@ -16,20 +16,23 @@ import static java.util.Collections.singletonList; @RunWith(SpringRunner.class) -public class TtxTest extends IntegrationTest { +public class ThirtyThreeAcrossTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFrom33Across() throws IOException, JSONException { // given - WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/ttx-exchange")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/ttx/test-ttx-bid-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/ttx/test-ttx-bid-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/thirtythreeacross-exchange")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/thirtythreeacross/test-thirtythreeacross-bid-request.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/thirtythreeacross/test-thirtythreeacross-bid-response.json")))); // when - final Response response = responseFor("openrtb2/ttx/test-auction-ttx-request.json", + final Response response = responseFor("openrtb2/thirtythreeacross/test-auction-thirtythreeacross-request.json", Endpoint.openrtb2_auction); // then - assertJsonEquals("openrtb2/ttx/test-auction-ttx-response.json", response, singletonList("ttx")); + assertJsonEquals("openrtb2/thirtythreeacross/test-auction-thirtythreeacross-response.json", + response, singletonList("thirtythreeacross")); } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-auction-thirtythreeacross-request.json similarity index 66% rename from src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json rename to src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-auction-thirtythreeacross-request.json index dd257a94191..571eaaf14e1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-auction-thirtythreeacross-request.json @@ -8,7 +8,7 @@ "h": 250 }, "ext": { - "ttx": { + "thirtythreeacross": { "siteId": "site-id", "productId": "inview", "zoneId": "zone-id" @@ -21,5 +21,15 @@ "ext": { "gdpr": 0 } + }, + "ext": { + "ttx": { + "caller": [ + { + "name": "caller", + "version": "1.0" + } + ] + } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-auction-thirtythreeacross-response.json similarity index 84% rename from src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json rename to src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-auction-thirtythreeacross-response.json index 50c30722255..89ac6871c53 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-auction-thirtythreeacross-response.json @@ -19,14 +19,14 @@ } } ], - "seat": "ttx", + "seat": "thirtythreeacross", "group": 0 } ], "cur": "USD", "ext": { "responsetimemillis": { - "ttx": "{{ ttx.response_time_ms }}" + "thirtythreeacross": "{{ thirtythreeacross.response_time_ms }}" }, "prebid": { "auctiontimestamp": 0 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-thirtythreeacross-bid-request.json similarity index 72% rename from src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request.json rename to src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-thirtythreeacross-bid-request.json index 0104d8914d3..776ec27f6a0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-thirtythreeacross-bid-request.json @@ -38,5 +38,19 @@ "ext": { "gdpr": 0 } + }, + "ext": { + "ttx": { + "caller": [ + { + "name": "caller", + "version": "1.0" + }, + { + "name": "Prebid-Server-Java", + "version": "n/a" + } + ] + } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-thirtythreeacross-bid-response.json similarity index 100% rename from src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-response.json rename to src/test/resources/org/prebid/server/it/openrtb2/thirtythreeacross/test-thirtythreeacross-bid-response.json diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 68f6b4596ee..20ad53b2dc2 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -233,10 +233,10 @@ adapters.triplelift.endpoint=http://localhost:8090/triplelift-exchange adapters.tripleliftnative.enabled=true adapters.tripleliftnative.endpoint=http://localhost:8090/triplelift_native-exchange adapters.tripleliftnative.whitelist=test -adapters.ttx.enabled=true -adapters.ttx.endpoint=http://localhost:8090/ttx-exchange -adapters.ttx.partner-id=partner -adapters.ttx.aliases.33across.enabled=true +adapters.thirtythreeacross.enabled=true +adapters.thirtythreeacross.endpoint=http://localhost:8090/thirtythreeacross-exchange +adapters.thirtythreeacross.partner-id=partner +adapters.thirtythreeacross.aliases.33across.enabled=true adapters.ucfunnel.enabled=true adapters.ucfunnel.endpoint=http://localhost:8090/ucfunnel-exchange adapters.unicorn.enabled=true