From 8b3fe6bd1d40236952bc5a69a440fa49cc7422bd Mon Sep 17 00:00:00 2001 From: antonbabak Date: Wed, 19 Mar 2025 18:56:32 +0100 Subject: [PATCH 1/2] ResetDigital Bidder Update --- .../resetdigital/ResetDigitalBidder.java | 285 ++++---- .../resetdigital/request/ResetDigitalImp.java | 19 + .../request/ResetDigitalImpExt.java | 9 + .../request/ResetDigitalImpMediaType.java | 15 + .../request/ResetDigitalImpMediaTypes.java | 27 + .../request/ResetDigitalImpZone.java | 11 + .../request/ResetDigitalRequest.java | 15 + .../request/ResetDigitalSite.java | 13 + .../response/ResetDigitalBid.java | 31 + .../response/ResetDigitalResponse.java | 11 + .../bidder/ResetDigitalConfiguration.java | 7 +- .../resources/bidder-config/resetdigital.yaml | 5 +- .../static/bidder-params/resetdigital.json | 22 +- .../resetdigital/ResetDigitalBidderTest.java | 617 +++++++++--------- .../test-auction-resetdigital-request.json | 23 +- .../test-auction-resetdigital-response.json | 19 +- .../test-resetdigital-bid-request.json | 64 +- .../test-resetdigital-bid-response.json | 29 +- 18 files changed, 696 insertions(+), 526 deletions(-) create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImp.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpExt.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpZone.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java create mode 100644 src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalResponse.java diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java b/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java index 3bc78b588b0..8604a2f8a80 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java @@ -1,182 +1,249 @@ package org.prebid.server.bidder.resetdigital; +import com.fasterxml.jackson.core.type.TypeReference; +import com.iab.openrtb.request.Audio; +import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Device; 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; +import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.ObjectUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.HttpRequest; -import org.prebid.server.bidder.model.Price; import org.prebid.server.bidder.model.Result; -import org.prebid.server.currency.CurrencyConversionService; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImp; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImpMediaType; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImpMediaTypes; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImpZone; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalRequest; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalSite; +import org.prebid.server.bidder.resetdigital.response.ResetDigitalBid; +import org.prebid.server.bidder.resetdigital.response.ResetDigitalResponse; 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.resetdigital.ExtImpResetDigital; import org.prebid.server.proto.openrtb.ext.response.BidType; -import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; -import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.stream.Stream; +import java.util.Set; -public class ResetDigitalBidder implements Bidder { +public class ResetDigitalBidder implements Bidder { - private static final String DEFAULT_CURRENCY = "USD"; + private static final TypeReference> IMP_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; + private static final String BID_CURRENCY = "USD"; private final String endpointUrl; - private final CurrencyConversionService currencyConversionService; private final JacksonMapper mapper; - public ResetDigitalBidder(String endpointUrl, - CurrencyConversionService currencyConversionService, - JacksonMapper mapper) { - + public ResetDigitalBidder(String endpointUrl, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); - this.currencyConversionService = Objects.requireNonNull(currencyConversionService); this.mapper = Objects.requireNonNull(mapper); } @Override - public Result>> makeHttpRequests(BidRequest request) { - final List bannerImps = new ArrayList<>(); - final List videoImps = new ArrayList<>(); - final List audioImps = new ArrayList<>(); - Price bidFloorPrice; + public Result>> makeHttpRequests(BidRequest request) { + final List> requests = new ArrayList<>(); + final List errors = new ArrayList<>(); - for (Imp imp : request.getImp()) { + for (Imp imp: request.getImp()) { try { - bidFloorPrice = resolveBidFloor(imp, request); + final ExtImpResetDigital extImp = parseImpExt(imp); + final ResetDigitalImp resetDigitalImp = makeImp(request, imp, extImp); + requests.add(makeHttpRequest(request, resetDigitalImp)); } catch (PreBidException e) { - return Result.withError(BidderError.badInput(e.getMessage())); + errors.add(BidderError.badInput(e.getMessage())); } - populateBannerImps(bannerImps, bidFloorPrice, imp); - populateVideoImps(videoImps, bidFloorPrice, imp); - populateAudiImps(audioImps, bidFloorPrice, imp); } - return Result.withValues(getHttpRequests(request, bannerImps, videoImps, audioImps)); + return Result.of(requests, errors); } - private List> getHttpRequests(BidRequest request, - List bannerImps, - List videoImps, - List audioImps) { + private ExtImpResetDigital parseImpExt(Imp imp) throws PreBidException { + try { + return mapper.mapper().convertValue(imp.getExt(), IMP_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage()); + } + } - return Stream.of(bannerImps, videoImps, audioImps) - .filter(CollectionUtils::isNotEmpty) - .map(imp -> makeHttpRequest(request, imp)) - .toList(); + private static ResetDigitalImp makeImp(BidRequest request, Imp imp, ExtImpResetDigital extImp) { + return ResetDigitalImp.builder() + .bidId(request.getId()) + .impId(imp.getId()) + .mediaTypes(resolveMediaTypes(imp)) + .zoneId(extImp.getPlacementId() == null ? null : ResetDigitalImpZone.of(extImp.getPlacementId())) + .build(); } - private HttpRequest makeHttpRequest(BidRequest bidRequest, List imp) { - final BidRequest outgoingRequest = bidRequest.toBuilder().imp(imp).build(); + private static ResetDigitalImpMediaTypes resolveMediaTypes(Imp imp) { + final Banner banner = imp.getBanner(); + final Video video = imp.getVideo(); + final Audio audio = imp.getAudio(); + + if (banner != null) { + final ResetDigitalImpMediaType mediaType = makeBanner(banner); + return mediaType == null ? null : ResetDigitalImpMediaTypes.banner(mediaType); + } else if (video != null) { + final ResetDigitalImpMediaType mediaType = makeVideo(video); + return mediaType == null ? null : ResetDigitalImpMediaTypes.video(mediaType); + } else if (audio != null) { + final ResetDigitalImpMediaType mediaType = makeAudio(audio); + return mediaType == null ? null : ResetDigitalImpMediaTypes.audio(mediaType); + } else { + throw new PreBidException("Banner, video or audio must be present in the imp %s".formatted(imp.getId())); + } + } - return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper); + private static ResetDigitalImpMediaType makeBanner(Banner banner) { + return makeMediaType(banner.getW(), banner.getH(), null); } - private static Imp modifyImp(Imp imp, Price bidFloorPrice) { - return imp.toBuilder() - .bidfloorcur(bidFloorPrice.getCurrency()) - .bidfloor(bidFloorPrice.getValue()) - .build(); + private static ResetDigitalImpMediaType makeVideo(Video video) { + return makeMediaType(video.getW(), video.getH(), video.getMimes()); } - private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { - final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); - return BidderUtil.isValidPrice(initialBidFloorPrice) - ? convertBidFloor(initialBidFloorPrice, imp.getId(), bidRequest) - : initialBidFloorPrice; + private static ResetDigitalImpMediaType makeAudio(Audio audio) { + return makeMediaType(null, null, audio.getMimes()); } - private Price convertBidFloor(Price bidFloorPrice, String impId, BidRequest bidRequest) { - final String bidFloorCur = bidFloorPrice.getCurrency(); - try { - final BigDecimal convertedPrice = currencyConversionService - .convertCurrency(bidFloorPrice.getValue(), bidRequest, bidFloorCur, DEFAULT_CURRENCY); - - return Price.of(DEFAULT_CURRENCY, convertedPrice); - } catch (PreBidException e) { - throw new PreBidException( - "Unable to convert provided bid floor currency from %s to %s for imp `%s`" - .formatted(bidFloorCur, DEFAULT_CURRENCY, impId)); + private static ResetDigitalImpMediaType makeMediaType(Integer width, Integer height, List mimes) { + final boolean hasValidSizes = isValidSizeValue(width) && isValidSizeValue(height); + final boolean hasMimes = CollectionUtils.isNotEmpty(mimes); + + if (!hasValidSizes && !hasMimes) { + return null; } + + return ResetDigitalImpMediaType.builder() + .sizes(hasValidSizes ? List.of(List.of(width, height)) : null) + .mimes(hasMimes ? mimes : null) + .build(); } - private static void populateBannerImps(List bannerImps, Price bidFloorPrice, Imp imp) { - if (imp.getBanner() != null) { - final Imp bannerImp = imp.toBuilder().video(null).xNative(null).audio(null).build(); - bannerImps.add(modifyImp(bannerImp, bidFloorPrice)); - } + private static boolean isValidSizeValue(Integer value) { + return value != null && value > 0; } - private static void populateVideoImps(List videoImps, Price bidFloorPrice, Imp imp) { - if (imp.getVideo() != null) { - final Imp videoImp = imp.toBuilder().banner(null).xNative(null).audio(null).build(); - videoImps.add(modifyImp(videoImp, bidFloorPrice)); - } + private HttpRequest makeHttpRequest(BidRequest request, ResetDigitalImp resetDigitalImp) { + final ResetDigitalRequest modifiedRequest = makeRequest(request, resetDigitalImp); + + return HttpRequest.builder() + .method(HttpMethod.POST) + .uri(endpointUrl) + .headers(makeHeaders(request)) + .impIds(Set.of(resetDigitalImp.getImpId())) + .body(mapper.encodeToBytes(modifiedRequest)) + .payload(modifiedRequest) + .build(); } - private static void populateAudiImps(List audioImps, Price bidFloorPrice, Imp imp) { - if (imp.getAudio() != null) { - final Imp audioImp = imp.toBuilder().banner(null).xNative(null).video(null).build(); - audioImps.add(modifyImp(audioImp, bidFloorPrice)); + private static ResetDigitalRequest makeRequest(BidRequest request, ResetDigitalImp resetDigitalImp) { + return ResetDigitalRequest.builder() + .site(makeSite(request.getSite())) + .imps(Collections.singletonList(resetDigitalImp)) + .build(); + } + + private static ResetDigitalSite makeSite(Site site) { + return site == null || ObjectUtils.allNull(site.getDomain(), site.getPage()) + ? null + : ResetDigitalSite.builder() + .domain(site.getDomain()) + .referrer(site.getPage()) + .build(); + } + + private static MultiMap makeHeaders(BidRequest request) { + final MultiMap headers = HttpUtil.headers(); + + final Device device = request.getDevice(); + if (device != null) { + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.ACCEPT_LANGUAGE_HEADER, device.getLanguage()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, device.getUa()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIp()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_REAL_IP_HEADER, device.getIp()); } + + final Site site = request.getSite(); + if (site != null) { + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.REFERER_HEADER, site.getPage()); + } + + return headers; } @Override - public final Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { - final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - return Result.withValues(extractBids(bidResponse, httpCall.getRequest().getPayload())); + final ResetDigitalResponse bidResponse = mapper.decodeValue( + httpCall.getResponse().getBody(), + ResetDigitalResponse.class); + return Result.withValues(extractBids(bidRequest, bidResponse)); } catch (DecodeException | PreBidException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); } } - private static List extractBids(BidResponse bidResponse, BidRequest bidRequest) { - if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { - return Collections.emptyList(); + private static List extractBids(BidRequest bidRequest, ResetDigitalResponse bidResponse) { + final List bids = bidResponse == null + ? Collections.emptyList() + : CollectionUtils.emptyIfNull(bidResponse.getBids()).stream().filter(Objects::nonNull).toList(); + + if (bids.size() != 1) { + throw new PreBidException("expected exactly one bid in the response, but got %d".formatted(bids.size())); } - if (bidResponse.getCur() != null && !StringUtils.equalsIgnoreCase(DEFAULT_CURRENCY, bidResponse.getCur())) { - throw new PreBidException("Bidder support only USD currency"); + + final ResetDigitalBid bid = bids.getFirst(); + final Imp correspondingImp = bidRequest.getImp().stream() + .filter(imp -> Objects.equals(imp.getId(), bid.getImpId())) + .findFirst() + .orElseThrow(() -> new PreBidException( + "no matching impression found for ImpID %s".formatted(bid.getImpId()))); + + return Collections.singletonList( + BidderBid.of(makeBid(bid), resolveBidType(correspondingImp), bid.getSeat(), BID_CURRENCY)); + } + + private static Bid makeBid(ResetDigitalBid bid) { + try { + return Bid.builder() + .id(bid.getBidId()) + .price(bid.getCpm()) + .impid(bid.getImpId()) + .cid(bid.getCid()) + .crid(bid.getCrid()) + .adm(bid.getHtml()) + .w(Integer.parseInt(bid.getW())) + .h(Integer.parseInt(bid.getH())) + .build(); + } catch (NumberFormatException e) { + throw new PreBidException(e.getMessage()); } - return bidsFromResponse(bidResponse, bidRequest); - } - - private static List bidsFromResponse(BidResponse bidResponse, BidRequest bidRequest) { - return bidResponse.getSeatbid().stream() - .filter(Objects::nonNull) - .map(SeatBid::getBid) - .filter(Objects::nonNull) - .flatMap(Collection::stream) - .map(bid -> BidderBid.of(bid, getBidType(bid, bidRequest.getImp()), DEFAULT_CURRENCY)) - .toList(); - } - - private static BidType getBidType(Bid bid, List imps) { - final String impId = bid.getImpid(); - for (Imp imp : imps) { - if (imp.getId().equals(impId)) { - if (imp.getBanner() != null) { - return BidType.banner; - } else if (imp.getVideo() != null) { - return BidType.video; - } else if (imp.getAudio() != null) { - return BidType.audio; - } - } + } + + private static BidType resolveBidType(Imp imp) throws PreBidException { + if (imp.getVideo() != null) { + return BidType.video; + } else if (imp.getAudio() != null) { + return BidType.audio; + } else { + return BidType.banner; } - throw new PreBidException("Failed to find banner/video/audio impression " + impId); } } diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImp.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImp.java new file mode 100644 index 00000000000..5674c2446a7 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImp.java @@ -0,0 +1,19 @@ +package org.prebid.server.bidder.resetdigital.request; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ResetDigitalImp { + + ResetDigitalImpZone zoneId; + + String bidId; + + String impId; + + ResetDigitalImpMediaTypes mediaTypes; + + ResetDigitalImpExt ext; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpExt.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpExt.java new file mode 100644 index 00000000000..16363a5e6d9 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpExt.java @@ -0,0 +1,9 @@ +package org.prebid.server.bidder.resetdigital.request; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class ResetDigitalImpExt { + + String gpid; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java new file mode 100644 index 00000000000..5ee15918c38 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java @@ -0,0 +1,15 @@ +package org.prebid.server.bidder.resetdigital.request; + +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +@Value(staticConstructor = "of") +@Builder +public class ResetDigitalImpMediaType { + + List> sizes; + + List mimes; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java new file mode 100644 index 00000000000..7483f318e0e --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java @@ -0,0 +1,27 @@ +package org.prebid.server.bidder.resetdigital.request; + +import lombok.Builder; +import lombok.Value; + +@Value(staticConstructor = "of") +@Builder +public class ResetDigitalImpMediaTypes { + + ResetDigitalImpMediaType banner; + + ResetDigitalImpMediaType video; + + ResetDigitalImpMediaType audio; + + public static ResetDigitalImpMediaTypes banner(ResetDigitalImpMediaType banner) { + return ResetDigitalImpMediaTypes.builder().banner(banner).build(); + } + + public static ResetDigitalImpMediaTypes video(ResetDigitalImpMediaType video) { + return ResetDigitalImpMediaTypes.builder().video(video).build(); + } + + public static ResetDigitalImpMediaTypes audio(ResetDigitalImpMediaType audio) { + return ResetDigitalImpMediaTypes.builder().audio(audio).build(); + } +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpZone.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpZone.java new file mode 100644 index 00000000000..516ee7ec8bd --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpZone.java @@ -0,0 +1,11 @@ +package org.prebid.server.bidder.resetdigital.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +@Value(staticConstructor = "of") +public class ResetDigitalImpZone { + + @JsonProperty("placementId") + String placementId; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java new file mode 100644 index 00000000000..8294ec1a469 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java @@ -0,0 +1,15 @@ +package org.prebid.server.bidder.resetdigital.request; + +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +@Value +@Builder +public class ResetDigitalRequest { + + ResetDigitalSite site; + + List imps; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java new file mode 100644 index 00000000000..77962b232b2 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java @@ -0,0 +1,13 @@ +package org.prebid.server.bidder.resetdigital.request; + +import lombok.Builder; +import lombok.Value; + +@Value +@Builder +public class ResetDigitalSite { + + String domain; + + String referrer; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java b/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java new file mode 100644 index 00000000000..fead0572112 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java @@ -0,0 +1,31 @@ +package org.prebid.server.bidder.resetdigital.response; + +import lombok.Builder; +import lombok.Value; + +import java.math.BigDecimal; + +@Value(staticConstructor = "of") +@Builder +public class ResetDigitalBid { + + String bidId; + + String impId; + + BigDecimal cpm; + + String cid; + + String crid; + + String adid; + + String w; + + String h; + + String seat; + + String html; +} diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalResponse.java b/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalResponse.java new file mode 100644 index 00000000000..2dcf57e8d80 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalResponse.java @@ -0,0 +1,11 @@ +package org.prebid.server.bidder.resetdigital.response; + +import lombok.Value; + +import java.util.List; + +@Value(staticConstructor = "of") +public class ResetDigitalResponse { + + List bids; +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ResetDigitalConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ResetDigitalConfiguration.java index 4e4de161f66..33823866d5f 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/ResetDigitalConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/ResetDigitalConfiguration.java @@ -2,7 +2,6 @@ import org.prebid.server.bidder.BidderDeps; import org.prebid.server.bidder.resetdigital.ResetDigitalBidder; -import org.prebid.server.currency.CurrencyConversionService; import org.prebid.server.json.JacksonMapper; import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; @@ -31,16 +30,12 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps resetDigitalBidderDeps(BidderConfigurationProperties resetDigitalConfigurationProperties, @NotBlank @Value("${external-url}") String externalUrl, - CurrencyConversionService currencyConversionService, JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(resetDigitalConfigurationProperties) .usersyncerCreator(UsersyncerCreator.create(externalUrl)) - .bidderCreator(config -> new ResetDigitalBidder( - config.getEndpoint(), - currencyConversionService, - mapper)) + .bidderCreator(config -> new ResetDigitalBidder(config.getEndpoint(), mapper)) .assemble(); } } diff --git a/src/main/resources/bidder-config/resetdigital.yaml b/src/main/resources/bidder-config/resetdigital.yaml index 885916d0d8d..3ae9e26bf3e 100644 --- a/src/main/resources/bidder-config/resetdigital.yaml +++ b/src/main/resources/bidder-config/resetdigital.yaml @@ -4,9 +4,6 @@ adapters: meta-info: maintainer-email: biddersupport@resetdigital.co app-media-types: - - banner - - video - - audio site-media-types: - banner - video @@ -16,6 +13,6 @@ adapters: usersync: cookie-family-name: resetdigital redirect: - url: https://sync.resetdigital.co/csync?pid=rubicon&redir={{redirect_url}} + url: https://sync.resetdigital.co/csync?redir={{redirect_url}} support-cors: false uid-macro: '$USER_ID' diff --git a/src/main/resources/static/bidder-params/resetdigital.json b/src/main/resources/static/bidder-params/resetdigital.json index 3710cfbc598..07a7bc2b551 100644 --- a/src/main/resources/static/bidder-params/resetdigital.json +++ b/src/main/resources/static/bidder-params/resetdigital.json @@ -1,23 +1,13 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "ResetDigital Adapter Params", - "description": "A schema which validates params accepted by the ResetDigital adapter", + "title": "Reset Digital Adapter Params", + "description": "A schema which validates params accepted by the Reset Digital adapter", "type": "object", "properties": { - "pubId": { + "placement_id": { "type": "string", - "description": "The publisher's ID provided" - }, - "zoneId": { - "type": "string", - "description": "Zone ID" - }, - "forceBid": { - "type": "boolean", - "description": "Force bids with a test creative" + "minLength": 1, + "description": "Placement ID for the Reset Digital ad unit. This is the identifier for the ad unit on the Reset Digital platform, and its optional" } - }, - "required": [ - "pubId" - ] + } } diff --git a/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java b/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java index dbcc555489a..9bd1656433e 100644 --- a/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java @@ -4,17 +4,14 @@ import com.iab.openrtb.request.Audio; import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Device; import com.iab.openrtb.request.Imp; import com.iab.openrtb.request.Native; +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 org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.VertxTest; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -22,484 +19,484 @@ 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.currency.CurrencyConversionService; -import org.prebid.server.exception.PreBidException; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImp; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImpMediaType; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImpMediaTypes; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalImpZone; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalRequest; +import org.prebid.server.bidder.resetdigital.request.ResetDigitalSite; +import org.prebid.server.bidder.resetdigital.response.ResetDigitalBid; +import org.prebid.server.bidder.resetdigital.response.ResetDigitalResponse; +import org.prebid.server.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.resetdigital.ExtImpResetDigital; import java.math.BigDecimal; import java.util.List; +import java.util.Set; import java.util.function.UnaryOperator; +import java.util.stream.Stream; -import static java.util.Collections.singletonList; 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.AssertionsForClassTypes.tuple; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.BDDMockito.given; import static org.prebid.server.proto.openrtb.ext.response.BidType.audio; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; +import static org.prebid.server.util.HttpUtil.ACCEPT_HEADER; +import static org.prebid.server.util.HttpUtil.ACCEPT_LANGUAGE_HEADER; +import static org.prebid.server.util.HttpUtil.APPLICATION_JSON_CONTENT_TYPE; +import static org.prebid.server.util.HttpUtil.CONTENT_TYPE_HEADER; +import static org.prebid.server.util.HttpUtil.REFERER_HEADER; +import static org.prebid.server.util.HttpUtil.USER_AGENT_HEADER; +import static org.prebid.server.util.HttpUtil.X_FORWARDED_FOR_HEADER; +import static org.prebid.server.util.HttpUtil.X_REAL_IP_HEADER; +import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; -@ExtendWith(MockitoExtension.class) public class ResetDigitalBidderTest extends VertxTest { public static final String ENDPOINT_URL = "https://test.endpoint.com"; - @Mock - private CurrencyConversionService currencyConversionService; - private ResetDigitalBidder target; @BeforeEach public void setUp() { - target = new ResetDigitalBidder(ENDPOINT_URL, currencyConversionService, jacksonMapper); + target = new ResetDigitalBidder(ENDPOINT_URL, jacksonMapper); } @Test public void creationShouldFailOnInvalidEndpointUrl() { assertThatIllegalArgumentException().isThrownBy(() -> - new ResetDigitalBidder("invalid_url", currencyConversionService, jacksonMapper)); + new ResetDigitalBidder("invalid_url", jacksonMapper)); } @Test - public void makeHttpRequestShouldReturnEmptyResponseIfAbsentAnyTypeInImp() { + public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder.banner(null)))) - .build(); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()).hasSize(0); - } - - @Test - public void makeHttpRequestShouldReturnEmptyResponseIfxNativeImpTypePresent() { - // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder.banner(null) - .xNative(Native.builder().build())))) - .build(); + final BidRequest bidRequest = givenBidRequest( + imp -> imp.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode())))); // when - final Result>> result = target.makeHttpRequests(bidRequest); + final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()).hasSize(0); + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1).allSatisfy(bidderError -> { + assertThat(bidderError.getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(bidderError.getMessage()).startsWith("Cannot deserialize value"); + }); } @Test - public void makeHttpRequestShouldReturnSeparateResponseWithBannerAndVideoAndAudioImp() { + public void makeHttpRequestsShouldMakeOneRequestPerImp() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder - .audio(Audio.builder().build()) - .video(Video.builder().build())))) - .build(); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); + final BidRequest bidRequest = givenBidRequest( + imp -> imp.id("givenImp1"), + imp -> imp.id("givenImp2"), + imp -> imp.id("givenImp3")); - // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()).hasSize(3); - assertThat(result.getValue().get(0)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getBanner) - .isNotNull(); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - assertThat(result.getValue().get(1)) + //then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(3) .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getVideo) - .isNotNull(); + .flatExtracting(ResetDigitalRequest::getImps) + .extracting(ResetDigitalImp::getImpId) + .containsExactlyInAnyOrder("givenImp1", "givenImp2", "givenImp3"); - assertThat(result.getValue().get(2)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getAudio) - .isNotNull(); + assertThat(result.getValue()).hasSize(3) + .extracting(HttpRequest::getImpIds) + .containsExactlyInAnyOrder(Set.of("givenImp1"), Set.of("givenImp2"), Set.of("givenImp3")); } @Test - public void makeHttpRequestShouldReturnSeparateResponseWithBannerAndVideoImp() { + public void makeHttpRequestsShouldHaveCorrectUri() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder - .video(Video.builder().build())))) - .build(); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); + final BidRequest bidRequest = givenBidRequest(imp -> imp.id("givenImp")); - // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()).hasSize(2); - assertThat(result.getValue().get(0)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getBanner) - .isNotNull(); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - assertThat(result.getValue().get(1)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getVideo) - .isNotNull(); + //then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(HttpRequest::getUri) + .containsExactlyInAnyOrder(ENDPOINT_URL); } @Test - public void makeHttpRequestShouldReturnSeparateResponseWithBannerAndAudioImp() { + public void makeHttpRequestsShouldReturnExpectedHeaders() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder - .audio(Audio.builder().build())))) + final BidRequest bidRequest = givenBidRequest(identity()).toBuilder() + .device(Device.builder().ip("ip").ua("ua").language("lang").build()) + .site(Site.builder().page("page").build()) .build(); // when - final Result>> result = target.makeHttpRequests(bidRequest); + final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()).hasSize(2); - assertThat(result.getValue().get(0)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getBanner) - .isNotNull(); - - assertThat(result.getValue().get(1)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getAudio) - .isNotNull(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getHeaders) + .satisfies(headers -> { + assertThat(headers.get(CONTENT_TYPE_HEADER)).isEqualTo(APPLICATION_JSON_CONTENT_TYPE); + assertThat(headers.get(ACCEPT_HEADER)).isEqualTo(APPLICATION_JSON_VALUE); + assertThat(headers.get(USER_AGENT_HEADER)).isEqualTo("ua"); + assertThat(headers.get(ACCEPT_LANGUAGE_HEADER)).isEqualTo("lang"); + assertThat(headers.get(X_FORWARDED_FOR_HEADER)).isEqualTo("ip"); + assertThat(headers.get(X_REAL_IP_HEADER)).isEqualTo("ip"); + assertThat(headers.get(REFERER_HEADER)).isEqualTo("page"); + }); + assertThat(result.getErrors()).isEmpty(); } @Test - public void makeHttpRequestShouldReturnSeparateResponseWithVideoAndAudioImp() { + public void makeHttpRequestsShouldReturnExpectedHeadersWhenDeviceAndSiteAreNotPresent() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder - .banner(null) - .video(Video.builder().build()) - .audio(Audio.builder().build())))) - .build(); + final BidRequest bidRequest = givenBidRequest(identity()); // when - final Result>> result = target.makeHttpRequests(bidRequest); + final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()).hasSize(2); - assertThat(result.getValue().get(0)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getVideo) - .isNotNull(); - - assertThat(result.getValue().get(1)) - .extracting(HttpRequest::getPayload) - .extracting(BidRequest::getImp) - .extracting(a -> a.getFirst()) - .extracting(Imp::getAudio) - .isNotNull(); + assertThat(result.getValue()).hasSize(1).first() + .extracting(HttpRequest::getHeaders) + .satisfies(headers -> { + assertThat(headers.get(CONTENT_TYPE_HEADER)).isEqualTo(APPLICATION_JSON_CONTENT_TYPE); + assertThat(headers.get(ACCEPT_HEADER)).isEqualTo(APPLICATION_JSON_VALUE); + assertThat(headers.get(USER_AGENT_HEADER)).isNull(); + assertThat(headers.get(ACCEPT_LANGUAGE_HEADER)).isNull(); + assertThat(headers.get(X_FORWARDED_FOR_HEADER)).isNull(); + assertThat(headers.get(X_REAL_IP_HEADER)).isNull(); + assertThat(headers.get(REFERER_HEADER)).isNull(); + }); + assertThat(result.getErrors()).isEmpty(); } @Test - public void makeHttpRequestShouldReturnResponseOnlyWithBannerImp() { + public void makeHttpRequestsShouldReturnBannerRequestFromBannerImp() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(identity()))) + final BidRequest bidRequest = givenBidRequest(imp -> imp + .id("impId") + .banner(Banner.builder().w(1).h(2).build())) + .toBuilder() + .id("requestId") .build(); - // when - final Result>> result = target.makeHttpRequests(bidRequest); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()) + //then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .allSatisfy(imp -> { - assertThat(imp.getBanner()).isNotNull(); - assertThat(imp.getVideo()).isNull(); - assertThat(imp.getAudio()).isNull(); - }); + .flatExtracting(ResetDigitalRequest::getImps) + .containsExactlyInAnyOrder(ResetDigitalImp.builder() + .impId("impId") + .bidId("requestId") + .zoneId(ResetDigitalImpZone.of("placementId")) + .mediaTypes(ResetDigitalImpMediaTypes.banner(ResetDigitalImpMediaType.builder() + .sizes(List.of(List.of(1, 2))) + .build())) + .build()); } @Test - public void makeHttpRequestShouldReturnResponseOnlyWithVideoImp() { + public void makeHttpRequestsShouldReturnVideoRequestFromVideoImp() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder.banner(null) - .video(Video.builder().build())))) + final BidRequest bidRequest = givenBidRequest(imp -> imp + .id("impId") + .banner(null) + .video(Video.builder().w(1).h(2).mimes(List.of("mime1", "mime2")).build())) + .toBuilder() + .id("requestId") .build(); - // when - final Result>> result = target.makeHttpRequests(bidRequest); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()) + //then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .allSatisfy(imp -> { - assertThat(imp.getBanner()).isNull(); - assertThat(imp.getVideo()).isNotNull(); - assertThat(imp.getAudio()).isNull(); - }); + .flatExtracting(ResetDigitalRequest::getImps) + .containsExactlyInAnyOrder(ResetDigitalImp.builder() + .impId("impId") + .bidId("requestId") + .zoneId(ResetDigitalImpZone.of("placementId")) + .mediaTypes(ResetDigitalImpMediaTypes.video(ResetDigitalImpMediaType.builder() + .sizes(List.of(List.of(1, 2))) + .mimes(List.of("mime1", "mime2")) + .build())) + .build()); } @Test - public void makeHttpRequestShouldReturnResponseOnlyWithAudioImp() { + public void makeHttpRequestsShouldReturnAudioRequestFromAudioImp() { // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(givenImp(impBuilder -> impBuilder.banner(null) - .audio(Audio.builder().build())))) + final BidRequest bidRequest = givenBidRequest(imp -> imp + .id("impId") + .banner(null) + .audio(Audio.builder().mimes(List.of("mime1", "mime2")).build())) + .toBuilder() + .id("requestId") .build(); - // when - final Result>> result = target.makeHttpRequests(bidRequest); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - // then - assertThat(result.getErrors()).hasSize(0); - assertThat(result.getValue()) + //then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .allSatisfy(imp -> { - assertThat(imp.getBanner()).isNull(); - assertThat(imp.getVideo()).isNull(); - assertThat(imp.getAudio()).isNotNull(); - }); + .flatExtracting(ResetDigitalRequest::getImps) + .containsExactlyInAnyOrder(ResetDigitalImp.builder() + .impId("impId") + .bidId("requestId") + .zoneId(ResetDigitalImpZone.of("placementId")) + .mediaTypes(ResetDigitalImpMediaTypes.audio(ResetDigitalImpMediaType.builder() + .mimes(List.of("mime1", "mime2")) + .build())) + .build()); } @Test - public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + public void makeHttpRequestsShouldReturnFailWhenImpIsNative() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidRequest bidRequest = givenBidRequest(imp -> imp + .id("impId") + .banner(null) + .xNative(Native.builder().build())) + .toBuilder() + .id("requestId") + .build(); - // when - final Result> result = target.makeBids(httpCall, null); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - // then - assertThat(result.getErrors()).hasSize(1) - .allSatisfy(error -> { - assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); - assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token"); - }); + //then assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1).allSatisfy(bidderError -> { + assertThat(bidderError.getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(bidderError.getMessage()).isEqualTo("Banner, video or audio must be present in the imp impId"); + }); } @Test - public void makeHttpRequestsShouldConvertCurrencyIfRequestCurrencyDoesNotMatchBidderCurrency() { + public void makeHttpRequestsShouldReturnCorrectSite() { // given - given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) - .willReturn(BigDecimal.TEN); - - final BidRequest bidRequest = givenBidRequest( - impBuilder -> impBuilder.bidfloor(BigDecimal.ONE).bidfloorcur("EUR")); + final BidRequest bidRequest = givenBidRequest(identity()) + .toBuilder() + .site(Site.builder().domain("domain").page("page").build()) + .build(); - // when - final Result>> result = target.makeHttpRequests(bidRequest); + //when + final Result>> result = target.makeHttpRequests(bidRequest); - // then + //then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) + assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .extracting(Imp::getBidfloor, Imp::getBidfloorcur) - .containsOnly(tuple(BigDecimal.TEN, "USD")); + .flatExtracting(ResetDigitalRequest::getSite) + .containsExactlyInAnyOrder(ResetDigitalSite.builder() + .referrer("page") + .domain("domain") + .build()); } @Test - public void makeHttpRequestsShouldReturnErrorMessageOnFailedCurrencyConversion() { + public void makeBidsShouldReturnErrorWhenResponseCanNotBeParsed() { // given - given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) - .willThrow(PreBidException.class); - - final BidRequest bidRequest = givenBidRequest( - impCustomizer -> impCustomizer.bidfloor(BigDecimal.ONE).bidfloorcur("EUR")); + final BidderCall httpCall = givenHttpCall("invalid"); // when - final Result>> result = target.makeHttpRequests(bidRequest); + final Result> actual = target.makeBids(httpCall, null); // then - assertThat(result.getErrors()).allSatisfy(bidderError -> { - assertThat(bidderError.getType()) - .isEqualTo(BidderError.Type.bad_input); - assertThat(bidderError.getMessage()) - .isEqualTo("Unable to convert provided bid floor currency from EUR to USD for imp `123`"); - }); + assertThat(actual.getValue()).isEmpty(); + assertThat(actual.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getMessage()).startsWith("Failed to decode: Unrecognized token 'invalid':"); + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + }); } @Test - public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { + public void makeBidsShouldReturnEmptyBidsWhenResponseDoesNotHaveBids() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(givenBidResponse()); // when - final Result> result = target.makeBids(httpCall, null); + final Result> actual = target.makeBids(httpCall, null); // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).isEmpty(); + assertThat(actual.getValue()).isEmpty(); + assertThat(actual.getErrors()) + .containsOnly(BidderError.badServerResponse("expected exactly one bid in the response, but got 0")); } @Test - public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { + public void makeBidsShouldReturnEmptyBidsWhenResponseHasMoreThanOneBid() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, - mapper.writeValueAsString(BidResponse.builder().build())); + final BidderCall httpCall = givenHttpCall(givenBidResponse(identity(), identity())); // when - final Result> result = target.makeBids(httpCall, null); + final Result> actual = target.makeBids(httpCall, null); // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).isEmpty(); + assertThat(actual.getValue()).isEmpty(); + assertThat(actual.getErrors()) + .containsOnly(BidderError.badServerResponse("expected exactly one bid in the response, but got 2")); } @Test - public void makeBidsShouldReturnBannerBidIfBannerIsPresentInRequestImp() throws JsonProcessingException { - // given - final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build())) - .build(), - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + public void makeBidsShouldReturnEmptyBidsWhenResponseDoesNotHaveBidThatMatchesAnyImp() + throws JsonProcessingException { - // when - final Result> result = target.makeBids(httpCall, null); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), banner, "USD")); - } - - @Test - public void makeBidsShouldReturnVideoBidIfVideoIsPresentInRequestImp() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").video(Video.builder().build()).build())) - .build(), - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid.impId("impId1"))); // when - final Result> result = target.makeBids(httpCall, null); + final Result> actual = target.makeBids(httpCall, givenBidRequest(imp -> imp.id("impId2"))); // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), video, "USD")); + assertThat(actual.getValue()).isEmpty(); + assertThat(actual.getErrors()) + .containsOnly(BidderError.badServerResponse("no matching impression found for ImpID impId1")); } @Test - public void makeBidsShouldReturnAudioBidIfAudioIsPresentInRequestImp() throws JsonProcessingException { + public void makeBidsShouldReturnBannerBidSuccessfully() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").audio(Audio.builder().build()).build())) - .build(), - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid + .cpm(BigDecimal.TEN) + .cid("cid") + .html("html") + .crid("crid") + .seat("seat") + .impId("impId") + .bidId("bidId") + .w("1") + .h("2"))); // when - final Result> result = target.makeBids(httpCall, null); + final Result> result = target.makeBids( + httpCall, + givenBidRequest(imp -> imp.id("impId").banner(Banner.builder().build()))); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), audio, "USD")); + final Bid expectedBid = Bid.builder() + .adm("html") + .price(BigDecimal.TEN) + .cid("cid") + .w(1) + .h(2) + .impid("impId") + .id("bidId") + .crid("crid") + .build(); + assertThat(result.getValue()).containsExactly(BidderBid.of(expectedBid, banner, "seat", "USD")); } @Test - public void makeBidsShouldReturnErrorBidIfBidTypeIsAbsentInRequestImp() throws JsonProcessingException { + public void makeBidsShouldReturnVideoBidSuccessfully() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").build())) - .build(), - mapper.writeValueAsString( - givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid + .cpm(BigDecimal.TEN) + .cid("cid") + .html("html") + .crid("crid") + .seat("seat") + .impId("impId") + .bidId("bidId") + .w("1") + .h("2"))); // when - final Result> result = target.makeBids(httpCall, null); + final Result> result = target.makeBids( + httpCall, + givenBidRequest(imp -> imp.id("impId").video(Video.builder().build()))); // then - assertThat(result.getErrors()).hasSize(1) - .extracting(BidderError::getMessage) - .containsExactly("Failed to find banner/video/audio impression 123"); - assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).isEmpty(); + final Bid expectedBid = Bid.builder() + .adm("html") + .price(BigDecimal.TEN) + .cid("cid") + .w(1) + .h(2) + .impid("impId") + .id("bidId") + .crid("crid") + .build(); + assertThat(result.getValue()).containsExactly(BidderBid.of(expectedBid, video, "seat", "USD")); } @Test - public void makeBidsShouldReturnErrorIfBidCurIsNotUsd() throws JsonProcessingException { + public void makeBidsShouldReturnAudioBidSuccessfully() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - BidRequest.builder() - .imp(singletonList(Imp.builder().id("123").build())) - .build(), - mapper.writeValueAsString(givenBidResponse(identity()).toBuilder().cur("EUR").build())); + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid -> bid + .cpm(BigDecimal.TEN) + .cid("cid") + .html("html") + .crid("crid") + .seat("seat") + .impId("impId") + .bidId("bidId") + .w("1") + .h("2"))); // when - final Result> result = target.makeBids(httpCall, null); + final Result> result = target.makeBids( + httpCall, + givenBidRequest(imp -> imp.id("impId").audio(Audio.builder().build()))); // then - assertThat(result.getErrors()).hasSize(1) - .extracting(BidderError::getMessage) - .containsExactly("Bidder support only USD currency"); - assertThat(result.getValue()).isEmpty(); - } - - private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, - UnaryOperator impCustomizer) { - - return bidRequestCustomizer.apply(BidRequest.builder() - .imp(singletonList(givenImp(impCustomizer)))) + assertThat(result.getErrors()).isEmpty(); + final Bid expectedBid = Bid.builder() + .adm("html") + .price(BigDecimal.TEN) + .cid("cid") + .w(1) + .h(2) + .impid("impId") + .id("bidId") + .crid("crid") .build(); + assertThat(result.getValue()).containsExactly(BidderBid.of(expectedBid, audio, "seat", "USD")); } - private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { - return givenBidRequest(identity(), impCustomizer); + private static BidRequest givenBidRequest(UnaryOperator... impCustomizers) { + return BidRequest.builder() + .imp(Stream.of(impCustomizers).map(ResetDigitalBidderTest::givenImp).toList()) + .build(); } private static Imp givenImp(UnaryOperator impCustomizer) { return impCustomizer.apply(Imp.builder() - .id("123") - .banner(Banner.builder().w(23).h(25).build())) + .id("impId") + .banner(Banner.builder().w(23).h(25).build()) + .ext(mapper.valueToTree(ExtPrebid.of( + null, + ExtImpResetDigital.of("placementId"))))) .build(); } - private static BidResponse givenBidResponse(UnaryOperator bidCustomizer) { - return BidResponse.builder() - .seatbid(singletonList(SeatBid.builder().bid(singletonList(bidCustomizer.apply(Bid.builder()).build())) - .build())) - .cur("USD") - .build(); - } - - private static BidderCall givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(String body) { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), + HttpRequest.builder().payload(null).build(), HttpResponse.of(200, null, body), null); } + + private String givenBidResponse(UnaryOperator... bidCustomizers) + throws JsonProcessingException { + + return mapper.writeValueAsString(ResetDigitalResponse.of( + Stream.of(bidCustomizers) + .map(bidCustomizer -> bidCustomizer.apply(ResetDigitalBid.builder()).build()) + .toList())); + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-request.json b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-request.json index 9ee75999128..9fffce432ec 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-request.json @@ -1,20 +1,31 @@ { - "id": "request_id", + "id": "12345", "imp": [ { - "id": "imp_id", + "id": "001", "banner": { - "w": 300, - "h": 250 + "h": 300, + "w": 250 }, "ext": { "resetdigital": { - "pubId": "lb.ads", - "zoneId": "publisherTestID" + "placement_id": "placement-id-1" } } } ], + "site": { + "domain": "https://test.com", + "page": "https://test.com/2016/06/12" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1", + "language": "EN" + }, "tmax": 5000, "regs": { "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-response.json b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-response.json index 556bc6d3217..53308c326ee 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-auction-resetdigital-response.json @@ -1,19 +1,18 @@ { - "id": "request_id", + "id": "12345", "seatbid": [ { "bid": [ { - "id": "bid_id", - "impid": "imp_id", - "exp": 300, - "price": 3.33, - "adm": "adm001", - "adid": "adid001", - "cid": "cid001", - "crid": "crid001", + "adm": "test markup", + "cid": "1002088", + "crid": "1000763-1002088", + "id": "01", + "impid": "001", + "price": 1.00, "w": 300, "h": 250, + "exp": 300, "ext": { "prebid": { "type": "banner", @@ -21,7 +20,7 @@ "adaptercode": "resetdigital" } }, - "origbidcpm": 3.33, + "origbidcpm": 1.00, "origbidcur": "USD" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-request.json index 43d9d50841b..3b12e3d3c8a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-request.json @@ -1,57 +1,25 @@ { - "id": "request_id", - "imp": [ + "imps": [ { - "id": "imp_id", - "secure": 1, - "banner": { - "w": 300, - "h": 250 - }, - "ext": { - "tid": "${json-unit.any-string}", - "bidder": { - "pubId": "lb.ads", - "zoneId": "publisherTestID" + "bid_id": "12345", + "imp_id": "001", + "media_types": { + "banner": { + "sizes": [ + [ + 250, + 300 + ] + ] } + }, + "zone_id": { + "placementId": "placement-id-1" } } ], - "source": { - "tid": "${json-unit.any-string}" - }, "site": { - "domain": "www.example.com", - "page": "http://www.example.com", - "publisher": { - "domain": "example.com" - }, - "ext": { - "amp": 0 - } - }, - "device": { - "ua": "userAgent", - "ip": "193.168.244.1" - }, - "at": 1, - "tmax": "${json-unit.any-number}", - "cur": [ - "USD" - ], - "regs": { - "ext": { - "gdpr": 0 - } - }, - "ext": { - "prebid": { - "server": { - "externalurl": "http://localhost:8080", - "gvlid": 1, - "datacenter": "local", - "endpoint": "/openrtb2/auction" - } - } + "domain": "https://test.com", + "referrer": "https://test.com/2016/06/12" } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-response.json index 631464ca55d..3397880777f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/resetdigital/test-resetdigital-bid-response.json @@ -1,21 +1,16 @@ { - "id": "request_id", - "seatbid": [ + "bids": [ { - "bid": [ - { - "id": "bid_id", - "impid": "imp_id", - "price": 3.33, - "adid": "adid001", - "crid": "crid001", - "cid": "cid001", - "adm": "adm001", - "h": 250, - "w": 300 - } - ] + "bid_id": "01", + "imp_id": "001", + "cpm": 1.00, + "cid": "1002088", + "crid": "1000763-1002088", + "adid": "1002088", + "w": "300", + "h": "250", + "seat": "resetdigital", + "html": "test markup" } - ], - "cur": "USD" + ] } From 5877f038cc44f4cc4da1a80a6b1e72d0f5ce9173 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Thu, 20 Mar 2025 15:34:04 +0100 Subject: [PATCH 2/2] Fix comments --- .../resetdigital/ResetDigitalBidder.java | 72 ++++++++++--------- .../request/ResetDigitalImpMediaType.java | 2 - .../request/ResetDigitalImpMediaTypes.java | 2 +- .../request/ResetDigitalRequest.java | 4 +- .../request/ResetDigitalSite.java | 4 +- .../response/ResetDigitalBid.java | 2 +- .../resetdigital/ResetDigitalBidderTest.java | 36 ++++------ 7 files changed, 58 insertions(+), 64 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java b/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java index 8604a2f8a80..5d292f9a093 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidder.java @@ -31,6 +31,7 @@ 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.ImpMediaType; import org.prebid.server.proto.openrtb.ext.request.resetdigital.ExtImpResetDigital; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; @@ -39,6 +40,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; public class ResetDigitalBidder implements Bidder { @@ -87,27 +89,34 @@ private static ResetDigitalImp makeImp(BidRequest request, Imp imp, ExtImpResetD .bidId(request.getId()) .impId(imp.getId()) .mediaTypes(resolveMediaTypes(imp)) - .zoneId(extImp.getPlacementId() == null ? null : ResetDigitalImpZone.of(extImp.getPlacementId())) + .zoneId(Optional.ofNullable(extImp.getPlacementId()) + .map(ResetDigitalImpZone::of) + .orElse(null)) .build(); } private static ResetDigitalImpMediaTypes resolveMediaTypes(Imp imp) { - final Banner banner = imp.getBanner(); - final Video video = imp.getVideo(); - final Audio audio = imp.getAudio(); - - if (banner != null) { - final ResetDigitalImpMediaType mediaType = makeBanner(banner); - return mediaType == null ? null : ResetDigitalImpMediaTypes.banner(mediaType); - } else if (video != null) { - final ResetDigitalImpMediaType mediaType = makeVideo(video); - return mediaType == null ? null : ResetDigitalImpMediaTypes.video(mediaType); - } else if (audio != null) { - final ResetDigitalImpMediaType mediaType = makeAudio(audio); - return mediaType == null ? null : ResetDigitalImpMediaTypes.audio(mediaType); - } else { - throw new PreBidException("Banner, video or audio must be present in the imp %s".formatted(imp.getId())); + return switch (mediaType(imp)) { + case banner -> ResetDigitalImpMediaTypes.banner(makeBanner(imp.getBanner())); + case video -> ResetDigitalImpMediaTypes.video(makeVideo(imp.getVideo())); + case audio -> ResetDigitalImpMediaTypes.audio(makeAudio(imp.getAudio())); + case null, default -> throw new PreBidException( + "Banner, video or audio must be present in the imp %s".formatted(imp.getId())); + }; + } + + private static ImpMediaType mediaType(Imp imp) { + if (imp.getBanner() != null) { + return ImpMediaType.banner; } + if (imp.getVideo() != null) { + return ImpMediaType.video; + } + if (imp.getAudio() != null) { + return ImpMediaType.audio; + } + + return null; } private static ResetDigitalImpMediaType makeBanner(Banner banner) { @@ -130,10 +139,9 @@ private static ResetDigitalImpMediaType makeMediaType(Integer width, Integer hei return null; } - return ResetDigitalImpMediaType.builder() - .sizes(hasValidSizes ? List.of(List.of(width, height)) : null) - .mimes(hasMimes ? mimes : null) - .build(); + return ResetDigitalImpMediaType.of( + hasValidSizes ? List.of(List.of(width, height)) : null, + hasMimes ? mimes : null); } private static boolean isValidSizeValue(Integer value) { @@ -154,19 +162,16 @@ private HttpRequest makeHttpRequest(BidRequest request, Res } private static ResetDigitalRequest makeRequest(BidRequest request, ResetDigitalImp resetDigitalImp) { - return ResetDigitalRequest.builder() - .site(makeSite(request.getSite())) - .imps(Collections.singletonList(resetDigitalImp)) - .build(); + return ResetDigitalRequest.of(makeSite(request.getSite()), Collections.singletonList(resetDigitalImp)); } private static ResetDigitalSite makeSite(Site site) { - return site == null || ObjectUtils.allNull(site.getDomain(), site.getPage()) - ? null - : ResetDigitalSite.builder() - .domain(site.getDomain()) - .referrer(site.getPage()) - .build(); + final String domain = site != null ? site.getDomain() : null; + final String page = site != null ? site.getPage() : null; + + return ObjectUtils.anyNotNull(domain, page) + ? ResetDigitalSite.of(domain, page) + : null; } private static MultiMap makeHeaders(BidRequest request) { @@ -240,10 +245,11 @@ private static Bid makeBid(ResetDigitalBid bid) { private static BidType resolveBidType(Imp imp) throws PreBidException { if (imp.getVideo() != null) { return BidType.video; - } else if (imp.getAudio() != null) { + } + if (imp.getAudio() != null) { return BidType.audio; - } else { - return BidType.banner; } + + return BidType.banner; } } diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java index 5ee15918c38..cd678266463 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaType.java @@ -1,12 +1,10 @@ package org.prebid.server.bidder.resetdigital.request; -import lombok.Builder; import lombok.Value; import java.util.List; @Value(staticConstructor = "of") -@Builder public class ResetDigitalImpMediaType { List> sizes; diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java index 7483f318e0e..45d714a530b 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalImpMediaTypes.java @@ -3,7 +3,7 @@ import lombok.Builder; import lombok.Value; -@Value(staticConstructor = "of") +@Value @Builder public class ResetDigitalImpMediaTypes { diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java index 8294ec1a469..bfce161aafa 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalRequest.java @@ -1,12 +1,10 @@ package org.prebid.server.bidder.resetdigital.request; -import lombok.Builder; import lombok.Value; import java.util.List; -@Value -@Builder +@Value(staticConstructor = "of") public class ResetDigitalRequest { ResetDigitalSite site; diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java index 77962b232b2..f52e5f1d12d 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/request/ResetDigitalSite.java @@ -1,10 +1,8 @@ package org.prebid.server.bidder.resetdigital.request; -import lombok.Builder; import lombok.Value; -@Value -@Builder +@Value(staticConstructor = "of") public class ResetDigitalSite { String domain; diff --git a/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java b/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java index fead0572112..d4ea28b47c2 100644 --- a/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java +++ b/src/main/java/org/prebid/server/bidder/resetdigital/response/ResetDigitalBid.java @@ -5,7 +5,7 @@ import java.math.BigDecimal; -@Value(staticConstructor = "of") +@Value @Builder public class ResetDigitalBid { diff --git a/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java b/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java index 9bd1656433e..ba59b996b9a 100644 --- a/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/resetdigital/ResetDigitalBidderTest.java @@ -103,11 +103,11 @@ public void makeHttpRequestsShouldMakeOneRequestPerImp() { .extracting(HttpRequest::getPayload) .flatExtracting(ResetDigitalRequest::getImps) .extracting(ResetDigitalImp::getImpId) - .containsExactlyInAnyOrder("givenImp1", "givenImp2", "givenImp3"); + .containsOnly("givenImp1", "givenImp2", "givenImp3"); assertThat(result.getValue()).hasSize(3) .extracting(HttpRequest::getImpIds) - .containsExactlyInAnyOrder(Set.of("givenImp1"), Set.of("givenImp2"), Set.of("givenImp3")); + .containsOnly(Set.of("givenImp1"), Set.of("givenImp2"), Set.of("givenImp3")); } @Test @@ -122,7 +122,7 @@ public void makeHttpRequestsShouldHaveCorrectUri() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) - .containsExactlyInAnyOrder(ENDPOINT_URL); + .containsOnly(ENDPOINT_URL); } @Test @@ -192,13 +192,12 @@ public void makeHttpRequestsShouldReturnBannerRequestFromBannerImp() { assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) .flatExtracting(ResetDigitalRequest::getImps) - .containsExactlyInAnyOrder(ResetDigitalImp.builder() + .containsOnly(ResetDigitalImp.builder() .impId("impId") .bidId("requestId") .zoneId(ResetDigitalImpZone.of("placementId")) - .mediaTypes(ResetDigitalImpMediaTypes.banner(ResetDigitalImpMediaType.builder() - .sizes(List.of(List.of(1, 2))) - .build())) + .mediaTypes(ResetDigitalImpMediaTypes.banner( + ResetDigitalImpMediaType.of(List.of(List.of(1, 2)), null))) .build()); } @@ -221,14 +220,13 @@ public void makeHttpRequestsShouldReturnVideoRequestFromVideoImp() { assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) .flatExtracting(ResetDigitalRequest::getImps) - .containsExactlyInAnyOrder(ResetDigitalImp.builder() + .containsOnly(ResetDigitalImp.builder() .impId("impId") .bidId("requestId") .zoneId(ResetDigitalImpZone.of("placementId")) - .mediaTypes(ResetDigitalImpMediaTypes.video(ResetDigitalImpMediaType.builder() - .sizes(List.of(List.of(1, 2))) - .mimes(List.of("mime1", "mime2")) - .build())) + .mediaTypes(ResetDigitalImpMediaTypes.video(ResetDigitalImpMediaType.of( + List.of(List.of(1, 2)), + List.of("mime1", "mime2")))) .build()); } @@ -251,18 +249,17 @@ public void makeHttpRequestsShouldReturnAudioRequestFromAudioImp() { assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) .flatExtracting(ResetDigitalRequest::getImps) - .containsExactlyInAnyOrder(ResetDigitalImp.builder() + .containsOnly(ResetDigitalImp.builder() .impId("impId") .bidId("requestId") .zoneId(ResetDigitalImpZone.of("placementId")) - .mediaTypes(ResetDigitalImpMediaTypes.audio(ResetDigitalImpMediaType.builder() - .mimes(List.of("mime1", "mime2")) - .build())) + .mediaTypes(ResetDigitalImpMediaTypes.audio( + ResetDigitalImpMediaType.of(null, List.of("mime1", "mime2")))) .build()); } @Test - public void makeHttpRequestsShouldReturnFailWhenImpIsNative() { + public void makeHttpRequestsShouldFailWhenImpIsNative() { // given final BidRequest bidRequest = givenBidRequest(imp -> imp .id("impId") @@ -299,10 +296,7 @@ public void makeHttpRequestsShouldReturnCorrectSite() { assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getPayload) .flatExtracting(ResetDigitalRequest::getSite) - .containsExactlyInAnyOrder(ResetDigitalSite.builder() - .referrer("page") - .domain("domain") - .build()); + .containsOnly(ResetDigitalSite.of("domain", "page")); } @Test