From 38abb6789f0245fe5822101d4c5dcc6ec5e7286d Mon Sep 17 00:00:00 2001 From: katherynhrabik Date: Thu, 13 Feb 2025 15:49:11 -0500 Subject: [PATCH 01/10] connatix updates thus far --- .../bidder/connatix/ConnatixBidder.java | 211 ++++++++++++++++++ .../connatix/proto/ConnatixImpExtBidder.java | 20 ++ .../ext/request/connatix/ExtImpConnatix.java | 15 ++ .../config/bidder/ConnatixConfiguration.java | 38 ++++ .../resources/bidder-config/connatix.yaml | 25 +++ .../static/bidder-params/connatix.json | 21 ++ 6 files changed, 330 insertions(+) create mode 100644 src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java create mode 100644 src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java create mode 100644 src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java create mode 100644 src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java create mode 100644 src/main/resources/bidder-config/connatix.yaml create mode 100644 src/main/resources/static/bidder-params/connatix.json diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java new file mode 100644 index 00000000000..dc5de0f5f21 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -0,0 +1,211 @@ +package org.prebid.server.bidder.connatix; + +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.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +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.connatix.proto.ConnatixImpExtBidder; +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.Result; +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.connatix.ExtImpConnatix; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.HttpUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +public class ConnatixBidder implements Bidder { + + private static final TypeReference> CONNATIX_EXT_TYPE_REFERENCE = new TypeReference<>() { + }; + + private static final int MAX_IMPS_PER_REQUEST = 1; + + private final String endpointUrl; + private final JacksonMapper mapper; + + private static final String PREBID_KEY = "prebid"; + private static final String SOURCE_PROPERTY = "source"; + private static final String VERSION_PROPERTY = "version"; + + public ConnatixBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + // Device IP required - bounce if not available + if (request.getDevice() == null || + (request.getDevice().getIp() == null && request.getDevice().getIpv6() == null)) { + return Result.withError(BidderError.badInput("Device IP is required")); + } + + // KATIE TO DO. UPDATE THIS LOGIC TO PAY ATTENTION TO display manager. + // display manager version can come from openrtb2 request OR imp.ext.prebid + String displayManagerVer = buildDisplayManagerVersion(request); + + final List> httpRequests = new ArrayList<>(); + + for (Imp imp : request.getImp()) { + final ExtImpConnatix extImpConnatix; + try { + extImpConnatix = parseExtImp(imp); + } catch (PreBidException e) { + return Result.withError(BidderError.badInput(e.getMessage())); + } + // KATIE to do - probably need to add logic for splitting requests somewhere in here + + final Imp modifiedImp = modifyImp(imp, extImpConnatix); + httpRequests.add(makeHttpRequest(request, modifiedImp)); + } + + return Result.withValues(httpRequests); + + } + + private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix) { + //KATIE to do - fix this method, it isn't right :) + final ConnatixImpExtBidder impExtBidder = resolveImpExt(extImpConnatix); + + final ObjectNode impExtBidderNode = mapper.mapper().valueToTree(impExtBidder); + + final ObjectNode modifiedImpExtBidder = imp.getExt() != null ? imp.getExt().deepCopy() : mapper.mapper().createObjectNode(); + + modifiedImpExtBidder.setAll(impExtBidderNode); + + return imp.toBuilder().ext(modifiedImpExtBidder).build(); + } + + @Override + public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { + try { + final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + // KATIE check validity of this logic for setting currency to usd. explicitly set to USD in go version + final BidResponse updatedResponse = bidResponse.toBuilder().cur("USD").build(); + final List bids = extractBids(httpCall.getRequest().getPayload(), updatedResponse); + return Result.withValues(bids); + } catch (DecodeException | PreBidException e) { + return Result.withError(BidderError.badServerResponse(e.getMessage())); + } + } + + // extract bids + private static List extractBids(BidRequest bidRequest, BidResponse bidResponse) { + if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { + return Collections.emptyList(); + } + + 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.getImpid(), bidRequest.getImp()), bidResponse.getCur())) + .toList(); + } + + + // parseExtImp + private ExtImpConnatix parseExtImp(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), CONNATIX_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage()); + } + } + + private ConnatixImpExtBidder resolveImpExt(ExtImpConnatix extImpConnatix) { + + final ConnatixImpExtBidder.ConnatixImpExtBidderBuilder builder = ConnatixImpExtBidder.builder(); + // KATIE check this is correct - adding placement ID and viewability percentage if available + if (StringUtils.isNotEmpty(extImpConnatix.getPlacementId())) { + builder.placementId(extImpConnatix.getPlacementId()); + } + if (extImpConnatix.getViewabilityPercentage() != null) { + builder.viewabilityPercentage(extImpConnatix.getViewabilityPercentage()); + } + + return builder.build(); + } + + private HttpRequest makeHttpRequest(BidRequest request, Imp imp) { + final BidRequest outgoingRequest = request.toBuilder().imp(List.of(imp)).build(); + + return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper); + } + + + private HttpRequest createHttpRequest(BidRequest bidRequest, List imps, String url) { + return BidderUtil.defaultRequest(bidRequest.toBuilder().imp(imps).build(), url, mapper); + } + + + private List> splitHttpRequests(BidRequest bidRequest, + List imps, + String url) { + + // KATIE TO DO: this is how we've done it elsewhere but go version has logic that + // explicitly modifies headers here - need to figure out what that's about + return ListUtils.partition(imps, MAX_IMPS_PER_REQUEST) + .stream() + .map(impsChunk -> createHttpRequest(bidRequest, impsChunk, url)) + .toList(); + } + + + // check display manager version + private String buildDisplayManagerVersion(BidRequest request) { + if (request.getApp() == null || request.getApp().getExt() == null) { + return ""; + } + + try { + JsonNode extNode = mapper.mapper().readTree(String.valueOf(request.getApp().getExt())); + JsonNode prebidNode = extNode.path(PREBID_KEY); + + String source = prebidNode.path(SOURCE_PROPERTY).asText(""); + String version = prebidNode.path(VERSION_PROPERTY).asText(""); + + return (StringUtils.isNotEmpty(source) && StringUtils.isNotEmpty(version)) + ? source + "-" + version + : ""; + + } catch (Exception e) { + return ""; + } + } + + private static BidType getBidType(String impId, List imps) { + for (Imp imp : imps) { + if (imp.getId().equals(impId)) { + // KATIE TO DO - this is how go version gets mediaType - validate this + String mediaType = imp.getExt().get("cnx").get("mediaType").asText(); + if (mediaType.equals("video")) { + return BidType.video; + } return BidType.banner; + } + break; + } + throw new PreBidException(String.format("Failed to find impression for ID: '%s'", impId)); + } +} diff --git a/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java b/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java new file mode 100644 index 00000000000..9ffb8517974 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java @@ -0,0 +1,20 @@ +package org.prebid.server.bidder.connatix.proto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; +import lombok.Value; + +@Builder +@Value +public class ConnatixImpExtBidder { + + String type; + + @JsonProperty(value = "placementId") + String placementId; + + // KATIE: viewability percentage, viewability container, and bidfloor are all optional. should they be included? + @JsonProperty(value = "viewabilityPercentage") + Float viewabilityPercentage; + +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java new file mode 100644 index 00000000000..32ed405e2ca --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java @@ -0,0 +1,15 @@ +package org.prebid.server.proto.openrtb.ext.request.connatix; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Value; + +@Value(staticConstructor = "of") +public class ExtImpConnatix { + + @JsonProperty("placementId") + String placementId; + + @JsonProperty("viewabilityPercentage") + Float viewabilityPercentage; + +} diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java new file mode 100644 index 00000000000..7f374a5f781 --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java @@ -0,0 +1,38 @@ +package org.prebid.server.spring.config.bidder; + +import jakarta.validation.constraints.NotBlank; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.connatix.ConnatixBidder; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.spring.config.bidder.model.BidderConfigurationProperties; +import org.prebid.server.spring.config.bidder.util.BidderDepsAssembler; +import org.prebid.server.spring.config.bidder.util.UsersyncerCreator; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/connatix.yaml", factory = YamlPropertySourceFactory.class) +public class ConnatixConfiguration { + + private static final String BIDDER_NAME = "connatix"; + + @Bean("connatixConfigurationProperties") + @ConfigurationProperties("adapters.connatix") + BidderConfigurationProperties configurationProperties() { return new BidderConfigurationProperties(); } + + @Bean + BidderDeps connatixBidderDeps(BidderConfigurationProperties connatixConfigurationProperties, + @NotBlank @Value("http://localhost:8080") String externalUrl, JacksonMapper mapper) { + + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(connatixConfigurationProperties) + .usersyncerCreator(UsersyncerCreator.create(externalUrl)) + .bidderCreator(config -> new ConnatixBidder(config.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/resources/bidder-config/connatix.yaml b/src/main/resources/bidder-config/connatix.yaml new file mode 100644 index 00000000000..8ae912dc419 --- /dev/null +++ b/src/main/resources/bidder-config/connatix.yaml @@ -0,0 +1,25 @@ +adapters: + connatix: + endpoint: "https://capi.connatix.com/rtb/ortb" + ortb: + multiformat-supported: false + meta-info: + maintainer-email: "pubsolutions@connatix.com" + vendor-id: 143 + app-media-types: + - banner + - video + site-media-types: + - banner + - video + usersync: + cookie-family-name: connatix + iframe: + url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + uid-macro: '$UID' + supportCors: false + redirect: + url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + uid-macro: '$UID' + supportCors: false + diff --git a/src/main/resources/static/bidder-params/connatix.json b/src/main/resources/static/bidder-params/connatix.json new file mode 100644 index 00000000000..865d38586c7 --- /dev/null +++ b/src/main/resources/static/bidder-params/connatix.json @@ -0,0 +1,21 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Connatix Adapter Params", + "description": "A schema which validates params accepted by the Connatix adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1, + "description": "Placement ID" + } + }, + "viewabilityPercentage": { + "type": "number", + "description": "Declared viewability percentage (values from 0 to 1, where 1 = 100%)", + "minimum": 0, + "maximum": 1 + }, + "required": ["placementId"] +} + From ff9a8d98849250f19bfa2ad28017595e3ae4d43c Mon Sep 17 00:00:00 2001 From: kim-ng93 <76963037+kim-ng93@users.noreply.github.com> Date: Tue, 18 Feb 2025 09:46:18 -0800 Subject: [PATCH 02/10] stylecheck and adding logic --- .../bidder/connatix/ConnatixBidder.java | 162 +++++++++++++----- .../config/bidder/ConnatixConfiguration.java | 15 +- .../resources/bidder-config/connatix.yaml | 4 +- .../static/bidder-params/connatix.json | 12 +- 4 files changed, 139 insertions(+), 54 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index dc5de0f5f21..4bea3be1e2c 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -1,14 +1,19 @@ package org.prebid.server.bidder.connatix; 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.App; +import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Format; import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; +import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.connatix.proto.ConnatixImpExtBidder; @@ -16,52 +21,66 @@ 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.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.ExtApp; +import org.prebid.server.proto.openrtb.ext.request.ExtAppPrebid; import org.prebid.server.proto.openrtb.ext.request.connatix.ExtImpConnatix; 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.Optional; public class ConnatixBidder implements Bidder { - private static final TypeReference> CONNATIX_EXT_TYPE_REFERENCE = new TypeReference<>() { - }; + private static final TypeReference> CONNATIX_EXT_TYPE_REFERENCE = + new TypeReference<>() { + }; private static final int MAX_IMPS_PER_REQUEST = 1; private final String endpointUrl; private final JacksonMapper mapper; - private static final String PREBID_KEY = "prebid"; - private static final String SOURCE_PROPERTY = "source"; - private static final String VERSION_PROPERTY = "version"; + // private static final String PREBID_KEY = "prebid"; + // private static final String SOURCE_PROPERTY = "source"; + // private static final String VERSION_PROPERTY = "version"; + private static final String BIDDER_CURRENCY = "USD"; - public ConnatixBidder(String endpointUrl, JacksonMapper mapper) { + private final CurrencyConversionService currencyConversionService; + + public ConnatixBidder(String endpointUrl, + CurrencyConversionService currencyConversionService, + JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.currencyConversionService = currencyConversionService; this.mapper = Objects.requireNonNull(mapper); } @Override public Result>> makeHttpRequests(BidRequest request) { // Device IP required - bounce if not available - if (request.getDevice() == null || - (request.getDevice().getIp() == null && request.getDevice().getIpv6() == null)) { + if (request.getDevice() == null + || (request.getDevice().getIp() == null && request.getDevice().getIpv6() == null)) { return Result.withError(BidderError.badInput("Device IP is required")); } // KATIE TO DO. UPDATE THIS LOGIC TO PAY ATTENTION TO display manager. // display manager version can come from openrtb2 request OR imp.ext.prebid - String displayManagerVer = buildDisplayManagerVersion(request); + // KIM: i updated the logic to do the same as Appnexus which seems to match? maybe + final String displayManagerVer = buildDisplayManagerVersion(request); final List> httpRequests = new ArrayList<>(); @@ -73,8 +92,9 @@ public Result>> makeHttpRequests(BidRequest request return Result.withError(BidderError.badInput(e.getMessage())); } // KATIE to do - probably need to add logic for splitting requests somewhere in here + final Price bidFloorPrice = convertBidFloor(imp, request); - final Imp modifiedImp = modifyImp(imp, extImpConnatix); + final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, bidFloorPrice); httpRequests.add(makeHttpRequest(request, modifiedImp)); } @@ -82,17 +102,40 @@ public Result>> makeHttpRequests(BidRequest request } - private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix) { + private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayManagerVer, Price bidFloorPrice) { //KATIE to do - fix this method, it isn't right :) + // KIM: added these thingies to the method - modified banner, display manager, modified bid floor and currency final ConnatixImpExtBidder impExtBidder = resolveImpExt(extImpConnatix); final ObjectNode impExtBidderNode = mapper.mapper().valueToTree(impExtBidder); - final ObjectNode modifiedImpExtBidder = imp.getExt() != null ? imp.getExt().deepCopy() : mapper.mapper().createObjectNode(); + final ObjectNode modifiedImpExtBidder = imp.getExt() != null ? imp.getExt().deepCopy() + : mapper.mapper().createObjectNode(); modifiedImpExtBidder.setAll(impExtBidderNode); - return imp.toBuilder().ext(modifiedImpExtBidder).build(); + return imp.toBuilder() + .ext(modifiedImpExtBidder) + .banner(modifyImpBanner(imp.getBanner())) + .displaymanagerver(displayManagerVer) + .bidfloor(bidFloorPrice.getValue()) + .bidfloorcur(bidFloorPrice.getCurrency()) + .build(); + } + + private Banner modifyImpBanner(Banner banner) { + if (banner == null) { + return null; + } + + if (banner.getW() == null && banner.getH() == null && !CollectionUtils.isEmpty(banner.getFormat())) { + final Format firstFormat = banner.getFormat().getFirst(); + return banner.toBuilder() + .w(firstFormat.getW()) + .h(firstFormat.getH()) + .build(); + } + return banner; } @Override @@ -108,6 +151,21 @@ public Result> makeBids(BidderCall httpCall, BidRequ } } + private Price convertBidFloor(Imp imp, BidRequest bidRequest) { + final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); + if (BidderUtil.isValidPrice(initialBidFloorPrice)) { + try { + final BigDecimal convertedPrice = currencyConversionService + .convertCurrency(imp.getBidfloor(), bidRequest, imp.getBidfloorcur(), BIDDER_CURRENCY); + return Price.of(BIDDER_CURRENCY, convertedPrice); + } catch (PreBidException e) { + throw new PreBidException("Unable to convert provided bid floor currency from %s to %s for imp `%s`" + .formatted(imp.getBidfloorcur(), BIDDER_CURRENCY, imp.getId())); + } + } + return initialBidFloorPrice; + } + // extract bids private static List extractBids(BidRequest bidRequest, BidResponse bidResponse) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { @@ -124,7 +182,6 @@ private static List extractBids(BidRequest bidRequest, BidResponse bi .toList(); } - // parseExtImp private ExtImpConnatix parseExtImp(Imp imp) { try { @@ -154,55 +211,78 @@ private HttpRequest makeHttpRequest(BidRequest request, Imp imp) { return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper); } - - private HttpRequest createHttpRequest(BidRequest bidRequest, List imps, String url) { - return BidderUtil.defaultRequest(bidRequest.toBuilder().imp(imps).build(), url, mapper); + private HttpRequest createHttpRequest(BidRequest bidRequest, + List imps, + String url, + MultiMap headers) { + return BidderUtil.defaultRequest(bidRequest.toBuilder().imp(imps).build(), headers, url, mapper); } - private List> splitHttpRequests(BidRequest bidRequest, List imps, String url) { - + final MultiMap httpHeaders = resolveHeaders(bidRequest.getDevice()); // KATIE TO DO: this is how we've done it elsewhere but go version has logic that // explicitly modifies headers here - need to figure out what that's about + // KIM: added the headers - seems like the same logic as AcuityadsBidder return ListUtils.partition(imps, MAX_IMPS_PER_REQUEST) .stream() - .map(impsChunk -> createHttpRequest(bidRequest, impsChunk, url)) + .map(impsChunk -> createHttpRequest(bidRequest, impsChunk, url, httpHeaders)) .toList(); } + private MultiMap resolveHeaders(Device device) { + final MultiMap headers = HttpUtil.headers(); + if (device != null) { + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, device.getUa()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIpv6()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIp()); + } + return headers; + } // check display manager version private String buildDisplayManagerVersion(BidRequest request) { - if (request.getApp() == null || request.getApp().getExt() == null) { - return ""; - } - - try { - JsonNode extNode = mapper.mapper().readTree(String.valueOf(request.getApp().getExt())); - JsonNode prebidNode = extNode.path(PREBID_KEY); - - String source = prebidNode.path(SOURCE_PROPERTY).asText(""); - String version = prebidNode.path(VERSION_PROPERTY).asText(""); - - return (StringUtils.isNotEmpty(source) && StringUtils.isNotEmpty(version)) - ? source + "-" + version - : ""; - - } catch (Exception e) { - return ""; - } + // KIM: copied this from the AppnexusBidder - i think this is what ExtAppPrebid is for + final Optional prebid = Optional.ofNullable(request.getApp()) + .map(App::getExt) + .map(ExtApp::getPrebid); + + final String source = prebid.map(ExtAppPrebid::getSource).orElse(null); + final String version = prebid.map(ExtAppPrebid::getVersion).orElse(null); + + return ObjectUtils.allNotNull(source, version) + ? "%s-%s".formatted(source, version) + : ""; +// if (request.getApp() == null || request.getApp().getExt() == null) { +// return ""; +// } +// +// try { +// final JsonNode extNode = mapper.mapper().readTree(String.valueOf(request.getApp().getExt())); +// final JsonNode prebidNode = extNode.path(PREBID_KEY); +// +// final String source = prebidNode.path(SOURCE_PROPERTY).asText(""); +// final String version = prebidNode.path(VERSION_PROPERTY).asText(""); +// +// return (StringUtils.isNotEmpty(source) && StringUtils.isNotEmpty(version)) +// ? source + "-" + version +// : ""; +// +// } catch (Exception e) { +// return ""; +// } } private static BidType getBidType(String impId, List imps) { for (Imp imp : imps) { if (imp.getId().equals(impId)) { // KATIE TO DO - this is how go version gets mediaType - validate this - String mediaType = imp.getExt().get("cnx").get("mediaType").asText(); + final String mediaType = imp.getExt().get("cnx").get("mediaType").asText(); if (mediaType.equals("video")) { return BidType.video; - } return BidType.banner; + } + return BidType.banner; } break; } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java index 7f374a5f781..5dfacdb1cfb 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java @@ -1,9 +1,8 @@ package org.prebid.server.spring.config.bidder; -import jakarta.validation.constraints.NotBlank; - import org.prebid.server.bidder.BidderDeps; import org.prebid.server.bidder.connatix.ConnatixBidder; +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; @@ -15,6 +14,8 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import jakarta.validation.constraints.NotBlank; + @Configuration @PropertySource(value = "classpath:/bidder-config/connatix.yaml", factory = YamlPropertySourceFactory.class) public class ConnatixConfiguration { @@ -23,16 +24,20 @@ public class ConnatixConfiguration { @Bean("connatixConfigurationProperties") @ConfigurationProperties("adapters.connatix") - BidderConfigurationProperties configurationProperties() { return new BidderConfigurationProperties(); } + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } @Bean BidderDeps connatixBidderDeps(BidderConfigurationProperties connatixConfigurationProperties, - @NotBlank @Value("http://localhost:8080") String externalUrl, JacksonMapper mapper) { + @NotBlank @Value("http://localhost:8080") String externalUrl, + JacksonMapper mapper, + CurrencyConversionService currencyConversionService) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(connatixConfigurationProperties) .usersyncerCreator(UsersyncerCreator.create(externalUrl)) - .bidderCreator(config -> new ConnatixBidder(config.getEndpoint(), mapper)) + .bidderCreator(config -> new ConnatixBidder(config.getEndpoint(), currencyConversionService, mapper)) .assemble(); } } diff --git a/src/main/resources/bidder-config/connatix.yaml b/src/main/resources/bidder-config/connatix.yaml index 8ae912dc419..c82ea57f8b3 100644 --- a/src/main/resources/bidder-config/connatix.yaml +++ b/src/main/resources/bidder-config/connatix.yaml @@ -15,11 +15,11 @@ adapters: usersync: cookie-family-name: connatix iframe: - url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&callback={{redirect_url}}" uid-macro: '$UID' supportCors: false redirect: - url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&callback={{.RedirectURL}}" + url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&callback={{redirect_url}}" uid-macro: '$UID' supportCors: false diff --git a/src/main/resources/static/bidder-params/connatix.json b/src/main/resources/static/bidder-params/connatix.json index 865d38586c7..697e9cd1529 100644 --- a/src/main/resources/static/bidder-params/connatix.json +++ b/src/main/resources/static/bidder-params/connatix.json @@ -8,13 +8,13 @@ "type": "string", "minLength": 1, "description": "Placement ID" + }, + "viewabilityPercentage": { + "type": "number", + "description": "Declared viewability percentage (values from 0 to 1, where 1 = 100%)", + "minimum": 0, + "maximum": 1 } - }, - "viewabilityPercentage": { - "type": "number", - "description": "Declared viewability percentage (values from 0 to 1, where 1 = 100%)", - "minimum": 0, - "maximum": 1 }, "required": ["placementId"] } From c8d983829a0eff01739b66db6e2057e64024c1a1 Mon Sep 17 00:00:00 2001 From: katherynhrabik Date: Wed, 19 Feb 2025 14:41:45 -0500 Subject: [PATCH 03/10] vague cleanup --- .../bidder/connatix/ConnatixBidder.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 4bea3be1e2c..10af69fbf52 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -54,9 +54,6 @@ public class ConnatixBidder implements Bidder { private final String endpointUrl; private final JacksonMapper mapper; - // private static final String PREBID_KEY = "prebid"; - // private static final String SOURCE_PROPERTY = "source"; - // private static final String VERSION_PROPERTY = "version"; private static final String BIDDER_CURRENCY = "USD"; private final CurrencyConversionService currencyConversionService; @@ -222,9 +219,6 @@ private List> splitHttpRequests(BidRequest bidRequest, List imps, String url) { final MultiMap httpHeaders = resolveHeaders(bidRequest.getDevice()); - // KATIE TO DO: this is how we've done it elsewhere but go version has logic that - // explicitly modifies headers here - need to figure out what that's about - // KIM: added the headers - seems like the same logic as AcuityadsBidder return ListUtils.partition(imps, MAX_IMPS_PER_REQUEST) .stream() .map(impsChunk -> createHttpRequest(bidRequest, impsChunk, url, httpHeaders)) @@ -243,7 +237,6 @@ private MultiMap resolveHeaders(Device device) { // check display manager version private String buildDisplayManagerVersion(BidRequest request) { - // KIM: copied this from the AppnexusBidder - i think this is what ExtAppPrebid is for final Optional prebid = Optional.ofNullable(request.getApp()) .map(App::getExt) .map(ExtApp::getPrebid); @@ -254,24 +247,6 @@ private String buildDisplayManagerVersion(BidRequest request) { return ObjectUtils.allNotNull(source, version) ? "%s-%s".formatted(source, version) : ""; -// if (request.getApp() == null || request.getApp().getExt() == null) { -// return ""; -// } -// -// try { -// final JsonNode extNode = mapper.mapper().readTree(String.valueOf(request.getApp().getExt())); -// final JsonNode prebidNode = extNode.path(PREBID_KEY); -// -// final String source = prebidNode.path(SOURCE_PROPERTY).asText(""); -// final String version = prebidNode.path(VERSION_PROPERTY).asText(""); -// -// return (StringUtils.isNotEmpty(source) && StringUtils.isNotEmpty(version)) -// ? source + "-" + version -// : ""; -// -// } catch (Exception e) { -// return ""; -// } } private static BidType getBidType(String impId, List imps) { From 816c3f5d174b2031d46deff041eafd9eba977621 Mon Sep 17 00:00:00 2001 From: kim-ng93 <76963037+kim-ng93@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:22:58 -0800 Subject: [PATCH 04/10] add testing --- .../bidder/connatix/ConnatixBidder.java | 76 ++-- .../ext/request/connatix/ExtImpConnatix.java | 2 + .../config/bidder/ConnatixConfiguration.java | 2 +- .../bidder/connatix/ConnatixBidderTest.java | 429 ++++++++++++++++++ .../org/prebid/server/it/ConnatixTest.java | 33 ++ .../test-banner-auction-connatix-request.json | 28 ++ ...test-banner-auction-connatix-response.json | 37 ++ .../test-banner-connatix-bid-request.json | 59 +++ .../test-banner-connatix-bid-response.json | 28 ++ .../server/it/test-application.properties | 2 + 10 files changed, 658 insertions(+), 38 deletions(-) create mode 100644 src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java create mode 100644 src/test/java/org/prebid/server/it/ConnatixTest.java create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 10af69fbf52..40bd6c2908a 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -1,6 +1,7 @@ package org.prebid.server.bidder.connatix; 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.App; import com.iab.openrtb.request.Banner; @@ -74,34 +75,36 @@ public Result>> makeHttpRequests(BidRequest request return Result.withError(BidderError.badInput("Device IP is required")); } - // KATIE TO DO. UPDATE THIS LOGIC TO PAY ATTENTION TO display manager. - // display manager version can come from openrtb2 request OR imp.ext.prebid - // KIM: i updated the logic to do the same as Appnexus which seems to match? maybe final String displayManagerVer = buildDisplayManagerVersion(request); + final MultiMap headers = resolveHeaders(request.getDevice()); - final List> httpRequests = new ArrayList<>(); + final List modifiedImps = new ArrayList<>(); + final List errors = new ArrayList<>(); for (Imp imp : request.getImp()) { final ExtImpConnatix extImpConnatix; + final Price bidFloorPrice; try { extImpConnatix = parseExtImp(imp); + bidFloorPrice = convertBidFloor(imp, request); + final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, bidFloorPrice); + + modifiedImps.add(modifiedImp); } catch (PreBidException e) { - return Result.withError(BidderError.badInput(e.getMessage())); + errors.add(BidderError.badInput(e.getMessage())); } - // KATIE to do - probably need to add logic for splitting requests somewhere in here - final Price bidFloorPrice = convertBidFloor(imp, request); + } - final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, bidFloorPrice); - httpRequests.add(makeHttpRequest(request, modifiedImp)); + if (modifiedImps.isEmpty()) { + return Result.withErrors(errors); } - return Result.withValues(httpRequests); + final List> httpRequests = splitHttpRequests(request, modifiedImps, headers); + return Result.withValues(httpRequests); } private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayManagerVer, Price bidFloorPrice) { - //KATIE to do - fix this method, it isn't right :) - // KIM: added these thingies to the method - modified banner, display manager, modified bid floor and currency final ConnatixImpExtBidder impExtBidder = resolveImpExt(extImpConnatix); final ObjectNode impExtBidderNode = mapper.mapper().valueToTree(impExtBidder); @@ -114,7 +117,8 @@ private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayMana return imp.toBuilder() .ext(modifiedImpExtBidder) .banner(modifyImpBanner(imp.getBanner())) - .displaymanagerver(displayManagerVer) + .displaymanagerver(!StringUtils.isEmpty(imp.getDisplaymanagerver()) + ? imp.getDisplaymanagerver() : displayManagerVer) .bidfloor(bidFloorPrice.getValue()) .bidfloorcur(bidFloorPrice.getCurrency()) .build(); @@ -139,9 +143,8 @@ private Banner modifyImpBanner(Banner banner) { public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - // KATIE check validity of this logic for setting currency to usd. explicitly set to USD in go version - final BidResponse updatedResponse = bidResponse.toBuilder().cur("USD").build(); - final List bids = extractBids(httpCall.getRequest().getPayload(), updatedResponse); + final List bids = extractBids(httpCall.getRequest().getPayload(), bidResponse); + return Result.withValues(bids); } catch (DecodeException | PreBidException e) { return Result.withError(BidderError.badServerResponse(e.getMessage())); @@ -175,7 +178,7 @@ private static List extractBids(BidRequest bidRequest, BidResponse bi .filter(Objects::nonNull) .flatMap(Collection::stream) .filter(Objects::nonNull) - .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest.getImp()), bidResponse.getCur())) + .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest), bidResponse.getCur())) .toList(); } @@ -189,9 +192,7 @@ private ExtImpConnatix parseExtImp(Imp imp) { } private ConnatixImpExtBidder resolveImpExt(ExtImpConnatix extImpConnatix) { - final ConnatixImpExtBidder.ConnatixImpExtBidderBuilder builder = ConnatixImpExtBidder.builder(); - // KATIE check this is correct - adding placement ID and viewability percentage if available if (StringUtils.isNotEmpty(extImpConnatix.getPlacementId())) { builder.placementId(extImpConnatix.getPlacementId()); } @@ -202,26 +203,21 @@ private ConnatixImpExtBidder resolveImpExt(ExtImpConnatix extImpConnatix) { return builder.build(); } - private HttpRequest makeHttpRequest(BidRequest request, Imp imp) { - final BidRequest outgoingRequest = request.toBuilder().imp(List.of(imp)).build(); - - return BidderUtil.defaultRequest(outgoingRequest, endpointUrl, mapper); - } + private HttpRequest makeHttpRequest(BidRequest request, List impsChunk, MultiMap headers) { + final BidRequest outgoingRequest = request.toBuilder() + .imp(impsChunk) + .cur(List.of(BIDDER_CURRENCY)) + .build(); - private HttpRequest createHttpRequest(BidRequest bidRequest, - List imps, - String url, - MultiMap headers) { - return BidderUtil.defaultRequest(bidRequest.toBuilder().imp(imps).build(), headers, url, mapper); + return BidderUtil.defaultRequest(outgoingRequest, headers, endpointUrl, mapper); } private List> splitHttpRequests(BidRequest bidRequest, List imps, - String url) { - final MultiMap httpHeaders = resolveHeaders(bidRequest.getDevice()); + MultiMap headers) { return ListUtils.partition(imps, MAX_IMPS_PER_REQUEST) .stream() - .map(impsChunk -> createHttpRequest(bidRequest, impsChunk, url, httpHeaders)) + .map(impsChunk -> makeHttpRequest(bidRequest, impsChunk, headers)) .toList(); } @@ -249,17 +245,23 @@ private String buildDisplayManagerVersion(BidRequest request) { : ""; } - private static BidType getBidType(String impId, List imps) { + private static BidType getBidType(String impId, BidRequest bidRequest) { + if (bidRequest == null || CollectionUtils.isEmpty(bidRequest.getImp())) { + return BidType.banner; + } + + final List imps = bidRequest.getImp(); for (Imp imp : imps) { if (imp.getId().equals(impId)) { - // KATIE TO DO - this is how go version gets mediaType - validate this - final String mediaType = imp.getExt().get("cnx").get("mediaType").asText(); - if (mediaType.equals("video")) { + final Optional mediaType = Optional.ofNullable(imp.getExt()) + .map(ext -> ext.get("connatix")) + .map(cnx -> cnx.get("mediaType")) + .map(JsonNode::asText); + if (mediaType.isPresent() && mediaType.get().equals("video")) { return BidType.video; } return BidType.banner; } - break; } throw new PreBidException(String.format("Failed to find impression for ID: '%s'", impId)); } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java index 32ed405e2ca..3d6ec22e20e 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java @@ -1,8 +1,10 @@ package org.prebid.server.proto.openrtb.ext.request.connatix; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Builder; import lombok.Value; +@Builder(toBuilder = true) @Value(staticConstructor = "of") public class ExtImpConnatix { diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java index 5dfacdb1cfb..09754adc489 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/ConnatixConfiguration.java @@ -30,7 +30,7 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps connatixBidderDeps(BidderConfigurationProperties connatixConfigurationProperties, - @NotBlank @Value("http://localhost:8080") String externalUrl, + @NotBlank @Value("${external-url}") String externalUrl, JacksonMapper mapper, CurrencyConversionService currencyConversionService) { diff --git a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java new file mode 100644 index 00000000000..9e1498c82ad --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java @@ -0,0 +1,429 @@ +package org.prebid.server.bidder.connatix; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.App; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.Format; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import io.netty.handler.codec.http.HttpHeaderValues; +import io.vertx.core.MultiMap; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; +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; +import org.prebid.server.bidder.model.BidderError; +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.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.ExtApp; +import org.prebid.server.proto.openrtb.ext.request.ExtAppPrebid; +import org.prebid.server.proto.openrtb.ext.request.connatix.ExtImpConnatix; +import org.prebid.server.proto.openrtb.ext.response.BidType; +import org.prebid.server.util.HttpUtil; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + +import static java.util.Arrays.asList; +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.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.BDDMockito.given; + +@ExtendWith(MockitoExtension.class) +public class ConnatixBidderTest extends VertxTest { + + private static final String CONNATIX_ENDPOINT = "https://test-url.com/"; + + @Mock + private CurrencyConversionService currencyConversionService; + + private ConnatixBidder target; + + @BeforeEach + public void setUp() { + target = new ConnatixBidder(CONNATIX_ENDPOINT, currencyConversionService, jacksonMapper); + } + + @Test + public void creationShouldFailOnInvalidEndpoint() { + assertThatIllegalArgumentException().isThrownBy(() -> + new ConnatixBidder("invalid_url", currencyConversionService, jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldErrorOnMissingDeviceIp() { + // given + final BidRequest bidRequest = BidRequest.builder() + .device(Device.builder() + .build()) + .build(); + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors()).containsExactly(BidderError.badInput("Device IP is required")); + } + + @Test + public void makeHttpRequestsShouldErrorOnInvalidImp() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()) + .extracting(BidderError::getMessage) + .hasSize(1) + .satisfies(errors -> assertThat(errors.getFirst()).startsWith("Cannot deserialize value of type")); + } + + @Test + public void makeHttpRequestsShouldUpdateDisplayManagerVer() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()) + .app(App.builder().ext(ExtApp.of( + ExtAppPrebid.of("source", "version"), null)) + .build()), + givenImp(givenExt(UnaryOperator.identity())) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getDisplaymanagerver) + .containsExactly("source-version"); + } + + @Test + public void makeHttpRequestsShouldNotUpdateDisplayManagerVerIfPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()) + .app(App.builder().ext(ExtApp.of( + ExtAppPrebid.of("source", "version"), null)) + .build()), + impBuilder -> impBuilder.displaymanagerver("displayManagerVer") + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getDisplaymanagerver) + .containsExactly("displayManagerVer"); + } + + @Test + public void makeHttpRequestsShouldNotUpdateBannerIfFormatsIsEmpty() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder.banner(Banner.builder() + .w(100) + .h(200) + .format(Collections.emptyList()) + .build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .containsExactly(Banner.builder().w(100).h(200).format(Collections.emptyList()).build()); + } + + @Test + public void makeHttpRequestsShouldUpdateBanner() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder.banner(Banner.builder().format(List.of( + Format.builder().w(300).h(250).build(), + Format.builder().w(1).h(1).build())).build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .containsExactly(Banner.builder() + .w(300) + .h(250) + .format(List.of( + Format.builder().w(300).h(250).build(), + Format.builder().w(1).h(1).build())) + .build() + ); + } + + @Test + public void makeHttpRequestsShouldErrorWhenBidFloorIsInvalid() { + // given + given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) + .willThrow(PreBidException.class); + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) + .bidfloorcur("EUR") + .bidfloor(BigDecimal.ONE) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()) + .hasSize(1) + .allSatisfy(bidderError -> { + assertThat(bidderError.getMessage()) + .startsWith("Unable to convert provided bid floor currency from EUR to USD"); + assertThat(bidderError.getType()).isEqualTo(BidderError.Type.bad_input); + }); + } + + @Test + public void makeHttpRequestsShouldConvertBidFloorWhenNotInBidderCurrency() { + // given + given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) + .willReturn(BigDecimal.TEN); + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) + .bidfloor(BigDecimal.ONE) + .bidfloorcur("EUR") + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBidfloor, Imp::getBidfloorcur) + .containsOnly(tuple(BigDecimal.TEN, "USD")); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getCur) + .containsExactly("USD"); + } + + @Test + public void makeHttpRequestsShouldSplitRequestIntoMultipleRequests() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpConnatix.builder() + .placementId("placement1").build()))), + impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpConnatix.builder() + .placementId("placement2").build()))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(2); + } + + @Test + public void makeHttpRequestsShouldIncludeResolvedHttpHeadersFromDevice() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").ipv6("deviceIpv6").ua("userAgent").build()), + impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) + ); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getHeaders) + .flatExtracting(MultiMap::entries) + .extracting(Map.Entry::getKey, Map.Entry::getValue) + .containsExactlyInAnyOrder( + tuple(HttpUtil.USER_AGENT_HEADER.toString(), "userAgent"), + tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "deviceIp"), + tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "deviceIpv6"), + tuple(HttpUtil.CONTENT_TYPE_HEADER.toString(), HttpUtil.APPLICATION_JSON_CONTENT_TYPE), + tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString()) + ); + } + + @Test + public void makeBidsShouldErrorIfResponseBodyCannotBeParsed() { + // given + final BidderCall httpCall = givenHttpCall("invalid"); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getValue()).isEmpty(); + assertThat(result.getErrors()).hasSize(1) + .allSatisfy(error -> { + assertThat(error.getType()).isEqualTo(BidderError.Type.bad_server_response); + assertThat(error.getMessage()).startsWith("Failed to decode:"); + }); + } + + @Test + public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsEmpty() throws JsonProcessingException { + // given + final BidderCall httpCall = givenHttpCall(BidResponse.builder().build()); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnBannerBidSuccessfully() throws JsonProcessingException { + // given + final Bid bid = Bid.builder().impid("impId").mtype(1).build(); + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsOnly(BidderBid.of(bid, BidType.banner, "USD")); + } + + @Test + public void makeBidsShouldReturnVideoBidSuccessfully() throws JsonProcessingException { + // given + final Bid bid = Bid.builder().impid("impId").mtype(2).build(); + final ObjectNode mediaType = mapper.createObjectNode().put("mediaType", "video"); + final ObjectNode cnxWrapper = mapper.createObjectNode().set("connatix", mediaType); + final BidRequest bidRequest = givenBidRequest( + request -> request.device(Device.builder().ip("deviceIp").build()), + impBuilder -> impBuilder.ext(cnxWrapper).id("impId") + ); + final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(bid)); + + // when + final Result> result = target.makeBids(httpCall, null); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).containsOnly(BidderBid.of(bid, BidType.video, "USD")); + } + + private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, + Imp... imps) { + return bidRequestCustomizer.apply(BidRequest.builder().imp(asList(imps))).build(); + } + + @SafeVarargs + private static BidRequest givenBidRequest(UnaryOperator bidRequestCustomizer, + UnaryOperator... impCustomizers) { + return bidRequestCustomizer.apply(BidRequest.builder() + .imp(Stream.of(impCustomizers) + .map(ConnatixBidderTest::givenImp) + .toList())) + .build(); + } + + private static Imp givenImp(UnaryOperator impCustomizer) { + return impCustomizer.apply(Imp.builder()).build(); + } + + private static Imp givenImp(ExtImpConnatix extImpConnatix) { + return givenImp(imp -> imp.ext(mapper.valueToTree(ExtPrebid.of(null, extImpConnatix)))); + } + + private static ExtImpConnatix givenExt(UnaryOperator extCustomizer) { + return extCustomizer.apply(ExtImpConnatix.builder().placementId("placementId")).build(); + } + + private static BidderCall givenHttpCall(BidResponse response) throws JsonProcessingException { + return givenHttpCall(mapper.writeValueAsString(response)); + } + + private static BidderCall givenHttpCall(String body) { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(null).build(), + HttpResponse.of(200, null, body), + null); + } + + private static BidderCall givenHttpCall(BidRequest request, + String response) throws JsonProcessingException { + return BidderCall.succeededHttp( + HttpRequest.builder().payload(request).build(), + HttpResponse.of(200, null, response), + null); + } + + private static String givenBidResponse(Bid... bid) throws JsonProcessingException { + return mapper.writeValueAsString(BidResponse.builder() + .cur("USD") + .seatbid(List.of(SeatBid.builder() + .bid(List.of(bid)) + .build())) + .build()); + } +} diff --git a/src/test/java/org/prebid/server/it/ConnatixTest.java b/src/test/java/org/prebid/server/it/ConnatixTest.java new file mode 100644 index 00000000000..79014019502 --- /dev/null +++ b/src/test/java/org/prebid/server/it/ConnatixTest.java @@ -0,0 +1,33 @@ +package org.prebid.server.it; + +import com.github.tomakehurst.wiremock.client.WireMock; +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.jupiter.api.Test; +import org.prebid.server.model.Endpoint; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static java.util.Collections.singletonList; + +public class ConnatixTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBannerBidFromConnatix() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(WireMock.post(urlPathEqualTo("/connatix-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/connatix/test-banner-connatix-bid-request.json"))) + .willReturn(WireMock.aResponse().withBody( + jsonFrom("openrtb2/connatix/test-banner-connatix-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/connatix/test-banner-auction-connatix-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/connatix/test-banner-auction-connatix-response.json", response, + singletonList("connatix")); + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json new file mode 100644 index 00000000000..7293a522b2a --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json @@ -0,0 +1,28 @@ +{ + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagId": "some-tag-id", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "user": { + "buyeruid": "some-user" + }, + "tmax": 1000 +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json new file mode 100644 index 00000000000..c0ed3596a5f --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json @@ -0,0 +1,37 @@ +{ + "id": "some-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impId": "some-impression-id", + "price": 0.3, + "adm": "some-test-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "connatix": "{{ connatix.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 0 + }, + "tmaxrequest": 1000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json new file mode 100644 index 00000000000..e92c1f491e4 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json @@ -0,0 +1,59 @@ +{ + "id": "some-request-id", + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "secure": 1, + "ext": { + "prebid": { + "bidder": { + "connatix": { + "placementId": "some-placement-id" + } + } + }, + "tid": "${json-unit.any-string}" + } + } + ], + "site": { + "domain": "www.example.com", + "page": "https://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "dnt": 0, + "ua": "test-user-agent", + "ipv6": "test-ip-v6", + "language": "en" + }, + "user": { + "buyeruid": "some-user" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "datacenter": "local", + "endpoint": "/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json new file mode 100644 index 00000000000..2afb04c00d8 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json @@ -0,0 +1,28 @@ +{ + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impId": "some-impression-id", + "price": 0.3, + "adm": "some-test-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 320, + "h": 50, + "ext": { + "connatix": { + "mediaType": "banner" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" +} 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 2e115d00348..af2cc6fb22e 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -145,6 +145,8 @@ adapters.bwx.enabled=true adapters.bwx.endpoint=http://localhost:8090/bwx-exchange adapters.cointraffic.enabled=true adapters.cointraffic.endpoint=http://localhost:8090/cointraffic-exchange +adapters.connatix.enabled=true +adapters.connatix.endpoint=http://localhost:8090/connatix-exchange adapters.connectad.enabled=true adapters.connectad.endpoint=http://localhost:8090/connectad-exchange adapters.concert.enabled=true From 7f6042e754a0ff9ad56315ea55c38c9d6f1558a1 Mon Sep 17 00:00:00 2001 From: kim-ng93 <76963037+kim-ng93@users.noreply.github.com> Date: Fri, 21 Feb 2025 11:44:13 -0800 Subject: [PATCH 05/10] fixing tests --- .../bidder/connatix/ConnatixBidder.java | 30 ++++---- .../bidder/connatix/ConnatixBidderTest.java | 10 +-- .../org/prebid/server/it/ConnatixTest.java | 17 +++++ .../test-banner-auction-connatix-request.json | 7 +- ...test-banner-auction-connatix-response.json | 13 +++- .../test-banner-connatix-bid-request.json | 22 +++--- .../test-banner-connatix-bid-response.json | 2 +- .../test-video-auction-connatix-request.json | 38 +++++++++++ .../test-video-auction-connatix-response.json | 44 ++++++++++++ .../test-video-connatix-bid-request.json | 68 +++++++++++++++++++ .../test-video-connatix-bid-response.json | 28 ++++++++ 11 files changed, 240 insertions(+), 39 deletions(-) create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json create mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 40bd6c2908a..4c32d31c8d5 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -9,6 +9,7 @@ import com.iab.openrtb.request.Device; import com.iab.openrtb.request.Format; import com.iab.openrtb.request.Imp; +import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; @@ -178,7 +179,7 @@ private static List extractBids(BidRequest bidRequest, BidResponse bi .filter(Objects::nonNull) .flatMap(Collection::stream) .filter(Objects::nonNull) - .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest), bidResponse.getCur())) + .map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur())) .toList(); } @@ -245,24 +246,17 @@ private String buildDisplayManagerVersion(BidRequest request) { : ""; } - private static BidType getBidType(String impId, BidRequest bidRequest) { - if (bidRequest == null || CollectionUtils.isEmpty(bidRequest.getImp())) { - return BidType.banner; + private static BidType getBidType(Bid bid) { + if (bid == null) { + return null; } - - final List imps = bidRequest.getImp(); - for (Imp imp : imps) { - if (imp.getId().equals(impId)) { - final Optional mediaType = Optional.ofNullable(imp.getExt()) - .map(ext -> ext.get("connatix")) - .map(cnx -> cnx.get("mediaType")) - .map(JsonNode::asText); - if (mediaType.isPresent() && mediaType.get().equals("video")) { - return BidType.video; - } - return BidType.banner; - } + final Optional bidType = Optional.ofNullable(bid.getExt()) + .map(ext -> ext.get("connatix")) + .map(cnx -> cnx.get("mediaType")) + .map(JsonNode::asText); + if (bidType.isPresent() && bidType.get().equals("video")) { + return BidType.video; } - throw new PreBidException(String.format("Failed to find impression for ID: '%s'", impId)); + return BidType.banner; } } diff --git a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java index 9e1498c82ad..242621a5f8e 100644 --- a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java @@ -341,7 +341,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsEmpty() throws Js @Test public void makeBidsShouldReturnBannerBidSuccessfully() throws JsonProcessingException { // given - final Bid bid = Bid.builder().impid("impId").mtype(1).build(); + final Bid bid = Bid.builder().impid("impId").build(); final BidderCall httpCall = givenHttpCall(givenBidResponse(bid)); // when @@ -355,14 +355,10 @@ public void makeBidsShouldReturnBannerBidSuccessfully() throws JsonProcessingExc @Test public void makeBidsShouldReturnVideoBidSuccessfully() throws JsonProcessingException { // given - final Bid bid = Bid.builder().impid("impId").mtype(2).build(); final ObjectNode mediaType = mapper.createObjectNode().put("mediaType", "video"); final ObjectNode cnxWrapper = mapper.createObjectNode().set("connatix", mediaType); - final BidRequest bidRequest = givenBidRequest( - request -> request.device(Device.builder().ip("deviceIp").build()), - impBuilder -> impBuilder.ext(cnxWrapper).id("impId") - ); - final BidderCall httpCall = givenHttpCall(bidRequest, givenBidResponse(bid)); + final Bid bid = Bid.builder().impid("impId").ext(cnxWrapper).build(); + final BidderCall httpCall = givenHttpCall(givenBidResponse(bid)); // when final Result> result = target.makeBids(httpCall, null); diff --git a/src/test/java/org/prebid/server/it/ConnatixTest.java b/src/test/java/org/prebid/server/it/ConnatixTest.java index 79014019502..757ad020dcf 100644 --- a/src/test/java/org/prebid/server/it/ConnatixTest.java +++ b/src/test/java/org/prebid/server/it/ConnatixTest.java @@ -30,4 +30,21 @@ public void openrtb2AuctionShouldRespondWithBannerBidFromConnatix() throws IOExc assertJsonEquals("openrtb2/connatix/test-banner-auction-connatix-response.json", response, singletonList("connatix")); } + + @Test + public void openrtb2AuctionShouldRespondWithVideoBidFromConnatix() throws IOException, JSONException { + // given + WIRE_MOCK_RULE.stubFor(WireMock.post(urlPathEqualTo("/connatix-exchange")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/connatix/test-video-connatix-bid-request.json"))) + .willReturn(WireMock.aResponse().withBody( + jsonFrom("openrtb2/connatix/test-video-connatix-bid-response.json")))); + + // when + final Response response = responseFor("openrtb2/connatix/test-video-auction-connatix-request.json", + Endpoint.openrtb2_auction); + + // then + assertJsonEquals("openrtb2/connatix/test-video-auction-connatix-response.json", response, + singletonList("connatix")); + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json index 7293a522b2a..22d8754250d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-request.json @@ -24,5 +24,10 @@ "user": { "buyeruid": "some-user" }, - "tmax": 1000 + "tmax": 1000, + "regs": { + "ext": { + "gdpr": 0 + } + } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json index c0ed3596a5f..3d1b37feaad 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-auction-connatix-response.json @@ -5,7 +5,7 @@ "bid": [ { "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impId": "some-impression-id", + "impid": "some-impression-id", "price": 0.3, "adm": "some-test-ad", "adomain": [ @@ -14,14 +14,21 @@ "crid": "112233", "w": 320, "h": 50, + "exp": 300, "ext": { "connatix": { "mediaType": "banner" + }, + "origbidcpm": 0.3, + "origbidcur": "USD", + "prebid": { + "type": "banner" } } } ], - "seat": "connatix" + "seat": "connatix", + "group": 0 } ], "cur": "USD", @@ -30,7 +37,7 @@ "connatix": "{{ connatix.response_time_ms }}" }, "prebid": { - "auctiontimestamp": 0 + "auctiontimestamp": "${json-unit.any-string}" }, "tmaxrequest": 1000 } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json index e92c1f491e4..1c3e49a97f2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json @@ -7,22 +7,20 @@ "w": 320, "h": 50 }, + "displaymanagerver": "", "secure": 1, "ext": { - "prebid": { - "bidder": { - "connatix": { - "placementId": "some-placement-id" - } - } + "tid": "${json-unit.any-string}", + "bidder": { + "placementId": "some-placement-id" }, - "tid": "${json-unit.any-string}" + "placementId": "some-placement-id" } } ], "site": { "domain": "www.example.com", - "page": "https://www.example.com", + "page": "http://www.example.com", "publisher": { "domain": "example.com" }, @@ -33,7 +31,7 @@ "device": { "dnt": 0, "ua": "test-user-agent", - "ipv6": "test-ip-v6", + "ip": "${json-unit.any-string}", "language": "en" }, "user": { @@ -47,10 +45,16 @@ "source": { "tid": "${json-unit.any-string}" }, + "regs": { + "ext": { + "gdpr": 0 + } + }, "ext": { "prebid": { "server": { "externalurl": "http://localhost:8080", + "gvlid": 1, "datacenter": "local", "endpoint": "/openrtb2/auction" } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json index 2afb04c00d8..a8464485389 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-response.json @@ -5,7 +5,7 @@ "bid": [ { "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impId": "some-impression-id", + "impid": "some-impression-id", "price": 0.3, "adm": "some-test-ad", "adomain": [ diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json new file mode 100644 index 00000000000..f105d81a6ab --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json @@ -0,0 +1,38 @@ +{ + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ipv6": "test-ip-v6", + "language": "en", + "dnt": 0 + }, + "imp": [ + { + "id": "some-impression-id", + "tagId": "some-tag-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "connatix": { + "placementId": "some-placement-id" + } + } + } + ], + "user": { + "buyeruid": "some-user" + }, + "tmax": 1000, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json new file mode 100644 index 00000000000..7f10b9b9f4a --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json @@ -0,0 +1,44 @@ +{ + "id": "some-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "exp": 1500, + "ext": { + "connatix": { + "mediaType": "video" + }, + "origbidcpm": 3.5, + "origbidcur": "USD", + "prebid": { + "type": "video" + } + } + } + ], + "seat": "connatix", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "connatix": "{{ connatix.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": "${json-unit.any-string}" + }, + "tmaxrequest": 1000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json new file mode 100644 index 00000000000..5cd895b9bb1 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json @@ -0,0 +1,68 @@ +{ + "id": "some-request-id", + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "minduration": 120, + "maxduration": 150, + "w": 640, + "h": 480 + }, + "displaymanagerver": "", + "secure": 1, + "ext": { + "tid": "${json-unit.any-string}", + "bidder": { + "placementId": "some-placement-id" + }, + "placementId": "some-placement-id" + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "dnt": 0, + "ua": "test-user-agent", + "ip": "${json-unit.any-string}", + "language": "en" + }, + "user": { + "buyeruid": "some-user" + }, + "at": 1, + "tmax": "${json-unit.any-number}", + "cur": [ + "USD" + ], + "source": { + "tid": "${json-unit.any-string}" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "prebid": { + "server": { + "externalurl": "http://localhost:8080", + "gvlid": 1, + "datacenter": "local", + "endpoint": "/openrtb2/auction" + } + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json new file mode 100644 index 00000000000..3d9cb510460 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json @@ -0,0 +1,28 @@ +{ + "id": "some-response-id", + "seatbid": [ + { + "bid": [ + { + "id": "b3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "some-test-vast-ad", + "adomain": [ + "awesome.com" + ], + "crid": "112233", + "w": 1280, + "h": 720, + "ext": { + "connatix": { + "mediaType": "video" + } + } + } + ], + "seat": "connatix" + } + ], + "cur": "USD" +} From 45975478fab5fcc19f20efaf0b8ad559ffaff29a Mon Sep 17 00:00:00 2001 From: kim-ng93 <76963037+kim-ng93@users.noreply.github.com> Date: Fri, 21 Feb 2025 12:21:54 -0800 Subject: [PATCH 06/10] Update ConnatixImpExtBidder.java --- .../server/bidder/connatix/proto/ConnatixImpExtBidder.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java b/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java index 9ffb8517974..a899ae11bdf 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java @@ -13,7 +13,6 @@ public class ConnatixImpExtBidder { @JsonProperty(value = "placementId") String placementId; - // KATIE: viewability percentage, viewability container, and bidfloor are all optional. should they be included? @JsonProperty(value = "viewabilityPercentage") Float viewabilityPercentage; From 583e7ce38deb7c904084a743c3e0a56bbf59444c Mon Sep 17 00:00:00 2001 From: katherynhrabik Date: Wed, 26 Feb 2025 14:28:21 -0500 Subject: [PATCH 07/10] requested changes --- .../bidder/connatix/ConnatixBidder.java | 127 +++++++----------- .../connatix/proto/ConnatixImpExtBidder.java | 19 --- .../ext/request/connatix/ExtImpConnatix.java | 3 +- .../resources/bidder-config/connatix.yaml | 8 +- .../org/prebid/server/it/ConnatixTest.java | 17 --- .../test-video-auction-connatix-request.json | 38 ------ .../test-video-auction-connatix-response.json | 44 ------ .../test-video-connatix-bid-request.json | 68 ---------- .../test-video-connatix-bid-response.json | 28 ---- 9 files changed, 54 insertions(+), 298 deletions(-) delete mode 100644 src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java delete mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json delete mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json delete mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json delete mode 100644 src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 4c32d31c8d5..2541edb659b 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -18,7 +18,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; -import org.prebid.server.bidder.connatix.proto.ConnatixImpExtBidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; import org.prebid.server.bidder.model.BidderError; @@ -31,7 +30,6 @@ import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtApp; -import org.prebid.server.proto.openrtb.ext.request.ExtAppPrebid; import org.prebid.server.proto.openrtb.ext.request.connatix.ExtImpConnatix; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; @@ -53,42 +51,40 @@ public class ConnatixBidder implements Bidder { private static final int MAX_IMPS_PER_REQUEST = 1; + private static final String BIDDER_CURRENCY = "USD"; + private final String endpointUrl; private final JacksonMapper mapper; - private static final String BIDDER_CURRENCY = "USD"; - private final CurrencyConversionService currencyConversionService; public ConnatixBidder(String endpointUrl, CurrencyConversionService currencyConversionService, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); - this.currencyConversionService = currencyConversionService; + this.currencyConversionService = Objects.requireNonNull(currencyConversionService); this.mapper = Objects.requireNonNull(mapper); } @Override public Result>> makeHttpRequests(BidRequest request) { - // Device IP required - bounce if not available - if (request.getDevice() == null - || (request.getDevice().getIp() == null && request.getDevice().getIpv6() == null)) { + final Device device = request.getDevice(); + + if (device == null + || (device.getIp() == null && device.getIpv6() == null)) { return Result.withError(BidderError.badInput("Device IP is required")); } final String displayManagerVer = buildDisplayManagerVersion(request); - final MultiMap headers = resolveHeaders(request.getDevice()); + final MultiMap headers = resolveHeaders(device); final List modifiedImps = new ArrayList<>(); final List errors = new ArrayList<>(); for (Imp imp : request.getImp()) { - final ExtImpConnatix extImpConnatix; - final Price bidFloorPrice; try { - extImpConnatix = parseExtImp(imp); - bidFloorPrice = convertBidFloor(imp, request); - final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, bidFloorPrice); + final ExtImpConnatix extImpConnatix = parseExtImp(imp); + final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, request); modifiedImps.add(modifiedImp); } catch (PreBidException e) { @@ -96,30 +92,24 @@ public Result>> makeHttpRequests(BidRequest request } } - if (modifiedImps.isEmpty()) { - return Result.withErrors(errors); - } - final List> httpRequests = splitHttpRequests(request, modifiedImps, headers); - return Result.withValues(httpRequests); + return Result.of(httpRequests, errors); } - private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayManagerVer, Price bidFloorPrice) { - final ConnatixImpExtBidder impExtBidder = resolveImpExt(extImpConnatix); + private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayManagerVer, BidRequest request) { - final ObjectNode impExtBidderNode = mapper.mapper().valueToTree(impExtBidder); - final ObjectNode modifiedImpExtBidder = imp.getExt() != null ? imp.getExt().deepCopy() - : mapper.mapper().createObjectNode(); + final Price bidFloorPrice = resolveBidFloor(imp, request); - modifiedImpExtBidder.setAll(impExtBidderNode); + final ObjectNode impExt = mapper.mapper().createObjectNode().set("connatix", mapper.mapper().valueToTree(extImpConnatix)); return imp.toBuilder() - .ext(modifiedImpExtBidder) + .ext(impExt) .banner(modifyImpBanner(imp.getBanner())) - .displaymanagerver(!StringUtils.isEmpty(imp.getDisplaymanagerver()) - ? imp.getDisplaymanagerver() : displayManagerVer) + .displaymanagerver(StringUtils.isBlank(imp.getDisplaymanagerver()) && StringUtils.isNotBlank(displayManagerVer) + ? displayManagerVer + : imp.getDisplaymanagerver()) .bidfloor(bidFloorPrice.getValue()) .bidfloorcur(bidFloorPrice.getCurrency()) .build(); @@ -130,7 +120,7 @@ private Banner modifyImpBanner(Banner banner) { return null; } - if (banner.getW() == null && banner.getH() == null && !CollectionUtils.isEmpty(banner.getFormat())) { + if (banner.getW() == null && banner.getH() == null && CollectionUtils.isNotEmpty(banner.getFormat())) { final Format firstFormat = banner.getFormat().getFirst(); return banner.toBuilder() .w(firstFormat.getW()) @@ -144,7 +134,7 @@ private Banner modifyImpBanner(Banner banner) { public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { final BidResponse bidResponse = mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); - final List bids = extractBids(httpCall.getRequest().getPayload(), bidResponse); + final List bids = extractBids(bidResponse); return Result.withValues(bids); } catch (DecodeException | PreBidException e) { @@ -152,23 +142,24 @@ public Result> makeBids(BidderCall httpCall, BidRequ } } - private Price convertBidFloor(Imp imp, BidRequest bidRequest) { + private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); - if (BidderUtil.isValidPrice(initialBidFloorPrice)) { - try { - final BigDecimal convertedPrice = currencyConversionService - .convertCurrency(imp.getBidfloor(), bidRequest, imp.getBidfloorcur(), BIDDER_CURRENCY); - return Price.of(BIDDER_CURRENCY, convertedPrice); - } catch (PreBidException e) { - throw new PreBidException("Unable to convert provided bid floor currency from %s to %s for imp `%s`" - .formatted(imp.getBidfloorcur(), BIDDER_CURRENCY, imp.getId())); - } - } - return initialBidFloorPrice; + return BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, BIDDER_CURRENCY) + ? convertBidFloor(initialBidFloorPrice, bidRequest) + : initialBidFloorPrice; } - // extract bids - private static List extractBids(BidRequest bidRequest, BidResponse bidResponse) { + private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) { + final BigDecimal convertedPrice = currencyConversionService.convertCurrency( + bidFloorPrice.getValue(), + bidRequest, + bidFloorPrice.getCurrency(), + BIDDER_CURRENCY); + + return Price.of(BIDDER_CURRENCY, convertedPrice); + } + + private static List extractBids(BidResponse bidResponse) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); } @@ -179,11 +170,10 @@ private static List extractBids(BidRequest bidRequest, BidResponse bi .filter(Objects::nonNull) .flatMap(Collection::stream) .filter(Objects::nonNull) - .map(bid -> BidderBid.of(bid, getBidType(bid), bidResponse.getCur())) + .map(bid -> BidderBid.of(bid, getBidType(bid), BIDDER_CURRENCY)) .toList(); } - // parseExtImp private ExtImpConnatix parseExtImp(Imp imp) { try { return mapper.mapper().convertValue(imp.getExt(), CONNATIX_EXT_TYPE_REFERENCE).getBidder(); @@ -192,18 +182,6 @@ private ExtImpConnatix parseExtImp(Imp imp) { } } - private ConnatixImpExtBidder resolveImpExt(ExtImpConnatix extImpConnatix) { - final ConnatixImpExtBidder.ConnatixImpExtBidderBuilder builder = ConnatixImpExtBidder.builder(); - if (StringUtils.isNotEmpty(extImpConnatix.getPlacementId())) { - builder.placementId(extImpConnatix.getPlacementId()); - } - if (extImpConnatix.getViewabilityPercentage() != null) { - builder.viewabilityPercentage(extImpConnatix.getViewabilityPercentage()); - } - - return builder.build(); - } - private HttpRequest makeHttpRequest(BidRequest request, List impsChunk, MultiMap headers) { final BidRequest outgoingRequest = request.toBuilder() .imp(impsChunk) @@ -232,31 +210,24 @@ private MultiMap resolveHeaders(Device device) { return headers; } - // check display manager version - private String buildDisplayManagerVersion(BidRequest request) { - final Optional prebid = Optional.ofNullable(request.getApp()) - .map(App::getExt) - .map(ExtApp::getPrebid); - - final String source = prebid.map(ExtAppPrebid::getSource).orElse(null); - final String version = prebid.map(ExtAppPrebid::getVersion).orElse(null); + private static String buildDisplayManagerVersion(BidRequest request) { + final String formatting = "%s-%s"; - return ObjectUtils.allNotNull(source, version) - ? "%s-%s".formatted(source, version) - : ""; + return Optional.ofNullable(request.getApp()) + .map(App::getExt) + .map(ExtApp::getPrebid) + .filter(prebid -> ObjectUtils.allNotNull(prebid.getSource(), prebid.getVersion())) + .map(prebid -> formatting.formatted(prebid.getSource(), prebid.getVersion())) + .orElse(StringUtils.EMPTY); } private static BidType getBidType(Bid bid) { - if (bid == null) { - return null; - } - final Optional bidType = Optional.ofNullable(bid.getExt()) + return Optional.ofNullable(bid.getExt()) .map(ext -> ext.get("connatix")) .map(cnx -> cnx.get("mediaType")) - .map(JsonNode::asText); - if (bidType.isPresent() && bidType.get().equals("video")) { - return BidType.video; - } - return BidType.banner; + .map(JsonNode::asText) + .filter(type -> Objects.equals(type, "video")) + .map(ignored -> BidType.video) + .orElse(BidType.banner); } } diff --git a/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java b/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java deleted file mode 100644 index a899ae11bdf..00000000000 --- a/src/main/java/org/prebid/server/bidder/connatix/proto/ConnatixImpExtBidder.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.prebid.server.bidder.connatix.proto; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Builder; -import lombok.Value; - -@Builder -@Value -public class ConnatixImpExtBidder { - - String type; - - @JsonProperty(value = "placementId") - String placementId; - - @JsonProperty(value = "viewabilityPercentage") - Float viewabilityPercentage; - -} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java index 3d6ec22e20e..57f9cec7902 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; import lombok.Value; +import java.math.BigDecimal; @Builder(toBuilder = true) @Value(staticConstructor = "of") @@ -12,6 +13,6 @@ public class ExtImpConnatix { String placementId; @JsonProperty("viewabilityPercentage") - Float viewabilityPercentage; + BigDecimal viewabilityPercentage; } diff --git a/src/main/resources/bidder-config/connatix.yaml b/src/main/resources/bidder-config/connatix.yaml index c82ea57f8b3..3653e4eb947 100644 --- a/src/main/resources/bidder-config/connatix.yaml +++ b/src/main/resources/bidder-config/connatix.yaml @@ -1,8 +1,6 @@ adapters: connatix: endpoint: "https://capi.connatix.com/rtb/ortb" - ortb: - multiformat-supported: false meta-info: maintainer-email: "pubsolutions@connatix.com" vendor-id: 143 @@ -16,10 +14,10 @@ adapters: cookie-family-name: connatix iframe: url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&callback={{redirect_url}}" - uid-macro: '$UID' + uid-macro: '[UID]' supportCors: false redirect: url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&callback={{redirect_url}}" - uid-macro: '$UID' - supportCors: false + uid-macro: '[UID]' + support-cors: false diff --git a/src/test/java/org/prebid/server/it/ConnatixTest.java b/src/test/java/org/prebid/server/it/ConnatixTest.java index 757ad020dcf..79014019502 100644 --- a/src/test/java/org/prebid/server/it/ConnatixTest.java +++ b/src/test/java/org/prebid/server/it/ConnatixTest.java @@ -30,21 +30,4 @@ public void openrtb2AuctionShouldRespondWithBannerBidFromConnatix() throws IOExc assertJsonEquals("openrtb2/connatix/test-banner-auction-connatix-response.json", response, singletonList("connatix")); } - - @Test - public void openrtb2AuctionShouldRespondWithVideoBidFromConnatix() throws IOException, JSONException { - // given - WIRE_MOCK_RULE.stubFor(WireMock.post(urlPathEqualTo("/connatix-exchange")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/connatix/test-video-connatix-bid-request.json"))) - .willReturn(WireMock.aResponse().withBody( - jsonFrom("openrtb2/connatix/test-video-connatix-bid-response.json")))); - - // when - final Response response = responseFor("openrtb2/connatix/test-video-auction-connatix-request.json", - Endpoint.openrtb2_auction); - - // then - assertJsonEquals("openrtb2/connatix/test-video-auction-connatix-response.json", response, - singletonList("connatix")); - } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json deleted file mode 100644 index f105d81a6ab..00000000000 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-request.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ipv6": "test-ip-v6", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "tagId": "some-tag-id", - "video": { - "mimes": [ - "video/mp4" - ], - "w": 640, - "h": 480, - "minduration": 120, - "maxduration": 150 - }, - "ext": { - "connatix": { - "placementId": "some-placement-id" - } - } - } - ], - "user": { - "buyeruid": "some-user" - }, - "tmax": 1000, - "regs": { - "ext": { - "gdpr": 0 - } - } -} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json deleted file mode 100644 index 7f10b9b9f4a..00000000000 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-auction-connatix-response.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "id": "some-request-id", - "seatbid": [ - { - "bid": [ - { - "id": "b3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "some-test-vast-ad", - "adomain": [ - "awesome.com" - ], - "crid": "112233", - "w": 1280, - "h": 720, - "exp": 1500, - "ext": { - "connatix": { - "mediaType": "video" - }, - "origbidcpm": 3.5, - "origbidcur": "USD", - "prebid": { - "type": "video" - } - } - } - ], - "seat": "connatix", - "group": 0 - } - ], - "cur": "USD", - "ext": { - "responsetimemillis": { - "connatix": "{{ connatix.response_time_ms }}" - }, - "prebid": { - "auctiontimestamp": "${json-unit.any-string}" - }, - "tmaxrequest": 1000 - } -} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json deleted file mode 100644 index 5cd895b9bb1..00000000000 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-request.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "id": "some-request-id", - "imp": [ - { - "id": "some-impression-id", - "video": { - "mimes": [ - "video/mp4" - ], - "minduration": 120, - "maxduration": 150, - "w": 640, - "h": 480 - }, - "displaymanagerver": "", - "secure": 1, - "ext": { - "tid": "${json-unit.any-string}", - "bidder": { - "placementId": "some-placement-id" - }, - "placementId": "some-placement-id" - } - } - ], - "site": { - "domain": "www.example.com", - "page": "http://www.example.com", - "publisher": { - "domain": "example.com" - }, - "ext": { - "amp": 0 - } - }, - "device": { - "dnt": 0, - "ua": "test-user-agent", - "ip": "${json-unit.any-string}", - "language": "en" - }, - "user": { - "buyeruid": "some-user" - }, - "at": 1, - "tmax": "${json-unit.any-number}", - "cur": [ - "USD" - ], - "source": { - "tid": "${json-unit.any-string}" - }, - "regs": { - "ext": { - "gdpr": 0 - } - }, - "ext": { - "prebid": { - "server": { - "externalurl": "http://localhost:8080", - "gvlid": 1, - "datacenter": "local", - "endpoint": "/openrtb2/auction" - } - } - } -} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json deleted file mode 100644 index 3d9cb510460..00000000000 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-video-connatix-bid-response.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "id": "some-response-id", - "seatbid": [ - { - "bid": [ - { - "id": "b3ae1b4e2fc24a4fb45540082e98e161", - "impid": "some-impression-id", - "price": 3.5, - "adm": "some-test-vast-ad", - "adomain": [ - "awesome.com" - ], - "crid": "112233", - "w": 1280, - "h": 720, - "ext": { - "connatix": { - "mediaType": "video" - } - } - } - ], - "seat": "connatix" - } - ], - "cur": "USD" -} From 764f2c45ff04b06220f2e17843f41e0a3762fc3c Mon Sep 17 00:00:00 2001 From: kim-ng93 <76963037+kim-ng93@users.noreply.github.com> Date: Wed, 26 Feb 2025 12:25:34 -0800 Subject: [PATCH 08/10] wrapping up changes and test fixes --- .../bidder/connatix/ConnatixBidder.java | 135 ++++++++---------- .../ext/request/connatix/ExtImpConnatix.java | 1 + .../bidder/connatix/ConnatixBidderTest.java | 27 ---- .../test-banner-connatix-bid-request.json | 7 +- 4 files changed, 64 insertions(+), 106 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 2541edb659b..3a0eaaf5a38 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -14,7 +14,6 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; @@ -49,8 +48,6 @@ public class ConnatixBidder implements Bidder { new TypeReference<>() { }; - private static final int MAX_IMPS_PER_REQUEST = 1; - private static final String BIDDER_CURRENCY = "USD"; private final String endpointUrl; @@ -78,7 +75,7 @@ public Result>> makeHttpRequests(BidRequest request final String displayManagerVer = buildDisplayManagerVersion(request); final MultiMap headers = resolveHeaders(device); - final List modifiedImps = new ArrayList<>(); + final List> httpRequests = new ArrayList<>(); final List errors = new ArrayList<>(); for (Imp imp : request.getImp()) { @@ -86,28 +83,56 @@ public Result>> makeHttpRequests(BidRequest request final ExtImpConnatix extImpConnatix = parseExtImp(imp); final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, request); - modifiedImps.add(modifiedImp); + httpRequests.add(makeHttpRequest(request, modifiedImp, headers)); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } } - final List> httpRequests = splitHttpRequests(request, modifiedImps, headers); - return Result.of(httpRequests, errors); } - private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayManagerVer, BidRequest request) { + private static String buildDisplayManagerVersion(BidRequest request) { + final String formatting = "%s-%s"; + + return Optional.ofNullable(request.getApp()) + .map(App::getExt) + .map(ExtApp::getPrebid) + .filter(prebid -> ObjectUtils.allNotNull(prebid.getSource(), prebid.getVersion())) + .map(prebid -> formatting.formatted(prebid.getSource(), prebid.getVersion())) + .orElse(StringUtils.EMPTY); + } + + private MultiMap resolveHeaders(Device device) { + final MultiMap headers = HttpUtil.headers(); + if (device != null) { + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, device.getUa()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIpv6()); + HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIp()); + } + return headers; + } + + private ExtImpConnatix parseExtImp(Imp imp) { + try { + return mapper.mapper().convertValue(imp.getExt(), CONNATIX_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage()); + } + } + private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayManagerVer, BidRequest request) { final Price bidFloorPrice = resolveBidFloor(imp, request); - final ObjectNode impExt = mapper.mapper().createObjectNode().set("connatix", mapper.mapper().valueToTree(extImpConnatix)); + final ObjectNode impExt = mapper.mapper() + .createObjectNode().set("connatix", mapper.mapper().valueToTree(extImpConnatix)); return imp.toBuilder() .ext(impExt) .banner(modifyImpBanner(imp.getBanner())) - .displaymanagerver(StringUtils.isBlank(imp.getDisplaymanagerver()) && StringUtils.isNotBlank(displayManagerVer) + .displaymanagerver(StringUtils.isBlank(imp.getDisplaymanagerver()) + && StringUtils.isNotBlank(displayManagerVer) ? displayManagerVer : imp.getDisplaymanagerver()) .bidfloor(bidFloorPrice.getValue()) @@ -115,6 +140,23 @@ private Imp modifyImp(Imp imp, ExtImpConnatix extImpConnatix, String displayMana .build(); } + private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { + final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); + return BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, BIDDER_CURRENCY) + ? convertBidFloor(initialBidFloorPrice, bidRequest) + : initialBidFloorPrice; + } + + private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) { + final BigDecimal convertedPrice = currencyConversionService.convertCurrency( + bidFloorPrice.getValue(), + bidRequest, + bidFloorPrice.getCurrency(), + BIDDER_CURRENCY); + + return Price.of(BIDDER_CURRENCY, convertedPrice); + } + private Banner modifyImpBanner(Banner banner) { if (banner == null) { return null; @@ -130,6 +172,15 @@ private Banner modifyImpBanner(Banner banner) { return banner; } + private HttpRequest makeHttpRequest(BidRequest request, Imp imp, MultiMap headers) { + final BidRequest outgoingRequest = request.toBuilder() + .imp(List.of(imp)) + .cur(List.of(BIDDER_CURRENCY)) + .build(); + + return BidderUtil.defaultRequest(outgoingRequest, headers, endpointUrl, mapper); + } + @Override public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { try { @@ -142,23 +193,6 @@ public Result> makeBids(BidderCall httpCall, BidRequ } } - private Price resolveBidFloor(Imp imp, BidRequest bidRequest) { - final Price initialBidFloorPrice = Price.of(imp.getBidfloorcur(), imp.getBidfloor()); - return BidderUtil.shouldConvertBidFloor(initialBidFloorPrice, BIDDER_CURRENCY) - ? convertBidFloor(initialBidFloorPrice, bidRequest) - : initialBidFloorPrice; - } - - private Price convertBidFloor(Price bidFloorPrice, BidRequest bidRequest) { - final BigDecimal convertedPrice = currencyConversionService.convertCurrency( - bidFloorPrice.getValue(), - bidRequest, - bidFloorPrice.getCurrency(), - BIDDER_CURRENCY); - - return Price.of(BIDDER_CURRENCY, convertedPrice); - } - private static List extractBids(BidResponse bidResponse) { if (bidResponse == null || CollectionUtils.isEmpty(bidResponse.getSeatbid())) { return Collections.emptyList(); @@ -174,53 +208,6 @@ private static List extractBids(BidResponse bidResponse) { .toList(); } - private ExtImpConnatix parseExtImp(Imp imp) { - try { - return mapper.mapper().convertValue(imp.getExt(), CONNATIX_EXT_TYPE_REFERENCE).getBidder(); - } catch (IllegalArgumentException e) { - throw new PreBidException(e.getMessage()); - } - } - - private HttpRequest makeHttpRequest(BidRequest request, List impsChunk, MultiMap headers) { - final BidRequest outgoingRequest = request.toBuilder() - .imp(impsChunk) - .cur(List.of(BIDDER_CURRENCY)) - .build(); - - return BidderUtil.defaultRequest(outgoingRequest, headers, endpointUrl, mapper); - } - - private List> splitHttpRequests(BidRequest bidRequest, - List imps, - MultiMap headers) { - return ListUtils.partition(imps, MAX_IMPS_PER_REQUEST) - .stream() - .map(impsChunk -> makeHttpRequest(bidRequest, impsChunk, headers)) - .toList(); - } - - private MultiMap resolveHeaders(Device device) { - final MultiMap headers = HttpUtil.headers(); - if (device != null) { - HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, device.getUa()); - HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIpv6()); - HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.X_FORWARDED_FOR_HEADER, device.getIp()); - } - return headers; - } - - private static String buildDisplayManagerVersion(BidRequest request) { - final String formatting = "%s-%s"; - - return Optional.ofNullable(request.getApp()) - .map(App::getExt) - .map(ExtApp::getPrebid) - .filter(prebid -> ObjectUtils.allNotNull(prebid.getSource(), prebid.getVersion())) - .map(prebid -> formatting.formatted(prebid.getSource(), prebid.getVersion())) - .orElse(StringUtils.EMPTY); - } - private static BidType getBidType(Bid bid) { return Optional.ofNullable(bid.getExt()) .map(ext -> ext.get("connatix")) diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java index 57f9cec7902..faedd30ffca 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/connatix/ExtImpConnatix.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Builder; import lombok.Value; + import java.math.BigDecimal; @Builder(toBuilder = true) diff --git a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java index 242621a5f8e..1b5f9e9c217 100644 --- a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java @@ -26,7 +26,6 @@ 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.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtApp; import org.prebid.server.proto.openrtb.ext.request.ExtAppPrebid; @@ -205,32 +204,6 @@ public void makeHttpRequestsShouldUpdateBanner() { ); } - @Test - public void makeHttpRequestsShouldErrorWhenBidFloorIsInvalid() { - // given - given(currencyConversionService.convertCurrency(any(), any(), anyString(), anyString())) - .willThrow(PreBidException.class); - final BidRequest bidRequest = givenBidRequest( - request -> request.device(Device.builder().ip("deviceIp").build()), - impBuilder -> impBuilder - .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) - .bidfloorcur("EUR") - .bidfloor(BigDecimal.ONE) - ); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()) - .hasSize(1) - .allSatisfy(bidderError -> { - assertThat(bidderError.getMessage()) - .startsWith("Unable to convert provided bid floor currency from EUR to USD"); - assertThat(bidderError.getType()).isEqualTo(BidderError.Type.bad_input); - }); - } - @Test public void makeHttpRequestsShouldConvertBidFloorWhenNotInBidderCurrency() { // given diff --git a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json index 1c3e49a97f2..616934ea2c5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/connatix/test-banner-connatix-bid-request.json @@ -7,14 +7,11 @@ "w": 320, "h": 50 }, - "displaymanagerver": "", "secure": 1, "ext": { - "tid": "${json-unit.any-string}", - "bidder": { + "connatix": { "placementId": "some-placement-id" - }, - "placementId": "some-placement-id" + } } } ], From 072c7bf407799a069cb58339b79109d18711a9ae Mon Sep 17 00:00:00 2001 From: katherynhrabik Date: Thu, 27 Feb 2025 09:58:22 -0500 Subject: [PATCH 09/10] last few updates --- .../bidder/connatix/ConnatixBidder.java | 6 ++--- .../bidder/connatix/ConnatixBidderTest.java | 24 +++++++------------ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 3a0eaaf5a38..7ab152be888 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -49,6 +49,7 @@ public class ConnatixBidder implements Bidder { }; private static final String BIDDER_CURRENCY = "USD"; + private static final String FORMATTING = "%s-%s"; private final String endpointUrl; private final JacksonMapper mapper; @@ -93,17 +94,16 @@ public Result>> makeHttpRequests(BidRequest request } private static String buildDisplayManagerVersion(BidRequest request) { - final String formatting = "%s-%s"; return Optional.ofNullable(request.getApp()) .map(App::getExt) .map(ExtApp::getPrebid) .filter(prebid -> ObjectUtils.allNotNull(prebid.getSource(), prebid.getVersion())) - .map(prebid -> formatting.formatted(prebid.getSource(), prebid.getVersion())) + .map(prebid -> FORMATTING.formatted(prebid.getSource(), prebid.getVersion())) .orElse(StringUtils.EMPTY); } - private MultiMap resolveHeaders(Device device) { + private static MultiMap resolveHeaders(Device device) { final MultiMap headers = HttpUtil.headers(); if (device != null) { HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER, device.getUa()); diff --git a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java index 1b5f9e9c217..6efeb93d195 100644 --- a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java @@ -134,8 +134,7 @@ public void makeHttpRequestsShouldNotUpdateDisplayManagerVerIfPresent() { ExtAppPrebid.of("source", "version"), null)) .build()), impBuilder -> impBuilder.displaymanagerver("displayManagerVer") - .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) - ); + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity()))))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -159,8 +158,7 @@ public void makeHttpRequestsShouldNotUpdateBannerIfFormatsIsEmpty() { .h(200) .format(Collections.emptyList()) .build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) - ); + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity()))))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -182,8 +180,7 @@ public void makeHttpRequestsShouldUpdateBanner() { impBuilder -> impBuilder.banner(Banner.builder().format(List.of( Format.builder().w(300).h(250).build(), Format.builder().w(1).h(1).build())).build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) - ); + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity()))))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -200,8 +197,7 @@ public void makeHttpRequestsShouldUpdateBanner() { .format(List.of( Format.builder().w(300).h(250).build(), Format.builder().w(1).h(1).build())) - .build() - ); + .build()); } @Test @@ -214,8 +210,7 @@ public void makeHttpRequestsShouldConvertBidFloorWhenNotInBidderCurrency() { impBuilder -> impBuilder .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) .bidfloor(BigDecimal.ONE) - .bidfloorcur("EUR") - ); + .bidfloorcur("EUR")); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -243,8 +238,7 @@ public void makeHttpRequestsShouldSplitRequestIntoMultipleRequests() { .placementId("placement1").build()))), impBuilder -> impBuilder .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpConnatix.builder() - .placementId("placement2").build()))) - ); + .placementId("placement2").build())))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -260,8 +254,7 @@ public void makeHttpRequestsShouldIncludeResolvedHttpHeadersFromDevice() { final BidRequest bidRequest = givenBidRequest( request -> request.device(Device.builder().ip("deviceIp").ipv6("deviceIpv6").ua("userAgent").build()), impBuilder -> impBuilder - .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity())))) - ); + .ext(mapper.valueToTree(ExtPrebid.of(null, givenExt(UnaryOperator.identity()))))); // when final Result>> result = target.makeHttpRequests(bidRequest); @@ -277,8 +270,7 @@ public void makeHttpRequestsShouldIncludeResolvedHttpHeadersFromDevice() { tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "deviceIp"), tuple(HttpUtil.X_FORWARDED_FOR_HEADER.toString(), "deviceIpv6"), tuple(HttpUtil.CONTENT_TYPE_HEADER.toString(), HttpUtil.APPLICATION_JSON_CONTENT_TYPE), - tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString()) - ); + tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString())); } @Test From 555dd267466104f0953bf884cdf7d8962916b783 Mon Sep 17 00:00:00 2001 From: katherynhrabik Date: Thu, 27 Feb 2025 10:28:38 -0500 Subject: [PATCH 10/10] second support-cors --- src/main/resources/bidder-config/connatix.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/bidder-config/connatix.yaml b/src/main/resources/bidder-config/connatix.yaml index 3653e4eb947..e835b1a5d30 100644 --- a/src/main/resources/bidder-config/connatix.yaml +++ b/src/main/resources/bidder-config/connatix.yaml @@ -15,7 +15,7 @@ adapters: iframe: url: "https://capi.connatix.com/us/pixel?pId=53&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&callback={{redirect_url}}" uid-macro: '[UID]' - supportCors: false + support-cors: false redirect: url: "https://capi.connatix.com/us/pixel?pId=52&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&callback={{redirect_url}}" uid-macro: '[UID]'