diff --git a/checkstyle.xml b/checkstyle.xml index b771119cb92..7793047a04f 100644 --- a/checkstyle.xml +++ b/checkstyle.xml @@ -50,9 +50,7 @@ - - - + @@ -147,6 +145,15 @@ - + + + + + + + + + + diff --git a/docs/config-app.md b/docs/config-app.md index b0af4ccb78a..48679890066 100644 --- a/docs/config-app.md +++ b/docs/config-app.md @@ -82,6 +82,9 @@ Removes and downloads file again if depending service cant process probably corr - `cookie-sync.coop-sync.default` - default value for coopSync when it missing in requests to `/cookie_sync` endpoint. - `cookie-sync.coop-sync.pri` - lists of bidders prioritised in groups. +## Vtrack +- `vtrack.allow-unkonwn-bidder` - flag allows servicing requests with bidders who were not configured in Prebid Server. + ## Adapters - `adapters.*` - the section for bidder specific configuration options. @@ -198,6 +201,8 @@ For caching available next options: - `settings.in-memory-cache.cache-size` - the size of LRU cache. - `settings.in-memory-cache.notification-endpoints-enabled` - if equals to `true` two additional endpoints will be available: [/storedrequests/openrtb2](endpoints/storedrequests/openrtb2.md) and [/storedrequests/amp](endpoints/storedrequests/amp.md). +- `settings.in-memory-cache.account-invalidation-enabled` - if equals to `true` additional admin protected endpoints will be +available: `/cache/invalidate?account={accountId}` which remove account from the cache. - `settings.in-memory-cache.http-update.endpoint` - the url to fetch stored request updates. - `settings.in-memory-cache.http-update.amp-endpoint` - the url to fetch AMP stored request updates. - `settings.in-memory-cache.http-update.refresh-rate` - refresh period in ms for stored request updates. @@ -240,9 +245,16 @@ If not defined in config all other Health Checkers would be disabled and endpoin - `gdpr.eea-countries` - comma separated list of countries in European Economic Area (EEA). - `gdpr.default-value` - determines GDPR in scope default value (if no information in request and no geolocation data). - `gdpr.host-vendor-id` - the organization running a cluster of Prebid Servers. -- `gdpr.vendorlist.http-endpoint-template` - template string for vendor list url, where `{VERSION}` is used as version number placeholder. -- `gdpr.vendorlist.http-default-timeout-ms` - default operation timeout for obtaining new vendor list. -- `gdpr.vendorlist.filesystem-cache-dir` - directory for local storage cache for vendor list. Should be with `WRITE` permissions for user application run from. +- `gdpr.enabled` - gdpr feature switch. Default `true`. +- `gdpr.purposes.pN.enforce-purpose` - define type of enforcement confirmation: `no`/`basic`/`full`. Default `full` +- `gdpr.purposes.pN.enforce-vendors` - if equals to `true`, user must give consent to use vendors. Purposes will be omitted. Default `true` +- `gdpr.purposes.pN.vendor-exceptions[]` - bidder names that will be treated opposite to `pN.enforce-vendors` value. +- `gdpr.special-features.sfN.enforce` - if equals to `true`, special feature will be enforced for purpose. Default `true` +- `gdpr.special-features.sfN.vendor-exceptions[]` - bidder names that will be treated opposite to `sfN.enforce` value. +- `gdpr.purpose-one-treatment-interpretation` - option that allows to skip the Purpose one enforcement workflow. +- `gdpr.vendorlist.vN.http-endpoint-template` - template string for vendor list url, where `{VERSION}` is used as version number placeholder. +- `gdpr.vendorlist.vN.http-default-timeout-ms` - default operation timeout for obtaining new vendor list. +- `gdpr.vendorlist.vN.cache-dir` - directory for local storage cache for vendor list. Should be with `WRITE` permissions for user application run from. ## CCPA - `ccpa.enforce` - if equals to `true` enforces to check ccpa policy, otherwise ignore ccpa verification. diff --git a/docs/endpoints/openrtb2/amp.md b/docs/endpoints/openrtb2/amp.md index 159fe9ebd6d..ce5a6cdb902 100644 --- a/docs/endpoints/openrtb2/amp.md +++ b/docs/endpoints/openrtb2/amp.md @@ -28,6 +28,16 @@ An example Stored Request is given below: }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { // This is equivalent to the deprecated "pricegranularity": "medium" "precision": 2, diff --git a/docs/endpoints/openrtb2/auction.md b/docs/endpoints/openrtb2/auction.md index 61a102670a1..6f77d3d232f 100644 --- a/docs/endpoints/openrtb2/auction.md +++ b/docs/endpoints/openrtb2/auction.md @@ -127,10 +127,16 @@ Bidders [are encouraged](../../developers/add-new-bidder.md) to make Net bids. H If you find that some bidders use Gross bids, publishers can adjust for it with `request.ext.prebid.bidadjustmentfactors`: ``` - { - "appnexus: 0.8, - "rubicon": 0.7 - } +{ + "ext": { + "prebid": { + "bidadjustmentfactors": { + "appnexus: 0.8, + "rubicon": 0.7 + } + } + } +} ``` This may also be useful for publishers who want to account for different discrepancies with different bidders. @@ -147,27 +153,21 @@ to set these params on the response at `response.seatbid[i].bid[j].ext.prebid.ta ``` { - "pricegranularity": { - "precision": 2, - "ranges": [ - { - "max": 20.00, - "increment": 0.10 // This is equivalent to the deprecated "pricegranularity": "medium" - } - ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 + "ext": { + "prebid": { + "targeting": { + "pricegranularity": { + "precision": 2, + "ranges": [{ + "max":20.00, + "increment":0.10 // This is equivalent to the deprecated "pricegranularity": "medium" + }] + }, + "includewinners": false, // Optional param defaulting to true + "includebidderkeys": false // Optional param defaulting to true } } - }, - "includewinners": false, // Optional param defaulting to true - "includebidderkeys": false // Optional param defaulting to true + } } ``` @@ -184,6 +184,16 @@ MediaType PriceGranularity - when a single OpenRTB request contains multiple imp ``` "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "mediatypepricegranularity": { "banner": { "ranges": [ @@ -205,9 +215,20 @@ MediaType PriceGranularity - when a single OpenRTB request contains multiple imp ``` { - "hb_bidder_{bidderName}": "The seatbid.seat which contains this bid", - "hb_size_{bidderName}": "A string like '300x250' using bid.w and bid.h for this bid", - "hb_pb_{bidderName}": "The bid.cpm, rounded down based on the price granularity." + "seatbid": [{ + "bid": [{ + ... + "ext": { + "prebid": { + "targeting": { + "hb_bidder_{bidderName}": "The seatbid.seat which contains this bid", + "hb_size_{bidderName}": "A string like '300x250' using bid.w and bid.h for this bid", + "hb_pb_{bidderName}": "The bid.cpm, rounded down based on the price granularity." + } + } + } + }] + }] } ``` @@ -226,8 +247,16 @@ In most cases, this is probably a bad idea. ``` { - "appnexus": "some-appnexus-id", - "rubicon": "some-rubicon-id" + "user": { + "ext": { + "prebid": { + "buyeruids": { + "appnexus": "some-appnexus-id", + "rubicon": "some-rubicon-id" + } + } + } + } } ``` @@ -288,11 +317,9 @@ This prevents breaking API changes as new Bidders are added to the project. For example, if the Request defines an alias like this: ``` -{ "aliases": { "appnexus": "rubicon" } -} ``` then any `imp.ext.appnexus` params will actually go to the **rubicon** adapter. @@ -316,19 +343,17 @@ For example, a request may return this in `response.ext` ``` { - "errors": { - "appnexus": [ - { - "code": 2, - "message": "A hybrid Banner/Audio Imp was offered, but Appnexus doesn't support Audio." - } - ], - "rubicon": [ - { - "code": 1, - "message: "The request exceeded the timeout allocated" - } - ] + "ext": { + "errors": { + "appnexus": [{ + "code": 2, + "message": "A hybrid Banner/Audio Imp was offered, but Appnexus doesn't support Audio." + }], + "rubicon": [{ + "code": 1, + "message": "The request exceeded the timeout allocated" + }] + } } } ``` @@ -362,7 +387,15 @@ A typical `storedrequest` value looks like this: ``` { - "id": "some-id" + "imp": [{ + "ext": { + "prebid": { + "storedrequest": { + "id": "some-id" + } + } + } + }] } ``` @@ -374,13 +407,19 @@ Bids can be temporarily cached on the server by sending the following data as `r ``` { - "bids": {}, - "vastxml": {} + "ext": { + "prebid": { + "cache": { + "bids": {}, + "vastxml": {} + } + } + } } ``` -Both `bids` and `vastxml` are optional, but one of the two is required. -This property will have no effect unless `request.ext.prebid.targeting` is also set in the request. +Both `bids` and `vastxml` are optional, but one of the two is required if you want to cache bids. This property will have no effect +unless `request.ext.prebid.targeting` is also set in the request. If `bids` is present, Prebid Server will make a _best effort_ to include these extra `bid.ext.prebid.targeting` keys: @@ -451,6 +490,37 @@ Example: PBS receiving a request for an interstitial imp and these parameters set, it will rewrite the format object within the interstitial imp. If the format array's first object is a size, PBS will take it as the max size for the interstitial. If that size is 1x1, it will look up the device's size and use that as the max size. If the format is not present, it will also use the device size as the max size. (1x1 support so that you don't have to omit the format object to use the device size) PBS with interstitial support will come preconfigured with a list of common ad sizes. Preferentially organized by weighing the larger and more common sizes first. But no guarantees to the ordering will be made. PBS will generate a new format list for the interstitial imp by traversing this list and picking the first 10 sizes that fall within the imp's max size and minimum percentage size. There will be no attempt to favor aspect ratios closer to the original size's aspect ratio. The limit of 10 is enforced to ensure we don't overload bidders with an overlong list. All the interstitial parameters will still be passed to the bidders, so they may recognize them and use their own size matching algorithms if they prefer. +#### Currency Support + +To set the desired 'ad server currency', use the standard OpenRTB `cur` attribute. Note that Prebid Server only looks at the first currency in the array. + +``` + "cur": ["USD"] +``` + +If you want or need to define currency conversion rates (e.g. for currencies that your Prebid Server doesn't support), +define ext.prebid.currency.rates. (Currently supported in PBS-Java only) + +``` +"ext": { + "prebid": { + "currency": { + "rates": { + "USD": { "UAH": 24.47, "ETB": 32.04 } + } + } + } +} +``` + +If it exists, a rate defined in ext.prebid.currency.rates has the highest priority. +If a currency rate doesn't exist in the request, the external file will be used. + +#### Rewarded Video (PBS-Java only) + +Rewarded video is a way to incentivize users to watch ads by giving them 'points' for viewing an ad. A Prebid Server +client can declare a given adunit as eligible for rewards by declaring `imp.ext.prebid.is_rewarded_inventory:1`. + #### Stored Responses While testing SDK and video integrations, it's important, but often difficult, to get consistent responses back from bidders that cover a range of scenarios like different CPM values, deals, etc. Prebid Server supports a debugging workflow in two ways: @@ -615,33 +685,33 @@ It specifies where in the OpenRTB request non-standard attributes should be pass ``` { - ext: { - prebid: { - data: { bidders: [ 'rubicon', 'appnexus' ] } // these are the bidders allowed to see protected data + "ext": { + "prebid": { + "data": { "bidders": [ "rubicon", "appnexus" ] } // these are the bidders allowed to see protected data } }, - site: { - keywords: "", - search: "", - ext: { + "site": { + "keywords": "", + "search": "", + "ext": { data: { GLOBAL CONTEXT DATA } // only seen by bidders named in ext.prebid.data.bidders[] } }, - user: { - keywords: "", - gender: "", - yob: 1999, - geo: {}, - ext: { + "user": { + "keywords": "", + "gender": "", + "yob": 1999, + "geo": {}, + "ext": { data: { GLOBAL USER DATA } // only seen by bidders named in ext.prebid.data.bidders[] } }, - imp: [ - ext: { - context: { - keywords: "", - search: "", - data: { ADUNIT SPECFIC CONTEXT DATA } // can be seen by all bidders + "imp": [ + "ext": { + "context": { + "keywords": "", + "search": "", + "data": { ADUNIT SPECFIC CONTEXT DATA } // can be seen by all bidders } } ] diff --git a/docs/metrics.md b/docs/metrics.md index 51947e93288..90920f21499 100644 --- a/docs/metrics.md +++ b/docs/metrics.md @@ -60,6 +60,7 @@ Following metrics are collected and submitted if account is configured with `det - `account...request_time` - timer tracking how long did it take to make a request to `` when incoming request was from `` - `account...bids_received` - number of bids received from `` when incoming request was from `` - `account...requests.(gotbids|nobid)` - number of requests made to `` broken down by result status when incoming request was from `` +- `account..requests.rejected` - number of rejected requests caused by incorrect `accountId` ([UnauthorizedAccountException.java](https://github.com/rubicon-project/prebid-server-java/blob/master/src/main/java/org/prebid/server/exception/UnauthorizedAccountException.java)) ## /cookie_sync endpoint metrics - `cookie_sync_requests` - number of requests received diff --git a/pom.xml b/pom.xml index be401a6abc0..73ab59603b3 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.prebid prebid-server - 1.29.0-SNAPSHOT + 1.34.0-SNAPSHOT prebid-server Prebid Server (Server-side Header Bidding) @@ -15,8 +15,8 @@ scm:git:git@github.com:rubicon-project/prebid-server-java.git - HEAD - + HEAD + UTF-8 @@ -29,7 +29,7 @@ 1.3.1 2.0.1.Final 6.1.0.Final - 3.7.1 + 3.8.3 1.18.4 3.6 4.1 @@ -45,6 +45,7 @@ 4.0.3 1.2.2 2.0.2 + 2.0.0-alpha.0 0.5.0 2.12.0 @@ -247,6 +248,11 @@ consent-string-sdk-java ${consent-string-sdk.version} + + com.iabtcf + iabtcf-core + ${iab-tcf} + io.prometheus simpleclient_vertx @@ -345,6 +351,7 @@ true false + true diff --git a/sample/prebid-config.yaml b/sample/prebid-config.yaml index 88f900393fb..9805562e9d7 100644 --- a/sample/prebid-config.yaml +++ b/sample/prebid-config.yaml @@ -18,5 +18,8 @@ settings: stored-responses-dir: /var/tmp gdpr: vendorlist: - filesystem-cache-dir: /var/tmp + v1: + cache-dir: /var/tmp/vendor1 + v2: + cache-dir: /var/tmp/vendor2 status-response: "ok" diff --git a/src/main/java/com/iab/openrtb/request/Video.java b/src/main/java/com/iab/openrtb/request/Video.java index 672782d8575..3cf7908f3e1 100644 --- a/src/main/java/com/iab/openrtb/request/Video.java +++ b/src/main/java/com/iab/openrtb/request/Video.java @@ -30,10 +30,14 @@ public class Video { */ List mimes; - /** Minimum video ad duration in seconds. (recommended) */ + /** + * Minimum video ad duration in seconds. (recommended) + */ Integer minduration; - /** Maximum video ad duration in seconds. (recommended) */ + /** + * Maximum video ad duration in seconds. (recommended) + */ Integer maxduration; /** @@ -62,7 +66,9 @@ public class Video { */ Integer startdelay; - /** Placement type for the impression. Refer to List 5.9. */ + /** + * Placement type for the impression. Refer to List 5.9. + */ Integer placement; /** @@ -83,13 +89,13 @@ public class Video { * Videos of total duration greater than this number of seconds can be * skippable; only applicable if the ad is skippable. */ - int skipmin; + Integer skipmin; /** * Number of seconds a video must play before skipping is enabled; only * applicable if the ad is skippable. */ - int skipafter; + Integer skipafter; /** * If multiple ad impressions are offered in the same bid request, the @@ -98,7 +104,9 @@ public class Video { */ Integer sequence; - /** Blocked creative attributes. Refer to List 5.3. */ + /** + * Blocked creative attributes. Refer to List 5.3. + */ List battr; /** @@ -110,10 +118,14 @@ public class Video { */ Integer maxextended; - /** Minimum bit rate in Kbps. */ + /** + * Minimum bit rate in Kbps. + */ Integer minbitrate; - /** Maximum bit rate in Kbps. */ + /** + * Maximum bit rate in Kbps. + */ Integer maxbitrate; /** @@ -131,7 +143,9 @@ public class Video { */ List playbackmethod; - /** The event that causes playback to end. Refer to List 5.11. */ + /** + * The event that causes playback to end. Refer to List 5.11. + */ Integer playbackend; /** @@ -140,10 +154,14 @@ public class Video { */ List delivery; - /** Ad position on screen. Refer to List 5.4. */ + /** + * Ad position on screen. Refer to List 5.4. + */ Integer pos; - /** Array of Banner objects (Section 3.2.6) if companion ads are available. */ + /** + * Array of Banner objects (Section 3.2.6) if companion ads are available. + */ List companionad; /** @@ -161,6 +179,8 @@ public class Video { */ List companiontype; - /** Placeholder for exchange-specific extensions to OpenRTB. */ + /** + * Placeholder for exchange-specific extensions to OpenRTB. + */ ObjectNode ext; } diff --git a/src/main/java/com/iab/openrtb/response/BidResponse.java b/src/main/java/com/iab/openrtb/response/BidResponse.java index 3065fb8b521..5fea1597e02 100644 --- a/src/main/java/com/iab/openrtb/response/BidResponse.java +++ b/src/main/java/com/iab/openrtb/response/BidResponse.java @@ -7,8 +7,6 @@ import java.util.Comparator; import java.util.List; -import static java.util.Objects.isNull; - /** * This object is the top-level bid response object (i.e., the unnamed outer * JSON object). The {@code id} attribute is a reflection of the bid request ID @@ -65,7 +63,7 @@ public class BidResponse { ObjectNode ext; public static final Comparator COMPARATOR = (left, right) -> { - if (isNull(left)) { + if (left == null) { return -1; } if (left.getSeatbid().isEmpty()) { @@ -74,7 +72,7 @@ public class BidResponse { if (left.getSeatbid().get(0).getBid().isEmpty()) { return -1; } - if (isNull(right)) { + if (right == null) { return -1; } if (right.getSeatbid().isEmpty()) { diff --git a/src/main/java/org/prebid/server/analytics/AnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/AnalyticsReporter.java index be76ae5fc95..58888228a99 100644 --- a/src/main/java/org/prebid/server/analytics/AnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/AnalyticsReporter.java @@ -3,6 +3,7 @@ /** * Type of component that does transactional logging. */ +@FunctionalInterface public interface AnalyticsReporter { /** diff --git a/src/main/java/org/prebid/server/analytics/model/NotificationEvent.java b/src/main/java/org/prebid/server/analytics/model/NotificationEvent.java index ad50bd63ee0..770e877346e 100644 --- a/src/main/java/org/prebid/server/analytics/model/NotificationEvent.java +++ b/src/main/java/org/prebid/server/analytics/model/NotificationEvent.java @@ -17,6 +17,10 @@ public class NotificationEvent { Account account; + String bidder; + + Long timestamp; + HttpContext httpContext; public enum Type { diff --git a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java index 11978fae62c..04761b2b744 100644 --- a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java @@ -21,7 +21,6 @@ import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.request.ExtBidRequest; -import org.prebid.server.proto.openrtb.ext.request.ExtCurrency; import org.prebid.server.proto.openrtb.ext.request.ExtMediaTypePriceGranularity; import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; @@ -512,8 +511,6 @@ private ExtRequestTargeting createTargetingWithDefaults(ExtRequestPrebid prebid) final ExtMediaTypePriceGranularity mediaTypePriceGranularity = isTargetingNull ? null : targeting.getMediatypepricegranularity(); - final ExtCurrency currency = isTargetingNull ? null : targeting.getCurrency(); - final boolean includeWinners = isTargetingNull || targeting.getIncludewinners() == null || targeting.getIncludewinners(); @@ -523,7 +520,6 @@ private ExtRequestTargeting createTargetingWithDefaults(ExtRequestPrebid prebid) return ExtRequestTargeting.builder() .pricegranularity(outgoingPriceGranularityNode) .mediatypepricegranularity(mediaTypePriceGranularity) - .currency(currency) .includewinners(includeWinners) .includebidderkeys(includeBidderKeys) .build(); diff --git a/src/main/java/org/prebid/server/auction/AmpResponsePostProcessor.java b/src/main/java/org/prebid/server/auction/AmpResponsePostProcessor.java index ebea1434c1d..1fce5be513e 100644 --- a/src/main/java/org/prebid/server/auction/AmpResponsePostProcessor.java +++ b/src/main/java/org/prebid/server/auction/AmpResponsePostProcessor.java @@ -10,6 +10,7 @@ * A hook that is pulled prior sending the AMP RTC response back to the client. * It allows companies that host Prebid Server to add custom key values in the AMP RTC response. */ +@FunctionalInterface public interface AmpResponsePostProcessor { /** diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index 2cde4c69bc0..828a0566065 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -31,6 +31,7 @@ import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.log.ConditionalLogger; import org.prebid.server.proto.openrtb.ext.request.ExtBidRequest; import org.prebid.server.proto.openrtb.ext.request.ExtMediaTypePriceGranularity; import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity; @@ -45,6 +46,7 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.settings.ApplicationSettings; import org.prebid.server.settings.model.Account; +import org.prebid.server.util.HttpUtil; import org.prebid.server.validation.RequestValidator; import org.prebid.server.validation.model.ValidationResult; @@ -68,6 +70,8 @@ public class AuctionRequestFactory { private static final Logger logger = LoggerFactory.getLogger(AuctionRequestFactory.class); + private static final ConditionalLogger EMPTY_ACCOUNT_LOGGER = new ConditionalLogger("empty_account", logger); + private static final ConditionalLogger UNKNOWN_ACCOUNT_LOGGER = new ConditionalLogger("unknown_account", logger); private final long maxRequestSize; private final boolean enforceValidAccount; @@ -161,7 +165,7 @@ Future toAuctionContext(RoutingContext routingContext, BidReques long startTime, TimeoutResolver timeoutResolver) { final Timeout timeout = timeout(bidRequest, startTime, timeoutResolver); - return accountFrom(bidRequest, timeout) + return accountFrom(bidRequest, timeout, routingContext) .map(account -> AuctionContext.builder() .routingContext(routingContext) .uidsCookie(uidsCookieService.parseFromRequest(routingContext)) @@ -487,7 +491,6 @@ private ExtRequestTargeting targetingOrNull(ExtRequestPrebid prebid, Set accountFrom(BidRequest bidRequest, Timeout timeout) { + private Future accountFrom(BidRequest bidRequest, Timeout timeout, RoutingContext routingContext) { final String accountId = accountIdFrom(bidRequest); final boolean blankAccountId = StringUtils.isBlank(accountId); @@ -658,19 +661,9 @@ private Future accountFrom(BidRequest bidRequest, Timeout timeout) { } return blankAccountId - ? responseToMissingAccount(accountId) + ? responseForEmptyAccount(routingContext) : applicationSettings.getAccountById(accountId, timeout) - .recover(exception -> accountFallback(exception, responseToMissingAccount(accountId))); - } - - /** - * Returns response depending on enforceValidAccount flag. - */ - private Future responseToMissingAccount(String accountId) { - return enforceValidAccount - ? Future.failedFuture(new UnauthorizedAccountException( - String.format("Unauthorised account id %s", accountId), accountId)) - : Future.succeededFuture(emptyAccount(accountId)); + .recover(exception -> accountFallback(exception, accountId, routingContext)); } /** @@ -683,7 +676,7 @@ private String accountIdFrom(BidRequest bidRequest) { final Site site = bidRequest.getSite(); final Publisher sitePublisher = site != null ? site.getPublisher() : null; - final Publisher publisher = ObjectUtils.firstNonNull(appPublisher, sitePublisher); + final Publisher publisher = ObjectUtils.defaultIfNull(appPublisher, sitePublisher); final String publisherId = publisher != null ? resolvePublisherId(publisher) : null; return ObjectUtils.defaultIfNull(publisherId, StringUtils.EMPTY); } @@ -716,21 +709,34 @@ private String parentAccountIdFromExtPublisher(ObjectNode extPublisherNode) { return extPublisherPrebid != null ? StringUtils.stripToNull(extPublisherPrebid.getParentAccount()) : null; } - /** - * Log any not {@link PreBidException} errors. Returns response provided in method parameters. - */ - private static Future accountFallback(Throwable exception, Future response) { - if (!(exception instanceof PreBidException)) { + private Future responseForEmptyAccount(RoutingContext routingContext) { + EMPTY_ACCOUNT_LOGGER.warn(accountErrorMessage("Account not specified", routingContext), 100); + return responseForUnknownAccount(StringUtils.EMPTY); + } + + private static String accountErrorMessage(String message, RoutingContext routingContext) { + final HttpServerRequest request = routingContext.request(); + return String.format("%s, Url: %s and Referer: %s", message, request.absoluteURI(), + request.headers().get(HttpUtil.REFERER_HEADER)); + } + + private Future accountFallback(Throwable exception, String accountId, + RoutingContext routingContext) { + if (exception instanceof PreBidException) { + UNKNOWN_ACCOUNT_LOGGER.warn(accountErrorMessage(exception.getMessage(), routingContext), 100); + } else { logger.warn("Error occurred while fetching account: {0}", exception.getMessage()); logger.debug("Error occurred while fetching account", exception); } - return response; + + // hide all errors occurred while fetching account + return responseForUnknownAccount(accountId); } - /** - * Creates {@link Account} instance with filled out ID field only. - */ - private static Account emptyAccount(String accountId) { - return Account.builder().id(accountId).build(); + private Future responseForUnknownAccount(String accountId) { + return enforceValidAccount + ? Future.failedFuture(new UnauthorizedAccountException( + String.format("Unauthorised account id %s", accountId), accountId)) + : Future.succeededFuture(Account.empty(accountId)); } } diff --git a/src/main/java/org/prebid/server/auction/BidResponseCreator.java b/src/main/java/org/prebid/server/auction/BidResponseCreator.java index 3e745ed3ad6..32642bbd115 100644 --- a/src/main/java/org/prebid/server/auction/BidResponseCreator.java +++ b/src/main/java/org/prebid/server/auction/BidResponseCreator.java @@ -33,6 +33,7 @@ import org.prebid.server.cache.model.CacheHttpResponse; import org.prebid.server.cache.model.CacheIdInfo; import org.prebid.server.cache.model.CacheServiceResult; +import org.prebid.server.events.EventsContext; import org.prebid.server.events.EventsService; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.PreBidException; @@ -51,6 +52,7 @@ import org.prebid.server.proto.openrtb.ext.response.Events; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidderError; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; @@ -84,13 +86,13 @@ public class BidResponseCreator { private final CacheService cacheService; private final BidderCatalog bidderCatalog; private final EventsService eventsService; + private final StoredRequestProcessor storedRequestProcessor; private final JacksonMapper mapper; + private final Boolean generateBidId; private final String cacheHost; private final String cachePath; private final String cacheAssetUrlTemplate; - private final StoredRequestProcessor storedRequestProcessor; - private final Boolean generateBidId; public BidResponseCreator(CacheService cacheService, BidderCatalog bidderCatalog, EventsService eventsService, StoredRequestProcessor storedRequestProcessor, @@ -98,12 +100,13 @@ public BidResponseCreator(CacheService cacheService, BidderCatalog bidderCatalog this.cacheService = Objects.requireNonNull(cacheService); this.bidderCatalog = Objects.requireNonNull(bidderCatalog); this.eventsService = Objects.requireNonNull(eventsService); - this.cacheHost = Objects.requireNonNull(cacheService.getEndpointHost()); - this.cachePath = Objects.requireNonNull(cacheService.getEndpointPath()); - this.cacheAssetUrlTemplate = Objects.requireNonNull(cacheService.getCachedAssetURLTemplate()); this.storedRequestProcessor = Objects.requireNonNull(storedRequestProcessor); this.mapper = Objects.requireNonNull(mapper); this.generateBidId = generateBidId; + + cacheHost = Objects.requireNonNull(cacheService.getEndpointHost()); + cachePath = Objects.requireNonNull(cacheService.getEndpointPath()); + cacheAssetUrlTemplate = Objects.requireNonNull(cacheService.getCachedAssetURLTemplate()); } /** @@ -112,7 +115,8 @@ public BidResponseCreator(CacheService cacheService, BidderCatalog bidderCatalog */ Future create(List bidderResponses, BidRequest bidRequest, ExtRequestTargeting targeting, BidRequestCacheInfo cacheInfo, Account account, - Timeout timeout, boolean debugEnabled) { + boolean eventsAllowedByRequest, long auctionTimestamp, boolean debugEnabled, + Timeout timeout) { final Future result; @@ -123,7 +127,8 @@ Future create(List bidderResponses, BidRequest bidR .nbr(0) // signal "Unknown Error" .seatbid(Collections.emptyList()) .ext(mapper.mapper().valueToTree(toExtBidResponse(bidderResponses, bidRequest, - CacheServiceResult.empty(), VideoStoredDataResult.empty(), debugEnabled, null))) + CacheServiceResult.empty(), VideoStoredDataResult.empty(), auctionTimestamp, debugEnabled, + null))) .build()); } else { final Set winningBids = newOrEmptySet(targeting); @@ -138,11 +143,12 @@ Future create(List bidderResponses, BidRequest bidR ? winningBids : bidderResponses.stream().flatMap(BidResponseCreator::getBids).collect(Collectors.toSet()); - result = toBidsWithCacheIds(bidderResponses, bidsToCache, bidRequest.getImp(), cacheInfo, account, timeout) + result = toBidsWithCacheIds(bidderResponses, bidsToCache, bidRequest.getImp(), cacheInfo, account, timeout, + auctionTimestamp) .compose(cacheResult -> videoStoredDataResult(bidRequest.getImp(), timeout) .map(videoStoredDataResult -> toBidResponse(bidderResponses, bidRequest, targeting, winningBids, winningBidsByBidder, cacheInfo, cacheResult, videoStoredDataResult, - account, debugEnabled))); + account, eventsAllowedByRequest, auctionTimestamp, debugEnabled))); } return result; @@ -163,7 +169,8 @@ private static boolean isEmptyBidderResponses(List bidderRespons */ private ExtBidResponse toExtBidResponse(List bidderResponses, BidRequest bidRequest, CacheServiceResult cacheResult, VideoStoredDataResult videoStoredDataResult, - boolean debugEnabled, Map> bidErrors) { + long auctionTimestamp, boolean debugEnabled, + Map> bidErrors) { final ExtResponseDebug extResponseDebug = debugEnabled ? ExtResponseDebug.of(toExtHttpCalls(bidderResponses, cacheResult), bidRequest) @@ -172,7 +179,8 @@ private ExtBidResponse toExtBidResponse(List bidderResponses, Bi toExtBidderErrors(bidderResponses, bidRequest, cacheResult, videoStoredDataResult, bidErrors); final Map responseTimeMillis = toResponseTimes(bidderResponses, cacheResult); - return ExtBidResponse.of(extResponseDebug, errors, responseTimeMillis, bidRequest.getTmax(), null); + return ExtBidResponse.of(extResponseDebug, errors, responseTimeMillis, bidRequest.getTmax(), null, + ExtBidResponsePrebid.of(auctionTimestamp)); } /** @@ -263,7 +271,7 @@ private static Stream getBids(BidderResponse bidderResponse) { */ private Future toBidsWithCacheIds(List bidderResponses, Set bidsToCache, List imps, BidRequestCacheInfo cacheInfo, - Account account, Timeout timeout) { + Account account, Timeout timeout, Long auctionTimestamp) { final Future result; if (!cacheInfo.isDoCaching()) { @@ -277,32 +285,42 @@ private Future toBidsWithCacheIds(List bidde final boolean shouldCacheVideoBids = cacheInfo.isShouldCacheVideoBids(); final boolean eventsEnabled = Objects.equals(account.getEventsEnabled(), true); - final List videoBidIdsToModify = shouldCacheVideoBids && eventsEnabled - ? getVideoBidIdsToModify(bidderResponses, imps) - : Collections.emptyList(); + final Map> bidderToVideoBidIdsToModify = shouldCacheVideoBids && eventsEnabled + ? getBidderAndVideoBidIdsToModify(bidderResponses, imps) + : Collections.emptyMap(); + final Map> bidderToBidIds = bidderResponses.stream() + .collect(Collectors.toMap(BidderResponse::getBidder, bidderResponse -> getBids(bidderResponse) + .map(Bid::getId) + .collect(Collectors.toList()))); final CacheContext cacheContext = CacheContext.builder() .cacheBidsTtl(cacheInfo.getCacheBidsTtl()) .cacheVideoBidsTtl(cacheInfo.getCacheVideoBidsTtl()) .shouldCacheBids(cacheInfo.isShouldCacheBids()) .shouldCacheVideoBids(shouldCacheVideoBids) - .videoBidIdsToModify(videoBidIdsToModify) + .bidderToVideoBidIdsToModify(bidderToVideoBidIdsToModify) + .bidderToBidIds(bidderToBidIds) + .build(); + + final EventsContext eventsContext = EventsContext.builder() + .auctionTimestamp(auctionTimestamp) .build(); - result = cacheService.cacheBidsOpenrtb(bidsWithNonZeroPrice, imps, cacheContext, account, timeout) + result = cacheService.cacheBidsOpenrtb(bidsWithNonZeroPrice, imps, cacheContext, account, eventsContext, + timeout) .map(cacheResult -> addNotCachedBids(cacheResult, bidsToCache)); } - return result; } - private List getVideoBidIdsToModify(List bidderResponses, List imps) { + private Map> getBidderAndVideoBidIdsToModify(List bidderResponses, + List imps) { return bidderResponses.stream() .filter(bidderResponse -> bidderCatalog.isModifyingVastXmlAllowed(bidderResponse.getBidder())) - .flatMap(BidResponseCreator::getBids) - .filter(bid -> isVideoBid(bid, imps)) - .map(Bid::getId) - .collect(Collectors.toList()); + .collect(Collectors.toMap(BidderResponse::getBidder, bidderResponse -> getBids(bidderResponse) + .filter(bid -> isVideoBid(bid, imps)) + .map(Bid::getId) + .collect(Collectors.toList()))); } private static boolean isVideoBid(Bid bid, List imps) { @@ -431,7 +449,6 @@ private static Map> extractPrebidErrors(CacheServic final List collectedErrors = Stream.concat(storedErrors.stream(), cacheErrors.stream()) .collect(Collectors.toList()); - return Collections.singletonMap(PREBID_EXT, collectedErrors); } @@ -504,19 +521,18 @@ private BidResponse toBidResponse( List bidderResponses, BidRequest bidRequest, ExtRequestTargeting targeting, Set winningBids, Set winningBidsByBidder, BidRequestCacheInfo cacheInfo, CacheServiceResult cacheResult, VideoStoredDataResult videoStoredDataResult, Account account, - boolean debugEnabled) { + boolean eventsAllowedByRequest, long auctionTimestamp, boolean debugEnabled) { final Map> bidErrors = new HashMap<>(); final List seatBids = bidderResponses.stream() .filter(bidderResponse -> !bidderResponse.getSeatBid().getBids().isEmpty()) .map(bidderResponse -> toSeatBid(bidderResponse, targeting, bidRequest, winningBids, winningBidsByBidder, cacheInfo, cacheResult.getCacheBids(), videoStoredDataResult, account, - bidErrors)) + eventsAllowedByRequest, bidErrors, auctionTimestamp)) .collect(Collectors.toList()); - final ExtBidResponse extBidResponse = - toExtBidResponse(bidderResponses, bidRequest, cacheResult, videoStoredDataResult, - debugEnabled, bidErrors); + final ExtBidResponse extBidResponse = toExtBidResponse(bidderResponses, bidRequest, cacheResult, + videoStoredDataResult, auctionTimestamp, debugEnabled, bidErrors); return BidResponse.builder() .id(bidRequest.getId()) @@ -570,12 +586,15 @@ private boolean checkEchoVideoAttrs(Imp imp) { private SeatBid toSeatBid(BidderResponse bidderResponse, ExtRequestTargeting targeting, BidRequest bidRequest, Set winningBids, Set winningBidsByBidder, BidRequestCacheInfo cacheInfo, Map cachedBids, VideoStoredDataResult videoStoredDataResult, - Account account, Map> bidErrors) { + Account account, boolean eventsAllowedByRequest, + Map> bidErrors, long auctionTimestamp) { + final String bidder = bidderResponse.getBidder(); final List bids = bidderResponse.getSeatBid().getBids().stream() .map(bidderBid -> toBid(bidderBid, bidder, targeting, bidRequest, winningBids, winningBidsByBidder, - cacheInfo, cachedBids, videoStoredDataResult.getImpIdToStoredVideo(), account, bidErrors)) + cacheInfo, cachedBids, videoStoredDataResult.getImpIdToStoredVideo(), account, + eventsAllowedByRequest, auctionTimestamp, bidErrors)) .filter(Objects::nonNull) .collect(Collectors.toList()); @@ -592,6 +611,7 @@ private SeatBid toSeatBid(BidderResponse bidderResponse, ExtRequestTargeting tar private Bid toBid(BidderBid bidderBid, String bidder, ExtRequestTargeting targeting, BidRequest bidRequest, Set winningBids, Set winningBidsByBidder, BidRequestCacheInfo cacheInfo, Map bidsWithCacheIds, Map impIdToStoredVideo, Account account, + boolean eventsAllowedByRequest, long auctionTimestamp, Map> bidErrors) { final Bid bid = bidderBid.getBid(); @@ -629,7 +649,7 @@ private Bid toBid(BidderBid bidderBid, String bidder, ExtRequestTargeting target keywordsCreatorByBidType(targeting, isApp); final boolean isWinningBid = winningBids.contains(bid); final String winUrl = eventsEnabled && bidType != BidType.video - ? HttpUtil.encodeUrl(eventsService.winUrlTargeting(account.getId())) + ? HttpUtil.encodeUrl(eventsService.winUrlTargeting(bidder, account.getId(), auctionTimestamp)) : null; targetingKeywords = keywordsCreatorByBidType.getOrDefault(bidType, keywordsCreator) .makeFor(bid, bidder, isWinningBid, cacheId, videoCacheId, cacheHost, cachePath, winUrl); @@ -645,7 +665,9 @@ private Bid toBid(BidderBid bidderBid, String bidder, ExtRequestTargeting target final String extBidPrebidId = BooleanUtils.toBoolean(this.generateBidId) ? UUID.randomUUID().toString() : null; final String eventId = BooleanUtils.toBoolean(this.generateBidId) ? extBidPrebidId : bid.getId(); final Video storedVideo = impIdToStoredVideo.get(bid.getImpid()); - final Events events = eventsEnabled ? eventsService.createEvent(eventId, account.getId()) : null; + final Events events = eventsEnabled && eventsAllowedByRequest + ? eventsService.createEvent(eventId, bidder, account.getId(), auctionTimestamp) + : null; final ExtBidPrebid prebidExt = ExtBidPrebid.of( extBidPrebidId, bidType, targetingKeywords, cache, storedVideo, events, null @@ -713,13 +735,12 @@ private static com.iab.openrtb.request.Asset getAssetById(int assetId, /** * Extracts targeting keywords settings from the bid request and creates {@link TargetingKeywordsCreator} * instance if it is present. - *

*/ private TargetingKeywordsCreator keywordsCreator(ExtRequestTargeting targeting, boolean isApp) { - final JsonNode pricegranularity = targeting.getPricegranularity(); - return pricegranularity == null || pricegranularity.isNull() + final JsonNode priceGranularityNode = targeting.getPricegranularity(); + return priceGranularityNode == null || priceGranularityNode.isNull() ? null - : TargetingKeywordsCreator.create(parsePriceGranularity(pricegranularity), + : TargetingKeywordsCreator.create(parsePriceGranularity(priceGranularityNode), targeting.getIncludewinners(), targeting.getIncludebidderkeys(), isApp); } @@ -762,8 +783,9 @@ private Map keywordsCreatorByBidType(ExtReque } /** - * Parse {@link JsonNode} to {@link List} of {@link ExtPriceGranularity}. Throws {@link PreBidException} in - * case of errors during decoding pricegranularity. + * Parse {@link JsonNode} to {@link List} of {@link ExtPriceGranularity}. + *

+ * Throws {@link PreBidException} in case of errors during decoding price granularity. */ private ExtPriceGranularity parsePriceGranularity(JsonNode priceGranularity) { try { diff --git a/src/main/java/org/prebid/server/auction/BidderAliases.java b/src/main/java/org/prebid/server/auction/BidderAliases.java new file mode 100644 index 00000000000..378946b2ca2 --- /dev/null +++ b/src/main/java/org/prebid/server/auction/BidderAliases.java @@ -0,0 +1,37 @@ +package org.prebid.server.auction; + +import org.apache.commons.lang3.ObjectUtils; + +import java.util.Collections; +import java.util.Map; + +/** + * Represents aliases configured for bidders - configuration might come in OpenRTB request but not limited to it. + */ +public class BidderAliases { + + private Map aliasToBidder; + + private Map aliasToVendorId; + + private BidderAliases(Map aliasToBidder, Map aliasToVendorId) { + this.aliasToBidder = ObjectUtils.firstNonNull(aliasToBidder, Collections.emptyMap()); + this.aliasToVendorId = ObjectUtils.firstNonNull(aliasToVendorId, Collections.emptyMap()); + } + + public static BidderAliases of(Map aliasToBidder, Map aliasToVendorId) { + return new BidderAliases(aliasToBidder, aliasToVendorId); + } + + public boolean isAliasDefined(String alias) { + return aliasToBidder.containsKey(alias); + } + + public String resolveBidder(String aliasOrBidder) { + return aliasToBidder.getOrDefault(aliasOrBidder, aliasOrBidder); + } + + public Integer resolveAliasVendorId(String alias) { + return aliasToVendorId.get(alias); + } +} diff --git a/src/main/java/org/prebid/server/auction/CpmRange.java b/src/main/java/org/prebid/server/auction/CpmRange.java index 009cf0fb1b1..d847fc93fe9 100644 --- a/src/main/java/org/prebid/server/auction/CpmRange.java +++ b/src/main/java/org/prebid/server/auction/CpmRange.java @@ -25,7 +25,7 @@ private CpmRange() { public static String fromCpm(BigDecimal cpm, PriceGranularity priceGranularity) { final BigDecimal value = fromCpmAsNumber(cpm, priceGranularity); return value != null - ? format(value, ObjectUtils.firstNonNull(priceGranularity.getPrecision(), 2)) + ? format(value, ObjectUtils.defaultIfNull(priceGranularity.getPrecision(), 2)) : StringUtils.EMPTY; } diff --git a/src/main/java/org/prebid/server/auction/ExchangeService.java b/src/main/java/org/prebid/server/auction/ExchangeService.java index 5853e65ce2b..5794190c5be 100644 --- a/src/main/java/org/prebid/server/auction/ExchangeService.java +++ b/src/main/java/org/prebid/server/auction/ExchangeService.java @@ -20,9 +20,9 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidRequestCacheInfo; +import org.prebid.server.auction.model.BidderPrivacyResult; import org.prebid.server.auction.model.BidderRequest; import org.prebid.server.auction.model.BidderResponse; -import org.prebid.server.auction.model.PrivacyEnforcementResult; import org.prebid.server.auction.model.StoredResponseResult; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.BidderCatalog; @@ -42,6 +42,7 @@ import org.prebid.server.proto.openrtb.ext.ExtPrebidBidders; import org.prebid.server.proto.openrtb.ext.request.ExtApp; import org.prebid.server.proto.openrtb.ext.request.ExtBidRequest; +import org.prebid.server.proto.openrtb.ext.request.ExtRequestCurrency; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidCache; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidData; @@ -142,24 +143,22 @@ public Future holdAuction(AuctionContext context) { final List imps = bidRequest.getImp(); final List storedResponse = new ArrayList<>(); - final Map aliases = aliases(requestExt); + final BidderAliases aliases = aliases(requestExt); final String publisherId = account.getId(); final ExtRequestTargeting targeting = targeting(requestExt); final BidRequestCacheInfo cacheInfo = bidRequestCacheInfo(targeting, requestExt); - final Boolean isGdprEnforced = account.getEnforceGdpr(); final boolean debugEnabled = isDebugEnabled(bidRequest, requestExt); return storedResponseProcessor.getStoredResponseResult(imps, aliases, timeout) .map(storedResponseResult -> populateStoredResponse(storedResponseResult, storedResponse)) - .compose(impsRequiredRequest -> extractBidderRequests(context, impsRequiredRequest, requestExt, - aliases, isGdprEnforced)) + .compose(impsRequiredRequest -> + extractBidderRequests(context, impsRequiredRequest, requestExt, aliases)) .map(bidderRequests -> - updateRequestMetric(bidderRequests, uidsCookie, aliases, publisherId, - requestTypeMetric)) + updateRequestMetric(bidderRequests, uidsCookie, aliases, publisherId, requestTypeMetric)) .compose(bidderRequests -> CompositeFuture.join(bidderRequests.stream() .map(bidderRequest -> requestBids(bidderRequest, auctionTimeout(timeout, cacheInfo.isDoCaching()), debugEnabled, aliases, - bidAdjustments(requestExt), currencyRates(targeting))) + bidAdjustments(requestExt), currencyRates(requestExt))) .collect(Collectors.toList()))) // send all the requests to the bidders and gathers results .map(CompositeFuture::list) @@ -168,29 +167,22 @@ public Future holdAuction(AuctionContext context) { .map(bidderResponses -> storedResponseProcessor.mergeWithBidderResponses(bidderResponses, storedResponse, imps)) .compose(bidderResponses -> - bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, account, timeout, - debugEnabled)) + bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, account, + eventsAllowedByRequest(requestExt), auctionTimestamp(requestExt), debugEnabled, + timeout)) .compose(bidResponse -> bidResponsePostProcessor.postProcess(routingContext, uidsCookie, bidRequest, bidResponse, account)); } - /** - * Populates storedResponse parameter with stored {@link List} and returns {@link List} for which - * request to bidders should be performed. - */ - private List populateStoredResponse(StoredResponseResult storedResponseResult, List storedResponse) { - storedResponse.addAll(storedResponseResult.getStoredResponse()); - return storedResponseResult.getRequiredRequestImps(); - } - /** * Extracts {@link ExtBidRequest} from {@link BidRequest}. */ private ExtBidRequest requestExt(BidRequest bidRequest) { try { return bidRequest.getExt() != null - ? mapper.mapper().treeToValue(bidRequest.getExt(), ExtBidRequest.class) : null; + ? mapper.mapper().treeToValue(bidRequest.getExt(), ExtBidRequest.class) + : null; } catch (JsonProcessingException e) { throw new PreBidException(String.format("Error decoding bidRequest.ext: %s", e.getMessage()), e); } @@ -199,10 +191,87 @@ private ExtBidRequest requestExt(BidRequest bidRequest) { /** * Extracts aliases from {@link ExtBidRequest}. */ - private static Map aliases(ExtBidRequest requestExt) { + private static BidderAliases aliases(ExtBidRequest requestExt) { final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; final Map aliases = prebid != null ? prebid.getAliases() : null; - return aliases != null ? aliases : Collections.emptyMap(); + final Map aliasgvlids = prebid != null ? prebid.getAliasgvlids() : null; + return BidderAliases.of(aliases, aliasgvlids); + } + + /** + * Extracts {@link ExtRequestTargeting} from {@link ExtBidRequest} model. + */ + private static ExtRequestTargeting targeting(ExtBidRequest requestExt) { + final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; + return prebid != null ? prebid.getTargeting() : null; + } + + /** + * Extracts currency rates from {@link ExtBidRequest}. + */ + private static Map> currencyRates(ExtBidRequest requestExt) { + final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; + final ExtRequestCurrency currency = prebid != null ? prebid.getCurrency() : null; + return currency != null ? currency.getRates() : null; + } + + /** + * Returns true if {@link ExtBidRequest} is present, otherwise - false. + */ + private static boolean eventsAllowedByRequest(ExtBidRequest requestExt) { + final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; + final ObjectNode eventsFromRequest = prebid != null ? prebid.getEvents() : null; + return eventsFromRequest != null; + } + + /** + * Extracts auction timestamp from {@link ExtBidRequest} or get it from {@link Clock} if it is null. + */ + private long auctionTimestamp(ExtBidRequest requestExt) { + final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; + final Long auctionTimestamp = prebid != null ? prebid.getAuctiontimestamp() : null; + return auctionTimestamp != null ? auctionTimestamp : clock.millis(); + } + + /** + * Creates {@link BidRequestCacheInfo} based on {@link ExtBidRequest} model. + */ + private static BidRequestCacheInfo bidRequestCacheInfo(ExtRequestTargeting targeting, ExtBidRequest requestExt) { + final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; + final ExtRequestPrebidCache cache = prebid != null ? prebid.getCache() : null; + + if (targeting != null && cache != null) { + final boolean shouldCacheBids = cache.getBids() != null; + final boolean shouldCacheVideoBids = cache.getVastxml() != null; + final boolean shouldCacheWinningBidsOnly = targeting.getIncludebidderkeys() + ? false // ext.prebid.targeting.includebidderkeys takes precedence + : ObjectUtils.defaultIfNull(cache.getWinningonly(), false); + + if (shouldCacheBids || shouldCacheVideoBids || shouldCacheWinningBidsOnly) { + final Integer cacheBidsTtl = shouldCacheBids ? cache.getBids().getTtlseconds() : null; + final Integer cacheVideoBidsTtl = shouldCacheVideoBids ? cache.getVastxml().getTtlseconds() : null; + + final boolean returnCreativeBid = shouldCacheBids + ? ObjectUtils.defaultIfNull(cache.getBids().getReturnCreative(), true) + : false; + final boolean returnCreativeVideoBid = shouldCacheVideoBids + ? ObjectUtils.defaultIfNull(cache.getVastxml().getReturnCreative(), true) + : false; + + return BidRequestCacheInfo.builder() + .doCaching(true) + .shouldCacheBids(shouldCacheBids) + .cacheBidsTtl(cacheBidsTtl) + .shouldCacheVideoBids(shouldCacheVideoBids) + .cacheVideoBidsTtl(cacheVideoBidsTtl) + .returnCreativeBids(returnCreativeBid) + .returnCreativeVideoBids(returnCreativeVideoBid) + .shouldCacheWinningBidsOnly(shouldCacheWinningBidsOnly) + .build(); + } + } + + return BidRequestCacheInfo.noCache(); } /** @@ -217,19 +286,13 @@ private static boolean isDebugEnabled(BidRequest bidRequest, ExtBidRequest extBi } /** - * Extracts bidAdjustments from {@link ExtBidRequest}. - */ - private static Map bidAdjustments(ExtBidRequest requestExt) { - final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; - final Map bidAdjustmentFactors = prebid != null ? prebid.getBidadjustmentfactors() : null; - return bidAdjustmentFactors != null ? bidAdjustmentFactors : Collections.emptyMap(); - } - - /** - * Extracts currency rates from {@link ExtRequestTargeting}. + * Populates storedResponse parameter with stored {@link List} and returns {@link List} for which + * request to bidders should be performed. */ - private static Map> currencyRates(ExtRequestTargeting targeting) { - return targeting != null && targeting.getCurrency() != null ? targeting.getCurrency().getRates() : null; + private static List populateStoredResponse(StoredResponseResult storedResponseResult, + List storedResponse) { + storedResponse.addAll(storedResponseResult.getStoredResponse()); + return storedResponseResult.getRequiredRequestImps(); } /** @@ -260,9 +323,10 @@ private static Map> currencyRates(ExtRequestTarg * NOTE: the return list will only contain entries for bidders that both have the extension field in at least one * {@link Imp}, and are known to {@link BidderCatalog} or aliases from bidRequest.ext.prebid.aliases. */ - private Future> extractBidderRequests(AuctionContext context, List requestedImps, - ExtBidRequest requestExt, Map aliases, - Boolean isGdprEnforced) { + private Future> extractBidderRequests(AuctionContext context, + List requestedImps, + ExtBidRequest requestExt, + BidderAliases aliases) { // sanity check: discard imps without extension final List imps = requestedImps.stream() .filter(imp -> imp.getExt() != null) @@ -276,7 +340,7 @@ private Future> extractBidderRequests(AuctionContext context .distinct() .collect(Collectors.toList()); - return makeBidderRequests(bidders, context, aliases, requestExt, imps, isGdprEnforced); + return makeBidderRequests(bidders, context, aliases, requestExt, imps); } private static Stream asStream(Iterator iterator) { @@ -287,8 +351,8 @@ private static Stream asStream(Iterator iterator) { /** * Checks if bidder name is valid in case when bidder can also be alias name. */ - private boolean isValidBidder(String bidder, Map aliases) { - return bidderCatalog.isValidName(bidder) || aliases.containsKey(bidder); + private boolean isValidBidder(String bidder, BidderAliases aliases) { + return bidderCatalog.isValidName(bidder) || aliases.isAliasDefined(bidder); } /** @@ -306,9 +370,11 @@ private boolean isValidBidder(String bidder, Map aliases) { * - bidrequest.user.ext.data, bidrequest.app.ext.data and bidrequest.site.ext.data will be removed for bidders * that don't have first party data allowed. */ - private Future> makeBidderRequests( - List bidders, AuctionContext context, Map aliases, - ExtBidRequest requestExt, List imps, Boolean isGdprEnforced) { + private Future> makeBidderRequests(List bidders, + AuctionContext context, + BidderAliases aliases, + ExtBidRequest requestExt, + List imps) { final BidRequest bidRequest = context.getBidRequest(); final ExtUser extUser = extUser(bidRequest.getUser()); @@ -323,9 +389,9 @@ private Future> makeBidderRequests( } return privacyEnforcementService - .mask(bidderToUser, extUser, bidders, aliases, bidRequest, isGdprEnforced, context.getTimeout()) - .map(bidderToPrivacyEnforcementResult -> getBidderRequests(bidderToPrivacyEnforcementResult, - bidRequest, requestExt, imps, firstPartyDataBidders)); + .mask(context, bidderToUser, extUser, bidders, aliases) + .map(bidderToPrivacyResult -> getBidderRequests(bidderToPrivacyResult, bidRequest, requestExt, imps, + firstPartyDataBidders)); } /** @@ -367,7 +433,7 @@ private static List firstPartyDataBidders(ExtBidRequest requestExt) { * Returns original {@link User} if user.buyeruid already contains uid value for bidder. * Otherwise, returns new {@link User} containing updated {@link ExtUser} and user.buyeruid. */ - private User prepareUser(User user, ExtUser extUser, String bidder, Map aliases, + private User prepareUser(User user, ExtUser extUser, String bidder, BidderAliases aliases, Map uidsBody, UidsCookie uidsCookie, boolean useFirstPartyData) { final ObjectNode updatedExt = updateUserExt(extUser, useFirstPartyData); final String updatedBuyerUid = updateUserBuyerUid(user, bidder, aliases, uidsBody, uidsCookie); @@ -401,16 +467,16 @@ private ObjectNode updateUserExt(ExtUser extUser, boolean useFirstPartyData) { final boolean removeFirstPartyData = !useFirstPartyData && extUser.getData() != null; if (removePrebid || removeFirstPartyData) { - final ExtUser.ExtUserBuilder builder = extUser.toBuilder(); + final ExtUser.ExtUserBuilder extUserBuilder = extUser.toBuilder(); if (removePrebid) { - builder.prebid(null); + extUserBuilder.prebid(null); } if (removeFirstPartyData) { - builder.data(null); + extUserBuilder.data(null); } - return mapper.mapper().valueToTree(builder.build()); + return mapper.mapper().valueToTree(extUserBuilder.build()); } } return null; @@ -419,9 +485,9 @@ private ObjectNode updateUserExt(ExtUser extUser, boolean useFirstPartyData) { /** * Returns updated buyerUid or null if it doesn't need to be updated. */ - private String updateUserBuyerUid(User user, String bidder, Map aliases, + private String updateUserBuyerUid(User user, String bidder, BidderAliases aliases, Map uidsBody, UidsCookie uidsCookie) { - final String buyerUidFromBodyOrCookie = extractUid(uidsBody, uidsCookie, resolveBidder(bidder, aliases)); + final String buyerUidFromBodyOrCookie = extractUid(uidsBody, uidsCookie, aliases.resolveBidder(bidder)); final String buyerUidFromUser = user != null ? user.getBuyeruid() : null; return StringUtils.isBlank(buyerUidFromUser) && StringUtils.isNotBlank(buyerUidFromBodyOrCookie) @@ -429,14 +495,6 @@ private String updateUserBuyerUid(User user, String bidder, Map : null; } - /** - * Returns the name associated with bidder if bidder is an alias. - * If it's not an alias, the bidder is returned. - */ - private static String resolveBidder(String bidder, Map aliases) { - return aliases.getOrDefault(bidder, bidder); - } - /** * Extracts UID from uids from body or {@link UidsCookie}. */ @@ -453,22 +511,27 @@ private String resolveCookieFamilyName(String bidder) { } /** - * Returns Shuffled List of {@link BidderRequest} + * Returns shuffled list of {@link BidderRequest}. */ - private List getBidderRequests( - Map bidderToPrivacyEnforcementResult, BidRequest bidRequest, - ExtBidRequest requestExt, List imps, List firstPartyDataBidders) { + private List getBidderRequests(List bidderPrivacyResults, + BidRequest bidRequest, + ExtBidRequest requestExt, + List imps, + List firstPartyDataBidders) { final Map bidderToPrebidBidders = bidderToPrebidBidders(requestExt); final Map bidderToPrebidSchains = bidderToPrebidSchains(requestExt); - final List bidderRequests = bidderToPrivacyEnforcementResult.entrySet().stream() + final List bidderRequests = bidderPrivacyResults.stream() // for each bidder create a new request that is a copy of original request except buyerid, imp // extensions, ext.prebid.data.bidders and ext.prebid.bidders. // Also, check whether to pass user.ext.data, app.ext.data and site.ext.data or not. - .map(entry -> createBidderRequest(entry.getKey(), bidRequest, requestExt, imps, entry.getValue(), + .map(bidderPrivacyResult -> createBidderRequest(bidderPrivacyResult, bidRequest, requestExt, imps, firstPartyDataBidders, bidderToPrebidBidders, bidderToPrebidSchains)) + .filter(Objects::nonNull) .collect(Collectors.toList()); + Collections.shuffle(bidderRequests); + return bidderRequests; } @@ -514,24 +577,29 @@ private static Map bidderToPrebidSchains(ExtBidRequest reque } /** - * Returns created {@link BidderRequest} + * Returns {@link BidderRequest} for the given bidder. */ - private BidderRequest createBidderRequest(String bidder, BidRequest bidRequest, ExtBidRequest requestExt, - List imps, PrivacyEnforcementResult privacyEnforcementResult, + private BidderRequest createBidderRequest(BidderPrivacyResult bidderPrivacyResult, + BidRequest bidRequest, + ExtBidRequest requestExt, + List imps, List firstPartyDataBidders, Map bidderToPrebidBidders, Map bidderToPrebidSchains) { + final String bidder = bidderPrivacyResult.getRequestBidder(); + if (bidderPrivacyResult.isBlockedRequestByTcf()) { + return null; + } + final App app = bidRequest.getApp(); - final ExtApp extApp = extApp(app); final Site site = bidRequest.getSite(); - final ExtSite extSite = extSite(site); return BidderRequest.of(bidder, bidRequest.toBuilder() - .user(privacyEnforcementResult.getUser()) - .device(privacyEnforcementResult.getDevice()) + .user(bidderPrivacyResult.getUser()) + .device(bidderPrivacyResult.getDevice()) .imp(prepareImps(bidder, imps, firstPartyDataBidders.contains(bidder))) - .app(prepareApp(app, extApp, firstPartyDataBidders.contains(bidder))) - .site(prepareSite(site, extSite, firstPartyDataBidders.contains(bidder))) + .app(prepareApp(app, extApp(app), firstPartyDataBidders.contains(bidder))) + .site(prepareSite(site, extSite(site), firstPartyDataBidders.contains(bidder))) .source(prepareSource(bidder, bidderToPrebidSchains, bidRequest.getSource())) .ext(prepareExt(bidder, firstPartyDataBidders, bidderToPrebidBidders, requestExt, bidRequest.getExt())) .build()); @@ -623,7 +691,7 @@ private Site prepareSite(Site site, ExtSite extSite, boolean useFirstPartyData) } /** - * Make Source with corresponding request.ext.prebid.schains + * Returns {@link Source} with corresponding request.ext.prebid.schains. */ private Source prepareSource(String bidder, Map bidderToSchain, Source receivedSource) { final ObjectNode defaultSchain = bidderToSchain.get(GENERIC_SCHAIN_KEY); @@ -633,19 +701,17 @@ private Source prepareSource(String bidder, Map bidderToScha return receivedSource; } - final ObjectNode jsonExtSource = mapper.mapper().valueToTree(ExtSource.of(bidderSchain)); + final ObjectNode extSourceNode = mapper.mapper().valueToTree(ExtSource.of(bidderSchain)); - if (receivedSource == null) { - return Source.builder().ext(jsonExtSource).build(); - } else { - return receivedSource.toBuilder().ext(jsonExtSource).build(); - } + return receivedSource == null + ? Source.builder().ext(extSourceNode).build() + : receivedSource.toBuilder().ext(extSourceNode).build(); } /** * Removes all bidders except the given bidder from bidrequest.ext.prebid.data.bidders and * bidrequest.ext.prebid.bidders to hide list of allowed bidders from initial request. - * Also mask bidrequest.ext.prebid.schains. + * Also masks bidrequest.ext.prebid.schains. */ private ObjectNode prepareExt(String bidder, List firstPartyDataBidders, Map bidderToPrebidBidders, ExtBidRequest requestExt, @@ -682,12 +748,12 @@ private ObjectNode prepareExt(String bidder, List firstPartyDataBidders, * Updates 'account.*.request', 'request' and 'no_cookie_requests' metrics for each {@link BidderRequest}. */ private List updateRequestMetric(List bidderRequests, UidsCookie uidsCookie, - Map aliases, String publisherId, + BidderAliases aliases, String publisherId, MetricName requestTypeMetric) { metrics.updateAccountRequestMetrics(publisherId, requestTypeMetric); for (BidderRequest bidderRequest : bidderRequests) { - final String bidder = resolveBidder(bidderRequest.getBidder(), aliases); + final String bidder = aliases.resolveBidder(bidderRequest.getBidder()); final boolean isApp = bidderRequest.getBidRequest().getApp() != null; final boolean noBuyerId = !bidderCatalog.isActive(bidder) || StringUtils.isBlank( uidsCookie.uidFrom(bidderCatalog.usersyncerByName(bidder).getCookieFamilyName())); @@ -698,52 +764,12 @@ private List updateRequestMetric(List bidderReques } /** - * Extracts {@link ExtRequestTargeting} from {@link ExtBidRequest} model. - */ - private static ExtRequestTargeting targeting(ExtBidRequest requestExt) { - final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; - return prebid != null ? prebid.getTargeting() : null; - } - - /** - * Creates {@link BidRequestCacheInfo} based on {@link ExtBidRequest} model. + * Extracts bidAdjustments from {@link ExtBidRequest}. */ - private BidRequestCacheInfo bidRequestCacheInfo(ExtRequestTargeting targeting, ExtBidRequest requestExt) { + private static Map bidAdjustments(ExtBidRequest requestExt) { final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null; - final ExtRequestPrebidCache cache = prebid != null ? prebid.getCache() : null; - - if (targeting != null && cache != null) { - final boolean shouldCacheBids = cache.getBids() != null; - final boolean shouldCacheVideoBids = cache.getVastxml() != null; - final boolean shouldCacheWinningBidsOnly = targeting.getIncludebidderkeys() - ? false // ext.prebid.targeting.includebidderkeys takes precedence - : ObjectUtils.defaultIfNull(cache.getWinningonly(), false); - - if (shouldCacheBids || shouldCacheVideoBids || shouldCacheWinningBidsOnly) { - final Integer cacheBidsTtl = shouldCacheBids ? cache.getBids().getTtlseconds() : null; - final Integer cacheVideoBidsTtl = shouldCacheVideoBids ? cache.getVastxml().getTtlseconds() : null; - - final boolean returnCreativeBid = shouldCacheBids - ? ObjectUtils.defaultIfNull(cache.getBids().getReturnCreative(), true) - : false; - final boolean returnCreativeVideoBid = shouldCacheVideoBids - ? ObjectUtils.defaultIfNull(cache.getVastxml().getReturnCreative(), true) - : false; - - return BidRequestCacheInfo.builder() - .doCaching(true) - .shouldCacheBids(shouldCacheBids) - .cacheBidsTtl(cacheBidsTtl) - .shouldCacheVideoBids(shouldCacheVideoBids) - .cacheVideoBidsTtl(cacheVideoBidsTtl) - .returnCreativeBids(returnCreativeBid) - .returnCreativeVideoBids(returnCreativeVideoBid) - .shouldCacheWinningBidsOnly(shouldCacheWinningBidsOnly) - .build(); - } - } - - return BidRequestCacheInfo.noCache(); + final Map bidAdjustmentFactors = prebid != null ? prebid.getBidadjustmentfactors() : null; + return bidAdjustmentFactors != null ? bidAdjustmentFactors : Collections.emptyMap(); } /** @@ -751,14 +777,14 @@ private BidRequestCacheInfo bidRequestCacheInfo(ExtRequestTargeting targeting, E * recorded response time. */ private Future requestBids(BidderRequest bidderRequest, Timeout timeout, - boolean debugEnabled, Map aliases, + boolean debugEnabled, BidderAliases aliases, Map bidAdjustments, Map> currencyConversionRates) { final String bidderName = bidderRequest.getBidder(); final BigDecimal bidPriceAdjustmentFactor = bidAdjustments.get(bidderName); final List cur = bidderRequest.getBidRequest().getCur(); final String adServerCurrency = cur.get(0); - final Bidder bidder = bidderCatalog.bidderByName(resolveBidder(bidderName, aliases)); + final Bidder bidder = bidderCatalog.bidderByName(aliases.resolveBidder(bidderName)); final long startTime = clock.millis(); return httpBidderRequester.requestBids(bidder, bidderRequest.getBidRequest(), timeout, debugEnabled) diff --git a/src/main/java/org/prebid/server/auction/PrivacyEnforcementService.java b/src/main/java/org/prebid/server/auction/PrivacyEnforcementService.java index 83471be0f6d..0fb3bebe38b 100644 --- a/src/main/java/org/prebid/server/auction/PrivacyEnforcementService.java +++ b/src/main/java/org/prebid/server/auction/PrivacyEnforcementService.java @@ -9,30 +9,33 @@ import com.iab.openrtb.request.User; import io.vertx.core.Future; import org.apache.commons.lang3.StringUtils; -import org.prebid.server.auction.model.PrivacyEnforcementResult; +import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.auction.model.BidderPrivacyResult; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.Timeout; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.privacy.PrivacyExtractor; import org.prebid.server.privacy.ccpa.Ccpa; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.VendorIdResolver; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; import org.prebid.server.privacy.model.Privacy; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; -import org.prebid.server.proto.response.BidderInfo; +import org.prebid.server.settings.model.AccountGdprConfig; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; -import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; -import java.util.Set; -import java.util.function.UnaryOperator; +import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -45,23 +48,26 @@ public class PrivacyEnforcementService { new DecimalFormat("###.##", DecimalFormatSymbols.getInstance(Locale.US)); private static final User EMPTY_USER = User.builder().build(); + private static final ExtUser EMPTY_USER_EXT = ExtUser.builder().build(); private final boolean useGeoLocation; - private final GdprService gdprService; private final BidderCatalog bidderCatalog; + private final TcfDefinerService tcfDefinerService; private final Metrics metrics; private final JacksonMapper mapper; private final boolean ccpaEnforce; private final PrivacyExtractor privacyExtractor; - public PrivacyEnforcementService(GdprService gdprService, - BidderCatalog bidderCatalog, + public PrivacyEnforcementService(BidderCatalog bidderCatalog, + TcfDefinerService tcfDefinerService, Metrics metrics, - JacksonMapper mapper, boolean useGeoLocation, + JacksonMapper mapper, + boolean useGeoLocation, boolean ccpaEnforce) { - this.gdprService = Objects.requireNonNull(gdprService); + this.bidderCatalog = Objects.requireNonNull(bidderCatalog); + this.tcfDefinerService = Objects.requireNonNull(tcfDefinerService); this.metrics = Objects.requireNonNull(metrics); this.mapper = Objects.requireNonNull(mapper); this.useGeoLocation = useGeoLocation; @@ -70,58 +76,72 @@ public PrivacyEnforcementService(GdprService gdprService, privacyExtractor = new PrivacyExtractor(mapper); } - /** - * Returns {@link Future <{@link Map}<{@link String}, {@link PrivacyEnforcementResult }>>}, where - * bidders name mapped to masked {@link PrivacyEnforcementResult}. - */ - Future> mask( - Map bidderToUser, ExtUser extUser, List bidders, Map aliases, - BidRequest bidRequest, Boolean isGdprEnforcedByAccount, Timeout timeout) { + Future> mask(AuctionContext auctionContext, + Map bidderToUser, + ExtUser extUser, + List bidders, + BidderAliases aliases) { + final BidRequest bidRequest = auctionContext.getBidRequest(); final Regs regs = bidRequest.getRegs(); final Device device = bidRequest.getDevice(); - final User user = bidRequest.getUser(); + // For now, COPPA and CCPA masking all values, so we can omit GDPR masking. if (isCoppaMaskingRequired(regs)) { - return maskCoppa(bidderToUser, device, user); + return Future.succeededFuture(maskCoppa(bidderToUser, device)); } - final Privacy privacy = privacyExtractor.validPrivacyFrom(regs, user); - if (isCcpaEnforced(privacy.getCcpa())) { - return maskCcpa(bidderToUser, device, user); + final Privacy privacy = privacyExtractor.validPrivacyFrom(regs, bidRequest.getUser()); + final Ccpa ccpa = privacy.getCcpa(); + updateCcpaMetrics(ccpa); + if (isCcpaEnforced(ccpa)) { + return maskCcpa(bidderToUser, device); } - return getVendorsToGdprPermission(device, bidders, aliases, extUser, regs, isGdprEnforcedByAccount, timeout) - .map(vendorToGdprPermission -> getBidderToPrivacyEnforcementResult(bidderToUser, device, aliases, - vendorToGdprPermission)); + final AccountGdprConfig accountConfig = auctionContext.getAccount().getGdpr(); + final Timeout timeout = auctionContext.getTimeout(); + final MetricName requestType = auctionContext.getRequestTypeMetric(); + return getBidderToEnforcementAction(device, bidders, aliases, extUser, regs, accountConfig, timeout) + .map(bidderToEnforcement -> updatePrivacyMetrics(bidderToEnforcement, requestType, device)) + .map(bidderToEnforcement -> getBidderToPrivacyResult(bidderToUser, device, bidderToEnforcement)); } - private Future> maskCoppa(Map bidderToUser, Device device, - User user) { - return Future.succeededFuture(bidderToUser.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - bidderUserEntry -> PrivacyEnforcementResult.of( - maskUser(user, PrivacyEnforcementService::maskGeoForCoppa, builder -> builder - .id(null) - .yob(null) - .gender(null)), - maskDevice(device, PrivacyEnforcementService::maskGeoForCoppa, - ip -> maskIpv6(ip, 2)))))); + public boolean isCcpaEnforced(Ccpa ccpa) { + return ccpaEnforce && ccpa.isCCPAEnforced(); } - private Future> maskCcpa(Map bidderToUser, Device device, - User user) { + private Future> maskCcpa(Map bidderToUser, Device device) { return Future.succeededFuture(bidderToUser.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - bidderUserEntry -> PrivacyEnforcementResult.of( - maskUser(user, PrivacyEnforcementService::maskGeoDefault, - UnaryOperator.identity()), - maskDevice(device, PrivacyEnforcementService::maskGeoDefault, - ip -> maskIpv6(ip, 1)))))); + .map(bidderAndUser -> BidderPrivacyResult.builder() + .requestBidder(bidderAndUser.getKey()) + .user(maskCcpaUser(bidderAndUser.getValue())) + .device(maskCcpaDevice(device)) + .build()) + .collect(Collectors.toList())); } - public boolean isCcpaEnforced(Ccpa ccpa) { - return ccpaEnforce && ccpa.isCCPAEnforced(); + private static User maskCcpaUser(User user) { + if (user != null) { + return nullIfEmpty(user.toBuilder() + .buyeruid(null) + .geo(maskGeoDefault(user.getGeo())) + .build()); + } + return null; + } + + private static Device maskCcpaDevice(Device device) { + return device != null + ? device.toBuilder() + .ip(maskIpv4(device.getIp())) + .ipv6(maskIpv6(device.getIpv6(), 1)) + .geo(maskGeoDefault(device.getGeo())) + .ifa(null) + .macsha1(null).macmd5(null) + .dpidsha1(null).dpidmd5(null) + .didsha1(null).didmd5(null) + .build() + : null; } /** @@ -131,26 +151,85 @@ private static boolean isCoppaMaskingRequired(Regs regs) { return regs != null && Objects.equals(regs.getCoppa(), 1); } + private List maskCoppa(Map bidderToUser, Device device) { + metrics.updatePrivacyCoppaMetric(); + + return bidderToUser.entrySet().stream() + .map(bidderAndUser -> BidderPrivacyResult.builder() + .requestBidder(bidderAndUser.getKey()) + .user(maskCoppaUser(bidderAndUser.getValue())) + .device(maskCoppaDevice(device)) + .build()) + .collect(Collectors.toList()); + } + + private static User maskCoppaUser(User user) { + if (user != null) { + return nullIfEmpty(user.toBuilder() + .id(null) + .yob(null) + .gender(null) + .buyeruid(null) + .geo(maskGeoForCoppa(user.getGeo())) + .build()); + } + return null; + } + + private static Device maskCoppaDevice(Device device) { + return device != null + ? device.toBuilder() + .ip(maskIpv4(device.getIp())) + .ipv6(maskIpv6(device.getIpv6(), 2)) + .geo(maskGeoForCoppa(device.getGeo())) + .ifa(null) + .macsha1(null).macmd5(null) + .dpidsha1(null).dpidmd5(null) + .didsha1(null).didmd5(null) + .build() + : null; + } + /** - * Returns {@link Future <{@link Map}<{@link Integer}, {@link Boolean}>>}, where bidders vendor id - * mapped to enabling or disabling GDPR in scope of pbs server. If bidder vendor id is not present in map, - * it means that pbs not enforced particular bidder to follow pbs GDPR procedure. + * Returns masked for COPPA {@link Geo}. + */ + private static Geo maskGeoForCoppa(Geo geo) { + final Geo updatedGeo = geo != null + ? geo.toBuilder().lat(null).lon(null).metro(null).city(null).zip(null).build() + : null; + return updatedGeo == null || updatedGeo.equals(Geo.EMPTY) ? null : updatedGeo; + } + + /** + * Returns {@link Future <{@link Map}<{@link String}, {@link PrivacyEnforcementAction}>>}, + * where bidder names mapped to actions for GDPR masking for pbs server. */ - private Future> getVendorsToGdprPermission( - Device device, List bidders, Map aliases, ExtUser extUser, Regs regs, - Boolean isGdprEnforcedByAccount, Timeout timeout) { + private Future> getBidderToEnforcementAction( + Device device, + List bidders, + BidderAliases aliases, + ExtUser extUser, + Regs regs, + AccountGdprConfig accountConfig, + Timeout timeout) { final ExtRegs extRegs = extRegs(regs); final Integer gdpr = extRegs != null ? extRegs.getGdpr() : null; final String gdprAsString = gdpr != null ? gdpr.toString() : null; final String gdprConsent = extUser != null ? extUser.getConsent() : null; final String ipAddress = useGeoLocation && device != null ? device.getIp() : null; - final Set vendorIds = extractGdprEnforcedVendors(bidders, aliases); - return gdprService.isGdprEnforced(gdprAsString, isGdprEnforcedByAccount, vendorIds) - ? gdprService.resultByVendor(vendorIds, gdprAsString, gdprConsent, ipAddress, timeout) - .map(GdprResponse::getVendorsToGdpr) - : Future.succeededFuture(Collections.emptyMap()); + final VendorIdResolver vendorIdResolver = VendorIdResolver.of(bidderCatalog, aliases); + + return tcfDefinerService.resultForBidderNames( + new HashSet<>(bidders), + vendorIdResolver, + gdprAsString, + gdprConsent, + ipAddress, + accountConfig, + timeout) + .map(tcfResponse -> mapTcfResponseToEachBidder(tcfResponse, bidders)); } /** @@ -168,107 +247,139 @@ private ExtRegs extRegs(Regs regs) { return null; } - /** - * Extracts GDPR enforced vendor IDs. - */ - private Set extractGdprEnforcedVendors(List bidders, Map aliases) { - return bidders.stream() - .map(bidder -> bidderCatalog.bidderInfoByName(resolveBidder(bidder, aliases)).getGdpr()) - .filter(BidderInfo.GdprInfo::isEnforced) - .map(BidderInfo.GdprInfo::getVendorId) - .collect(Collectors.toSet()); + private Map mapTcfResponseToEachBidder( + TcfResponse tcfResponse, List bidders) { + + final Map bidderNameToAction = tcfResponse.getActions(); + return bidders.stream().collect(Collectors.toMap(Function.identity(), bidderNameToAction::get)); } - /** - * Returns the name associated with bidder if bidder is an alias. - * If it's not an alias, the bidder is returned. - */ - private static String resolveBidder(String bidder, Map aliases) { - return aliases.getOrDefault(bidder, bidder); + private void updateCcpaMetrics(Ccpa ccpa) { + metrics.updatePrivacyCcpaMetrics(ccpa.isNotEmpty(), ccpa.isCCPAEnforced()); } - /** - * Returns {@link Map}<{@link String}, {@link PrivacyEnforcementResult}>, where bidder name mapped to masked - * {@link PrivacyEnforcementResult}. Masking depends on GDPR and COPPA. - */ - private Map getBidderToPrivacyEnforcementResult( - Map bidderToUser, Device device, Map aliases, - Map vendorToGdprPermission) { + private Map updatePrivacyMetrics( + Map bidderToEnforcement, MetricName requestType, Device device) { - final Integer deviceLmt = device != null ? device.getLmt() : null; - return bidderToUser.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - bidderUserEntry -> createPrivacyEnforcementResult(bidderUserEntry.getValue(), device, - bidderUserEntry.getKey(), aliases, deviceLmt, vendorToGdprPermission))); + for (final Map.Entry bidderEnforcement : bidderToEnforcement.entrySet()) { + final String bidder = bidderEnforcement.getKey(); + final PrivacyEnforcementAction enforcement = bidderEnforcement.getValue(); + + metrics.updateAuctionTcfMetrics( + bidder, + requestType, + enforcement.isRemoveUserIds(), + enforcement.isMaskGeo(), + enforcement.isBlockBidderRequest(), + enforcement.isBlockAnalyticsReport()); + } + + if (isLmtEnabled(device)) { + metrics.updatePrivacyLmtMetric(); + } + + return bidderToEnforcement; } /** - * Returns {@link PrivacyEnforcementResult} with GDPR and COPPA masking. + * Returns {@link Map}<{@link String}, {@link BidderPrivacyResult}>, where bidder name mapped to masked + * {@link BidderPrivacyResult}. Masking depends on GDPR and COPPA. */ - private PrivacyEnforcementResult createPrivacyEnforcementResult( - User user, Device device, String bidder, Map aliases, Integer deviceLmt, - Map vendorToGdprPermission) { - - final boolean gdprMasking = isGdprMaskingRequiredFor(bidder, aliases, deviceLmt, vendorToGdprPermission); + private List getBidderToPrivacyResult( + Map bidderToUser, Device device, Map bidderToEnforcement) { - final User maskedUser = gdprMasking - ? maskUser(user, PrivacyEnforcementService::maskGeoDefault, UnaryOperator.identity()) - : user; - final Device maskedDevice = gdprMasking - ? maskDevice(device, PrivacyEnforcementService::maskGeoDefault, ip -> maskIpv6(ip, 1)) - : device; - - return PrivacyEnforcementResult.of(maskedUser, maskedDevice); + final boolean isLmtEnabled = isLmtEnabled(device); + return bidderToUser.entrySet().stream() + .map(bidderUserEntry -> createBidderPrivacyResult(bidderUserEntry.getValue(), device, + bidderUserEntry.getKey(), isLmtEnabled, bidderToEnforcement)) + .collect(Collectors.toList()); } /** - * Returns flag if GDPR masking is required for bidder. + * Returns {@link BidderPrivacyResult} with GDPR masking. */ - private boolean isGdprMaskingRequiredFor(String bidder, Map aliases, Integer deviceLmt, - Map vendorToGdprPermission) { - final boolean maskingRequired; - final boolean isLmtEnabled = deviceLmt != null && deviceLmt.equals(1); - if (vendorToGdprPermission.isEmpty() && !isLmtEnabled) { - maskingRequired = false; - } else { - final String resolvedBidderName = resolveBidder(bidder, aliases); - final int vendorId = bidderCatalog.bidderInfoByName(resolvedBidderName).getGdpr().getVendorId(); - final Boolean gdprAllowsUserData = vendorToGdprPermission.get(vendorId); - - // if bidder was not found in vendorToGdprPermission, it means that it was not enforced for GDPR, - // so request for this bidder should be sent without changes - maskingRequired = (gdprAllowsUserData != null && !gdprAllowsUserData) || isLmtEnabled; - if (maskingRequired) { - metrics.updateGdprMaskedMetric(resolvedBidderName); - } + private BidderPrivacyResult createBidderPrivacyResult(User user, + Device device, + String bidder, + boolean isLmtEnabled, + Map bidderToEnforcement) { + + final PrivacyEnforcementAction privacyEnforcementAction = bidderToEnforcement.get(bidder); + final boolean blockBidderRequest = privacyEnforcementAction.isBlockBidderRequest(); + final boolean blockAnalyticsReport = privacyEnforcementAction.isBlockAnalyticsReport(); + if (blockBidderRequest) { + return BidderPrivacyResult.builder() + .requestBidder(bidder) + .blockedRequestByTcf(true) + .blockedAnalyticsByTcf(blockAnalyticsReport) + .build(); } - return maskingRequired; + + final boolean maskGeo = privacyEnforcementAction.isMaskGeo() || isLmtEnabled; + final boolean maskUserIds = privacyEnforcementAction.isRemoveUserIds() || isLmtEnabled; + final User maskedUser = maskTcfUser(user, maskUserIds, maskGeo); + + final boolean maskIp = privacyEnforcementAction.isMaskDeviceIp() || isLmtEnabled; + final boolean maskInfo = privacyEnforcementAction.isMaskDeviceInfo() || isLmtEnabled; + final Device maskedDevice = maskTcfDevice(device, maskIp, maskGeo, maskInfo); + + return BidderPrivacyResult.builder() + .requestBidder(bidder) + .user(maskedUser) + .device(maskedDevice) + .blockedAnalyticsByTcf(blockAnalyticsReport) + .build(); } /** * Returns masked {@link User}. */ - private static User maskUser(User user, UnaryOperator maskGeo, - UnaryOperator additionalMasking) { + private User maskTcfUser(User user, boolean maskUserIds, boolean maskGeo) { if (user != null) { - User.UserBuilder builder = user.toBuilder(); - builder - .buyeruid(null) - .geo(maskGeo.apply(user.getGeo())); - builder = additionalMasking.apply(builder); - return nullIfEmpty(builder.build()); + final User.UserBuilder userBuilder = user.toBuilder(); + + if (maskGeo) { + userBuilder.geo(maskGeoDefault(user.getGeo())); + } + + if (maskUserIds) { + userBuilder + .id(null) + .buyeruid(null) + .ext(maskUserExt(user.getExt())); + } + + return nullIfEmpty(userBuilder.build()); } return null; } /** - * Returns masked for COPPA {@link Geo}. + * Returns masked device accordingly for each flag. */ - private static Geo maskGeoForCoppa(Geo geo) { - final Geo updatedGeo = geo != null - ? geo.toBuilder().lat(null).lon(null).metro(null).city(null).zip(null).build() - : null; - return updatedGeo == null || updatedGeo.equals(Geo.EMPTY) ? null : updatedGeo; + private static Device maskTcfDevice(Device device, boolean maskIp, boolean maskGeo, boolean maskInfo) { + if (device != null) { + final Device.DeviceBuilder deviceBuilder = device.toBuilder(); + if (maskIp) { + deviceBuilder + .ip(maskIpv4(device.getIp())) + .ipv6(maskIpv6(device.getIpv6(), 1)); + } + + if (maskGeo) { + deviceBuilder.geo(maskGeoDefault(device.getGeo())); + } + + if (maskInfo) { + deviceBuilder.ifa(null) + .macsha1(null).macmd5(null) + .dpidsha1(null).dpidmd5(null) + .didsha1(null).didmd5(null); + } + + return deviceBuilder.build(); + } + return null; } /** @@ -291,27 +402,32 @@ private static Float maskGeoCoordinate(Float coordinate) { } /** - * Returns null if {@link User} has no data in case of masking was applied. + * Returns masked digitrust and eids of user ext. */ - private static User nullIfEmpty(User user) { - return Objects.equals(user, EMPTY_USER) ? null : user; + private ObjectNode maskUserExt(ObjectNode userExt) { + try { + final ExtUser extUser = userExt != null ? mapper.mapper().treeToValue(userExt, ExtUser.class) : null; + final ExtUser maskedExtUser = extUser != null + ? nullIfEmpty(extUser.toBuilder().eids(null).digitrust(null).build()) + : null; + return maskedExtUser != null ? mapper.mapper().valueToTree(maskedExtUser) : null; + } catch (JsonProcessingException e) { + throw new PreBidException(e.getMessage(), e); + } } /** - * Returns masked device with masked ipv4, ipv6 and geo. + * Returns null if {@link ExtUser} has no data in case of masking was applied. */ - private static Device maskDevice(Device device, UnaryOperator maskGeo, UnaryOperator maskIpv6) { - return device != null - ? device.toBuilder() - .ip(maskIpv4(device.getIp())) - .ipv6(maskIpv6.apply(device.getIpv6())) - .geo(maskGeo.apply(device.getGeo())) - .ifa(null) - .macsha1(null).macmd5(null) - .dpidsha1(null).dpidmd5(null) - .didsha1(null).didmd5(null) - .build() - : null; + private static ExtUser nullIfEmpty(ExtUser userExt) { + return Objects.equals(userExt, EMPTY_USER_EXT) ? null : userExt; + } + + /** + * Returns null if {@link User} has no data in case of masking was applied. + */ + private static User nullIfEmpty(User user) { + return Objects.equals(user, EMPTY_USER) ? null : user; } /** @@ -343,4 +459,8 @@ private static String maskIp(String ip, String delimiter, int groups) { IntStream.range(0, groups).mapToObj(ignored -> "0") .collect(Collectors.joining(delimiter, delimiter, ""))); } + + private static boolean isLmtEnabled(Device device) { + return device != null && Objects.equals(device.getLmt(), 1); + } } diff --git a/src/main/java/org/prebid/server/auction/StoredResponseProcessor.java b/src/main/java/org/prebid/server/auction/StoredResponseProcessor.java index 243e438ed4d..6aea4ae5d14 100644 --- a/src/main/java/org/prebid/server/auction/StoredResponseProcessor.java +++ b/src/main/java/org/prebid/server/auction/StoredResponseProcessor.java @@ -65,7 +65,9 @@ public StoredResponseProcessor(ApplicationSettings applicationSettings, this.mapper = Objects.requireNonNull(mapper); } - Future getStoredResponseResult(List imps, Map aliases, Timeout timeout) { + Future getStoredResponseResult( + List imps, BidderAliases aliases, Timeout timeout) { + final List requiredRequestImps = new ArrayList<>(); final Map storedResponseIdToImpId = new HashMap<>(); @@ -109,7 +111,7 @@ List mergeWithBidderResponses(List bidderRespons private void fillStoredResponseIdsAndRequestingImps(List imps, List requiredRequestImps, Map storedResponseIdToImpId, - Map aliases) { + BidderAliases aliases) { for (final Imp imp : imps) { final String impId = imp.getId(); final ObjectNode extImpNode = imp.getExt(); @@ -142,8 +144,9 @@ private ExtImp getExtImp(ObjectNode extImpNode, String impId) { } private void resolveStoredBidResponse(List requiredRequestImps, Map storedResponseIdToImpId, - Map aliases, Imp imp, String impId, ObjectNode extImpNode, - ExtImpPrebid extImpPrebid) { + BidderAliases aliases, Imp imp, String impId, + ObjectNode extImpNode, ExtImpPrebid extImpPrebid) { + final List storedBidResponse = extImpPrebid.getStoredBidResponse(); final Map bidderToStoredId = storedBidResponse != null ? getBidderToStoredResponseId(storedBidResponse, impId) @@ -192,7 +195,7 @@ private Imp removeStoredResponseBidders(Imp imp, ObjectNode extImp, Set return isUpdated ? imp.toBuilder().ext(extImp).build() : imp; } - private boolean hasValidBidder(Map aliases, Imp resolvedBiddersImp) { + private boolean hasValidBidder(BidderAliases aliases, Imp resolvedBiddersImp) { return asStream(resolvedBiddersImp.getExt().fieldNames()) .anyMatch(bidder -> !Objects.equals(bidder, PREBID_EXT) && !Objects.equals(bidder, CONTEXT_EXT) && isValidBidder(bidder, aliases)); @@ -203,8 +206,8 @@ private Stream asStream(Iterator iterator) { return StreamSupport.stream(iterable.spliterator(), false); } - private boolean isValidBidder(String bidder, Map aliases) { - return bidderCatalog.isValidName(bidder) || aliases.containsKey(bidder); + private boolean isValidBidder(String bidder, BidderAliases aliases) { + return bidderCatalog.isValidName(bidder) || aliases.isAliasDefined(bidder); } private List convertToSeatBid(StoredResponseDataResult storedResponseDataResult, diff --git a/src/main/java/org/prebid/server/auction/model/AuctionContext.java b/src/main/java/org/prebid/server/auction/model/AuctionContext.java index 49f177cb639..2655d850bfd 100644 --- a/src/main/java/org/prebid/server/auction/model/AuctionContext.java +++ b/src/main/java/org/prebid/server/auction/model/AuctionContext.java @@ -1,5 +1,6 @@ package org.prebid.server.auction.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.iab.openrtb.request.BidRequest; import io.vertx.ext.web.RoutingContext; import lombok.Builder; @@ -13,12 +14,15 @@ @Value public class AuctionContext { + @JsonIgnore RoutingContext routingContext; + @JsonIgnore UidsCookie uidsCookie; BidRequest bidRequest; + @JsonIgnore Timeout timeout; Account account; diff --git a/src/main/java/org/prebid/server/auction/model/PrivacyEnforcementResult.java b/src/main/java/org/prebid/server/auction/model/BidderPrivacyResult.java similarity index 50% rename from src/main/java/org/prebid/server/auction/model/PrivacyEnforcementResult.java rename to src/main/java/org/prebid/server/auction/model/BidderPrivacyResult.java index 1b282317bb5..460ab32be11 100644 --- a/src/main/java/org/prebid/server/auction/model/PrivacyEnforcementResult.java +++ b/src/main/java/org/prebid/server/auction/model/BidderPrivacyResult.java @@ -2,15 +2,21 @@ import com.iab.openrtb.request.Device; import com.iab.openrtb.request.User; -import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Value; -@AllArgsConstructor(staticName = "of") +@Builder(toBuilder = true) @Value -public class PrivacyEnforcementResult { +public class BidderPrivacyResult { + + String requestBidder; User user; Device device; + + boolean blockedRequestByTcf; + + boolean blockedAnalyticsByTcf; } diff --git a/src/main/java/org/prebid/server/bidder/BidderCatalog.java b/src/main/java/org/prebid/server/bidder/BidderCatalog.java index 1b678581591..483342af873 100644 --- a/src/main/java/org/prebid/server/bidder/BidderCatalog.java +++ b/src/main/java/org/prebid/server/bidder/BidderCatalog.java @@ -22,6 +22,7 @@ public class BidderCatalog { private final Map bidderDepsMap; private final Map deprecatedNameToError = new HashMap<>(); private final Map aliases = new HashMap<>(); + private final Map vendorIdToBidderName = new HashMap<>(); public BidderCatalog(List bidderDeps) { bidderDepsMap = Objects.requireNonNull(bidderDeps).stream() @@ -30,6 +31,13 @@ public BidderCatalog(List bidderDeps) { for (BidderDeps deps : bidderDeps) { deprecatedNameToError.putAll(createErrorsForDeprecatedNames(deps.getDeprecatedNames(), deps.getName())); aliases.putAll(createAliases(deps.getAliases(), deps.getName())); + + final BidderInfo bidderInfo = deps.getBidderInfo(); + final BidderInfo.GdprInfo gdprInfo = bidderInfo != null ? bidderInfo.getGdpr() : null; + final Integer vendorId = gdprInfo != null ? gdprInfo.getVendorId() : null; + if (vendorId != null && vendorId != 0) { + vendorIdToBidderName.put(vendorId, deps.getName()); + } } } @@ -123,6 +131,39 @@ public BidderInfo bidderInfoByName(String name) { return bidderDeps != null ? bidderDeps.getBidderInfo() : null; } + /** + * Returns an VendorId registered by the given name or null if there is none. + *

+ * Therefore this method should be called only for names that previously passed validity check + * through calling {@link #isValidName(String)}. + */ + public Integer vendorIdByName(String name) { + final BidderDeps bidderDeps = bidderDepsMap.get(name); + final BidderInfo bidderInfo = bidderDeps != null ? bidderDeps.getBidderInfo() : null; + final BidderInfo.GdprInfo gdprInfo = bidderInfo != null ? bidderInfo.getGdpr() : null; + return gdprInfo != null ? gdprInfo.getVendorId() : null; + } + + /** + * Returns a Bidder name registered by the vendor ID or null if there is none. + */ + public String nameByVendorId(Integer vendorId) { + return vendorIdToBidderName.get(vendorId); + } + + /** + * Returns VendorIds configured in configuration for prebid server. + */ + public Set knownVendorIds() { + return bidderDepsMap.values().stream() + .map(BidderDeps::getBidderInfo) + .map(BidderInfo::getGdpr) + .map(BidderInfo.GdprInfo::getVendorId) + // TODO change to notNull when migrate from primitives to Object + // .filter(id -> id != 0) + .collect(Collectors.toSet()); + } + /** * Returns an {@link Usersyncer} registered by the given name or null if there is none. *

diff --git a/src/main/java/org/prebid/server/bidder/BidderRequestCompletionTrackerFactory.java b/src/main/java/org/prebid/server/bidder/BidderRequestCompletionTrackerFactory.java index 65cf99e2dc6..0f508b896ef 100644 --- a/src/main/java/org/prebid/server/bidder/BidderRequestCompletionTrackerFactory.java +++ b/src/main/java/org/prebid/server/bidder/BidderRequestCompletionTrackerFactory.java @@ -2,6 +2,7 @@ import com.iab.openrtb.request.BidRequest; +@FunctionalInterface public interface BidderRequestCompletionTrackerFactory { BidderRequestCompletionTracker create(BidRequest bidRequest); diff --git a/src/main/java/org/prebid/server/bidder/adform/AdformAdapter.java b/src/main/java/org/prebid/server/bidder/adform/AdformAdapter.java index 3651ad1de48..eb238edecd9 100644 --- a/src/main/java/org/prebid/server/bidder/adform/AdformAdapter.java +++ b/src/main/java/org/prebid/server/bidder/adform/AdformAdapter.java @@ -127,8 +127,8 @@ private String getUrl(PreBidRequestContext preBidRequestContext, List getPriceTypes(List adformParams) { private MultiMap headers(PreBidRequestContext preBidRequestContext, AdformDigitrust adformDigitrust) { return httpUtil.buildAdformHeaders( VERSION, - ObjectUtils.firstNonNull(preBidRequestContext.getUa(), ""), - ObjectUtils.firstNonNull(preBidRequestContext.getIp(), ""), + ObjectUtils.defaultIfNull(preBidRequestContext.getUa(), ""), + ObjectUtils.defaultIfNull(preBidRequestContext.getIp(), ""), preBidRequestContext.getReferer(), preBidRequestContext.getUidsCookie().uidFrom(cookieFamilyName), adformDigitrust); diff --git a/src/main/java/org/prebid/server/bidder/adform/AdformBidder.java b/src/main/java/org/prebid/server/bidder/adform/AdformBidder.java index 27d8a298509..65fe6e7d99f 100644 --- a/src/main/java/org/prebid/server/bidder/adform/AdformBidder.java +++ b/src/main/java/org/prebid/server/bidder/adform/AdformBidder.java @@ -234,28 +234,28 @@ private Boolean getSecure(List imps) { * Retrieves userAgent from {@link Device}. */ private String getUserAgent(Device device) { - return device != null ? ObjectUtils.firstNonNull(device.getUa(), "") : ""; + return device != null ? ObjectUtils.defaultIfNull(device.getUa(), "") : ""; } /** * Retrieves ip from {@link Device}. */ private String getIp(Device device) { - return device != null ? ObjectUtils.firstNonNull(device.getIp(), "") : ""; + return device != null ? ObjectUtils.defaultIfNull(device.getIp(), "") : ""; } /** * Retrieves ifs from {@link Device}. */ private String getIfa(Device device) { - return device != null ? ObjectUtils.firstNonNull(device.getIfa(), "") : ""; + return device != null ? ObjectUtils.defaultIfNull(device.getIfa(), "") : ""; } /** * Retrieves tid from {@link Source}. */ private String getTid(Source source) { - return source != null ? ObjectUtils.firstNonNull(source.getTid(), "") : ""; + return source != null ? ObjectUtils.defaultIfNull(source.getTid(), "") : ""; } /** diff --git a/src/main/java/org/prebid/server/bidder/adform/AdformRequestUtil.java b/src/main/java/org/prebid/server/bidder/adform/AdformRequestUtil.java index 9f94a55a6fa..29fb646f4d4 100644 --- a/src/main/java/org/prebid/server/bidder/adform/AdformRequestUtil.java +++ b/src/main/java/org/prebid/server/bidder/adform/AdformRequestUtil.java @@ -64,7 +64,7 @@ String getGdprApplies(Regs regs) { */ String getConsent(ExtUser extUser) { final String gdprConsent = extUser != null ? extUser.getConsent() : ""; - return ObjectUtils.firstNonNull(gdprConsent, ""); + return ObjectUtils.defaultIfNull(gdprConsent, ""); } /** diff --git a/src/main/java/org/prebid/server/bidder/brightroll/BrightrollBidder.java b/src/main/java/org/prebid/server/bidder/brightroll/BrightrollBidder.java index 9916b5657a3..915f9dd5d2c 100644 --- a/src/main/java/org/prebid/server/bidder/brightroll/BrightrollBidder.java +++ b/src/main/java/org/prebid/server/bidder/brightroll/BrightrollBidder.java @@ -14,7 +14,9 @@ import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.brightroll.model.PublisherOverride; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.HttpCall; @@ -28,10 +30,8 @@ import org.prebid.server.proto.openrtb.ext.request.brightroll.ExtImpBrightroll; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; -import org.springframework.util.StringUtils; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; @@ -43,27 +43,23 @@ */ public class BrightrollBidder implements Bidder { - private static final String VERSION = "2.5"; + private static final String OPENRTB_VERSION = "2.5"; private static final CharSequence OPEN_RTB_VERSION_HEADER = HttpHeaders.createOptimized("x-openrtb-version"); - - private static final List BLOCKED_CREATIVETYPES_FOR_AD_THRIVE = Arrays.asList(1, 2, 3, 6, 9, 10); - private static final List BLOCKED_CATEGORIES_FOR_ADTHRIVE = - Arrays.asList("IAB8-5", "IAB8-18", "IAB15-1", "IAB7-30", "IAB14-1", "IAB22-1", "IAB3-7", "IAB7-3", - "IAB14-3", "IAB11", "IAB11-1", "IAB11-2", "IAB11-3", "IAB11-4", "IAB11-5", "IAB23", "IAB23-1", - "IAB23-2", "IAB23-3", "IAB23-4", "IAB23-5", "IAB23-6", "IAB23-7", "IAB23-8", "IAB23-9", "IAB23-10", - "IAB7-39", "IAB9-30", "IAB7-44", "IAB25", "IAB25-1", "IAB25-2", "IAB25-3", "IAB25-4", "IAB25-5", - "IAB25-6", "IAB25-7", "IAB26", "IAB26-1", "IAB26-2", "IAB26-3", "IAB26-4"); - private static final TypeReference> BRIGHTROLL_EXT_TYPE_REFERENCE = new TypeReference>() { }; private final String endpointUrl; private final JacksonMapper mapper; + private final Map publisherIdToOverride; + + public BrightrollBidder(String endpointUrl, + JacksonMapper mapper, + Map publisherIdToOverride) { - public BrightrollBidder(String endpointUrl, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); this.mapper = Objects.requireNonNull(mapper); + this.publisherIdToOverride = Objects.requireNonNull(publisherIdToOverride); } /** @@ -125,6 +121,10 @@ private String getAndValidateImpExt(Imp imp) { throw new PreBidException("publisher is empty"); } + if (!publisherIdToOverride.containsKey(publisher)) { + throw new PreBidException("publisher is not valid"); + } + return publisher; } @@ -132,20 +132,22 @@ private String getAndValidateImpExt(Imp imp) { * Updates {@link BidRequest} with default auction type * and {@link Imp}s if something changed or dropped from the list. */ - private static BidRequest updateBidRequest(BidRequest bidRequest, String firstImpExtPublisher, - List errors) { + private BidRequest updateBidRequest(BidRequest bidRequest, String firstImpExtPublisher, + List errors) { final BidRequest.BidRequestBuilder builder = bidRequest.toBuilder(); // Defaulting to first price auction for all prebid requests builder.at(1); - final boolean isAdthrivePublisher = Objects.equals(firstImpExtPublisher, "adthrive"); - if (isAdthrivePublisher) { - builder.bcat(BLOCKED_CATEGORIES_FOR_ADTHRIVE); + final PublisherOverride publisherOverride = publisherIdToOverride.get(firstImpExtPublisher); + + if (publisherOverride != null) { + builder.bcat(publisherOverride.getBcat()) + .badv(publisherOverride.getBadv()); } builder.imp(bidRequest.getImp().stream() .filter(imp -> isImpValid(imp, errors)) - .map(imp -> updateImp(imp, isAdthrivePublisher)) + .map(imp -> updateImp(imp, publisherOverride)) .collect(Collectors.toList())); return builder.build(); @@ -167,7 +169,7 @@ private static boolean isImpValid(Imp imp, List errors) { /** * Updates {@link Imp} {@link Banner} and/or {@link Video}. */ - private static Imp updateImp(Imp imp, boolean isAdthrivePublisher) { + private Imp updateImp(Imp imp, PublisherOverride publisherOverride) { final Banner banner = imp.getBanner(); if (banner != null) { final Banner.BannerBuilder bannerBuilder = banner.toBuilder(); @@ -178,18 +180,18 @@ private static Imp updateImp(Imp imp, boolean isAdthrivePublisher) { .w(firstFormat.getW()) .h(firstFormat.getH()); } - if (isAdthrivePublisher) { - bannerBuilder.battr(BLOCKED_CREATIVETYPES_FOR_AD_THRIVE); + if (publisherOverride != null) { + bannerBuilder.battr(publisherOverride.getImpBattr()); } return imp.toBuilder() .banner(bannerBuilder.build()) .build(); } final Video video = imp.getVideo(); - if (video != null && isAdthrivePublisher) { + if (video != null && publisherOverride != null) { return imp.toBuilder() .video(video.toBuilder() - .battr(BLOCKED_CREATIVETYPES_FOR_AD_THRIVE) + .battr(publisherOverride.getImpBattr()) .build()) .build(); } @@ -202,7 +204,7 @@ private static Imp updateImp(Imp imp, boolean isAdthrivePublisher) { private MultiMap createHeaders(Device device) { final MultiMap headers = HttpUtil.headers(); - headers.add(OPEN_RTB_VERSION_HEADER, VERSION); + headers.add(OPEN_RTB_VERSION_HEADER, OPENRTB_VERSION); if (device != null) { HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.USER_AGENT_HEADER.toString(), device.getUa()); diff --git a/src/main/java/org/prebid/server/bidder/brightroll/model/PublisherOverride.java b/src/main/java/org/prebid/server/bidder/brightroll/model/PublisherOverride.java new file mode 100644 index 00000000000..772f8098973 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/brightroll/model/PublisherOverride.java @@ -0,0 +1,25 @@ +package org.prebid.server.bidder.brightroll.model; + +import lombok.AllArgsConstructor; +import lombok.Value; + +import java.util.List; + +@Value +@AllArgsConstructor(staticName = "of") +public class PublisherOverride { + /** + * Blocked advertisers. + */ + private List badv; + + /** + * Blocked advertisers. + */ + private List bcat; + + /** + * Blocked IAB categories. + */ + private List impBattr; +} diff --git a/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java b/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java index ba4e7e10e8a..d8870e588bb 100644 --- a/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java +++ b/src/main/java/org/prebid/server/bidder/gamma/GammaBidder.java @@ -146,7 +146,7 @@ private String makeUri(ExtImpGamma extImpGamma, String impId, Device device, App .append("?id=").append(extImpGamma.getId()) .append("&zid=").append(extImpGamma.getZid()) .append("&wid=").append(extImpGamma.getWid()) - .append("&bidid=").append(ObjectUtils.firstNonNull(impId, "")) + .append("&bidid=").append(ObjectUtils.defaultIfNull(impId, "")) .append("&hb=pbmobile"); if (device != null) { diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticAdapter.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticAdapter.java index 017d12dd5b2..88115973f7c 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticAdapter.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticAdapter.java @@ -11,10 +11,10 @@ import com.iab.openrtb.request.Site; import com.iab.openrtb.response.BidResponse; import io.vertx.core.MultiMap; +import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpMethod; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; -import io.vertx.ext.web.Cookie; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -368,7 +368,7 @@ private String makeUserCookie(PreBidRequestContext preBidRequestContext) { final UidsCookie uidsCookie = preBidRequestContext.getUidsCookie(); final String cookieValue = uidsCookie != null ? uidsCookie.uidFrom(cookieFamilyName) : null; - return Cookie.cookie("KADUSERCOOKIE", ObjectUtils.firstNonNull(cookieValue, "")).encode(); + return Cookie.cookie("KADUSERCOOKIE", ObjectUtils.defaultIfNull(cookieValue, "")).encode(); } @Override diff --git a/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java b/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java index 31480c2d63b..ce7024015c7 100644 --- a/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java +++ b/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java @@ -27,7 +27,6 @@ import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.client.utils.URIBuilder; @@ -462,8 +461,8 @@ private static boolean isFullyPopulatedVideo(Video video) { } private Video makeVideo(Video video, RubiconVideoParams rubiconVideoParams, ExtImpPrebid prebidImpExt) { - final String videoType = prebidImpExt != null - && BooleanUtils.isTrue(prebidImpExt.getIsRewardedInventory()) ? "rewarded" : null; + final String videoType = prebidImpExt != null && prebidImpExt.getIsRewardedInventory() != null + && prebidImpExt.getIsRewardedInventory() == 1 ? "rewarded" : null; if (rubiconVideoParams == null && videoType == null) { return video; diff --git a/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtil.java b/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtil.java index 7219bc6f6b7..6d865eca4bd 100644 --- a/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtil.java +++ b/src/main/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtil.java @@ -89,7 +89,7 @@ String getPage(Site site) { */ String retrieveFromUserInfo(UserInfo userInfo, Function retrieve) { final String gdprConsent = userInfo != null ? retrieve.apply(userInfo) : ""; - return ObjectUtils.firstNonNull(gdprConsent, ""); + return ObjectUtils.defaultIfNull(gdprConsent, ""); } /** diff --git a/src/main/java/org/prebid/server/bidder/sovrn/SovrnAdapter.java b/src/main/java/org/prebid/server/bidder/sovrn/SovrnAdapter.java index c91dfb9de60..80ff7c94fff 100644 --- a/src/main/java/org/prebid/server/bidder/sovrn/SovrnAdapter.java +++ b/src/main/java/org/prebid/server/bidder/sovrn/SovrnAdapter.java @@ -7,8 +7,8 @@ import com.iab.openrtb.request.User; import com.iab.openrtb.response.BidResponse; import io.vertx.core.MultiMap; +import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpMethod; -import io.vertx.ext.web.Cookie; import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.model.AdUnitBid; import org.prebid.server.auction.model.AdapterRequest; diff --git a/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java b/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java index cef3d595b00..2fd7761bc96 100644 --- a/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java +++ b/src/main/java/org/prebid/server/bidder/sovrn/SovrnBidder.java @@ -10,8 +10,8 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; +import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpMethod; -import io.vertx.ext.web.Cookie; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -111,7 +111,7 @@ private Imp makeImp(Imp imp) { final ExtImpSovrn sovrnExt = parseExtImpSovrn(imp); return imp.toBuilder() .bidfloor(sovrnExt.getBidfloor()) - .tagid(ObjectUtils.firstNonNull(sovrnExt.getTagid(), sovrnExt.getLegacyTagId())) + .tagid(ObjectUtils.defaultIfNull(sovrnExt.getTagid(), sovrnExt.getLegacyTagId())) .build(); } diff --git a/src/main/java/org/prebid/server/bidder/yieldone/YieldoneBidder.java b/src/main/java/org/prebid/server/bidder/yieldone/YieldoneBidder.java new file mode 100644 index 00000000000..9e7615c69d2 --- /dev/null +++ b/src/main/java/org/prebid/server/bidder/yieldone/YieldoneBidder.java @@ -0,0 +1,160 @@ +package org.prebid.server.bidder.yieldone; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +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.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.http.HttpMethod; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.bidder.Bidder; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpCall; +import org.prebid.server.bidder.model.HttpRequest; +import org.prebid.server.bidder.model.Result; +import org.prebid.server.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.yieldone.ExtImpYieldone; +import org.prebid.server.proto.openrtb.ext.response.BidType; +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.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * Yieldone {@link Bidder} implementation. + */ +public class YieldoneBidder implements Bidder { + private static final TypeReference> YIELDONE_EXT_TYPE_REFERENCE = + new TypeReference>() { + }; + private static final String DEFAULT_BID_CURRENCY = "USD"; + private final String endpointUrl; + private final JacksonMapper mapper; + + public YieldoneBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.mapper = Objects.requireNonNull(mapper); + } + + @Override + public Result>> makeHttpRequests(BidRequest request) { + final List errors = new ArrayList<>(); + final List validImps = new ArrayList<>(); + + for (Imp imp : request.getImp()) { + try { + final Imp updatedImp = modifyImp(imp); + validateImpExt(updatedImp); + + validImps.add(updatedImp); + } catch (PreBidException e) { + errors.add(BidderError.badInput(e.getMessage())); + } + } + + final BidRequest outgoingRequest = request.toBuilder().imp(validImps).build(); + final String body = mapper.encode(outgoingRequest); + + return Result.of(Collections.singletonList( + HttpRequest.builder() + .method(HttpMethod.POST) + .uri(endpointUrl) + .headers(HttpUtil.headers()) + .payload(outgoingRequest) + .body(body) + .build()), + errors); + } + + private Imp modifyImp(Imp imp) { + final Banner banner = imp.getBanner(); + if (banner != null) { + if (banner.getH() == null && banner.getW() == null && CollectionUtils.isNotEmpty(banner.getFormat())) { + final Format firstFormat = banner.getFormat().get(0); + final Banner modifiedBanner = banner.toBuilder() + .h(firstFormat.getH()) + .w(firstFormat.getW()) + .build(); + return imp.toBuilder().banner(modifiedBanner).build(); + } + } + return imp; + } + + private void validateImpExt(Imp imp) { + try { + final ExtImpYieldone extImpYieldone = mapper.mapper().convertValue(imp.getExt(), + YIELDONE_EXT_TYPE_REFERENCE).getBidder(); + } catch (IllegalArgumentException e) { + throw new PreBidException(e.getMessage(), e); + } + } + + @Override + public Result> makeBids(HttpCall httpCall, BidRequest bidRequest) { + final int statusCode = httpCall.getResponse().getStatusCode(); + if (statusCode == HttpResponseStatus.NO_CONTENT.code()) { + return Result.of(Collections.emptyList(), Collections.emptyList()); + } else if (statusCode == HttpResponseStatus.BAD_REQUEST.code()) { + return Result.emptyWithError(BidderError.badInput("bad request")); + } else if (statusCode != HttpResponseStatus.OK.code()) { + return Result.emptyWithError(BidderError.badServerResponse(String.format("Unexpected HTTP status %s.", + statusCode))); + } + + try { + final BidResponse bidResponse = decodeBodyToBidResponse(httpCall); + final List bidderBids = bidResponse.getSeatbid().stream() + .filter(Objects::nonNull) + .map(SeatBid::getBid) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .map(bid -> BidderBid.of(bid, getBidType(bid.getImpid(), bidRequest.getImp()), + DEFAULT_BID_CURRENCY)) + .collect(Collectors.toList()); + return Result.of(bidderBids, Collections.emptyList()); + } catch (PreBidException e) { + return Result.emptyWithError(BidderError.badInput(e.getMessage())); + } + } + + private BidResponse decodeBodyToBidResponse(HttpCall httpCall) { + try { + return mapper.decodeValue(httpCall.getResponse().getBody(), BidResponse.class); + } catch (DecodeException e) { + throw new PreBidException(e.getMessage(), e); + } + } + + private static BidType getBidType(String impId, List imps) { + for (Imp imp : imps) { + if (imp.getId().equals(impId)) { + if (imp.getBanner() != null) { + return BidType.banner; + } else if (imp.getVideo() != null) { + return BidType.video; + } + } + } + throw new PreBidException(String.format("Failed to find impression %s", impId)); + } + + @Override + public Map extractTargeting(ObjectNode ext) { + return Collections.emptyMap(); + } +} + diff --git a/src/main/java/org/prebid/server/cache/CacheService.java b/src/main/java/org/prebid/server/cache/CacheService.java index 07de1a6e873..8599fee4b16 100644 --- a/src/main/java/org/prebid/server/cache/CacheService.java +++ b/src/main/java/org/prebid/server/cache/CacheService.java @@ -1,12 +1,14 @@ package org.prebid.server.cache; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.TextNode; import com.iab.openrtb.request.Imp; import io.vertx.core.Future; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.prebid.server.cache.model.CacheBid; import org.prebid.server.cache.model.CacheContext; @@ -22,6 +24,7 @@ import org.prebid.server.cache.proto.request.PutObject; import org.prebid.server.cache.proto.response.BidCacheResponse; import org.prebid.server.cache.proto.response.CacheObject; +import org.prebid.server.events.EventsContext; import org.prebid.server.events.EventsService; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.Timeout; @@ -183,14 +186,20 @@ private List updatePutObjects(List putObjects, Set final List updatedPutObjects = new ArrayList<>(); for (PutObject putObject : putObjects) { + final PutObject.PutObjectBuilder builder = putObject.toBuilder() + // remove "/vtrack" specific fields + .bidid(null) + .bidder(null) + .timestamp(null); + final JsonNode value = putObject.getValue(); if (biddersAllowingVastUpdate.contains(putObject.getBidder()) && value != null) { - final String updatedVastValue = modifyVastXml(value.asText(), putObject.getBidid(), accountId); - final PutObject updatedPutObject = putObject.toBuilder().value(new TextNode(updatedVastValue)).build(); - updatedPutObjects.add(updatedPutObject); - } else { - updatedPutObjects.add(putObject); + final String updatedVastXml = modifyVastXml(value.asText(), putObject.getBidid(), + putObject.getBidder(), accountId, putObject.getTimestamp()); + builder.value(new TextNode(updatedVastXml)).build(); } + + updatedPutObjects.add(builder.build()); } return updatedPutObjects; } @@ -199,7 +208,8 @@ private List updatePutObjects(List putObjects, Set * Makes cache for OpenRTB {@link com.iab.openrtb.response.Bid}s. */ public Future cacheBidsOpenrtb(List bids, List imps, - CacheContext cacheContext, Account account, Timeout timeout) { + CacheContext cacheContext, Account account, + EventsContext eventsContext, Timeout timeout) { final Future result; if (CollectionUtils.isEmpty(bids)) { @@ -220,11 +230,12 @@ public Future cacheBidsOpenrtb(List cacheBids = getCacheBids(cacheContext.isShouldCacheBids(), bids, impIdToTtl, impWithNoExpExists, cacheContext.getCacheBidsTtl(), account); + final List videoCacheBids = getVideoCacheBids(shouldCacheVideoBids, bids, impIdToTtl, videoImpIds, impWithNoExpExists, cacheContext.getCacheVideoBidsTtl(), account); - result = doCacheOpenrtb(cacheBids, videoCacheBids, cacheContext.getVideoBidIdsToModify(), account.getId(), - timeout); + result = doCacheOpenrtb(cacheBids, videoCacheBids, cacheContext.getBidderToVideoBidIdsToModify(), + cacheContext.getBidderToBidIds(), account, eventsContext.getAuctionTimestamp(), timeout); } return result; @@ -297,12 +308,15 @@ private CacheBid toCacheBid(com.iab.openrtb.response.Bid bid, Map * The returned result will always have the number of elements equals to sum of sizes of bids and video bids. */ - private Future doCacheOpenrtb( - List bids, List videoBids, List videoBidIdsToModify, String accountId, - Timeout timeout) { + private Future doCacheOpenrtb(List bids, List videoBids, + Map> bidderToVideoBidIdsToModify, + Map> biddersToCacheBidIds, + Account account, Long auctionTimestamp, Timeout timeout) { final List putObjects = Stream.concat( - bids.stream().map(this::createJsonPutObjectOpenrtb), - videoBids.stream().map(cacheBid -> createXmlPutObjectOpenrtb(cacheBid, videoBidIdsToModify, accountId))) + bids.stream().map(cacheBid -> createJsonPutObjectOpenrtb(cacheBid, biddersToCacheBidIds, account, + auctionTimestamp)), + videoBids.stream().map(cacheBid -> createXmlPutObjectOpenrtb(cacheBid, bidderToVideoBidIdsToModify, + account.getId(), auctionTimestamp))) .collect(Collectors.toList()); if (putObjects.isEmpty()) { @@ -379,12 +393,27 @@ private static PutObject createPutObjectVideoOnly(Bid bid) { } /** - * Makes JSON type {@link PutObject} from {@link com.iab.openrtb.response.Bid}. Used for OpenRTB auction request. + * Makes JSON type {@link PutObject} from {@link com.iab.openrtb.response.Bid}. + * Used for OpenRTB auction request. Also, adds win url to result object if events are enabled. */ - private PutObject createJsonPutObjectOpenrtb(CacheBid cacheBid) { + private PutObject createJsonPutObjectOpenrtb(CacheBid cacheBid, Map> biddersToCacheBidIds, + Account account, Long auctionTimestamp) { + final com.iab.openrtb.response.Bid bid = cacheBid.getBid(); + final ObjectNode bidObjectNode = mapper.mapper().valueToTree(bid); + + if (BooleanUtils.isTrue(account.getEventsEnabled())) { + final String bidId = bid.getId(); + biddersToCacheBidIds.entrySet().stream() + .filter(biddersAndBidIds -> biddersAndBidIds.getValue().contains(bidId)) + .findFirst() + .map(Map.Entry::getKey) + .ifPresent(bidder -> bidObjectNode.put("wurl", eventsService.winUrl(bidId, bidder, account.getId(), + auctionTimestamp))); + } + return PutObject.builder() .type("json") - .value(mapper.mapper().valueToTree(cacheBid.getBid())) + .value(bidObjectNode) .expiry(cacheBid.getTtl()) .build(); } @@ -392,8 +421,9 @@ private PutObject createJsonPutObjectOpenrtb(CacheBid cacheBid) { /** * Makes XML type {@link PutObject} from {@link com.iab.openrtb.response.Bid}. Used for OpenRTB auction request. */ - private PutObject createXmlPutObjectOpenrtb(CacheBid cacheBid, List videoBidIdsToModify, - String accountId) { + private PutObject createXmlPutObjectOpenrtb(CacheBid cacheBid, + Map> bidderToVideoBidIdsToModify, + String accountId, Long auctionTimestamp) { final com.iab.openrtb.response.Bid bid = cacheBid.getBid(); String vastXml; if (bid.getAdm() == null) { @@ -407,18 +437,21 @@ private PutObject createXmlPutObjectOpenrtb(CacheBid cacheBid, List vide } final String bidId = bid.getId(); - if (CollectionUtils.isNotEmpty(videoBidIdsToModify) && videoBidIdsToModify.contains(bidId)) { - vastXml = modifyVastXml(vastXml, bidId, accountId); - } + final String modifiedVastXml = bidderToVideoBidIdsToModify.entrySet().stream() + .filter(biddersAndBidIds -> biddersAndBidIds.getValue().contains(bidId)) + .findFirst() + .map(Map.Entry::getKey) + .map(bidder -> modifyVastXml(vastXml, bidId, bidder, accountId, auctionTimestamp)) + .orElse(vastXml); return PutObject.builder() .type("xml") - .value(new TextNode(vastXml)) + .value(new TextNode(modifiedVastXml)) .expiry(cacheBid.getTtl()) .build(); } - private String modifyVastXml(String stringValue, String bidId, String accountId) { + private String modifyVastXml(String stringValue, String bidId, String bidder, String accountId, Long timestamp) { final String closeTag = ""; final int closeTagIndex = stringValue.indexOf(closeTag); @@ -427,7 +460,8 @@ private String modifyVastXml(String stringValue, String bidId, String accountId) return stringValue; } - final String impressionUrl = ""; + final String vastUrlTracking = eventsService.vastUrlTracking(bidId, bidder, accountId, timestamp); + final String impressionUrl = ""; final String openTag = ""; // empty impression tag - just insert the link diff --git a/src/main/java/org/prebid/server/cache/model/CacheContext.java b/src/main/java/org/prebid/server/cache/model/CacheContext.java index bc64af9cb12..f26c975c212 100644 --- a/src/main/java/org/prebid/server/cache/model/CacheContext.java +++ b/src/main/java/org/prebid/server/cache/model/CacheContext.java @@ -4,6 +4,7 @@ import lombok.Value; import java.util.List; +import java.util.Map; /** * Holds the state needed to perform caching response bids. @@ -20,5 +21,7 @@ public class CacheContext { Integer cacheVideoBidsTtl; - List videoBidIdsToModify; + Map> bidderToVideoBidIdsToModify; + + Map> bidderToBidIds; } diff --git a/src/main/java/org/prebid/server/cache/proto/request/PutObject.java b/src/main/java/org/prebid/server/cache/proto/request/PutObject.java index 3bfb525e1f7..a68a689687b 100644 --- a/src/main/java/org/prebid/server/cache/proto/request/PutObject.java +++ b/src/main/java/org/prebid/server/cache/proto/request/PutObject.java @@ -14,10 +14,11 @@ public class PutObject { Integer expiry; - String bidid; + Integer ttlseconds; - String bidder; + String bidid; // this is "/vtrack" specific - Integer ttlseconds; -} + String bidder; // this is "/vtrack" specific + Long timestamp; // this is "/vtrack" specific +} diff --git a/src/main/java/org/prebid/server/cookie/UidsCookieService.java b/src/main/java/org/prebid/server/cookie/UidsCookieService.java index 8622e6a8421..1fa3f1d0364 100644 --- a/src/main/java/org/prebid/server/cookie/UidsCookieService.java +++ b/src/main/java/org/prebid/server/cookie/UidsCookieService.java @@ -1,9 +1,9 @@ package org.prebid.server.cookie; import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.Cookie; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; -import io.vertx.ext.web.Cookie; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; diff --git a/src/main/java/org/prebid/server/events/EventRequest.java b/src/main/java/org/prebid/server/events/EventRequest.java index 66da416acc4..cf631b33dbc 100644 --- a/src/main/java/org/prebid/server/events/EventRequest.java +++ b/src/main/java/org/prebid/server/events/EventRequest.java @@ -16,6 +16,10 @@ public class EventRequest { String accountId; + String bidder; + + Long timestamp; + Format format; Analytics analytics; diff --git a/src/main/java/org/prebid/server/events/EventUtil.java b/src/main/java/org/prebid/server/events/EventUtil.java index e154fd0c71d..8fb4f6833a4 100644 --- a/src/main/java/org/prebid/server/events/EventUtil.java +++ b/src/main/java/org/prebid/server/events/EventUtil.java @@ -22,6 +22,9 @@ public class EventUtil { // Optional query string parameters + private static final String BIDDER_PARAMETER = "bidder"; + private static final String TIMESTAMP_PARAMETER = "ts"; + private static final String FORMAT_PARAMETER = "f"; private static final String BLANK_FORMAT = "b"; // default private static final String IMAGE_FORMAT = "i"; @@ -42,14 +45,6 @@ public static void validateType(RoutingContext context) { } } - public static void validateBidId(RoutingContext context) { - final String bidId = context.request().params().get(BID_ID_PARAMETER); - if (StringUtils.isBlank(bidId)) { - throw new IllegalArgumentException(String.format( - "BidId '%s' is required query parameter and can't be empty", BID_ID_PARAMETER)); - } - } - public static void validateAccountId(RoutingContext context) { final String accountId = context.request().params().get(ACCOUNT_ID_PARAMETER); if (StringUtils.isBlank(accountId)) { @@ -58,6 +53,14 @@ public static void validateAccountId(RoutingContext context) { } } + public static void validateBidId(RoutingContext context) { + final String bidId = context.request().params().get(BID_ID_PARAMETER); + if (StringUtils.isBlank(bidId)) { + throw new IllegalArgumentException(String.format( + "BidId '%s' is required query parameter and can't be empty", BID_ID_PARAMETER)); + } + } + public static void validateFormat(RoutingContext context) { final String format = context.request().params().get(FORMAT_PARAMETER); if (StringUtils.isNotEmpty(format) && !format.equals(BLANK_FORMAT) && !format.equals(IMAGE_FORMAT)) { @@ -77,6 +80,18 @@ public static void validateAnalytics(RoutingContext context) { } } + public static void validateTimestamp(RoutingContext context) { + final String timestamp = StringUtils.stripToNull(context.request().params().get(TIMESTAMP_PARAMETER)); + if (timestamp != null) { + try { + Long.parseLong(timestamp); + } catch (NumberFormatException e) { + throw new IllegalArgumentException(String.format( + "Timestamp '%s' query parameter is not valid number: %s", TIMESTAMP_PARAMETER, timestamp)); + } + } + } + public static EventRequest from(RoutingContext context) { final MultiMap queryParams = context.request().params(); @@ -90,10 +105,15 @@ public static EventRequest from(RoutingContext context) { queryParams.get(ANALYTICS_PARAMETER)) ? EventRequest.Analytics.disabled : EventRequest.Analytics.enabled; + final String timestampAsString = StringUtils.stripToNull(queryParams.get(TIMESTAMP_PARAMETER)); + final Long timestamp = timestampAsString != null ? Long.valueOf(timestampAsString) : null; + return EventRequest.builder() .type(type) .bidId(queryParams.get(BID_ID_PARAMETER)) .accountId(queryParams.get(ACCOUNT_ID_PARAMETER)) + .bidder(queryParams.get(BIDDER_PARAMETER)) + .timestamp(timestamp) .format(format) .analytics(analytics) .build(); @@ -105,25 +125,37 @@ static String toUrl(String externalUrl, EventRequest eventRequest) { eventRequest.getBidId(), eventRequest.getAccountId()); - final String formatQueryString; + return urlWithRequiredParameters + optionalParameters(eventRequest); + } + + private static String optionalParameters(EventRequest eventRequest) { + final StringBuilder result = new StringBuilder(); + + // timestamp + if (eventRequest.getTimestamp() != null) { + result.append(nameValueAsQueryString(TIMESTAMP_PARAMETER, eventRequest.getTimestamp().toString())); + } + + // bidder + if (eventRequest.getBidder() != null) { + result.append(nameValueAsQueryString(BIDDER_PARAMETER, eventRequest.getBidder())); + } + + // format if (eventRequest.getFormat() == EventRequest.Format.blank) { - formatQueryString = nameValueAsQueryString(FORMAT_PARAMETER, BLANK_FORMAT); + result.append(nameValueAsQueryString(FORMAT_PARAMETER, BLANK_FORMAT)); } else if (eventRequest.getFormat() == EventRequest.Format.image) { - formatQueryString = nameValueAsQueryString(FORMAT_PARAMETER, IMAGE_FORMAT); - } else { - formatQueryString = StringUtils.EMPTY; // skip parameter + result.append(nameValueAsQueryString(FORMAT_PARAMETER, IMAGE_FORMAT)); } - final String analyticsQueryString; + // analytics if (eventRequest.getAnalytics() == EventRequest.Analytics.enabled) { - analyticsQueryString = nameValueAsQueryString(ANALYTICS_PARAMETER, ENABLED_ANALYTICS); + result.append(nameValueAsQueryString(ANALYTICS_PARAMETER, ENABLED_ANALYTICS)); } else if (eventRequest.getAnalytics() == EventRequest.Analytics.disabled) { - analyticsQueryString = nameValueAsQueryString(ANALYTICS_PARAMETER, DISABLED_ANALYTICS); - } else { - analyticsQueryString = StringUtils.EMPTY; // skip parameter + result.append(nameValueAsQueryString(ANALYTICS_PARAMETER, DISABLED_ANALYTICS)); } - return urlWithRequiredParameters + formatQueryString + analyticsQueryString; + return result.toString(); } private static String nameValueAsQueryString(String name, String value) { diff --git a/src/main/java/org/prebid/server/events/EventsContext.java b/src/main/java/org/prebid/server/events/EventsContext.java new file mode 100644 index 00000000000..5d16762dfb3 --- /dev/null +++ b/src/main/java/org/prebid/server/events/EventsContext.java @@ -0,0 +1,14 @@ +package org.prebid.server.events; + +import lombok.Builder; +import lombok.Value; + +/** + * Accumulates information for proceeding events. + */ +@Builder +@Value +public class EventsContext { + + Long auctionTimestamp; +} diff --git a/src/main/java/org/prebid/server/events/EventsService.java b/src/main/java/org/prebid/server/events/EventsService.java index 5724010fa26..1f6fbefe388 100644 --- a/src/main/java/org/prebid/server/events/EventsService.java +++ b/src/main/java/org/prebid/server/events/EventsService.java @@ -18,31 +18,42 @@ public EventsService(String externalUrl) { /** * Returns {@link Events} object based on given params. */ - public Events createEvent(String bidId, String accountId) { + public Events createEvent(String bidId, String bidder, String accountId, Long timestamp) { return Events.of( - eventUrl(EventRequest.Type.win, bidId, accountId, EventRequest.Format.image), - eventUrl(EventRequest.Type.imp, bidId, accountId, EventRequest.Format.image)); + eventUrl(EventRequest.Type.win, bidId, bidder, accountId, timestamp, EventRequest.Format.image), + eventUrl(EventRequest.Type.imp, bidId, bidder, accountId, timestamp, EventRequest.Format.image)); } /** * Returns value for "hb_winurl" targeting keyword. */ - public String winUrlTargeting(String accountId) { - return eventUrl(EventRequest.Type.win, BIDID_PLACEHOLDER, accountId, EventRequest.Format.image); + public String winUrlTargeting(String bidder, String accountId, Long timestamp) { + return eventUrl(EventRequest.Type.win, BIDID_PLACEHOLDER, bidder, accountId, timestamp, + EventRequest.Format.image); + } + + /** + * Returns url for win tracking. + */ + public String winUrl(String bidId, String bidder, String accountId, Long timestamp) { + return eventUrl(EventRequest.Type.win, bidId, bidder, accountId, timestamp, EventRequest.Format.image); } /** * Returns url for VAST tracking. */ - public String vastUrlTracking(String bidId, String accountId) { - return eventUrl(EventRequest.Type.imp, bidId, accountId, EventRequest.Format.blank); + public String vastUrlTracking(String bidId, String bidder, String accountId, Long timestamp) { + return eventUrl(EventRequest.Type.imp, bidId, bidder, accountId, timestamp, EventRequest.Format.blank); } - private String eventUrl(EventRequest.Type type, String bidId, String accountId, EventRequest.Format format) { + private String eventUrl(EventRequest.Type type, String bidId, String bidder, String accountId, Long timestamp, + EventRequest.Format format) { final EventRequest eventRequest = EventRequest.builder() .type(type) .bidId(bidId) .accountId(accountId) + .bidder(bidder) + .timestamp(timestamp) .format(format) .build(); diff --git a/src/main/java/org/prebid/server/execution/LogModifier.java b/src/main/java/org/prebid/server/execution/LogModifier.java deleted file mode 100644 index 8dc908667b7..00000000000 --- a/src/main/java/org/prebid/server/execution/LogModifier.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.prebid.server.execution; - -import io.vertx.core.logging.Logger; - -import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; - -public class LogModifier { - - private AtomicInteger errorLevelCount; - private volatile BiConsumer defaultLogModifier; - private volatile BiConsumer logModifier; - - public LogModifier(Logger defaultLogger) { - defaultLogModifier = defaultLogModifier(defaultLogger); - } - - private static BiConsumer defaultLogModifier(Logger defaultLogger) { - if (defaultLogger.isTraceEnabled()) { - return Logger::trace; - } else if (defaultLogger.isDebugEnabled()) { - return Logger::debug; - } else if (defaultLogger.isInfoEnabled()) { - return Logger::info; - } else if (defaultLogger.isWarnEnabled()) { - return Logger::warn; - } - return Logger::error; - } - - public void set(BiConsumer logModifier, int requestCount) { - this.errorLevelCount = new AtomicInteger(requestCount); - this.logModifier = Objects.requireNonNull(logModifier); - } - - public BiConsumer get() { - if (errorLevelCount != null && errorLevelCount.get() > 0) { - errorLevelCount.decrementAndGet(); - return logModifier; - } - return defaultLogModifier; - } -} - diff --git a/src/main/java/org/prebid/server/execution/RemoteFileSyncer.java b/src/main/java/org/prebid/server/execution/RemoteFileSyncer.java index d1de722cc3c..dc71788274e 100644 --- a/src/main/java/org/prebid/server/execution/RemoteFileSyncer.java +++ b/src/main/java/org/prebid/server/execution/RemoteFileSyncer.java @@ -2,6 +2,7 @@ import io.vertx.core.AsyncResult; import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.file.AsyncFile; import io.vertx.core.file.CopyOptions; @@ -100,78 +101,79 @@ public void syncForFilepath(RemoteFileProcessor remoteFileProcessor) { } private Future downloadIfNotExist(RemoteFileProcessor fileProcessor) { - final Future future = Future.future(); + final Promise promise = Promise.promise(); checkFileExist(saveFilePath).setHandler(existResult -> - handleFileExistingWithSync(existResult, fileProcessor, future)); - return future; + handleFileExistingWithSync(existResult, fileProcessor, promise)); + return promise.future(); } private Future checkFileExist(String filePath) { - final Future result = Future.future(); + final Promise promise = Promise.promise(); fileSystem.exists(filePath, async -> { if (async.succeeded()) { - result.complete(async.result()); + promise.complete(async.result()); } else { - result.fail(String.format("Cant check if file exists %s", filePath)); + promise.fail(String.format("Cant check if file exists %s", filePath)); } }); - return result; + return promise.future(); } private void handleFileExistingWithSync(AsyncResult existResult, RemoteFileProcessor fileProcessor, - Future future) { + Promise promise) { if (existResult.succeeded()) { if (existResult.result()) { fileProcessor.setDataPath(saveFilePath) - .setHandler(serviceRespond -> handleServiceRespond(serviceRespond, future)); + .setHandler(serviceRespond -> handleServiceRespond(serviceRespond, promise)); } else { - syncRemoteFiles().setHandler(future); + syncRemoteFiles().setHandler(promise); } } else { - future.fail(existResult.cause()); + promise.fail(existResult.cause()); } } - private void handleServiceRespond(AsyncResult processResult, Future future) { + private void handleServiceRespond(AsyncResult processResult, Promise promise) { if (processResult.failed()) { final Throwable cause = processResult.cause(); - cleanUp(saveFilePath).setHandler(removalResult -> handleCorruptedFileRemoval(removalResult, future, cause)); + cleanUp(saveFilePath).setHandler(removalResult -> handleCorruptedFileRemoval(removalResult, promise, + cause)); } else { - future.complete(false); + promise.complete(false); logger.info("Existing file {0} was successfully reused for service", saveFilePath); } } private Future cleanUp(String filePath) { - final Future future = Future.future(); - checkFileExist(filePath).setHandler(existResult -> handleFileExistsWithDelete(filePath, existResult, future)); - return future; + final Promise promise = Promise.promise(); + checkFileExist(filePath).setHandler(existResult -> handleFileExistsWithDelete(filePath, existResult, promise)); + return promise.future(); } - private void handleFileExistsWithDelete(String filePath, AsyncResult existResult, Future future) { + private void handleFileExistsWithDelete(String filePath, AsyncResult existResult, Promise promise) { if (existResult.succeeded()) { if (existResult.result()) { - fileSystem.delete(filePath, future); + fileSystem.delete(filePath, promise); } else { - future.complete(); + promise.complete(); } } else { - future.fail(new PreBidException(String.format("Cant check if file exists %s", filePath))); + promise.fail(new PreBidException(String.format("Cant check if file exists %s", filePath))); } } - private void handleCorruptedFileRemoval(AsyncResult removalResult, Future future, - Throwable serviceCause) { + private void handleCorruptedFileRemoval( + AsyncResult removalResult, Promise promise, Throwable serviceCause) { if (removalResult.failed()) { final Throwable cause = removalResult.cause(); - future.fail(new PreBidException( + promise.fail(new PreBidException( String.format("Corrupted file %s cant be deleted. Please check permission or delete manually.", saveFilePath), cause)); } else { logger.info("Existing file {0} cant be processed by service, try to download after removal", serviceCause, saveFilePath); - syncRemoteFiles().setHandler(future); + syncRemoteFiles().setHandler(promise); } } @@ -182,107 +184,110 @@ private Future syncRemoteFiles() { } private Future tryDownload() { - final Future result = Future.future(); - cleanUp(tmpFilePath).setHandler(event -> handleTmpDelete(event, result)); - return result; + final Promise promise = Promise.promise(); + cleanUp(tmpFilePath).setHandler(event -> handleTmpDelete(event, promise)); + return promise.future(); } - private void handleTmpDelete(AsyncResult tmpDeleteResult, Future result) { + private void handleTmpDelete(AsyncResult tmpDeleteResult, Promise promise) { if (tmpDeleteResult.failed()) { - result.fail(tmpDeleteResult.cause()); + promise.fail(tmpDeleteResult.cause()); } else { - download().setHandler(downloadResult -> handleDownload(downloadResult, result)); + download().setHandler(downloadResult -> handleDownload(downloadResult, promise)); } } private Future download() { - final Future future = Future.future(); + final Promise promise = Promise.promise(); final OpenOptions openOptions = new OpenOptions().setCreateNew(true); - fileSystem.open(tmpFilePath, openOptions, openResult -> handleFileOpenWithDownload(openResult, future)); - return future; + fileSystem.open(tmpFilePath, openOptions, openResult -> handleFileOpenWithDownload(openResult, promise)); + return promise.future(); } - private void handleFileOpenWithDownload(AsyncResult openResult, Future future) { + private void handleFileOpenWithDownload(AsyncResult openResult, Promise promise) { if (openResult.succeeded()) { final AsyncFile asyncFile = openResult.result(); try { - httpClient.getAbs(downloadUrl, response -> pumpFileFromRequest(response, asyncFile, future)).end(); + httpClient.getAbs(downloadUrl, response -> pumpFileFromRequest(response, asyncFile, promise)).end(); } catch (Exception e) { - future.fail(e); + promise.fail(e); } } else { - future.fail(openResult.cause()); + promise.fail(openResult.cause()); } } - private void pumpFileFromRequest(HttpClientResponse httpClientResponse, AsyncFile asyncFile, Future future) { + private void pumpFileFromRequest( + HttpClientResponse httpClientResponse, AsyncFile asyncFile, Promise promise) { + logger.info("Trying to download file from {0}", downloadUrl); httpClientResponse.pause(); final Pump pump = Pump.pump(httpClientResponse, asyncFile); pump.start(); httpClientResponse.resume(); - final long idTimer = setTimeoutTimer(asyncFile, pump, future); + final long idTimer = setTimeoutTimer(asyncFile, pump, promise); - httpClientResponse.endHandler(responseEndResult -> handleResponseEnd(asyncFile, idTimer, future)); + httpClientResponse.endHandler(responseEndResult -> handleResponseEnd(asyncFile, idTimer, promise)); } - private long setTimeoutTimer(AsyncFile asyncFile, Pump pump, Future future) { - return vertx.setTimer(timeout, timerId -> handleTimeout(asyncFile, pump, future)); + private long setTimeoutTimer(AsyncFile asyncFile, Pump pump, Promise promise) { + return vertx.setTimer(timeout, timerId -> handleTimeout(asyncFile, pump, promise)); } - private void handleTimeout(AsyncFile asyncFile, Pump pump, Future future) { + private void handleTimeout(AsyncFile asyncFile, Pump pump, Promise promise) { pump.stop(); asyncFile.close(); - if (!future.isComplete()) { - future.fail(new TimeoutException("Timeout on download")); + if (!promise.future().isComplete()) { + promise.fail(new TimeoutException("Timeout on download")); } } - private void handleResponseEnd(AsyncFile asyncFile, long idTimer, Future future) { + private void handleResponseEnd(AsyncFile asyncFile, long idTimer, Promise promise) { vertx.cancelTimer(idTimer); - asyncFile.flush().close(future); + asyncFile.flush().close(promise); } - private void handleDownload(AsyncResult downloadResult, Future future) { + private void handleDownload(AsyncResult downloadResult, Promise promise) { if (downloadResult.failed()) { - retryDownload(future, retryInterval, retryCount); + retryDownload(promise, retryInterval, retryCount); } else { - future.complete(); + promise.complete(); } } - private void retryDownload(Future receivedFuture, long retryInterval, long retryCount) { + private void retryDownload(Promise receivedPromise, long retryInterval, long retryCount) { logger.info("Set retry {0} to download from {1}. {2} retries left", retryInterval, downloadUrl, retryCount); - vertx.setTimer(retryInterval, retryTimerId -> handleRetry(receivedFuture, retryInterval, retryCount)); + vertx.setTimer(retryInterval, retryTimerId -> handleRetry(receivedPromise, retryInterval, retryCount)); } - private void handleRetry(Future receivedFuture, long retryInterval, long retryCount) { + private void handleRetry(Promise receivedPromise, long retryInterval, long retryCount) { if (retryCount > 0) { final long next = retryCount - 1; cleanUp(tmpFilePath).compose(ignore -> download()) - .setHandler(retryResult -> handleRetryResult(retryInterval, next, retryResult, receivedFuture)); + .setHandler(retryResult -> handleRetryResult(retryInterval, next, retryResult, receivedPromise)); } else { - cleanUp(tmpFilePath).setHandler(ignore -> receivedFuture.fail(new PreBidException( + cleanUp(tmpFilePath).setHandler(ignore -> receivedPromise.fail(new PreBidException( String.format("File sync failed after %s retries", this.retryCount - retryCount)))); } } - private void handleRetryResult(long retryInterval, long next, AsyncResult retryResult, Future future) { + private void handleRetryResult(long retryInterval, long next, AsyncResult retryResult, + Promise promise) { if (retryResult.succeeded()) { - future.complete(); + promise.complete(); } else { - retryDownload(future, retryInterval, next); + retryDownload(promise, retryInterval, next); } } private Future swapFiles() { - final Future result = Future.future(); + final Promise promise = Promise.promise(); logger.info("Sync {0} to {1}", tmpFilePath, saveFilePath); final CopyOptions copyOptions = new CopyOptions().setReplaceExisting(true); - fileSystem.move(tmpFilePath, saveFilePath, copyOptions, result); - return result; + fileSystem.move(tmpFilePath, saveFilePath, copyOptions, promise); + return promise.future(); } private void handleSync(RemoteFileProcessor remoteFileProcessor, AsyncResult syncResult) { @@ -329,14 +334,14 @@ private Future tryUpdate() { } private Future isNeedToUpdate() { - final Future isNeedToUpdate = Future.future(); + final Promise isNeedToUpdate = Promise.promise(); httpClient.headAbs(downloadUrl, response -> checkNewVersion(response, isNeedToUpdate)) .exceptionHandler(isNeedToUpdate::fail) .end(); - return isNeedToUpdate; + return isNeedToUpdate.future(); } - private void checkNewVersion(HttpClientResponse response, Future isNeedToUpdate) { + private void checkNewVersion(HttpClientResponse response, Promise isNeedToUpdate) { final String contentLengthParameter = response.getHeader(HttpHeaders.CONTENT_LENGTH); if (StringUtils.isNumeric(contentLengthParameter) && !contentLengthParameter.equals("0")) { final long contentLength = Long.parseLong(contentLengthParameter); diff --git a/src/main/java/org/prebid/server/execution/Timeout.java b/src/main/java/org/prebid/server/execution/Timeout.java index 0eb6c0d2e9d..0fbf44a1ebb 100644 --- a/src/main/java/org/prebid/server/execution/Timeout.java +++ b/src/main/java/org/prebid/server/execution/Timeout.java @@ -8,6 +8,7 @@ public class Timeout { private final Clock clock; + private final long deadline; Timeout(Clock clock, long deadline) { diff --git a/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java b/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java index 4a769184de2..dd19676e7f6 100755 --- a/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java +++ b/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java @@ -6,11 +6,13 @@ import io.vertx.core.logging.LoggerFactory; import org.prebid.server.execution.Timeout; import org.prebid.server.geolocation.model.GeoInfo; +import org.prebid.server.log.ConditionalLogger; import org.prebid.server.metric.Metrics; import org.prebid.server.vertx.CircuitBreaker; import java.time.Clock; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * Wrapper for geo location service with circuit breaker. @@ -18,6 +20,8 @@ public class CircuitBreakerSecuredGeoLocationService implements GeoLocationService { private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerSecuredGeoLocationService.class); + private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger); + private static final int LOG_PERIOD_SECONDS = 5; private final CircuitBreaker breaker; private final GeoLocationService geoLocationService; @@ -40,7 +44,8 @@ public CircuitBreakerSecuredGeoLocationService(Vertx vertx, GeoLocationService g } private void circuitOpened() { - logger.warn("GeoLocation service is unavailable, circuit opened."); + conditionalLogger.warn("GeoLocation service is unavailable, circuit opened.", + LOG_PERIOD_SECONDS, TimeUnit.SECONDS); metrics.updateGeoLocationCircuitBreakerMetric(true); } @@ -55,6 +60,6 @@ private void circuitClosed() { @Override public Future lookup(String ip, Timeout timeout) { - return breaker.execute(future -> geoLocationService.lookup(ip, timeout).setHandler(future)); + return breaker.execute(promise -> geoLocationService.lookup(ip, timeout).setHandler(promise)); } } diff --git a/src/main/java/org/prebid/server/handler/AccountCacheInvalidationHandler.java b/src/main/java/org/prebid/server/handler/AccountCacheInvalidationHandler.java new file mode 100644 index 00000000000..68bb4f3ad0c --- /dev/null +++ b/src/main/java/org/prebid/server/handler/AccountCacheInvalidationHandler.java @@ -0,0 +1,38 @@ +package org.prebid.server.handler; + +import io.netty.handler.codec.http.HttpResponseStatus; +import io.vertx.core.Handler; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.ext.web.RoutingContext; +import org.apache.commons.lang3.StringUtils; +import org.prebid.server.settings.CachingApplicationSettings; +import org.prebid.server.util.HttpUtil; + +import java.util.Objects; + +/** + * Handles HTTP requests for invalidating account settings cache. + */ +public class AccountCacheInvalidationHandler implements Handler { + + private static final String ACCOUNT_ID_PARAM = "account"; + + private final CachingApplicationSettings cachingApplicationSettings; + + public AccountCacheInvalidationHandler(CachingApplicationSettings cachingApplicationSettings) { + this.cachingApplicationSettings = Objects.requireNonNull(cachingApplicationSettings); + } + + @Override + public void handle(RoutingContext context) { + final HttpServerRequest request = context.request(); + final String accountId = request.getParam(ACCOUNT_ID_PARAM); + + if (StringUtils.isBlank(accountId)) { + HttpUtil.respondWith(context, HttpResponseStatus.BAD_REQUEST, "Account id is not defined"); + } else { + cachingApplicationSettings.invalidateAccountCache(accountId); + HttpUtil.respondWith(context, HttpResponseStatus.OK, null); + } + } +} diff --git a/src/main/java/org/prebid/server/handler/AdminHandler.java b/src/main/java/org/prebid/server/handler/AdminHandler.java index c5ddc039eef..6400be3e29a 100644 --- a/src/main/java/org/prebid/server/handler/AdminHandler.java +++ b/src/main/java/org/prebid/server/handler/AdminHandler.java @@ -7,33 +7,35 @@ import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; -import org.prebid.server.execution.LogModifier; +import org.prebid.server.manager.AdminManager; import java.util.Objects; import java.util.function.BiConsumer; public class AdminHandler implements Handler { - private static final String RECORDS_PARAM = "records"; private static final String LOGGING_PARAM = "logging"; + private static final String RECORDS_PARAM = "records"; - private final LogModifier logModifier; + private final AdminManager adminManager; - public AdminHandler(LogModifier logModifier) { - this.logModifier = Objects.requireNonNull(logModifier); + public AdminHandler(AdminManager adminManager) { + this.adminManager = Objects.requireNonNull(adminManager); } @Override public void handle(RoutingContext context) { final HttpServerRequest request = context.request(); + final BiConsumer loggingLevelModifier; - final String loggingParam = request.getParam(LOGGING_PARAM); - final String recordsParam = request.getParam(RECORDS_PARAM); final int records; + final String loggingLevel = request.getParam(LOGGING_PARAM); + final String recordsAsString = request.getParam(RECORDS_PARAM); + try { - loggingLevelModifier = loggingLevel(loggingParam); - records = records(recordsParam); + loggingLevelModifier = loggingLevel(loggingLevel); + records = records(recordsAsString); } catch (IllegalArgumentException e) { context.response() .setStatusCode(HttpResponseStatus.BAD_REQUEST.code()) @@ -41,16 +43,16 @@ public void handle(RoutingContext context) { return; } - logModifier.set(loggingLevelModifier, records); + adminManager.setupByCounter(AdminManager.COUNTER_KEY, records, loggingLevelModifier, onFinish()); + context.response() - .end(String.format("Logging level was changed to %s, for %s requests", loggingParam, recordsParam)); + .end(String.format("Logging level was changed to %s, for %s requests", loggingLevel, recordsAsString)); } - private BiConsumer loggingLevel(String level) { - if (StringUtils.isBlank(level)) { - throw new IllegalArgumentException(String.format("Invalid LoggingLevel: %s", level)); + private static BiConsumer loggingLevel(String level) { + if (StringUtils.isEmpty(level)) { + throw new IllegalArgumentException("Logging level cannot be empty"); } - switch (level) { case "info": return Logger::info; @@ -65,11 +67,28 @@ private BiConsumer loggingLevel(String level) { case "debug": return Logger::debug; default: - throw new IllegalArgumentException(String.format("Invalid LoggingLevel: %s", level)); + throw new IllegalArgumentException(String.format("Invalid logging level: %s", level)); } } - private int records(String records) { + private BiConsumer onFinish() { + return (logger, message) -> defaultLogModifier(logger).accept(logger, message); + } + + private static BiConsumer defaultLogModifier(Logger defaultLogger) { + if (defaultLogger.isTraceEnabled()) { + return Logger::trace; + } else if (defaultLogger.isDebugEnabled()) { + return Logger::debug; + } else if (defaultLogger.isInfoEnabled()) { + return Logger::info; + } else if (defaultLogger.isWarnEnabled()) { + return Logger::warn; + } + return Logger::error; + } + + private static int records(String records) { if (!StringUtils.isNumeric(records)) { throw new IllegalArgumentException(String.format("Invalid records parameter: %s", records)); } @@ -77,9 +96,8 @@ private int records(String records) { final int numberOfRecords = NumberUtils.toInt(records); if (numberOfRecords < 0 || numberOfRecords >= 100_000) { throw new IllegalArgumentException(String.format("Invalid records parameter: %s, must be between" - + " 0 and 100_000", records)); + + " 0 and 100 000", records)); } return numberOfRecords; } } - diff --git a/src/main/java/org/prebid/server/handler/AuctionHandler.java b/src/main/java/org/prebid/server/handler/AuctionHandler.java index eb7748abe6a..dcbabd94c75 100644 --- a/src/main/java/org/prebid/server/handler/AuctionHandler.java +++ b/src/main/java/org/prebid/server/handler/AuctionHandler.java @@ -28,8 +28,8 @@ import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.privacy.PrivacyExtractor; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprPurpose; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; import org.prebid.server.privacy.model.Privacy; import org.prebid.server.proto.request.AdUnit; import org.prebid.server.proto.request.PreBidRequest; @@ -49,8 +49,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -64,8 +62,6 @@ public class AuctionHandler implements Handler { private static final MetricName REQUEST_TYPE_METRIC = MetricName.legacy; private static final BigDecimal THOUSAND = BigDecimal.valueOf(1000); - private static final Set GDPR_PURPOSES = - Collections.unmodifiableSet(EnumSet.of(GdprPurpose.informationStorageAndAccess)); private final ApplicationSettings applicationSettings; private final BidderCatalog bidderCatalog; @@ -74,7 +70,7 @@ public class AuctionHandler implements Handler { private final Metrics metrics; private final HttpAdapterConnector httpAdapterConnector; private final Clock clock; - private final GdprService gdprService; + private final TcfDefinerService tcfDefinerService; private final PrivacyExtractor privacyExtractor; private final JacksonMapper mapper; private final Integer gdprHostVendorId; @@ -87,7 +83,7 @@ public AuctionHandler(ApplicationSettings applicationSettings, Metrics metrics, HttpAdapterConnector httpAdapterConnector, Clock clock, - GdprService gdprService, + TcfDefinerService tcfDefinerService, PrivacyExtractor privacyExtractor, JacksonMapper mapper, Integer gdprHostVendorId, boolean useGeoLocation) { @@ -99,7 +95,7 @@ public AuctionHandler(ApplicationSettings applicationSettings, this.metrics = Objects.requireNonNull(metrics); this.httpAdapterConnector = Objects.requireNonNull(httpAdapterConnector); this.clock = Objects.requireNonNull(clock); - this.gdprService = Objects.requireNonNull(gdprService); + this.tcfDefinerService = Objects.requireNonNull(tcfDefinerService); this.privacyExtractor = Objects.requireNonNull(privacyExtractor); this.mapper = Objects.requireNonNull(mapper); this.gdprHostVendorId = gdprHostVendorId; @@ -136,7 +132,7 @@ public void handle(RoutingContext context) { bidderResults.list()))) .compose((Tuple3> result) -> - resolveVendorsToGdpr(result.getLeft(), result.getRight()) + resolveVendorsToGdpr(result.getLeft(), result.getMiddle(), result.getRight()) .map(vendorsToGdpr -> Tuple3.of(result.getLeft(), result.getMiddle(), composePreBidResponse(result.getLeft(), result.getRight(), vendorsToGdpr)))) @@ -205,6 +201,7 @@ private static Future failWith(String message, Throwable exception) { return Future.failedFuture(new PreBidException(message, exception)); } + @SuppressWarnings("rawtypes") private List submitRequestsToExchanges(PreBidRequestContext preBidRequestContext) { return preBidRequestContext.getAdapterRequests().stream() .filter(ar -> isValidAdapterName(ar.getBidderCode())) @@ -234,7 +231,9 @@ private BidderInfo bidderInfoByName(String name) { } private Future> resolveVendorsToGdpr(PreBidRequestContext preBidRequestContext, + Account account, List adapterResponses) { + // todo Process also but bidders name (not every bidder have GVL id) final Set vendorIds = adapterResponses.stream() .map(adapterResponse -> adapterResponse.getBidderStatus().getBidder()) .filter(this::isValidAdapterName) @@ -250,22 +249,29 @@ private Future> resolveVendorsToGdpr(PreBidRequestContext final Privacy privacy = privacyExtractor.validPrivacyFrom(preBidRequest.getRegs(), preBidRequest.getUser()); final String ip = useGeoLocation ? preBidRequestContext.getIp() : null; - return gdprService.resultByVendor(GDPR_PURPOSES, vendorIds, privacy.getGdpr(), privacy.getConsent(), ip, + return tcfDefinerService.resultForVendorIds( + vendorIds, + privacy.getGdpr(), + privacy.getConsent(), + ip, + account.getGdpr(), preBidRequestContext.getTimeout()) - .map(gdprResponse -> toVendorsToGdpr(gdprResponse.getVendorsToGdpr(), hostVendorIdIsMissing)); + .map(gdprResponse -> toVendorsToGdpr(gdprResponse.getActions(), hostVendorIdIsMissing)); } - private Map toVendorsToGdpr(Map vendorsToGdpr, boolean hostVendorIdIsMissing) { + private Map toVendorsToGdpr( + Map vendorToAction, boolean hostVendorIdIsMissing) { + final Map result; - if (Objects.equals(vendorsToGdpr.get(gdprHostVendorId), false)) { + if (vendorToAction.containsKey(gdprHostVendorId) && vendorToAction.get(gdprHostVendorId).isBlockPixelSync()) { result = Collections.emptyMap(); // deny all by host vendor - } else if (hostVendorIdIsMissing) { - final Map vendorsToGdprWithoutHost = new HashMap<>(vendorsToGdpr); - vendorsToGdprWithoutHost.remove(gdprHostVendorId); // just to be clean with bidders - result = vendorsToGdprWithoutHost; } else { - result = vendorsToGdpr; + result = vendorToAction.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> !entry.getValue().isBlockPixelSync())); + if (hostVendorIdIsMissing) { + result.remove(gdprHostVendorId); + } } return result; @@ -349,7 +355,7 @@ private void updateBidResultMetrics(AdapterResponse adapterResponse, PreBidReque for (final Bid bid : adapterResponse.getBids()) { final long cpm = bid.getPrice().multiply(THOUSAND).longValue(); metrics.updateAdapterBidMetrics(bidder, accountId, cpm, bid.getAdm() != null, - ObjectUtils.firstNonNull(bid.getMediaType(), MediaType.banner).toString()); // default to banner + ObjectUtils.defaultIfNull(bid.getMediaType(), MediaType.banner).toString()); // default to banner } if (Objects.equals(bidderStatus.getNoBid(), Boolean.TRUE)) { diff --git a/src/main/java/org/prebid/server/handler/CookieSyncHandler.java b/src/main/java/org/prebid/server/handler/CookieSyncHandler.java index 2bdff8629dc..505eb261ef3 100644 --- a/src/main/java/org/prebid/server/handler/CookieSyncHandler.java +++ b/src/main/java/org/prebid/server/handler/CookieSyncHandler.java @@ -3,13 +3,13 @@ import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.AsyncResult; +import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.buffer.Buffer; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.web.RoutingContext; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.analytics.AnalyticsReporter; @@ -27,20 +27,22 @@ import org.prebid.server.json.JacksonMapper; import org.prebid.server.metric.Metrics; import org.prebid.server.privacy.ccpa.Ccpa; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprPurpose; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; import org.prebid.server.privacy.model.Privacy; import org.prebid.server.proto.request.CookieSyncRequest; import org.prebid.server.proto.response.BidderUsersyncStatus; import org.prebid.server.proto.response.CookieSyncResponse; import org.prebid.server.proto.response.UsersyncInfo; +import org.prebid.server.settings.ApplicationSettings; +import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountGdprConfig; import org.prebid.server.util.HttpUtil; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -52,18 +54,16 @@ public class CookieSyncHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(CookieSyncHandler.class); - private static final Set GDPR_PURPOSES = - Collections.unmodifiableSet(EnumSet.of(GdprPurpose.informationStorageAndAccess)); - - private static final String REJECTED_BY_GDPR = "Rejected by GDPR"; + private static final String REJECTED_BY_TCF = "Rejected by TCF"; private static final String REJECTED_BY_CCPA = "Rejected by CCPA"; private final String externalUrl; private final long defaultTimeout; private final UidsCookieService uidsCookieService; + private final ApplicationSettings applicationSettings; private final BidderCatalog bidderCatalog; - private final Collection activeBidders; - private final GdprService gdprService; + private final Set activeBidders; + private final TcfDefinerService tcfDefinerService; private final PrivacyEnforcementService privacyEnforcementService; private final Integer gdprHostVendorId; private final boolean useGeoLocation; @@ -77,8 +77,9 @@ public class CookieSyncHandler implements Handler { public CookieSyncHandler(String externalUrl, long defaultTimeout, UidsCookieService uidsCookieService, + ApplicationSettings applicationSettings, BidderCatalog bidderCatalog, - GdprService gdprService, + TcfDefinerService tcfDefinerService, PrivacyEnforcementService privacyEnforcementService, Integer gdprHostVendorId, boolean useGeoLocation, @@ -92,9 +93,10 @@ public CookieSyncHandler(String externalUrl, this.externalUrl = HttpUtil.validateUrl(Objects.requireNonNull(externalUrl)); this.defaultTimeout = defaultTimeout; this.uidsCookieService = Objects.requireNonNull(uidsCookieService); + this.applicationSettings = Objects.requireNonNull(applicationSettings); this.bidderCatalog = Objects.requireNonNull(bidderCatalog); - activeBidders = activeBidders(bidderCatalog); - this.gdprService = Objects.requireNonNull(gdprService); + this.activeBidders = activeBidders(bidderCatalog); + this.tcfDefinerService = Objects.requireNonNull(tcfDefinerService); this.privacyEnforcementService = Objects.requireNonNull(privacyEnforcementService); this.gdprHostVendorId = gdprHostVendorId; this.useGeoLocation = useGeoLocation; @@ -108,7 +110,7 @@ public CookieSyncHandler(String externalUrl, this.mapper = Objects.requireNonNull(mapper); } - private static Collection activeBidders(BidderCatalog bidderCatalog) { + private static Set activeBidders(BidderCatalog bidderCatalog) { return bidderCatalog.names().stream().filter(bidderCatalog::isActive).collect(Collectors.toSet()); } @@ -119,17 +121,18 @@ public void handle(RoutingContext context) { final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(context); if (!uidsCookie.allowsSync()) { final int status = HttpResponseStatus.UNAUTHORIZED.code(); - context.response().setStatusCode(status).setStatusMessage("User has opted out").end(); - analyticsReporter.processEvent(CookieSyncEvent.error(status, "user has opted out")); + final String message = "User has opted out"; + context.response().setStatusCode(status).setStatusMessage(message).end(); + analyticsReporter.processEvent(CookieSyncEvent.error(status, message)); return; } final Buffer body = context.getBody(); if (body == null) { - logger.info("Incoming request has no body."); final int status = HttpResponseStatus.BAD_REQUEST.code(); - context.response().setStatusCode(status).end(); - analyticsReporter.processEvent(CookieSyncEvent.error(status, "request has no body")); + final String message = "Request has no body"; + context.response().setStatusCode(status).setStatusMessage(message).end(); + analyticsReporter.processEvent(CookieSyncEvent.error(status, message)); return; } @@ -137,10 +140,11 @@ public void handle(RoutingContext context) { try { cookieSyncRequest = mapper.decodeValue(body, CookieSyncRequest.class); } catch (DecodeException e) { - logger.info("Failed to parse /cookie_sync request body", e); final int status = HttpResponseStatus.BAD_REQUEST.code(); - context.response().setStatusCode(status).setStatusMessage("JSON parse failed").end(); - analyticsReporter.processEvent(CookieSyncEvent.error(status, "JSON parse failed")); + final String message = "Request body cannot be parsed"; + context.response().setStatusCode(status).setStatusMessage(message).end(); + analyticsReporter.processEvent(CookieSyncEvent.error(status, message)); + logger.info(message, e); return; } @@ -156,10 +160,7 @@ public void handle(RoutingContext context) { final Integer limit = cookieSyncRequest.getLimit(); final Boolean coopSync = cookieSyncRequest.getCoopSync(); - final Collection biddersToSync = biddersToSync(cookieSyncRequest.getBidders(), coopSync, limit); - - final Set vendorIds = gdprVendorIdsFor(biddersToSync); - vendorIds.add(gdprHostVendorId); + final Set biddersToSync = biddersToSync(cookieSyncRequest.getBidders(), coopSync, limit); final String gdprAsString = gdpr != null ? gdpr.toString() : null; final Ccpa ccpa = Ccpa.of(cookieSyncRequest.getUsPrivacy()); @@ -170,11 +171,16 @@ public void handle(RoutingContext context) { return; } + final String requestAccount = cookieSyncRequest.getAccount(); + final Set vendorIds = Collections.singleton(gdprHostVendorId); final String ip = useGeoLocation ? HttpUtil.ipFrom(context.request()) : null; final Timeout timeout = timeoutFactory.create(defaultTimeout); - gdprService.resultByVendor(GDPR_PURPOSES, vendorIds, gdprAsString, gdprConsent, ip, timeout) - .setHandler(asyncResult -> handleResult(asyncResult, context, uidsCookie, biddersToSync, privacy, - limit)); + + accountById(requestAccount, timeout) + .compose(account -> prepareTcfResponse(gdprConsent, biddersToSync, gdprAsString, vendorIds, ip, account, + timeout)) + .setHandler(asyncResult -> + handleBidderNamesResult(asyncResult, context, uidsCookie, biddersToSync, privacy, limit)); } /** @@ -182,23 +188,23 @@ public void handle(RoutingContext context) { *

* If bidder list was omitted in request, that means sync should be done for all bidders. */ - private Collection biddersToSync(List requestBidders, Boolean requestCoop, Integer requestLimit) { + private Set biddersToSync(List requestBidders, Boolean requestCoop, Integer requestLimit) { if (CollectionUtils.isEmpty(requestBidders)) { return activeBidders; } - final boolean coop = requestCoop == null ? defaultCoopSync : requestCoop; - + final boolean coop = requestCoop != null ? requestCoop : defaultCoopSync; if (coop) { return requestLimit == null - ? addAllCoopSyncBidders(requestBidders) : addCoopSyncBidders(requestBidders, requestLimit); + ? addAllCoopSyncBidders(requestBidders) + : addCoopSyncBidders(requestBidders, requestLimit); } - return requestBidders; + return new HashSet<>(requestBidders); } - private Collection addAllCoopSyncBidders(List bidders) { - final Collection updatedBidders = listOfCoopSyncBidders.stream() + private Set addAllCoopSyncBidders(List bidders) { + final Set updatedBidders = listOfCoopSyncBidders.stream() .flatMap(Collection::stream) .collect(Collectors.toSet()); @@ -206,9 +212,9 @@ private Collection addAllCoopSyncBidders(List bidders) { return updatedBidders; } - private Collection addCoopSyncBidders(List bidders, int limit) { + private Set addCoopSyncBidders(List bidders, int limit) { if (limit <= 0) { - return bidders; + return new HashSet<>(bidders); } final Set allBidders = new HashSet<>(bidders); @@ -236,58 +242,63 @@ private Collection addCoopSyncBidders(List bidders, int limit) { } /** - * Fetches GDPR Vendor IDs for given bidders. + * Determines original bidder's name. */ - private Set gdprVendorIdsFor(Collection bidders) { - return bidders.stream() - .map(this::gdprVendorIdFor) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); + private String bidderNameFor(String bidder) { + return bidderCatalog.isAlias(bidder) ? bidderCatalog.nameByAlias(bidder) : bidder; } - /** - * Fetches GDPR Vendor ID for given bidder. - */ - private Integer gdprVendorIdFor(String bidder) { - final String resolvedBidder = bidderNameFor(bidder); - return bidderCatalog.isActive(resolvedBidder) - ? bidderCatalog.bidderInfoByName(resolvedBidder).getGdpr().getVendorId() - : null; + private Future> prepareTcfResponse(String gdprConsent, + Set biddersToSync, + String gdprAsString, + Set vendorIds, + String ip, + Account account, + Timeout timeout) { + final AccountGdprConfig accountGdpr = account.getGdpr(); + return tcfDefinerService.resultForVendorIds(vendorIds, gdprAsString, gdprConsent, ip, accountGdpr, timeout) + .compose(this::handleVendorIdResult) + .compose(ignored -> tcfDefinerService.resultForBidderNames(biddersToSync, gdprAsString, gdprConsent, + ip, accountGdpr, timeout)); } - /** - * Determines original bidder's name. - */ - private String bidderNameFor(String bidder) { - return bidderCatalog.isAlias(bidder) ? bidderCatalog.nameByAlias(bidder) : bidder; + private Future handleVendorIdResult(TcfResponse tcfResponse) { + + final Map vendorIdToAction = tcfResponse.getActions(); + final PrivacyEnforcementAction hostActions = vendorIdToAction != null + ? vendorIdToAction.get(gdprHostVendorId) + : null; + + if (hostActions == null || hostActions.isBlockPixelSync()) { + return Future.failedFuture("host vendor should be allowed by TCF verification"); + } + + return Future.succeededFuture(); } /** - * Handles GDPR verification result. + * Handles TCF verification result. */ - private void handleResult(AsyncResult asyncResult, RoutingContext context, UidsCookie uidsCookie, - Collection biddersToSync, Privacy privacy, Integer limit) { + private void handleBidderNamesResult(AsyncResult> asyncResult, + RoutingContext context, + UidsCookie uidsCookie, + Collection biddersToSync, + Privacy privacy, + Integer limit) { if (asyncResult.failed()) { - respondWith(context, uidsCookie, privacy, biddersToSync, biddersToSync, limit, REJECTED_BY_GDPR); + respondWith(context, uidsCookie, privacy, biddersToSync, biddersToSync, limit, REJECTED_BY_TCF); } else { - final Map vendorsToGdpr = asyncResult.result().getVendorsToGdpr(); + final TcfResponse tcfResponse = asyncResult.result(); - final Boolean gdprResult = vendorsToGdpr.get(gdprHostVendorId); - if (BooleanUtils.isNotTrue(gdprResult)) { // host vendor should be allowed by GDPR verification - respondWith(context, uidsCookie, privacy, biddersToSync, biddersToSync, limit, REJECTED_BY_GDPR); - } else { - final Set vendorIds = vendorsToGdpr.entrySet().stream() - .filter(Map.Entry::getValue) // get only vendors passed GDPR verification - .map(Map.Entry::getKey) - .collect(Collectors.toSet()); + final Map bidderNameToAction = tcfResponse.getActions(); - final Set biddersRejectedByGdpr = biddersToSync.stream() - .filter(bidder -> !vendorIds.contains(gdprVendorIdFor(bidder))) - .collect(Collectors.toSet()); + final Set biddersRejectedByTcf = biddersToSync.stream() + .filter(bidder -> + !bidderNameToAction.containsKey(bidder) + || bidderNameToAction.get(bidder).isBlockPixelSync()) + .collect(Collectors.toSet()); - respondWith(context, uidsCookie, privacy, biddersToSync, biddersRejectedByGdpr, limit, - REJECTED_BY_GDPR); - } + respondWith(context, uidsCookie, privacy, biddersToSync, biddersRejectedByTcf, limit, REJECTED_BY_TCF); } } @@ -295,11 +306,11 @@ private void handleResult(AsyncResult asyncResult, RoutingContext * Make HTTP response for given bidders. */ private void respondWith(RoutingContext context, UidsCookie uidsCookie, Privacy privacy, Collection bidders, - Collection biddersRejectedByGdpr, Integer limit, String rejectMessage) { - updateCookieSyncGdprMetrics(bidders, biddersRejectedByGdpr); + Collection biddersRejectedByTcf, Integer limit, String rejectMessage) { + updateCookieSyncTcfMetrics(bidders, biddersRejectedByTcf); final List bidderStatuses = bidders.stream() - .map(bidder -> bidderStatusFor(bidder, context, uidsCookie, biddersRejectedByGdpr, privacy, + .map(bidder -> bidderStatusFor(bidder, context, uidsCookie, biddersRejectedByTcf, privacy, rejectMessage)) .filter(Objects::nonNull) // skip bidder with live UID .collect(Collectors.toList()); @@ -332,10 +343,10 @@ private void respondWith(RoutingContext context, UidsCookie uidsCookie, Privacy .build()); } - private void updateCookieSyncGdprMetrics(Collection syncBidders, Collection rejectedBidders) { + private void updateCookieSyncTcfMetrics(Collection syncBidders, Collection rejectedBidders) { for (String bidder : syncBidders) { if (rejectedBidders.contains(bidder)) { - metrics.updateCookieSyncGdprPreventMetric(bidder); + metrics.updateCookieSyncTcfBlockedMetric(bidder); } else { metrics.updateCookieSyncGenMetric(bidder); } @@ -353,7 +364,7 @@ private void updateCookieSyncMatchMetrics(Collection syncBidders, * Creates {@link BidderUsersyncStatus} for given bidder. */ private BidderUsersyncStatus bidderStatusFor(String bidder, RoutingContext context, UidsCookie uidsCookie, - Collection biddersRejectedByGdpr, Privacy privacy, + Collection biddersRejectedByTcf, Privacy privacy, String rejectMessage) { final BidderUsersyncStatus result; final boolean isNotAlias = !bidderCatalog.isAlias(bidder); @@ -368,7 +379,7 @@ private BidderUsersyncStatus bidderStatusFor(String bidder, RoutingContext conte + "If you believe this should work, contact the company hosting the service " + "and tell them to check their configuration.", bidder)) .build(); - } else if (isNotAlias && biddersRejectedByGdpr.contains(bidder)) { + } else if (isNotAlias && biddersRejectedByTcf.contains(bidder)) { result = bidderStatusBuilder(bidder) .error(rejectMessage) .build(); @@ -431,4 +442,11 @@ private UsersyncInfo hostBidderUsersyncInfo(RoutingContext context, Privacy priv } return null; } + + private Future accountById(String accountId, Timeout timeout) { + return StringUtils.isBlank(accountId) + ? Future.succeededFuture(Account.empty(accountId)) + : applicationSettings.getAccountById(accountId, timeout) + .otherwise(Account.empty(accountId)); + } } diff --git a/src/main/java/org/prebid/server/handler/NotificationEventHandler.java b/src/main/java/org/prebid/server/handler/NotificationEventHandler.java index 63f7ee7cc9f..335afcd344c 100644 --- a/src/main/java/org/prebid/server/handler/NotificationEventHandler.java +++ b/src/main/java/org/prebid/server/handler/NotificationEventHandler.java @@ -68,6 +68,7 @@ public void handle(RoutingContext context) { try { EventUtil.validateType(context); EventUtil.validateBidId(context); + EventUtil.validateTimestamp(context); EventUtil.validateFormat(context); EventUtil.validateAnalytics(context); } catch (IllegalArgumentException e) { @@ -120,6 +121,8 @@ private void handleEvent(AsyncResult async, EventRequest eventRequest, ? NotificationEvent.Type.win : NotificationEvent.Type.imp) .bidId(eventRequest.getBidId()) .account(account) + .bidder(eventRequest.getBidder()) + .timestamp(eventRequest.getTimestamp()) .httpContext(HttpContext.from(context)) .build(); analyticsReporter.processEvent(notificationEvent); diff --git a/src/main/java/org/prebid/server/handler/OptoutHandler.java b/src/main/java/org/prebid/server/handler/OptoutHandler.java index 4a698251ecd..8d5261f94f5 100644 --- a/src/main/java/org/prebid/server/handler/OptoutHandler.java +++ b/src/main/java/org/prebid/server/handler/OptoutHandler.java @@ -2,9 +2,9 @@ import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Handler; +import io.vertx.core.http.Cookie; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; -import io.vertx.ext.web.Cookie; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.StringUtils; import org.prebid.server.cookie.UidsCookie; diff --git a/src/main/java/org/prebid/server/handler/SetuidHandler.java b/src/main/java/org/prebid/server/handler/SetuidHandler.java index 57b5f065d85..eb236594ce9 100644 --- a/src/main/java/org/prebid/server/handler/SetuidHandler.java +++ b/src/main/java/org/prebid/server/handler/SetuidHandler.java @@ -2,11 +2,13 @@ import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.AsyncResult; +import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.http.Cookie; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; -import io.vertx.ext.web.Cookie; import io.vertx.ext.web.RoutingContext; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.analytics.AnalyticsReporter; import org.prebid.server.analytics.model.SetuidEvent; @@ -15,15 +17,18 @@ import org.prebid.server.cookie.UidsCookie; import org.prebid.server.cookie.UidsCookieService; import org.prebid.server.exception.InvalidRequestException; +import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.metric.Metrics; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprPurpose; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; +import org.prebid.server.settings.ApplicationSettings; +import org.prebid.server.settings.model.Account; import org.prebid.server.util.HttpUtil; import java.util.Collections; -import java.util.EnumSet; +import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -32,9 +37,6 @@ public class SetuidHandler implements Handler { private static final Logger logger = LoggerFactory.getLogger(SetuidHandler.class); - private static final Set GDPR_PURPOSES = - Collections.unmodifiableSet(EnumSet.of(GdprPurpose.informationStorageAndAccess)); - private static final String BIDDER_PARAM = "bidder"; private static final String GDPR_PARAM = "gdpr"; private static final String GDPR_CONSENT_PARAM = "gdpr_consent"; @@ -42,24 +44,28 @@ public class SetuidHandler implements Handler { private static final String FORMAT_PARAM = "format"; private static final String IMG_FORMAT_PARAM = "img"; private static final String PIXEL_FILE_PATH = "static/tracking-pixel.png"; + private static final String ACCOUNT_PARAM = "account"; private final long defaultTimeout; private final UidsCookieService uidsCookieService; - private final GdprService gdprService; - private final Set gdprVendorIds; + private final ApplicationSettings applicationSettings; + private final TcfDefinerService tcfDefinerService; + private final Integer gdprHostVendorId; private final boolean useGeoLocation; private final AnalyticsReporter analyticsReporter; private final Metrics metrics; private final TimeoutFactory timeoutFactory; private final Set activeCookieFamilyNames; - public SetuidHandler(long defaultTimeout, UidsCookieService uidsCookieService, BidderCatalog bidderCatalog, - GdprService gdprService, Integer gdprHostVendorId, boolean useGeoLocation, + public SetuidHandler(long defaultTimeout, UidsCookieService uidsCookieService, + ApplicationSettings applicationSettings, BidderCatalog bidderCatalog, + TcfDefinerService tcfDefinerService, Integer gdprHostVendorId, boolean useGeoLocation, AnalyticsReporter analyticsReporter, Metrics metrics, TimeoutFactory timeoutFactory) { this.defaultTimeout = defaultTimeout; this.uidsCookieService = Objects.requireNonNull(uidsCookieService); - this.gdprService = Objects.requireNonNull(gdprService); - this.gdprVendorIds = Collections.singleton(gdprHostVendorId); + this.applicationSettings = Objects.requireNonNull(applicationSettings); + this.tcfDefinerService = Objects.requireNonNull(tcfDefinerService); + this.gdprHostVendorId = gdprHostVendorId; this.useGeoLocation = useGeoLocation; this.analyticsReporter = Objects.requireNonNull(analyticsReporter); this.metrics = Objects.requireNonNull(metrics); @@ -94,46 +100,74 @@ public void handle(RoutingContext context) { return; } + final Set vendorIds = Collections.singleton(gdprHostVendorId); + final String requestAccount = context.request().getParam(ACCOUNT_PARAM); final String gdpr = context.request().getParam(GDPR_PARAM); final String gdprConsent = context.request().getParam(GDPR_CONSENT_PARAM); final String ip = useGeoLocation ? HttpUtil.ipFrom(context.request()) : null; - gdprService.resultByVendor(GDPR_PURPOSES, gdprVendorIds, gdpr, gdprConsent, ip, - timeoutFactory.create(defaultTimeout)) + final Timeout timeout = timeoutFactory.create(defaultTimeout); + + accountById(requestAccount, timeout) + .compose(account -> tcfDefinerService.resultForVendorIds(vendorIds, gdpr, gdprConsent, ip, + account.getGdpr(), timeout)) .setHandler(asyncResult -> handleResult(asyncResult, context, uidsCookie, cookieName)); } - private void handleResult(AsyncResult asyncResult, RoutingContext context, + private Future accountById(String accountId, Timeout timeout) { + return StringUtils.isBlank(accountId) + ? Future.succeededFuture(Account.empty(accountId)) + : applicationSettings.getAccountById(accountId, timeout) + .otherwise(Account.empty(accountId)); + } + + private void handleResult(AsyncResult> asyncResult, RoutingContext context, UidsCookie uidsCookie, String bidder) { - final boolean gdprProcessingFailed = asyncResult.failed(); - final GdprResponse gdprResponse = !gdprProcessingFailed ? asyncResult.result() : null; + if (asyncResult.failed()) { + respondWithError(context, bidder, asyncResult.cause()); + } else { + // allow cookie only if user is not in GDPR scope or vendor passed GDPR check + final TcfResponse tcfResponse = asyncResult.result(); - // allow cookie only if user is not in GDPR scope or vendor passes GDPR check - final boolean allowedCookie = gdprResponse != null - && (!gdprResponse.isUserInGdprScope() || gdprResponse.getVendorsToGdpr().values().iterator().next()); + final boolean notInGdprScope = BooleanUtils.isFalse(tcfResponse.getUserInGdprScope()); - if (allowedCookie) { - respondWithCookie(context, bidder, uidsCookie); - } else { - final int status; - final String body; - - if (gdprProcessingFailed) { - final Throwable exception = asyncResult.cause(); - if (exception instanceof InvalidRequestException) { - status = HttpResponseStatus.BAD_REQUEST.code(); - body = String.format("GDPR processing failed with error: %s", exception.getMessage()); - } else { - status = HttpResponseStatus.INTERNAL_SERVER_ERROR.code(); - body = "Unexpected GDPR processing error"; - logger.warn(body, exception); - } + final Map vendorIdToAction = tcfResponse.getActions(); + final PrivacyEnforcementAction privacyEnforcementAction = vendorIdToAction != null + ? vendorIdToAction.get(gdprHostVendorId) + : null; + final boolean blockPixelSync = privacyEnforcementAction == null + || privacyEnforcementAction.isBlockPixelSync(); + + final boolean allowedCookie = notInGdprScope || !blockPixelSync; + + if (allowedCookie) { + respondWithCookie(context, bidder, uidsCookie); } else { - status = HttpResponseStatus.OK.code(); - body = "The gdpr_consent param prevents cookies from being saved"; + respondWithoutCookie(context, HttpResponseStatus.OK.code(), + "The gdpr_consent param prevents cookies from being saved", bidder); } + } + } + + private void respondWithError(RoutingContext context, String bidder, Throwable exception) { + final int status; + final String body; - respondWithoutCookie(context, status, body, bidder); + if (exception instanceof InvalidRequestException) { + status = HttpResponseStatus.BAD_REQUEST.code(); + body = String.format("GDPR processing failed with error: %s", exception.getMessage()); + } else { + status = HttpResponseStatus.INTERNAL_SERVER_ERROR.code(); + body = "Unexpected GDPR processing error"; + logger.warn(body, exception); } + + respondWithoutCookie(context, status, body, bidder); + } + + private void respondWithoutCookie(RoutingContext context, int status, String body, String bidder) { + respondWith(context, status, body); + metrics.updateUserSyncTcfBlockedMetric(bidder); + analyticsReporter.processEvent(SetuidEvent.error(status)); } private void respondWithCookie(RoutingContext context, String bidder, UidsCookie uidsCookie) { @@ -178,12 +212,6 @@ private void addCookie(RoutingContext context, Cookie cookie) { context.response().headers().add(HttpUtil.SET_COOKIE_HEADER, HttpUtil.toSetCookieHeaderValue(cookie)); } - private void respondWithoutCookie(RoutingContext context, int status, String body, String bidder) { - respondWith(context, status, body); - metrics.updateUserSyncGdprPreventMetric(bidder); - analyticsReporter.processEvent(SetuidEvent.error(status)); - } - private static void respondWith(RoutingContext context, int status, String body) { // don't send the response if client has gone if (context.response().closed()) { diff --git a/src/main/java/org/prebid/server/handler/VtrackHandler.java b/src/main/java/org/prebid/server/handler/VtrackHandler.java index 385d6d4d1a8..4ea4bb1002c 100644 --- a/src/main/java/org/prebid/server/handler/VtrackHandler.java +++ b/src/main/java/org/prebid/server/handler/VtrackHandler.java @@ -37,6 +37,7 @@ public class VtrackHandler implements Handler { private static final String ACCOUNT_PARAMETER = "a"; private final long defaultTimeout; + private final boolean allowUnknownBidder; private final ApplicationSettings applicationSettings; private final BidderCatalog bidderCatalog; private final CacheService cacheService; @@ -44,6 +45,7 @@ public class VtrackHandler implements Handler { private final JacksonMapper mapper; public VtrackHandler(long defaultTimeout, + boolean allowUnknownBidder, ApplicationSettings applicationSettings, BidderCatalog bidderCatalog, CacheService cacheService, @@ -51,6 +53,7 @@ public VtrackHandler(long defaultTimeout, JacksonMapper mapper) { this.defaultTimeout = defaultTimeout; + this.allowUnknownBidder = allowUnknownBidder; this.applicationSettings = Objects.requireNonNull(applicationSettings); this.bidderCatalog = Objects.requireNonNull(bidderCatalog); this.cacheService = Objects.requireNonNull(cacheService); @@ -69,8 +72,8 @@ public void handle(RoutingContext context) { respondWithBadRequest(context, e.getMessage()); return; } - final Timeout timeout = timeoutFactory.create(defaultTimeout); + applicationSettings.getAccountById(accountId, timeout) .recover(exception -> handleAccountExceptionOrFallback(exception, accountId)) .setHandler(async -> handleAccountResult(async, context, vtrackPuts, accountId, timeout)); @@ -129,7 +132,6 @@ private void handleAccountResult(AsyncResult asyncAccount, RoutingConte final Set biddersAllowingVastUpdate = Objects.equals(asyncAccount.result().getEventsEnabled(), true) ? biddersAllowingVastUpdate(vtrackPuts) : Collections.emptySet(); - cacheService.cachePutObjects(vtrackPuts, biddersAllowingVastUpdate, accountId, timeout) .setHandler(asyncCache -> handleCacheResult(asyncCache, context)); } @@ -141,10 +143,18 @@ private void handleAccountResult(AsyncResult asyncAccount, RoutingConte private Set biddersAllowingVastUpdate(List vtrackPuts) { return vtrackPuts.stream() .map(PutObject::getBidder) - .filter(bidderCatalog::isModifyingVastXmlAllowed) + .filter(this::isAllowVastForBidder) .collect(Collectors.toSet()); } + private boolean isAllowVastForBidder(String bidderName) { + if (bidderCatalog.isValidName(bidderName)) { + return bidderCatalog.isModifyingVastXmlAllowed(bidderName); + } else { + return allowUnknownBidder; + } + } + private void handleCacheResult(AsyncResult async, RoutingContext context) { if (async.failed()) { respondWithServerError(context, "Error occurred while sending request to cache", async.cause()); diff --git a/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java b/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java index cd3d1072194..029d26a53d0 100644 --- a/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java +++ b/src/main/java/org/prebid/server/handler/openrtb2/AmpHandler.java @@ -36,9 +36,9 @@ import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.PreBidException; import org.prebid.server.exception.UnauthorizedAccountException; -import org.prebid.server.execution.LogModifier; import org.prebid.server.json.JacksonMapper; import org.prebid.server.log.ConditionalLogger; +import org.prebid.server.manager.AdminManager; import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.proto.openrtb.ext.ExtPrebid; @@ -82,7 +82,7 @@ public class AmpHandler implements Handler { private final BidderCatalog bidderCatalog; private final Set biddersSupportingCustomTargeting; private final AmpResponsePostProcessor ampResponsePostProcessor; - private final LogModifier logModifier; + private final AdminManager adminManager; private final JacksonMapper mapper; public AmpHandler(AmpRequestFactory ampRequestFactory, @@ -93,7 +93,7 @@ public AmpHandler(AmpRequestFactory ampRequestFactory, BidderCatalog bidderCatalog, Set biddersSupportingCustomTargeting, AmpResponsePostProcessor ampResponsePostProcessor, - LogModifier logModifier, + AdminManager adminManager, JacksonMapper mapper) { this.ampRequestFactory = Objects.requireNonNull(ampRequestFactory); @@ -104,7 +104,7 @@ public AmpHandler(AmpRequestFactory ampRequestFactory, this.bidderCatalog = Objects.requireNonNull(bidderCatalog); this.biddersSupportingCustomTargeting = Objects.requireNonNull(biddersSupportingCustomTargeting); this.ampResponsePostProcessor = Objects.requireNonNull(ampResponsePostProcessor); - this.logModifier = Objects.requireNonNull(logModifier); + this.adminManager = Objects.requireNonNull(adminManager); this.mapper = Objects.requireNonNull(mapper); } @@ -312,7 +312,8 @@ private void handleResult(AsyncResult responseResult, AmpEvent.AmpE .map(msg -> String.format("Invalid request format: %s", msg)) .collect(Collectors.toList()); final String message = String.join("\n", errorMessages); - logModifier.get().accept(logger, logMessageFrom(invalidRequestException, message, context)); + adminManager.accept(AdminManager.COUNTER_KEY, logger, + logMessageFrom(invalidRequestException, message, context)); status = HttpResponseStatus.BAD_REQUEST.code(); body = message; diff --git a/src/main/java/org/prebid/server/handler/openrtb2/AuctionHandler.java b/src/main/java/org/prebid/server/handler/openrtb2/AuctionHandler.java index d8b1e5117ab..a8286491231 100644 --- a/src/main/java/org/prebid/server/handler/openrtb2/AuctionHandler.java +++ b/src/main/java/org/prebid/server/handler/openrtb2/AuctionHandler.java @@ -22,9 +22,9 @@ import org.prebid.server.exception.BlacklistedAppException; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.UnauthorizedAccountException; -import org.prebid.server.execution.LogModifier; import org.prebid.server.json.JacksonMapper; import org.prebid.server.log.ConditionalLogger; +import org.prebid.server.manager.AdminManager; import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.util.HttpUtil; @@ -46,7 +46,7 @@ public class AuctionHandler implements Handler { private final AnalyticsReporter analyticsReporter; private final Metrics metrics; private final Clock clock; - private final LogModifier logModifier; + private final AdminManager adminManager; private final JacksonMapper mapper; public AuctionHandler(AuctionRequestFactory auctionRequestFactory, @@ -54,7 +54,7 @@ public AuctionHandler(AuctionRequestFactory auctionRequestFactory, AnalyticsReporter analyticsReporter, Metrics metrics, Clock clock, - LogModifier logModifier, + AdminManager adminManager, JacksonMapper mapper) { this.auctionRequestFactory = Objects.requireNonNull(auctionRequestFactory); @@ -62,7 +62,7 @@ public AuctionHandler(AuctionRequestFactory auctionRequestFactory, this.analyticsReporter = Objects.requireNonNull(analyticsReporter); this.metrics = Objects.requireNonNull(metrics); this.clock = Objects.requireNonNull(clock); - this.logModifier = Objects.requireNonNull(logModifier); + this.adminManager = Objects.requireNonNull(adminManager); this.mapper = Objects.requireNonNull(mapper); } @@ -148,7 +148,8 @@ private void handleResult(AsyncResult> respo .map(msg -> String.format("Invalid request format: %s", msg)) .collect(Collectors.toList()); final String message = String.join("\n", errorMessages); - logModifier.get().accept(logger, logMessageFrom(invalidRequestException, message, context)); + adminManager.accept(AdminManager.COUNTER_KEY, logger, + logMessageFrom(invalidRequestException, message, context)); status = HttpResponseStatus.BAD_REQUEST.code(); body = message; @@ -160,8 +161,8 @@ private void handleResult(AsyncResult> respo status = HttpResponseStatus.UNAUTHORIZED.code(); body = message; - String userId = ((UnauthorizedAccountException) exception).getAccountId(); - metrics.updateAccountRequestRejectedMetrics(userId); + final String accountId = ((UnauthorizedAccountException) exception).getAccountId(); + metrics.updateAccountRequestRejectedMetrics(accountId); } else if (exception instanceof BlacklistedAppException || exception instanceof BlacklistedAccountException) { metricRequestStatus = exception instanceof BlacklistedAccountException diff --git a/src/main/java/org/prebid/server/health/DatabaseHealthChecker.java b/src/main/java/org/prebid/server/health/DatabaseHealthChecker.java index 1820dad53a7..a0b1c9e61eb 100644 --- a/src/main/java/org/prebid/server/health/DatabaseHealthChecker.java +++ b/src/main/java/org/prebid/server/health/DatabaseHealthChecker.java @@ -1,6 +1,6 @@ package org.prebid.server.health; -import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.ext.jdbc.JDBCClient; import io.vertx.ext.sql.SQLConnection; @@ -36,9 +36,9 @@ public String name() { @Override void updateStatus() { - final Future connectionFuture = Future.future(); - jdbcClient.getConnection(connectionFuture.completer()); - connectionFuture.setHandler(result -> + final Promise connectionPromise = Promise.promise(); + jdbcClient.getConnection(connectionPromise); + connectionPromise.future().setHandler(result -> status = StatusResponse.of( result.succeeded() ? Status.UP.name() : Status.DOWN.name(), ZonedDateTime.now(Clock.systemUTC()))); diff --git a/src/main/java/org/prebid/server/json/ObjectMapperProvider.java b/src/main/java/org/prebid/server/json/ObjectMapperProvider.java index 2604144baf9..a92a33ea676 100644 --- a/src/main/java/org/prebid/server/json/ObjectMapperProvider.java +++ b/src/main/java/org/prebid/server/json/ObjectMapperProvider.java @@ -7,14 +7,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; -import io.vertx.core.json.Json; +import io.vertx.core.json.jackson.DatabindCodec; public final class ObjectMapperProvider { private static final ObjectMapper MAPPER; static { - MAPPER = Json.mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false) + MAPPER = DatabindCodec.mapper().configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false) .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true) .enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN) diff --git a/src/main/java/org/prebid/server/log/ConditionalLogger.java b/src/main/java/org/prebid/server/log/ConditionalLogger.java index c15e950c687..d453a3b4865 100644 --- a/src/main/java/org/prebid/server/log/ConditionalLogger.java +++ b/src/main/java/org/prebid/server/log/ConditionalLogger.java @@ -1,43 +1,111 @@ package org.prebid.server.log; +import com.github.benmanes.caffeine.cache.Caffeine; import io.vertx.core.logging.Logger; +import org.apache.commons.lang3.ObjectUtils; -import java.util.concurrent.ConcurrentHashMap; +import java.time.Instant; +import java.util.Objects; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; public class ConditionalLogger { - private ConcurrentHashMap messageToCount; + + private static final int CACHE_MAXIMUM_SIZE = 10_000; + private static final int EXPIRE_CACHE_DURATION = 1; + + private final String key; private final Logger logger; + private ConcurrentMap messageToCount; + private ConcurrentMap messageToWait; + + public ConditionalLogger(String key, Logger logger) { + this.key = key; // can be null + this.logger = Objects.requireNonNull(logger); + + messageToCount = Caffeine.newBuilder() + .maximumSize(CACHE_MAXIMUM_SIZE) + .expireAfterWrite(EXPIRE_CACHE_DURATION, TimeUnit.HOURS) + .build() + .asMap(); + + messageToWait = Caffeine.newBuilder() + .maximumSize(CACHE_MAXIMUM_SIZE) + .expireAfterWrite(EXPIRE_CACHE_DURATION, TimeUnit.HOURS) + .build() + .asMap(); + } + public ConditionalLogger(Logger logger) { - this.logger = logger; - this.messageToCount = new ConcurrentHashMap<>(); + this(null, logger); + } + + public void info(String message, int limit) { + log(message, limit, logger -> logger.info(message)); + } + + public void info(String message, long duration, TimeUnit unit) { + log(message, duration, unit, logger -> logger.info(message)); } - public void info(String message, Integer maxValue) { - log(message, maxValue, logger -> logger.info(message)); + public void error(String message, int limit) { + log(message, limit, logger -> logger.error(message)); } - public void error(String message, Integer maxValue) { - log(message, maxValue, logger -> logger.error(message)); + public void error(String message, long duration, TimeUnit unit) { + log(message, duration, unit, logger -> logger.error(message)); } - public void debug(String message, Integer maxValue) { - log(message, maxValue, logger -> logger.debug(message)); + public void debug(String message, int limit) { + log(message, limit, logger -> logger.debug(message)); } - public void warn(String message, Integer maxValue) { - log(message, maxValue, logger -> logger.warn(message)); + public void debug(String message, long duration, TimeUnit unit) { + log(message, duration, unit, logger -> logger.debug(message)); } - private void log(String key, Integer maxValue, Consumer consumer) { - final AtomicInteger currentValue = messageToCount.compute( - key, (currentKey, currentCounter) -> currentCounter != null ? currentCounter : new AtomicInteger(0) - ); - if (currentValue.incrementAndGet() >= maxValue) { - currentValue.set(0); + public void warn(String message, int limit) { + log(message, limit, logger -> logger.warn(message)); + } + + public void warn(String message, long duration, TimeUnit unit) { + log(message, duration, unit, logger -> logger.warn(message)); + } + + /** + * Calls {@link Consumer} if the given limit for specified key is not exceeded. + */ + private void log(String key, int limit, Consumer consumer) { + final String resolvedKey = ObjectUtils.defaultIfNull(this.key, key); + final AtomicInteger count = messageToCount.computeIfAbsent(resolvedKey, ignored -> new AtomicInteger()); + if (count.incrementAndGet() >= limit) { + count.set(0); consumer.accept(logger); } } + + /** + * Calls {@link Consumer} if the given time for specified key is not exceeded. + */ + private void log(String key, long duration, TimeUnit unit, Consumer consumer) { + final long currentTime = Instant.now().toEpochMilli(); + final String resolvedKey = ObjectUtils.defaultIfNull(this.key, key); + final long endTime = messageToWait.computeIfAbsent(resolvedKey, ignored -> calculateEndTime(duration, unit)); + + if (currentTime >= endTime) { + messageToWait.replace(resolvedKey, endTime, calculateEndTime(duration, unit)); + consumer.accept(logger); + } + } + + /** + * Returns time in millis as current time incremented by specified duration. + */ + private static long calculateEndTime(long duration, TimeUnit unit) { + final long durationInMillis = unit.toMillis(duration); + return Instant.now().plusMillis(durationInMillis).toEpochMilli(); + } } diff --git a/src/main/java/org/prebid/server/manager/AdminManager.java b/src/main/java/org/prebid/server/manager/AdminManager.java new file mode 100644 index 00000000000..8fa0a8999db --- /dev/null +++ b/src/main/java/org/prebid/server/manager/AdminManager.java @@ -0,0 +1,120 @@ +package org.prebid.server.manager; + +import lombok.AllArgsConstructor; + +import java.time.Instant; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; + +/** + * class to manage requests from Admin panel + */ +public class AdminManager { + + public static final String COUNTER_KEY = "admin_counter"; + public static final String TIME_KEY = "admin_time"; + + private ConcurrentHashMap> actionMap; + + public AdminManager() { + actionMap = new ConcurrentHashMap<>(); + } + + /** + * @param key key of the given action + * @param amount max count of action executions + * @param action do while counter is less then max value + * @param onFinish do when counter is over then max value + */ + public void setupByCounter(String key, Integer amount, BiConsumer action, BiConsumer onFinish) { + actionMap.put(key, new CounterRule(action, onFinish, amount)); + } + + /** + * @param key key of the given action + * @param timeMillis duration in millis + * @param action do while time is not over + * @param onFinish do when time is over + */ + public void setupByTime(String key, long timeMillis, BiConsumer action, BiConsumer onFinish) { + actionMap.put(key, new TimeRule(action, onFinish, timeMillis)); + } + + /** + * Runs the BiConsumer by key. + */ + @SuppressWarnings("unchecked") + public void accept(String key, T t, U u) { + if (contains(key)) { + final Rule rule = (Rule) actionMap.get(key); + rule.applyRule().accept(t, u); + } + } + + /** + * Returns true if Rule is contains by key. + */ + public boolean contains(String key) { + return actionMap.containsKey(key); + } + + /** + * Returns state of BiConsumer by key. + */ + public boolean isRunning(String key) { + return contains(key) && !actionMap.get(key).isFinished; + } + + @AllArgsConstructor + private abstract static class Rule { + + protected BiConsumer onRun; + + protected BiConsumer onFinish; + + protected boolean isFinished; + + abstract BiConsumer applyRule(); + } + + private static class TimeRule extends Rule { + + private Instant time; + + TimeRule(BiConsumer onRun, BiConsumer onFinish, Long timeMillis) { + super(onRun, onFinish, false); + this.onFinish = onFinish; + this.time = Instant.now().plusMillis(timeMillis); + } + + @Override + BiConsumer applyRule() { + if (time != null && time.isAfter(Instant.now())) { + return onRun; + } + this.isFinished = true; + return onFinish; + } + } + + private static class CounterRule extends Rule { + + private AtomicInteger counter; + + CounterRule(BiConsumer onRun, BiConsumer onFinish, Integer counter) { + super(onRun, onFinish, false); + this.counter = new AtomicInteger(counter); + } + + @Override + BiConsumer applyRule() { + if (counter != null && counter.get() > 0) { + counter.decrementAndGet(); + return onRun; + } + this.isFinished = true; + return onFinish; + } + } +} diff --git a/src/main/java/org/prebid/server/metric/AccountMetrics.java b/src/main/java/org/prebid/server/metric/AccountMetrics.java index bf59ff33ae7..7f9d1420b52 100644 --- a/src/main/java/org/prebid/server/metric/AccountMetrics.java +++ b/src/main/java/org/prebid/server/metric/AccountMetrics.java @@ -17,7 +17,8 @@ class AccountMetrics extends UpdatableMetrics { // this all boils down to metrics lookup by underlying metric registry and that operation is guaranteed to be // thread-safe private final Map adapterMetrics; - private final RequestTypeMetrics requestTypeMetrics; + private final Function requestTypeMetricsCreator; + private final Map requestTypeMetrics; private final RequestMetrics requestsMetrics; AccountMetrics(MetricRegistry metricRegistry, CounterType counterType, String account) { @@ -25,7 +26,9 @@ class AccountMetrics extends UpdatableMetrics { nameCreator(createPrefix(Objects.requireNonNull(account)))); adapterMetricsCreator = adapterType -> new AdapterMetrics(metricRegistry, counterType, account, adapterType); adapterMetrics = new HashMap<>(); - requestTypeMetrics = new RequestTypeMetrics(metricRegistry, counterType, createPrefix(account)); + requestTypeMetricsCreator = requestType -> + new RequestTypeMetrics(metricRegistry, counterType, createPrefix(account), requestType); + requestTypeMetrics = new HashMap<>(); requestsMetrics = new RequestMetrics(metricRegistry, counterType, createPrefix(account)); } @@ -41,8 +44,8 @@ AdapterMetrics forAdapter(String adapterType) { return adapterMetrics.computeIfAbsent(adapterType, adapterMetricsCreator); } - RequestTypeMetrics requestType() { - return requestTypeMetrics; + RequestTypeMetrics requestType(MetricName requestType) { + return requestTypeMetrics.computeIfAbsent(requestType, requestTypeMetricsCreator); } RequestMetrics requests() { diff --git a/src/main/java/org/prebid/server/metric/AdapterMetrics.java b/src/main/java/org/prebid/server/metric/AdapterMetrics.java index ce4d876c02a..80b406ec94a 100644 --- a/src/main/java/org/prebid/server/metric/AdapterMetrics.java +++ b/src/main/java/org/prebid/server/metric/AdapterMetrics.java @@ -12,7 +12,8 @@ */ class AdapterMetrics extends UpdatableMetrics { - private final RequestTypeMetrics requestTypeMetrics; + private final Function requestTypeMetricsCreator; + private final Map requestTypeMetrics; private final RequestMetrics requestMetrics; private final Function bidTypeMetricsCreator; private final Map bidTypeMetrics; @@ -23,7 +24,9 @@ class AdapterMetrics extends UpdatableMetrics { bidTypeMetricsCreator = bidType -> new BidTypeMetrics(metricRegistry, counterType, createAdapterPrefix(adapterType), bidType); - requestTypeMetrics = new RequestTypeMetrics(metricRegistry, counterType, createAdapterPrefix(adapterType)); + requestTypeMetricsCreator = requestType -> + new RequestTypeMetrics(metricRegistry, counterType, createAdapterPrefix(adapterType), requestType); + requestTypeMetrics = new HashMap<>(); requestMetrics = new RequestMetrics(metricRegistry, counterType, createAdapterPrefix(adapterType)); bidTypeMetrics = new HashMap<>(); } @@ -37,8 +40,9 @@ class AdapterMetrics extends UpdatableMetrics { createAccountAdapterPrefix(account, adapterType)); // not used for account.adapter metrics - bidTypeMetricsCreator = null; + requestTypeMetricsCreator = null; requestTypeMetrics = null; + bidTypeMetricsCreator = null; bidTypeMetrics = null; } @@ -54,8 +58,8 @@ private static Function nameCreator(String prefix) { return metricName -> String.format("%s.%s", prefix, metricName.toString()); } - RequestTypeMetrics requestType() { - return requestTypeMetrics; + RequestTypeMetrics requestType(MetricName requestType) { + return requestTypeMetrics.computeIfAbsent(requestType, requestTypeMetricsCreator); } RequestMetrics request() { diff --git a/src/main/java/org/prebid/server/metric/CookieSyncMetrics.java b/src/main/java/org/prebid/server/metric/CookieSyncMetrics.java index f1013b93d53..f61a1fea072 100644 --- a/src/main/java/org/prebid/server/metric/CookieSyncMetrics.java +++ b/src/main/java/org/prebid/server/metric/CookieSyncMetrics.java @@ -28,13 +28,24 @@ CookieSyncMetrics.BidderCookieSyncMetrics forBidder(String bidder) { static class BidderCookieSyncMetrics extends UpdatableMetrics { + private final TcfMetrics tcfMetrics; + BidderCookieSyncMetrics(MetricRegistry metricRegistry, CounterType counterType, String bidder) { super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), - nameCreator(Objects.requireNonNull(bidder))); + nameCreator(Objects.requireNonNull(createCookieSyncPrefix(bidder)))); + tcfMetrics = new TcfMetrics(metricRegistry, counterType, createCookieSyncPrefix(bidder)); + } + + TcfMetrics tcf() { + return tcfMetrics; + } + + private static String createCookieSyncPrefix(String bidder) { + return String.format("cookie_sync.%s", bidder); } - private static Function nameCreator(String bidder) { - return metricName -> String.format("cookie_sync.%s.%s", bidder, metricName.toString()); + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.%s", prefix, metricName.toString()); } } } diff --git a/src/main/java/org/prebid/server/metric/MetricName.java b/src/main/java/org/prebid/server/metric/MetricName.java index fe524c37ebf..dee25f05190 100644 --- a/src/main/java/org/prebid/server/metric/MetricName.java +++ b/src/main/java/org/prebid/server/metric/MetricName.java @@ -65,8 +65,23 @@ public enum MetricName { sets, gen, matches, - gdpr_prevent, - gdpr_masked, + blocked, + + // tcf + userid_removed, + geo_masked, + request_blocked, + analytics_blocked, + + // privacy + coppa, + lmt, + specified, + opt_out("opt-out"), + invalid, + in_geo("in-geo"), + out_geo("out-geo"), + unknown_geo("unknown-geo"), // stored data stored_requests_found, diff --git a/src/main/java/org/prebid/server/metric/Metrics.java b/src/main/java/org/prebid/server/metric/Metrics.java index d60af6edb77..872134b5fe2 100644 --- a/src/main/java/org/prebid/server/metric/Metrics.java +++ b/src/main/java/org/prebid/server/metric/Metrics.java @@ -22,7 +22,7 @@ public class Metrics extends UpdatableMetrics { private static final String METRICS_UNKNOWN_BIDDER = "UNKNOWN"; - private AccountMetricsVerbosity accountMetricsVerbosity; + private final AccountMetricsVerbosity accountMetricsVerbosity; private final BidderCatalog bidderCatalog; private final Function requestMetricsCreator; @@ -36,6 +36,7 @@ public class Metrics extends UpdatableMetrics { private final Map adapterMetrics; private final UserSyncMetrics userSyncMetrics; private final CookieSyncMetrics cookieSyncMetrics; + private final PrivacyMetrics privacyMetrics; public Metrics(MetricRegistry metricRegistry, CounterType counterType, AccountMetricsVerbosity accountMetricsVerbosity, BidderCatalog bidderCatalog) { @@ -52,6 +53,7 @@ public Metrics(MetricRegistry metricRegistry, CounterType counterType, AccountMe adapterMetrics = new HashMap<>(); userSyncMetrics = new UserSyncMetrics(metricRegistry, counterType); cookieSyncMetrics = new CookieSyncMetrics(metricRegistry, counterType); + privacyMetrics = new PrivacyMetrics(metricRegistry, counterType); } RequestStatusMetrics forRequestType(MetricName requestType) { @@ -74,6 +76,10 @@ CookieSyncMetrics cookieSync() { return cookieSyncMetrics; } + PrivacyMetrics privacy() { + return privacyMetrics; + } + public void updateSafariRequestsMetric(boolean isSafari) { if (isSafari) { incCounter(MetricName.safari_requests); @@ -159,7 +165,7 @@ public void updateAccountRequestMetrics(String accountId, MetricName requestType accountMetrics.incCounter(MetricName.requests); if (verbosityLevel.isAtLeast(AccountMetricsVerbosityLevel.detailed)) { - accountMetrics.requestType().incCounter(requestType); + accountMetrics.requestType(requestType).incCounter(MetricName.requests); } } } @@ -172,7 +178,7 @@ public void updateAccountRequestRejectedMetrics(String accountId) { public void updateAdapterRequestTypeAndNoCookieMetrics(String bidder, MetricName requestType, boolean noCookie) { final AdapterMetrics adapterMetrics = forAdapter(resolveMetricsBidderName(bidder)); - adapterMetrics.requestType().incCounter(requestType); + adapterMetrics.requestType(requestType).incCounter(MetricName.requests); if (noCookie) { adapterMetrics.incCounter(MetricName.no_cookie_requests); @@ -245,8 +251,8 @@ public void updateUserSyncSetsMetric(String bidder) { userSync().forBidder(bidder).incCounter(MetricName.sets); } - public void updateUserSyncGdprPreventMetric(String bidder) { - userSync().forBidder(bidder).incCounter(MetricName.gdpr_prevent); + public void updateUserSyncTcfBlockedMetric(String bidder) { + userSync().forBidder(bidder).tcf().incCounter(MetricName.blocked); } public void updateCookieSyncRequestMetric() { @@ -261,12 +267,66 @@ public void updateCookieSyncMatchesMetric(String bidder) { cookieSync().forBidder(bidder).incCounter(MetricName.matches); } - public void updateCookieSyncGdprPreventMetric(String bidder) { - cookieSync().forBidder(resolveMetricsBidderName(bidder)).incCounter(MetricName.gdpr_prevent); + public void updateCookieSyncTcfBlockedMetric(String bidder) { + cookieSync().forBidder(resolveMetricsBidderName(bidder)).tcf().incCounter(MetricName.blocked); + } + + public void updateAuctionTcfMetrics(String bidder, + MetricName requestType, + boolean useridRemoved, + boolean geoMasked, + boolean requestBlocked, + boolean analyticsBlocked) { + + final TcfMetrics tcf = forAdapter(bidder).requestType(requestType).tcf(); + + if (useridRemoved) { + tcf.incCounter(MetricName.userid_removed); + } + if (geoMasked) { + tcf.incCounter(MetricName.geo_masked); + } + if (requestBlocked) { + tcf.incCounter(MetricName.request_blocked); + } + if (analyticsBlocked) { + tcf.incCounter(MetricName.analytics_blocked); + } + } + + public void updatePrivacyCoppaMetric() { + privacy().incCounter(MetricName.coppa); } - public void updateGdprMaskedMetric(String bidder) { - forAdapter(bidder).incCounter(MetricName.gdpr_masked); + public void updatePrivacyLmtMetric() { + privacy().incCounter(MetricName.lmt); + } + + public void updatePrivacyCcpaMetrics(boolean isSpecified, boolean isEnforced) { + if (isSpecified) { + privacy().usp().incCounter(MetricName.specified); + } + if (isEnforced) { + privacy().usp().incCounter(MetricName.opt_out); + } + } + + public void updatePrivacyTcfInvalidMetric() { + privacy().tcf().incCounter(MetricName.invalid); + } + + public void updatePrivacyTcfGeoMetric(int version, Boolean inEea) { + final UpdatableMetrics versionMetrics; + if (version == 2) { + versionMetrics = privacy().tcf().v2(); + } else { + versionMetrics = privacy().tcf().v1(); + } + + final MetricName metricName = inEea == null + ? MetricName.unknown_geo + : inEea ? MetricName.in_geo : MetricName.out_geo; + versionMetrics.incCounter(metricName); } public void updateConnectionAcceptErrors() { diff --git a/src/main/java/org/prebid/server/metric/PrivacyMetrics.java b/src/main/java/org/prebid/server/metric/PrivacyMetrics.java new file mode 100644 index 00000000000..781ee396ab2 --- /dev/null +++ b/src/main/java/org/prebid/server/metric/PrivacyMetrics.java @@ -0,0 +1,42 @@ +package org.prebid.server.metric; + +import com.codahale.metrics.MetricRegistry; + +import java.util.Objects; +import java.util.function.Function; + +/** + * Contains user sync metrics for a bidders metrics support. + */ +class PrivacyMetrics extends UpdatableMetrics { + + private final USPrivacyMetrics usPrivacyMetrics; + private final TcfMetrics tcfMetrics; + + PrivacyMetrics(MetricRegistry metricRegistry, CounterType counterType) { + super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), + metricName -> String.format("privacy.%s", metricName.toString())); + usPrivacyMetrics = new USPrivacyMetrics(metricRegistry, counterType, "privacy"); + tcfMetrics = new TcfMetrics(metricRegistry, counterType, "privacy"); + } + + USPrivacyMetrics usp() { + return usPrivacyMetrics; + } + + TcfMetrics tcf() { + return tcfMetrics; + } + + static class USPrivacyMetrics extends UpdatableMetrics { + + USPrivacyMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix) { + super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), + nameCreator(Objects.requireNonNull(prefix))); + } + + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.usp.%s", prefix, metricName.toString()); + } + } +} diff --git a/src/main/java/org/prebid/server/metric/RequestTypeMetrics.java b/src/main/java/org/prebid/server/metric/RequestTypeMetrics.java index 1bc5ca6cfc4..05e3fece6b3 100644 --- a/src/main/java/org/prebid/server/metric/RequestTypeMetrics.java +++ b/src/main/java/org/prebid/server/metric/RequestTypeMetrics.java @@ -10,12 +10,23 @@ */ class RequestTypeMetrics extends UpdatableMetrics { - RequestTypeMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix) { + private final TcfMetrics tcfMetrics; + + RequestTypeMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix, MetricName requestType) { super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), - nameCreator(Objects.requireNonNull(prefix))); + nameCreator(Objects.requireNonNull(prefix), Objects.requireNonNull(requestType))); + tcfMetrics = new TcfMetrics(metricRegistry, counterType, createTcfPrefix(prefix, requestType)); + } + + TcfMetrics tcf() { + return tcfMetrics; + } + + private static Function nameCreator(String prefix, MetricName requestType) { + return metricName -> String.format("%s.%s.type.%s", prefix, metricName.toString(), requestType.toString()); } - private static Function nameCreator(String prefix) { - return metricName -> String.format("%s.requests.type.%s", prefix, metricName.toString()); + private static String createTcfPrefix(String prefix, MetricName requestType) { + return String.format("%s.%s", prefix, requestType.toString()); } } diff --git a/src/main/java/org/prebid/server/metric/TcfMetrics.java b/src/main/java/org/prebid/server/metric/TcfMetrics.java new file mode 100644 index 00000000000..a4fa7c0cbe7 --- /dev/null +++ b/src/main/java/org/prebid/server/metric/TcfMetrics.java @@ -0,0 +1,59 @@ +package org.prebid.server.metric; + +import com.codahale.metrics.MetricRegistry; + +import java.util.Objects; +import java.util.function.Function; + +/** + * Support for TCF metrics. + */ +class TcfMetrics extends UpdatableMetrics { + + private final TcfVersionMetrics tcfVersion1Metrics; + private final TcfVersionMetrics tcfVersion2Metrics; + + TcfMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix) { + super( + Objects.requireNonNull(metricRegistry), + Objects.requireNonNull(counterType), + nameCreator(createTcfPrefix(Objects.requireNonNull(prefix)))); + + tcfVersion1Metrics = new TcfVersionMetrics(metricRegistry, counterType, createTcfPrefix(prefix), "v1"); + tcfVersion2Metrics = new TcfVersionMetrics(metricRegistry, counterType, createTcfPrefix(prefix), "v2"); + } + + TcfVersionMetrics v1() { + return tcfVersion1Metrics; + } + + TcfVersionMetrics v2() { + return tcfVersion2Metrics; + } + + private static String createTcfPrefix(String prefix) { + return String.format("%s.tcf", prefix); + } + + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.%s", prefix, metricName.toString()); + } + + static class TcfVersionMetrics extends UpdatableMetrics { + + TcfVersionMetrics(MetricRegistry metricRegistry, CounterType counterType, String prefix, String version) { + super( + Objects.requireNonNull(metricRegistry), + Objects.requireNonNull(counterType), + nameCreator(createVersionPrefix(Objects.requireNonNull(prefix), Objects.requireNonNull(version)))); + } + + private static String createVersionPrefix(String prefix, String version) { + return String.format("%s.%s", prefix, version); + } + + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.%s", prefix, metricName.toString()); + } + } +} diff --git a/src/main/java/org/prebid/server/metric/UserSyncMetrics.java b/src/main/java/org/prebid/server/metric/UserSyncMetrics.java index 8980b4f6b8c..ad218447441 100644 --- a/src/main/java/org/prebid/server/metric/UserSyncMetrics.java +++ b/src/main/java/org/prebid/server/metric/UserSyncMetrics.java @@ -31,13 +31,24 @@ BidderUserSyncMetrics forBidder(String bidder) { static class BidderUserSyncMetrics extends UpdatableMetrics { + private final TcfMetrics tcfMetrics; + BidderUserSyncMetrics(MetricRegistry metricRegistry, CounterType counterType, String bidder) { super(Objects.requireNonNull(metricRegistry), Objects.requireNonNull(counterType), - nameCreator(Objects.requireNonNull(bidder))); + nameCreator(Objects.requireNonNull(createUserSyncPrefix(bidder)))); + tcfMetrics = new TcfMetrics(metricRegistry, counterType, createUserSyncPrefix(bidder)); + } + + TcfMetrics tcf() { + return tcfMetrics; + } + + private static String createUserSyncPrefix(String bidder) { + return String.format("usersync.%s", bidder); } - private static Function nameCreator(String bidder) { - return metricName -> String.format("usersync.%s.%s", bidder, metricName.toString()); + private static Function nameCreator(String prefix) { + return metricName -> String.format("%s.%s", prefix, metricName.toString()); } } } diff --git a/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java b/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java index 7ad01020ddf..870a4c396a3 100644 --- a/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java +++ b/src/main/java/org/prebid/server/privacy/ccpa/Ccpa.java @@ -22,6 +22,10 @@ public class Ccpa { public static final Ccpa EMPTY = Ccpa.of(""); + public boolean isNotEmpty() { + return StringUtils.isNotEmpty(usPrivacy); + } + public boolean isCCPAEnforced() { try { validateUsPrivacy(usPrivacy); diff --git a/src/main/java/org/prebid/server/privacy/gdpr/GdprService.java b/src/main/java/org/prebid/server/privacy/gdpr/GdprService.java index a8499261799..3a9ef7d7c3e 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/GdprService.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/GdprService.java @@ -6,26 +6,18 @@ import io.vertx.core.Future; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; -import lombok.AllArgsConstructor; -import lombok.Value; -import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.exception.InvalidRequestException; -import org.prebid.server.execution.Timeout; -import org.prebid.server.geolocation.GeoLocationService; -import org.prebid.server.geolocation.model.GeoInfo; -import org.prebid.server.metric.Metrics; -import org.prebid.server.privacy.gdpr.model.GdprPurpose; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; import org.prebid.server.privacy.gdpr.vendorlist.VendorListService; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV1; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV1; -import java.util.HashMap; -import java.util.List; +import java.util.Collection; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.function.BiFunction; -import java.util.function.Function; import java.util.stream.Collectors; /** @@ -36,131 +28,66 @@ public class GdprService { private static final Logger logger = LoggerFactory.getLogger(GdprService.class); + private static final int PURPOSE_ONE_ID = 1; - private static final String GDPR_ZERO = "0"; - private static final String GDPR_ONE = "1"; + private final VendorListService vendorListService; - private final List eeaCountries; - private final String gdprDefaultValue; - private final GeoLocationService geoLocationService; - private final Metrics metrics; - private final VendorListService vendorListService; - - public GdprService(List eeaCountries, - String gdprDefaultValue, - GeoLocationService geoLocationService, - Metrics metrics, - VendorListService vendorListService) { - - this.geoLocationService = geoLocationService; - this.metrics = Objects.requireNonNull(metrics); - this.eeaCountries = Objects.requireNonNull(eeaCountries); + public GdprService(VendorListService vendorListService) { this.vendorListService = Objects.requireNonNull(vendorListService); - this.gdprDefaultValue = Objects.requireNonNull(gdprDefaultValue); } /** - * Returns the verdict about enforcing of GDPR processing: - *

- * - If GDPR from request is valid - returns TRUE if it equals to 1, otherwise FALSE. - * - If GDPR doesn't enforced by account - returns FALSE. - * - If there are no GDPR enforced vendors - returns FALSE. + * Determines what is allowed and what is not (in terms of TCF v1.1 implementation aka GDPR) for each vendor + * taking into account user consent string (version 1.1). + * + * @param vendorIds to examine in consent string and vendor list + * @param vendorConsentString user consent string + * @return collection of {@link VendorPermission}s indicating what vendor is allowed to do */ - public boolean isGdprEnforced(String gdpr, Boolean isGdprEnforcedByAccount, Set vendorIds) { - return isValidGdpr(gdpr) - ? gdpr.equals(GDPR_ONE) - : ObjectUtils.defaultIfNull(isGdprEnforcedByAccount, !vendorIds.isEmpty()); - } + public Future> resultFor(Set vendorIds, String vendorConsentString) { - /** - * Implements "each vendor has all given purposes" checking strategy. - *

- * Returns {@link GdprResponse} which handles information about a map with Vendor ID as a key and GDPR result - * [true/false] and country user comes from. - */ - public Future resultByVendor(Set purposes, Set vendorIds, String gdpr, - String gdprConsent, String ipAddress, Timeout timeout) { - return toGdprInfo(gdpr, gdprConsent, ipAddress, timeout) - .compose(gdprInfo -> toResultByVendor(gdprInfo, vendorIds, - purposesForVendorCheck(gdprInfo, purposes), GdprService::verdictForVendorHasAllGivenPurposes) - .map(vendorIdToResult -> - GdprResponse.of(inScope(gdprInfo), vendorIdToResult, gdprInfo.getCountry()))); + final VendorConsent vendorConsent = vendorConsentFrom(vendorConsentString); + if (vendorConsent == null) { + // consent string is broken + return Future.succeededFuture(vendorIds.stream() + .map(vendorId -> VendorPermission.of(vendorId, null, allDenied())) + .collect(Collectors.toList())); + } + + return vendorListService.forVersion(vendorConsent.getVendorListVersion()) + .map(vendorListMapping -> toResult(vendorListMapping, vendorIds, vendorConsent)); } /** - * Implements "consent string has all vendor purposes" checking strategy. + * Parses consent string to {@link VendorConsent} model. Returns null if: *

- * Returns {@link GdprResponse} which handles information about a map with Vendor ID as a key and GDPR result - * [true/false] and country user comes from. + * - consent string is missing *

- * GDPR purposes will be fetched from consent string. - */ - public Future resultByVendor(Set vendorIds, String gdpr, - String gdprConsent, String ipAddress, Timeout timeout) { - return toGdprInfo(gdpr, gdprConsent, ipAddress, timeout) - .compose(gdprInfo -> toResultByVendor(gdprInfo, vendorIds, - purposesForConsentCheck(gdprInfo), GdprService::verdictForConsentHasAllVendorPurposes) - .map(vendorIdToResult -> - GdprResponse.of(inScope(gdprInfo), vendorIdToResult, gdprInfo.getCountry()))); - } - - /** - * Returns purpose IDs from the given {@link GdprPurpose} collection or null if it is not needed by flow. - */ - private Set purposesForVendorCheck(GdprInfoWithCountry gdprInfo, Set purposes) { - return inScope(gdprInfo) && gdprInfo.getVendorConsent() != null - ? purposes.stream().map(GdprPurpose::getId).collect(Collectors.toSet()) - : null; - } - - /** - * Confirms vendor has all given purposes. - */ - private static boolean verdictForVendorHasAllGivenPurposes(Set givenPurposeIds, - Set vendorPurposeIds) { - return vendorPurposeIds.containsAll(givenPurposeIds); - } - - /** - * Returns purpose IDs from consent string or null if it is not needed by flow. + * - parsing of consent string is failed */ - private Set purposesForConsentCheck(GdprInfoWithCountry gdprInfo) { - return inScope(gdprInfo) && gdprInfo.getVendorConsent() != null - ? getAllowedPurposeIdsFromConsent(gdprInfo.getVendorConsent()) - : null; + private VendorConsent vendorConsentFrom(String vendorConsentString) { + if (StringUtils.isEmpty(vendorConsentString)) { + return null; + } + try { + return VendorConsentDecoder.fromBase64String(vendorConsentString); + } catch (IllegalArgumentException | IllegalStateException e) { + logger.warn("Parsing consent string failed with error: {0}", e.getMessage()); + return null; + } } /** - * Confirms consent purposes (as superset) contains all vendor purposes (as subset). + * Processes {@link VendorListService} response and returns GDPR result for every vendor ID. */ - private static Boolean verdictForConsentHasAllVendorPurposes(Set consentPurposeIds, - Set vendorPurposeIds) { - return consentPurposeIds.containsAll(vendorPurposeIds); - } - - private Future> toResultByVendor( - GdprInfoWithCountry gdprInfo, Set vendorIds, Set purposeIds, - BiFunction, Set, Boolean> verdictForPurposes) { - - if (!inScope(gdprInfo)) { - return sameResultFor(vendorIds, true); // allow all vendors - } - - final VendorConsent vendorConsent = gdprInfo.getVendorConsent(); - if (vendorConsent == null) { - return sameResultFor(vendorIds, false); // consent is broken - } + private static Collection toResult(Map vendorListMapping, + Set vendorIds, + VendorConsent vendorConsent) { final Set allowedPurposeIds = getAllowedPurposeIdsFromConsent(vendorConsent); - - // consent string confirms user has allowed given purposes - if (allowedPurposeIds != purposeIds && !allowedPurposeIds.containsAll(purposeIds)) { - return sameResultFor(vendorIds, false); - } - - return vendorListService.forVersion(vendorConsent.getVendorListVersion()) - .map(vendorIdToPurposes -> - toResult(vendorIdToPurposes, vendorIds, vendorConsent, purposeIds, verdictForPurposes)); + return vendorIds.stream() + .map(vendorId -> toVendorPermission(vendorId, vendorListMapping, vendorConsent, allowedPurposeIds)) + .collect(Collectors.toList()); } /** @@ -176,44 +103,31 @@ private static Set getAllowedPurposeIdsFromConsent(VendorConsent vendor } } - /** - * Creates the same result for all given vendors. - */ - private static Future> sameResultFor(Set vendorIds, boolean result) { - return Future.succeededFuture(vendorIds.stream() - .collect(Collectors.toMap(Function.identity(), id -> result))); - } + private static VendorPermission toVendorPermission(Integer vendorId, + Map vendorListMapping, + VendorConsent vendorConsent, + Set allowedPurposeIds) { - /** - * Processes {@link VendorListService} response and returns GDPR result by vendor ID. - */ - private static Map toResult( - Map> vendorIdToPurposes, Set vendorIds, VendorConsent vendorConsent, - Set purposeIds, BiFunction, Set, Boolean> verdictForPurposes) { + // confirm that there is consent for vendor and it has entry in vendor list + if (!isVendorAllowed(vendorConsent, vendorId) || !vendorListMapping.containsKey(vendorId)) { + return VendorPermission.of(vendorId, null, allDenied()); + } - final Map result = new HashMap<>(vendorIds.size()); - for (Integer vendorId : vendorIds) { - // confirm consent is allowed the vendor - final boolean vendorIsAllowed = isVendorAllowed(vendorConsent, vendorIdToPurposes, vendorId); + final VendorV1 vendorListEntry = vendorListMapping.get(vendorId); - // confirm purposes - final boolean purposesAreMatched = vendorIsAllowed - && verdictForPurposes.apply(purposeIds, vendorIdToPurposes.get(vendorId)); + // confirm purposes + final Set claimedPurposes = vendorListEntry.combinedPurposes(); + final boolean claimedPurposesAllowed = allowedPurposeIds.containsAll(claimedPurposes); + final boolean purposeOneClaimedAndAllowed = isPurposeOneClaimedAndAllowed(claimedPurposes, allowedPurposeIds); - result.put(vendorId, vendorIsAllowed && purposesAreMatched); - } - return result; + return VendorPermission.of(vendorId, null, toAction(claimedPurposesAllowed, purposeOneClaimedAndAllowed)); } /** * Checks if vendorId is in list of allowed vendors in consent string. Throws {@link InvalidRequestException} * in case of gdpr sdk throws exception when consent string is not valid. */ - private static boolean isVendorAllowed(VendorConsent vendorConsent, Map> vendorIdToPurposes, - Integer vendorId) { - if (vendorId == null || !vendorIdToPurposes.containsKey(vendorId)) { - return false; - } + private static boolean isVendorAllowed(VendorConsent vendorConsent, Integer vendorId) { try { return vendorConsent.isVendorAllowed(vendorId); } catch (ArrayIndexOutOfBoundsException | VendorConsentParseException e) { @@ -222,99 +136,23 @@ private static boolean isVendorAllowed(VendorConsent vendorConsent, Map toGdprInfo(String gdpr, String gdprConsent, String ipAddress, Timeout timeout) { - // from request param - if (isValidGdpr(gdpr)) { - return Future.succeededFuture(GdprInfoWithCountry.of(gdpr, vendorConsentFrom(gdpr, gdprConsent), null)); - } - - // from geo location - if (ipAddress != null && geoLocationService != null) { - return geoLocationService.lookup(ipAddress, timeout) - .map(GeoInfo::getCountry) - .map(resolvedCountry -> createGdprInfoWithCountry(gdprConsent, resolvedCountry)) - .otherwise(exception -> updateMetricsAndReturnDefault(exception, gdprConsent)); - } - - // use default - return Future.succeededFuture(defaultGdprInfoWithCountry(gdprConsent)); + private static boolean isPurposeOneClaimedAndAllowed(Set claimedPurposes, Set allowedPurposeIds) { + return claimedPurposes.contains(PURPOSE_ONE_ID) && allowedPurposeIds.contains(PURPOSE_ONE_ID); } - /** - * Checks GDPR flag has valid value. - */ - private boolean isValidGdpr(String gdpr) { - return gdpr != null && (gdpr.equals(GDPR_ZERO) || gdpr.equals(GDPR_ONE)); + private static PrivacyEnforcementAction allDenied() { + return toAction(false, false); } - /** - * Parses consent string to {@link VendorConsent} model. Returns null if: - *

- * - GDPR flag is not equal to 1 - *

- * - consent string is missing - *

- * - parsing of consent string is failed - */ - private VendorConsent vendorConsentFrom(String gdpr, String gdprConsent) { - if (!Objects.equals(gdpr, GDPR_ONE) || StringUtils.isEmpty(gdprConsent)) { - return null; - } - try { - return VendorConsentDecoder.fromBase64String(gdprConsent); - } catch (IllegalArgumentException | IllegalStateException e) { - logger.warn("Parsing consent string failed with error: {0}", e.getMessage()); - return null; - } - } - - /** - * Updates Geo {@link Metrics} and creates {@link GdprInfoWithCountry} which GDPR value depends on if country is - * in eea list. - */ - private GdprInfoWithCountry createGdprInfoWithCountry(String gdprConsent, String country) { - metrics.updateGeoLocationMetric(true); - final String gdpr = country == null ? gdprDefaultValue : eeaCountries.contains(country) ? GDPR_ONE : GDPR_ZERO; - return GdprInfoWithCountry.of(gdpr, vendorConsentFrom(gdpr, gdprConsent), country); - } - - /** - * Updates Geo {@link Metrics} and returns default {@link GdprInfoWithCountry}. - */ - private GdprInfoWithCountry updateMetricsAndReturnDefault(Throwable exception, String gdprConsent) { - logger.info("Geolocation lookup failed", exception); - metrics.updateGeoLocationMetric(false); - return defaultGdprInfoWithCountry(gdprConsent); - } - - /** - * Creates default {@link GdprInfoWithCountry} with null country, default GDPR value and GDPR consent from request. - */ - private GdprInfoWithCountry defaultGdprInfoWithCountry(String gdprConsent) { - return GdprInfoWithCountry.of(gdprDefaultValue, vendorConsentFrom(gdprDefaultValue, gdprConsent), null); - } - - /** - * Determines if user is in GDPR scope. - */ - private static boolean inScope(GdprInfoWithCountry gdprInfo) { - return Objects.equals(gdprInfo.getGdpr(), GDPR_ONE); - } - - /** - * Internal class for holding GDPR information and country. - */ - @AllArgsConstructor(staticName = "of") - @Value - private static class GdprInfoWithCountry { - - String gdpr; - - VendorConsent vendorConsent; - - String country; + private static PrivacyEnforcementAction toAction(boolean allowPrivateInfo, boolean allowUserSync) { + return PrivacyEnforcementAction.builder() + .removeUserIds(!allowPrivateInfo) + .maskGeo(!allowPrivateInfo) + .maskDeviceIp(!allowPrivateInfo) + .maskDeviceInfo(!allowPrivateInfo) + .blockAnalyticsReport(false) + .blockBidderRequest(false) + .blockPixelSync(!allowUserSync) + .build(); } } diff --git a/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java b/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java new file mode 100644 index 00000000000..0fca3d84648 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java @@ -0,0 +1,337 @@ +package org.prebid.server.privacy.gdpr; + +import com.iabtcf.decoder.TCString; +import io.vertx.core.Future; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeFourStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeOneStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeSevenStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeTwoStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature.SpecialFeaturesOneStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature.SpecialFeaturesStrategy; +import org.prebid.server.privacy.gdpr.vendorlist.VendorListServiceV2; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.settings.model.AccountGdprConfig; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.GdprConfig; +import org.prebid.server.settings.model.Purpose; +import org.prebid.server.settings.model.PurposeOneTreatmentInterpretation; +import org.prebid.server.settings.model.Purposes; +import org.prebid.server.settings.model.SpecialFeature; +import org.prebid.server.settings.model.SpecialFeatures; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +public class Tcf2Service { + + private final Purposes defaultPurposes; + private final SpecialFeatures defaultSpecialFeatures; + private final VendorListServiceV2 vendorListServiceV2; + private final List supportedPurposeStrategies; + private final List supportedSpecialFeatureStrategies; + private final BidderCatalog bidderCatalog; + private PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation; + + public Tcf2Service(GdprConfig gdprConfig, VendorListServiceV2 vendorListServiceV2, BidderCatalog bidderCatalog) { + + this.defaultPurposes = gdprConfig.getPurposes() == null ? Purposes.builder().build() : gdprConfig.getPurposes(); + this.defaultSpecialFeatures = gdprConfig.getSpecialFeatures() == null + ? SpecialFeatures.builder().build() + : gdprConfig.getSpecialFeatures(); + this.purposeOneTreatmentInterpretation = gdprConfig.getPurposeOneTreatmentInterpretation(); + this.vendorListServiceV2 = Objects.requireNonNull(vendorListServiceV2); + this.bidderCatalog = Objects.requireNonNull(bidderCatalog); + this.supportedPurposeStrategies = supportedPurposeStrategies(); + this.supportedSpecialFeatureStrategies = supportedSpecialFeatureStrategies(); + } + + private static List supportedPurposeStrategies() { + final FullEnforcePurposeStrategy fullEnforcePurposeStrategy = new FullEnforcePurposeStrategy(); + final BasicEnforcePurposeStrategy basicEnforcePurposeStrategy = new BasicEnforcePurposeStrategy(); + final NoEnforcePurposeStrategy noEnforcePurposeStrategy = new NoEnforcePurposeStrategy(); + + final PurposeOneStrategy purposeOneStrategy = new PurposeOneStrategy(fullEnforcePurposeStrategy, + basicEnforcePurposeStrategy, + noEnforcePurposeStrategy); + final PurposeTwoStrategy purposeTwoStrategy = new PurposeTwoStrategy(fullEnforcePurposeStrategy, + basicEnforcePurposeStrategy, + noEnforcePurposeStrategy); + final PurposeFourStrategy purposeFourStrategy = new PurposeFourStrategy(fullEnforcePurposeStrategy, + basicEnforcePurposeStrategy, + noEnforcePurposeStrategy); + final PurposeSevenStrategy purposeSevenStrategy = new PurposeSevenStrategy(fullEnforcePurposeStrategy, + basicEnforcePurposeStrategy, + noEnforcePurposeStrategy); + + return Arrays.asList(purposeOneStrategy, purposeTwoStrategy, purposeFourStrategy, purposeSevenStrategy); + } + + private static List supportedSpecialFeatureStrategies() { + return Collections.singletonList(new SpecialFeaturesOneStrategy()); + } + + public Future> permissionsFor(Set vendorIds, TCString tcfConsent) { + final Collection vendorPermissions = vendorPermissions(vendorIds); + return permissionsForInternal(vendorPermissions, tcfConsent, null); + } + + public Future> permissionsFor(Set bidderNames, + VendorIdResolver vendorIdResolver, + TCString tcfConsent, + AccountGdprConfig accountGdprConfig) { + final Collection vendorPermissions = vendorPermissions(bidderNames, vendorIdResolver); + return permissionsForInternal(vendorPermissions, tcfConsent, accountGdprConfig); + } + + private Collection vendorPermissions(Set vendorIds) { + return vendorIds.stream() + // this check only for illegal arguments... + .filter(Objects::nonNull) + .map(vendorId -> VendorPermission.of( + vendorId, bidderCatalog.nameByVendorId(vendorId), PrivacyEnforcementAction.restrictAll())) + .collect(Collectors.toList()); + } + + private Collection vendorPermissions(Set bidderNames, + VendorIdResolver vendorIdResolver) { + + return bidderNames.stream() + // this check only for illegal arguments... + .filter(Objects::nonNull) + .map(bidderName -> VendorPermission.of( + vendorIdResolver.resolve(bidderName), bidderName, PrivacyEnforcementAction.restrictAll())) + .collect(Collectors.toList()); + } + + private Future> permissionsForInternal(Collection vendorPermissions, + TCString tcfConsent, + AccountGdprConfig accountGdprConfig) { + + final Purposes mergedPurposes = mergeAccountPurposes(accountGdprConfig); + final SpecialFeatures mergedSpecialFeatures = mergeAccountSpecialFeatures(accountGdprConfig); + final PurposeOneTreatmentInterpretation mergedPurposeOneTreatmentInterpretation = + mergePurposeOneTreatmentInterpretation(accountGdprConfig); + + return vendorListServiceV2.forVersion(tcfConsent.getVendorListVersion()) + .map(vendorGvlPermissions -> wrapWithGVL(vendorPermissions, vendorGvlPermissions)) + + .compose(gvlResult -> processSupportedPurposeStrategies(tcfConsent, gvlResult, mergedPurposes, + purposeOneTreatmentInterpretation), + ignoredFailed -> processDowngradedSupportedPurposeStrategies(tcfConsent, vendorPermissions, + mergedPurposes, mergedPurposeOneTreatmentInterpretation)) + + .map(changedVendorPermissions -> processSupportedSpecialFeatureStrategies(tcfConsent, + changedVendorPermissions, mergedSpecialFeatures)); + + } + + private static Collection wrapWithGVL(Collection vendorPermissions, + Map vendorGvlPermissions) { + return vendorPermissions.stream() + .map(vendorPermission -> wrapWithGVL(vendorPermission, vendorGvlPermissions)) + .collect(Collectors.toList()); + } + + private static VendorPermissionWithGvl wrapWithGVL(VendorPermission vendorPermission, + Map vendorGvlPermissions) { + final Integer vendorId = vendorPermission.getVendorId(); + final VendorV2 vendorGvlByVendorId = vendorId != null + ? vendorGvlPermissions.getOrDefault(vendorId, VendorV2.empty(vendorId)) + : VendorV2.empty(vendorId); + + return VendorPermissionWithGvl.of(vendorPermission, vendorGvlByVendorId); + } + + private Future> processSupportedPurposeStrategies( + TCString tcfConsent, + Collection vendorPermissionsWithGvl, + Purposes purposes, + PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation) { + + for (PurposeStrategy purposeStrategy : supportedPurposeStrategies) { + final int purposeId = purposeStrategy.getPurposeId(); + final Purpose purposeById = findPurposeById(purposeId, purposes); + processPurposeStrategy(tcfConsent, vendorPermissionsWithGvl, purposeById, purposeStrategy, + purposeOneTreatmentInterpretation); + } + + return Future.succeededFuture(vendorPermissionsWithGvl.stream() + .map(VendorPermissionWithGvl::getVendorPermission) + .collect(Collectors.toList())); + } + + private Future> processDowngradedSupportedPurposeStrategies( + TCString tcfConsent, + Collection vendorPermissions, + Purposes purposes, + PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation) { + + final List vendorPermissionsWithGvl = wrapWithEmptyGVL(vendorPermissions); + + for (PurposeStrategy purposeStrategy : supportedPurposeStrategies) { + final int purposeId = purposeStrategy.getPurposeId(); + final Purpose downgradedPurpose = downgradePurpose(findPurposeById(purposeId, purposes)); + processPurposeStrategy(tcfConsent, vendorPermissionsWithGvl, downgradedPurpose, purposeStrategy, + purposeOneTreatmentInterpretation); + } + return Future.succeededFuture(vendorPermissions); + } + + private void processPurposeStrategy(TCString tcfConsent, + Collection vendorPermissionsWithGvl, + Purpose purpose, + PurposeStrategy purposeStrategy, + PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation) { + if (purposeStrategy.getPurposeId() == 1 && tcfConsent.getPurposeOneTreatment()) { + processPurposeOneTreatment(purposeOneTreatmentInterpretation, tcfConsent, purpose, + purposeStrategy, vendorPermissionsWithGvl); + } else { + purposeStrategy.processTypePurposeStrategy(tcfConsent, purpose, vendorPermissionsWithGvl); + } + } + + private void processPurposeOneTreatment(PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation, + TCString tcfConsent, + Purpose purposeOne, + PurposeStrategy purposeOneStrategy, + Collection vendorPermissionsWithGvl) { + switch (purposeOneTreatmentInterpretation) { + case accessAllowed: + vendorPermissionsWithGvl.forEach(vendorPermission -> purposeOneStrategy.allow( + vendorPermission.getVendorPermission().getPrivacyEnforcementAction())); + break; + case noAccessAllowed: + // no need for special processing of no-access-allowed since everything is disallowed from the beginning + break; + case ignore: + default: + purposeOneStrategy.processTypePurposeStrategy(tcfConsent, purposeOne, vendorPermissionsWithGvl); + } + } + + private static List wrapWithEmptyGVL(Collection vendorPermissions) { + return vendorPermissions.stream() + .map(vendorPermission -> VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(vendorPermission.getVendorId()))) + .collect(Collectors.toList()); + } + + private static Purpose downgradePurpose(Purpose purpose) { + final EnforcePurpose enforcePurpose = purpose.getEnforcePurpose(); + return enforcePurpose == null || Objects.equals(enforcePurpose, EnforcePurpose.full) + ? Purpose.of(EnforcePurpose.basic, purpose.getEnforceVendors(), purpose.getVendorExceptions()) + : purpose; + } + + private Collection processSupportedSpecialFeatureStrategies( + TCString tcfConsent, + Collection vendorPermissions, + SpecialFeatures specialFeatures) { + + for (SpecialFeaturesStrategy specialFeaturesStrategy : supportedSpecialFeatureStrategies) { + final int specialFeatureId = specialFeaturesStrategy.getSpecialFeatureId(); + final SpecialFeature specialFeatureById = findSpecialFeatureById(specialFeatureId, specialFeatures); + specialFeaturesStrategy.processSpecialFeaturesStrategy(tcfConsent, specialFeatureById, vendorPermissions); + } + + return vendorPermissions; + } + + private Purposes mergeAccountPurposes(AccountGdprConfig accountGdprConfig) { + if (accountGdprConfig == null || accountGdprConfig.getPurposes() == null) { + return defaultPurposes; + } + final Purposes accountPurposes = accountGdprConfig.getPurposes(); + return Purposes.builder() + .p1(mergeItem(accountPurposes.getP1(), defaultPurposes.getP1())) + .p2(mergeItem(accountPurposes.getP2(), defaultPurposes.getP2())) + .p3(mergeItem(accountPurposes.getP3(), defaultPurposes.getP3())) + .p4(mergeItem(accountPurposes.getP4(), defaultPurposes.getP4())) + .p5(mergeItem(accountPurposes.getP5(), defaultPurposes.getP5())) + .p6(mergeItem(accountPurposes.getP6(), defaultPurposes.getP6())) + .p7(mergeItem(accountPurposes.getP7(), defaultPurposes.getP7())) + .p8(mergeItem(accountPurposes.getP8(), defaultPurposes.getP8())) + .p9(mergeItem(accountPurposes.getP9(), defaultPurposes.getP9())) + .p9(mergeItem(accountPurposes.getP10(), defaultPurposes.getP10())) + .build(); + } + + private SpecialFeatures mergeAccountSpecialFeatures(AccountGdprConfig accountGdprConfig) { + if (accountGdprConfig == null || accountGdprConfig.getSpecialFeatures() == null) { + return defaultSpecialFeatures; + } + final SpecialFeatures accountSpecialFeatures = accountGdprConfig.getSpecialFeatures(); + return SpecialFeatures.builder() + .sf1(mergeItem(accountSpecialFeatures.getSf1(), defaultSpecialFeatures.getSf1())) + .sf2(mergeItem(accountSpecialFeatures.getSf2(), defaultSpecialFeatures.getSf2())) + .build(); + } + + private Purpose findPurposeById(int tcfPurposeId, Purposes purposes) { + switch (tcfPurposeId) { + case 1: + return purposes.getP1(); + case 2: + return purposes.getP2(); + case 3: + return purposes.getP3(); + case 4: + return purposes.getP4(); + case 5: + return purposes.getP5(); + case 6: + return purposes.getP6(); + case 7: + return purposes.getP7(); + case 8: + return purposes.getP8(); + case 9: + return purposes.getP9(); + case 10: + return purposes.getP10(); + default: + throw new IllegalArgumentException(String.format("Illegal TCF code for purpose: %d", + tcfPurposeId)); + } + } + + private SpecialFeature findSpecialFeatureById(int tcfSpecialFeaturesId, SpecialFeatures specialFeatures) { + switch (tcfSpecialFeaturesId) { + case 1: + return specialFeatures.getSf1(); + case 2: + return specialFeatures.getSf2(); + default: + throw new IllegalArgumentException(String.format("Illegal TCF code for special feature: %d", + tcfSpecialFeaturesId)); + } + } + + private PurposeOneTreatmentInterpretation mergePurposeOneTreatmentInterpretation( + AccountGdprConfig accountGdprConfig) { + + if (accountGdprConfig == null || accountGdprConfig.getPurposeOneTreatmentInterpretation() == null) { + return purposeOneTreatmentInterpretation; + } + + return mergeItem(accountGdprConfig.getPurposeOneTreatmentInterpretation(), purposeOneTreatmentInterpretation); + } + + private static T mergeItem(T prioritisedItem, T item) { + return prioritisedItem == null ? item : prioritisedItem; + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/TcfDefinerService.java b/src/main/java/org/prebid/server/privacy/gdpr/TcfDefinerService.java new file mode 100644 index 00000000000..bb1d1b4a853 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/TcfDefinerService.java @@ -0,0 +1,331 @@ +package org.prebid.server.privacy.gdpr; + +import com.iabtcf.decoder.TCString; +import io.vertx.core.Future; +import io.vertx.core.logging.Logger; +import io.vertx.core.logging.LoggerFactory; +import org.apache.commons.lang3.BooleanUtils; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.execution.Timeout; +import org.prebid.server.geolocation.GeoLocationService; +import org.prebid.server.geolocation.model.GeoInfo; +import org.prebid.server.metric.Metrics; +import org.prebid.server.privacy.gdpr.model.GdprInfoWithCountry; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TCStringEmpty; +import org.prebid.server.privacy.gdpr.model.TcfResponse; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.settings.model.AccountGdprConfig; +import org.prebid.server.settings.model.GdprConfig; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class TcfDefinerService { + + private static final Logger logger = LoggerFactory.getLogger(TcfDefinerService.class); + + private static final String GDPR_ZERO = "0"; + private static final String GDPR_ONE = "1"; + + private final boolean gdprEnabled; + private final String gdprDefaultValue; + private final GdprService gdprService; + private final Tcf2Service tcf2Service; + private final Set eeaCountries; + private final GeoLocationService geoLocationService; + private final BidderCatalog bidderCatalog; + private final Metrics metrics; + + public TcfDefinerService(GdprConfig gdprConfig, + Set eeaCountries, + GdprService gdprService, + Tcf2Service tcf2Service, + GeoLocationService geoLocationService, + BidderCatalog bidderCatalog, + Metrics metrics) { + + this.gdprEnabled = gdprConfig != null && BooleanUtils.isNotFalse(gdprConfig.getEnabled()); + this.gdprDefaultValue = gdprConfig != null ? gdprConfig.getDefaultValue() : null; + this.gdprService = Objects.requireNonNull(gdprService); + this.tcf2Service = Objects.requireNonNull(tcf2Service); + this.eeaCountries = Objects.requireNonNull(eeaCountries); + this.geoLocationService = geoLocationService; + this.bidderCatalog = Objects.requireNonNull(bidderCatalog); + this.metrics = Objects.requireNonNull(metrics); + } + + // vendorIds and BidderNames can't contain null elements + public Future> resultForVendorIds(Set vendorIds, + String gdpr, + String gdprConsent, + String ipAddress, + AccountGdprConfig accountGdprConfig, + Timeout timeout) { + return resultForInternal( + gdpr, + gdprConsent, + ipAddress, + accountGdprConfig, + timeout, + country -> createAllowAllTcfResponse(vendorIds, country), + (consentString, country) -> tcf2Service.permissionsFor(vendorIds, consentString) + .map(vendorPermissions -> createVendorIdTcfResponse(vendorPermissions, country)), + (consentString, country) -> gdprService.resultFor(vendorIds, consentString) + .map(vendorPermissions -> createVendorIdTcfResponse(vendorPermissions, country))); + } + + // vendorIds and BidderNames can't contain null elements + public Future> resultForBidderNames(Set bidderNames, + VendorIdResolver vendorIdResolver, + String gdpr, + String gdprConsent, + String ipAddress, + AccountGdprConfig accountGdprConfig, + Timeout timeout) { + return resultForInternal( + gdpr, + gdprConsent, + ipAddress, + accountGdprConfig, + timeout, + country -> createAllowAllTcfResponse(bidderNames, country), + (consentString, country) -> + tcf2Service.permissionsFor(bidderNames, vendorIdResolver, consentString, accountGdprConfig) + .map(vendorPermissions -> createBidderNameTcfResponse(vendorPermissions, country)), + (consentString, country) -> + bidderNameResultFromGdpr(bidderNames, vendorIdResolver, consentString, country)); + } + + // vendorIds and BidderNames can't contain null elements + public Future> resultForBidderNames(Set bidderNames, + String gdpr, + String gdprConsent, + String ipAddress, + AccountGdprConfig accountGdprConfig, + Timeout timeout) { + return resultForBidderNames( + bidderNames, + VendorIdResolver.of(bidderCatalog), + gdpr, + gdprConsent, + ipAddress, + accountGdprConfig, + timeout); + } + + private Future> resultForInternal( + String gdpr, + String gdprConsent, + String ipAddress, + AccountGdprConfig accountGdprConfig, + Timeout timeout, + Function>> allowAllTcfResponseCreator, + BiFunction>> tcf2Strategy, + BiFunction>> gdprStrategy) { + + if (!isGdprEnabled(accountGdprConfig)) { + return allowAllTcfResponseCreator.apply(null); + } + + return toGdprInfo(gdpr, gdprConsent, ipAddress, timeout) + .compose(gdprInfoWithCountry -> + dispatchToService(gdprInfoWithCountry, allowAllTcfResponseCreator, tcf2Strategy, gdprStrategy)); + } + + private boolean isGdprEnabled(AccountGdprConfig accountGdprConfig) { + return accountGdprConfig != null && accountGdprConfig.getEnabled() != null + ? accountGdprConfig.getEnabled() + : gdprEnabled; + } + + private Future> toGdprInfo( + String gdpr, String gdprConsent, String ipAddress, Timeout timeout) { + + // from request param + final boolean isValidGdpr = gdpr != null && (gdpr.equals(GDPR_ZERO) || gdpr.equals(GDPR_ONE)); + if (isValidGdpr) { + return Future.succeededFuture(GdprInfoWithCountry.of(gdpr, gdprConsent)); + } + + // from geo location + if (ipAddress != null && geoLocationService != null) { + return geoLocationService.lookup(ipAddress, timeout) + .map(GeoInfo::getCountry) + .map(resolvedCountry -> createGdprInfoWithCountry(gdprConsent, resolvedCountry)) + .otherwise(exception -> updateMetricsAndReturnDefault(exception, gdprConsent)); + } + + // use default + return Future.succeededFuture(defaultGdprInfoWithCountry(gdprConsent)); + } + + private GdprInfoWithCountry createGdprInfoWithCountry(String gdprConsent, String country) { + metrics.updateGeoLocationMetric(true); + + final Boolean inEea = country != null ? eeaCountries.contains(country) : null; + final String gdpr = inEea == null + ? gdprDefaultValue + : inEea ? GDPR_ONE : GDPR_ZERO; + return GdprInfoWithCountry.of(gdpr, gdprConsent, country, inEea); + } + + private GdprInfoWithCountry updateMetricsAndReturnDefault(Throwable exception, String gdprConsent) { + logger.info("Geolocation lookup failed", exception); + metrics.updateGeoLocationMetric(false); + return defaultGdprInfoWithCountry(gdprConsent); + } + + private GdprInfoWithCountry defaultGdprInfoWithCountry(String gdprConsent) { + return GdprInfoWithCountry.of(gdprDefaultValue, gdprConsent); + } + + private Future> dispatchToService( + GdprInfoWithCountry gdprInfoWithCountry, + Function>> allowAllTcfResponseCreator, + BiFunction>> tcf2Strategy, + BiFunction>> gdprStrategy) { + + TCString tcString = decodeTcString(gdprInfoWithCountry); + + updatePrivacyTcfMetrics(gdprInfoWithCountry, tcString); + + final String country = gdprInfoWithCountry.getCountry(); + if (!inScope(gdprInfoWithCountry)) { + return allowAllTcfResponseCreator.apply(country); + } + + // parsing TC string should not fail the entire request, assume the user does not consent + if (tcString == null) { + tcString = new TCStringEmpty(2); + } + + if (tcString.getVersion() == 2) { + return tcf2Strategy.apply(tcString, country); + } + + return gdprStrategy.apply(gdprInfoWithCountry.getConsent(), country); + } + + private void updatePrivacyTcfMetrics(GdprInfoWithCountry gdprInfoWithCountry, TCString tcString) { + if (tcString == null) { + metrics.updatePrivacyTcfInvalidMetric(); + } else { + metrics.updatePrivacyTcfGeoMetric(tcString.getVersion(), gdprInfoWithCountry.getInEea()); + } + } + + private Future> createAllowAllTcfResponse(Set keys, String country) { + return Future.succeededFuture(TcfResponse.of(false, allowAll(keys), country)); + } + + private static TcfResponse createVendorIdTcfResponse( + Collection vendorPermissions, String country) { + + return TcfResponse.of( + true, + vendorPermissions.stream() + .collect(Collectors.toMap( + VendorPermission::getVendorId, + VendorPermission::getPrivacyEnforcementAction)), + country); + } + + private static TcfResponse createBidderNameTcfResponse( + Collection vendorPermissions, String country) { + + return TcfResponse.of( + true, + vendorPermissions.stream() + .collect(Collectors.toMap( + VendorPermission::getBidderName, + VendorPermission::getPrivacyEnforcementAction)), + country); + } + + private Future> bidderNameResultFromGdpr( + Set bidderNames, VendorIdResolver vendorIdResolver, String consentString, String country) { + + final Map bidderToVendorId = resolveBidderToVendorId(bidderNames, vendorIdResolver); + final Set vendorIds = bidderToVendorId.values().stream() + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + return gdprService.resultFor(vendorIds, consentString) + .map(vendorPermissions -> gdprResponseToTcfResponse(vendorPermissions, bidderToVendorId, country)); + } + + private static Map resolveBidderToVendorId( + Set bidderNames, VendorIdResolver vendorIdResolver) { + + final Map bidderToVendorId = new HashMap<>(); + bidderNames.forEach(bidderName -> bidderToVendorId.put(bidderName, vendorIdResolver.resolve(bidderName))); + return bidderToVendorId; + } + + private static TcfResponse gdprResponseToTcfResponse(Collection vendorPermissions, + Map bidderToVendorId, + String country) { + + final Map bidderNameToAction = new HashMap<>(); + + final Map> vendorIdToBidders = bidderToVendorId.entrySet().stream() + .filter(entry -> entry.getValue() != null) + .collect(Collectors.groupingBy( + Map.Entry::getValue, + Collectors.mapping(Map.Entry::getKey, Collectors.toSet()))); + + for (final VendorPermission vendorPermission : vendorPermissions) { + final Integer vendorId = vendorPermission.getVendorId(); + + if (vendorIdToBidders.containsKey(vendorId)) { + final PrivacyEnforcementAction action = vendorPermission.getPrivacyEnforcementAction(); + vendorIdToBidders.get(vendorId).forEach(bidderName -> bidderNameToAction.put(bidderName, action)); + } + } + + // process bidders whose vendorIds weren't resolved + bidderToVendorId.entrySet().stream() + .filter(entry -> entry.getValue() == null) + .map(Map.Entry::getKey) + .forEach(bidder -> bidderNameToAction.put(bidder, restrictAllButAnalyticsAndAuction())); + + return TcfResponse.of(true, bidderNameToAction, country); + } + + private static Map allowAll(Collection identifiers) { + return identifiers.stream() + .collect(Collectors.toMap(Function.identity(), ignored -> PrivacyEnforcementAction.allowAll())); + } + + private static boolean inScope(GdprInfoWithCountry gdprInfo) { + return Objects.equals(gdprInfo.getGdpr(), GDPR_ONE); + } + + private static TCString decodeTcString(GdprInfoWithCountry gdprInfo) { + try { + return TCString.decode(gdprInfo.getConsent()); + } catch (Throwable e) { + logger.warn("Parsing consent string failed with error: {0}", e.getMessage()); + return null; + } + } + + private static PrivacyEnforcementAction restrictAllButAnalyticsAndAuction() { + return PrivacyEnforcementAction.builder() + .removeUserIds(true) + .maskGeo(true) + .maskDeviceIp(true) + .maskDeviceInfo(true) + .blockAnalyticsReport(false) + .blockBidderRequest(false) + .blockPixelSync(true) + .build(); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/VendorIdResolver.java b/src/main/java/org/prebid/server/privacy/gdpr/VendorIdResolver.java new file mode 100644 index 00000000000..f9a002705c2 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/VendorIdResolver.java @@ -0,0 +1,40 @@ +package org.prebid.server.privacy.gdpr; + +import org.prebid.server.auction.BidderAliases; +import org.prebid.server.bidder.BidderCatalog; + +import java.util.Objects; + +public class VendorIdResolver { + + private final BidderCatalog bidderCatalog; + private final BidderAliases aliases; + + private VendorIdResolver(BidderCatalog bidderCatalog, BidderAliases aliases) { + this.bidderCatalog = Objects.requireNonNull(bidderCatalog); + this.aliases = aliases; + } + + public static VendorIdResolver of(BidderCatalog bidderCatalog, BidderAliases aliases) { + return new VendorIdResolver(bidderCatalog, aliases); + } + + public static VendorIdResolver of(BidderCatalog bidderCatalog) { + return new VendorIdResolver(bidderCatalog, null); + } + + public Integer resolve(String aliasOrBidder) { + if (aliases == null) { + return resolveViaCatalog(aliasOrBidder); + } + + final Integer aliasVendorId = aliases.resolveAliasVendorId(aliasOrBidder); + + return aliasVendorId != null ? aliasVendorId : resolveViaCatalog(aliases.resolveBidder(aliasOrBidder)); + + } + + private Integer resolveViaCatalog(String bidderName) { + return bidderCatalog.isActive(bidderName) ? bidderCatalog.vendorIdByName(bidderName) : null; + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/GdprInfoWithCountry.java b/src/main/java/org/prebid/server/privacy/gdpr/model/GdprInfoWithCountry.java new file mode 100644 index 00000000000..35982156450 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/GdprInfoWithCountry.java @@ -0,0 +1,25 @@ +package org.prebid.server.privacy.gdpr.model; + +import lombok.AllArgsConstructor; +import lombok.Value; + +/** + * Internal class for holding GDPR information and country. + */ +@AllArgsConstructor(staticName = "of") +@Value +public class GdprInfoWithCountry { + + String gdpr; + + T consent; + + String country; + + Boolean inEea; + + public static GdprInfoWithCountry of(String gdpr, T consent) { + return of(gdpr, consent, null, null); + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/GdprPurpose.java b/src/main/java/org/prebid/server/privacy/gdpr/model/GdprPurpose.java deleted file mode 100644 index 5936284c8ba..00000000000 --- a/src/main/java/org/prebid/server/privacy/gdpr/model/GdprPurpose.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.prebid.server.privacy.gdpr.model; - -public enum GdprPurpose { - - /** - * The storage of information, or access to information that is already stored, on your device - * such as advertising identifiers, device identifiers, cookies, and similar technologies. - */ - informationStorageAndAccess(1), - - /** - * The collection of information, and combination with previously collected information, - * to select and deliver advertisements for you, and to measure the delivery and effectiveness of - * such advertisements. This includes using previously collected information about your interests - * to select ads, processing data about what advertisements were shown, how often they were shown, - * when and where they were shown, and whether you took any action related to the advertisement, - * including for example clicking an ad or making a purchase. This does not include personalisation, - * which is the collection and processing of information about your use of this service to subsequently - * personalise advertising and/or content for you in other contexts, such as websites or apps, over time. - */ - adSelectionAndDeliveryAndReporting(3); - - private int id; - - GdprPurpose(int id) { - this.id = id; - } - - public int getId() { - return id; - } -} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/PrivacyEnforcementAction.java b/src/main/java/org/prebid/server/privacy/gdpr/model/PrivacyEnforcementAction.java new file mode 100644 index 00000000000..4da89cc9a48 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/PrivacyEnforcementAction.java @@ -0,0 +1,39 @@ +package org.prebid.server.privacy.gdpr.model; + +import lombok.Builder; +import lombok.Data; + +@Builder(toBuilder = true) +@Data +public class PrivacyEnforcementAction { + + boolean removeUserIds; // user.buyeruid, user.id, user.ext.eids, user.ext.digitrust + + boolean maskGeo; // user.geo, device.geo + + boolean maskDeviceIp; // ip, ipv6 + + boolean maskDeviceInfo; // ifa, macsha1, macmd5, dpidsha1, dpidmd5, didsha1, didmd5 + + boolean blockAnalyticsReport; + + boolean blockBidderRequest; + + boolean blockPixelSync; + + public static PrivacyEnforcementAction restrictAll() { + return PrivacyEnforcementAction.builder() + .removeUserIds(true) + .maskGeo(true) + .maskDeviceIp(true) + .maskDeviceInfo(true) + .blockAnalyticsReport(true) + .blockBidderRequest(true) + .blockPixelSync(true) + .build(); + } + + public static PrivacyEnforcementAction allowAll() { + return PrivacyEnforcementAction.builder().build(); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/PublisherRestrictionEmpty.java b/src/main/java/org/prebid/server/privacy/gdpr/model/PublisherRestrictionEmpty.java new file mode 100644 index 00000000000..03de2fdd19f --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/PublisherRestrictionEmpty.java @@ -0,0 +1,12 @@ +package org.prebid.server.privacy.gdpr.model; + +import com.iabtcf.utils.BitSetIntIterable; +import com.iabtcf.v2.PublisherRestriction; +import com.iabtcf.v2.RestrictionType; + +public class PublisherRestrictionEmpty extends PublisherRestriction { + + public PublisherRestrictionEmpty(int purposeId) { + super(purposeId, RestrictionType.UNDEFINED, BitSetIntIterable.EMPTY); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/TCStringEmpty.java b/src/main/java/org/prebid/server/privacy/gdpr/model/TCStringEmpty.java new file mode 100644 index 00000000000..98123ba2248 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/TCStringEmpty.java @@ -0,0 +1,149 @@ +package org.prebid.server.privacy.gdpr.model; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.BitSetIntIterable; +import com.iabtcf.utils.IntIterable; +import com.iabtcf.v2.PublisherRestriction; + +import java.time.Instant; +import java.util.Collections; +import java.util.List; + +public class TCStringEmpty implements TCString { + + private int version; + + public TCStringEmpty(int version) { + this.version = version; + } + + @Override + public int getVersion() { + return version; + } + + @Override + public Instant getCreated() { + return null; + } + + @Override + public Instant getLastUpdated() { + return null; + } + + @Override + public int getCmpId() { + return 0; + } + + @Override + public int getCmpVersion() { + return 0; + } + + @Override + public int getConsentScreen() { + return 0; + } + + @Override + public String getConsentLanguage() { + return null; + } + + @Override + public int getVendorListVersion() { + return 0; + } + + @Override + public IntIterable getPurposesConsent() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getVendorConsent() { + return BitSetIntIterable.EMPTY; + } + + @Override + public boolean getDefaultVendorConsent() { + return false; + } + + @Override + public int getTcfPolicyVersion() { + return 0; + } + + @Override + public boolean isServiceSpecific() { + return false; + } + + @Override + public boolean getUseNonStandardStacks() { + return false; + } + + @Override + public IntIterable getSpecialFeatureOptIns() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getPurposesLITransparency() { + return BitSetIntIterable.EMPTY; + } + + @Override + public boolean getPurposeOneTreatment() { + return false; + } + + @Override + public String getPublisherCC() { + return null; + } + + @Override + public IntIterable getVendorLegitimateInterest() { + return BitSetIntIterable.EMPTY; + } + + @Override + public List getPublisherRestrictions() { + return Collections.emptyList(); + } + + @Override + public IntIterable getAllowedVendors() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getDisclosedVendors() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getPubPurposesConsent() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getPubPurposesLITransparency() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getCustomPurposesConsent() { + return BitSetIntIterable.EMPTY; + } + + @Override + public IntIterable getCustomPurposesLITransparency() { + return BitSetIntIterable.EMPTY; + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/GdprResponse.java b/src/main/java/org/prebid/server/privacy/gdpr/model/TcfResponse.java similarity index 53% rename from src/main/java/org/prebid/server/privacy/gdpr/model/GdprResponse.java rename to src/main/java/org/prebid/server/privacy/gdpr/model/TcfResponse.java index d8224fb0c10..dc182ae2bb6 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/model/GdprResponse.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/TcfResponse.java @@ -1,23 +1,21 @@ package org.prebid.server.privacy.gdpr.model; -import lombok.AllArgsConstructor; import lombok.Value; import java.util.Map; -@AllArgsConstructor(staticName = "of") -@Value -public class GdprResponse { +@Value(staticConstructor = "of") +public class TcfResponse { /** * Defines if user is in GDPR scope flag. Can be useful for analyzing GDPR processing result. */ - boolean userInGdprScope; + Boolean userInGdprScope; /** - * Gdpr processing result map where key is vendor ID and value is GDPR allowed flag. + * Gdpr processing result map where key is vendor ID or bidder name and value is permissions. */ - Map vendorsToGdpr; + Map actions; /** * Defines a country where user comes from. diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/VendorPermission.java b/src/main/java/org/prebid/server/privacy/gdpr/model/VendorPermission.java new file mode 100644 index 00000000000..fbc7c771aff --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/VendorPermission.java @@ -0,0 +1,14 @@ +package org.prebid.server.privacy.gdpr.model; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class VendorPermission { + + Integer vendorId; + + String bidderName; + + PrivacyEnforcementAction privacyEnforcementAction; +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/model/VendorPermissionWithGvl.java b/src/main/java/org/prebid/server/privacy/gdpr/model/VendorPermissionWithGvl.java new file mode 100644 index 00000000000..426590d72f5 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/model/VendorPermissionWithGvl.java @@ -0,0 +1,12 @@ +package org.prebid.server.privacy.gdpr.model; + +import lombok.Value; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; + +@Value(staticConstructor = "of") +public class VendorPermissionWithGvl { + + VendorPermission vendorPermission; + + VendorV2 vendorV2; +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeFourStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeFourStrategy.java new file mode 100644 index 00000000000..5e1507311cf --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeFourStrategy.java @@ -0,0 +1,29 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; + +public class PurposeFourStrategy extends PurposeStrategy { + + private static final int PURPOSE_ID = 4; + + public PurposeFourStrategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy, + BasicEnforcePurposeStrategy basicEnforcePurposeStrategy, + NoEnforcePurposeStrategy noEnforcePurposeStrategy) { + super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy); + } + + @Override + public void allow(PrivacyEnforcementAction privacyEnforcementAction) { + privacyEnforcementAction.setRemoveUserIds(false); + privacyEnforcementAction.setMaskDeviceInfo(false); + } + + @Override + public int getPurposeId() { + return PURPOSE_ID; + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeOneStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeOneStrategy.java new file mode 100644 index 00000000000..4b48d91af20 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeOneStrategy.java @@ -0,0 +1,28 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; + +public class PurposeOneStrategy extends PurposeStrategy { + + private static final int PURPOSE_ID = 1; + + public PurposeOneStrategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy, + BasicEnforcePurposeStrategy basicEnforcePurposeStrategy, + NoEnforcePurposeStrategy noEnforcePurposeStrategy) { + super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy); + } + + @Override + public void allow(PrivacyEnforcementAction privacyEnforcementAction) { + privacyEnforcementAction.setBlockPixelSync(false); + } + + @Override + public int getPurposeId() { + return PURPOSE_ID; + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeSevenStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeSevenStrategy.java new file mode 100644 index 00000000000..8b4142d72a6 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeSevenStrategy.java @@ -0,0 +1,29 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; + +public class PurposeSevenStrategy extends PurposeStrategy { + + private static final int PURPOSE_ID = 7; + + public PurposeSevenStrategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy, + BasicEnforcePurposeStrategy basicEnforcePurposeStrategy, + NoEnforcePurposeStrategy noEnforcePurposeStrategy) { + super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy); + } + + @Override + public void allow(PrivacyEnforcementAction privacyEnforcementAction) { + privacyEnforcementAction.setBlockAnalyticsReport(false); + } + + @Override + public int getPurposeId() { + return PURPOSE_ID; + } + +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeStrategy.java new file mode 100644 index 00000000000..9b60c86d134 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeStrategy.java @@ -0,0 +1,112 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import com.iabtcf.decoder.TCString; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.Purpose; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public abstract class PurposeStrategy { + + private FullEnforcePurposeStrategy fullEnforcePurposeStrategy; + private BasicEnforcePurposeStrategy basicEnforcePurposeStrategy; + private NoEnforcePurposeStrategy noEnforcePurposeStrategy; + + public PurposeStrategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy, + BasicEnforcePurposeStrategy basicEnforcePurposeStrategy, + NoEnforcePurposeStrategy noEnforcePurposeStrategy) { + this.fullEnforcePurposeStrategy = fullEnforcePurposeStrategy; + this.basicEnforcePurposeStrategy = basicEnforcePurposeStrategy; + this.noEnforcePurposeStrategy = noEnforcePurposeStrategy; + } + + public abstract int getPurposeId(); + + public abstract void allow(PrivacyEnforcementAction privacyEnforcementAction); + + public Collection processTypePurposeStrategy( + TCString vendorConsent, Purpose purpose, Collection vendorPermissions) { + + allowedByTypeStrategy(vendorConsent, purpose, vendorPermissions).stream() + .map(VendorPermission::getPrivacyEnforcementAction) + .forEach(this::allow); + + return vendorPermissions.stream() + .map(VendorPermissionWithGvl::getVendorPermission) + .collect(Collectors.toList()); + } + + private Collection allowedByTypeStrategy(TCString vendorConsent, + Purpose purpose, + Collection vendorPermissions) { + final Collection excludedVendors = excludedVendors(vendorPermissions, purpose); + final Collection vendorForPurpose = vendorPermissions.stream() + .filter(vendorPermission -> !excludedVendors.contains(vendorPermission)) + .collect(Collectors.toList()); + final boolean isEnforceVendors = BooleanUtils.isNotFalse(purpose.getEnforceVendors()); + + final EnforcePurpose purposeType = purpose.getEnforcePurpose(); + if (Objects.equals(purposeType, EnforcePurpose.basic)) { + return allowedByBasicTypeStrategy(vendorConsent, isEnforceVendors, vendorForPurpose, excludedVendors); + } + + if (Objects.equals(purposeType, EnforcePurpose.no)) { + return allowedByNoTypeStrategy(vendorConsent, isEnforceVendors, vendorForPurpose, excludedVendors); + } + + // Full by default + if (purposeType == null || Objects.equals(purposeType, EnforcePurpose.full)) { + return allowedByFullTypeStrategy(vendorConsent, isEnforceVendors, vendorForPurpose, excludedVendors); + } + + throw new IllegalArgumentException( + String.format("Invalid type strategy provided. no/base/full != %s", purposeType)); + } + + protected Collection excludedVendors(Collection vendorPermissions, + Purpose purpose) { + final List bidderNameExceptions = purpose.getVendorExceptions(); + return CollectionUtils.isEmpty(bidderNameExceptions) + ? Collections.emptyList() + : CollectionUtils.select(vendorPermissions, vendorPermission -> + bidderNameExceptions.contains(vendorPermission.getVendorPermission().getBidderName())); + } + + protected Collection allowedByBasicTypeStrategy( + TCString vendorConsent, boolean isEnforceVendors, Collection vendorForPurpose, + Collection excludedVendors) { + + return basicEnforcePurposeStrategy.allowedByTypeStrategy(getPurposeId(), vendorConsent, vendorForPurpose, + excludedVendors, isEnforceVendors); + } + + protected Collection allowedByNoTypeStrategy( + TCString vendorConsent, boolean isEnforceVendors, Collection vendorForPurpose, + Collection excludedVendors) { + + return noEnforcePurposeStrategy.allowedByTypeStrategy(getPurposeId(), vendorConsent, vendorForPurpose, + excludedVendors, isEnforceVendors); + } + + protected Collection allowedByFullTypeStrategy( + TCString vendorConsent, boolean isEnforceVendors, Collection vendorForPurpose, + Collection excludedVendors) { + + return fullEnforcePurposeStrategy.allowedByTypeStrategy(getPurposeId(), vendorConsent, vendorForPurpose, + excludedVendors, isEnforceVendors); + + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeTwoStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeTwoStrategy.java new file mode 100644 index 00000000000..753838ebdb1 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeTwoStrategy.java @@ -0,0 +1,28 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; + +public class PurposeTwoStrategy extends PurposeStrategy { + + private static final int PURPOSE_ID = 2; + + public PurposeTwoStrategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy, + BasicEnforcePurposeStrategy basicEnforcePurposeStrategy, + NoEnforcePurposeStrategy noEnforcePurposeStrategy) { + super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy); + } + + @Override + public void allow(PrivacyEnforcementAction privacyEnforcementAction) { + privacyEnforcementAction.setBlockBidderRequest(false); + } + + @Override + public int getPurposeId() { + return PURPOSE_ID; + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/BasicEnforcePurposeStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/BasicEnforcePurposeStrategy.java new file mode 100644 index 00000000000..cd8e046a31c --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/BasicEnforcePurposeStrategy.java @@ -0,0 +1,35 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import io.vertx.core.logging.Logger; +import io.vertx.core.logging.LoggerFactory; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class BasicEnforcePurposeStrategy extends EnforcePurposeStrategy { + + private static final Logger logger = LoggerFactory.getLogger(BasicEnforcePurposeStrategy.class); + + public Collection allowedByTypeStrategy(int purposeId, + TCString vendorConsent, + Collection vendorsForPurpose, + Collection excludedVendors, + boolean isEnforceVendors) { + + logger.debug("Basic strategy used fo purpose {0}", purposeId); + final List allowedVendorPermissions = vendorsForPurpose.stream() + .map(VendorPermissionWithGvl::getVendorPermission) + .filter(vendorPermission -> vendorPermission.getVendorId() != null) + .filter(vendorPermission -> isAllowedBySimpleConsentOrLegitimateInterest(purposeId, + vendorPermission.getVendorId(), isEnforceVendors, vendorConsent)) + .collect(Collectors.toList()); + + return CollectionUtils.union(allowedVendorPermissions, toVendorPermissions(excludedVendors)); + + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/EnforcePurposeStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/EnforcePurposeStrategy.java new file mode 100644 index 00000000000..4734685e68d --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/EnforcePurposeStrategy.java @@ -0,0 +1,61 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; + +import java.util.Collection; +import java.util.stream.Collectors; + +public abstract class EnforcePurposeStrategy { + + public abstract Collection allowedByTypeStrategy( + int purposeId, TCString vendorConsent, Collection vendorsForPurpose, + Collection excludedVendors, boolean isEnforceVendors); + + protected boolean isAllowedBySimpleConsentOrLegitimateInterest(int purposeId, + Integer vendorId, + boolean isEnforceVendor, + TCString tcString) { + return isAllowedBySimpleConsent(purposeId, vendorId, isEnforceVendor, tcString) + || isAllowedByLegitimateInterest(purposeId, vendorId, isEnforceVendor, tcString); + + } + + protected boolean isAllowedBySimpleConsent(int purposeId, + Integer vendorId, + boolean isEnforceVendor, + TCString tcString) { + final IntIterable purposesConsent = tcString.getPurposesConsent(); + final IntIterable vendorConsent = tcString.getVendorConsent(); + return isAllowedByConsents(purposeId, vendorId, isEnforceVendor, purposesConsent, vendorConsent); + } + + protected boolean isAllowedByLegitimateInterest(int purposeId, + Integer vendorId, + boolean isEnforceVendor, + TCString tcString) { + final IntIterable purposesConsent = tcString.getPurposesLITransparency(); + final IntIterable vendorConsent = tcString.getVendorLegitimateInterest(); + return isAllowedByConsents(purposeId, vendorId, isEnforceVendor, purposesConsent, vendorConsent); + } + + private boolean isAllowedByConsents(int purposeId, + Integer vendorId, + boolean isEnforceVendors, + IntIterable purposesConsent, + IntIterable vendorConsent) { + final boolean isPurposeAllowed = purposesConsent.contains(purposeId); + final boolean isVendorAllowed = !isEnforceVendors || vendorConsent.contains(vendorId); + return isPurposeAllowed && isVendorAllowed; + } + + protected static Collection toVendorPermissions( + Collection vendorPermissionWithGvls) { + + return vendorPermissionWithGvls.stream() + .map(VendorPermissionWithGvl::getVendorPermission) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/FullEnforcePurposeStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/FullEnforcePurposeStrategy.java new file mode 100644 index 00000000000..598c8c21b07 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/FullEnforcePurposeStrategy.java @@ -0,0 +1,153 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.v2.PublisherRestriction; +import com.iabtcf.v2.RestrictionType; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class FullEnforcePurposeStrategy extends EnforcePurposeStrategy { + + public Collection allowedByTypeStrategy(int purposeId, + TCString vendorConsent, + Collection vendorsForPurpose, + Collection excludedVendors, + boolean isEnforceVendors) { + + final List publisherRestrictions = vendorConsent.getPublisherRestrictions().stream() + .filter(publisherRestriction -> publisherRestriction.getPurposeId() == purposeId) + .collect(Collectors.toList()); + + final List allowedExcluded = allowedExcludedVendorPermission(excludedVendors, + publisherRestrictions); + + final Map vendorPermissionToRestriction = mapVendorPermission( + vendorsForPurpose, publisherRestrictions); + + final List allowedVendorPermissions = vendorPermissionToRestriction.entrySet().stream() + .filter(permissionAndRestriction -> + isAllowedByPublisherRestrictionAndFlexible(purposeId, isEnforceVendors, + permissionAndRestriction.getKey(), vendorConsent, permissionAndRestriction.getValue())) + .map(Map.Entry::getKey) + .map(VendorPermissionWithGvl::getVendorPermission) + .collect(Collectors.toList()); + + return CollectionUtils.union(allowedExcluded, allowedVendorPermissions); + } + + private List allowedExcludedVendorPermission( + Collection excludedVendors, + Collection publisherRestrictions) { + + final List notAllowedVendorIds = publisherRestrictions.stream() + .filter(publisherRestriction -> publisherRestriction.getRestrictionType() + .equals(RestrictionType.NOT_ALLOWED)) + .map(PublisherRestriction::getVendorIds) + .flatMap(vendorIds -> StreamSupport.stream(vendorIds.spliterator(), false)) + .collect(Collectors.toList()); + + return excludedVendors.stream() + .map(VendorPermissionWithGvl::getVendorPermission) + .filter(vendorPermissionWithGvl -> isNotRestricted(notAllowedVendorIds, vendorPermissionWithGvl)) + .collect(Collectors.toList()); + } + + private boolean isNotRestricted(List notAllowedVendorIds, VendorPermission vendorPermission) { + final Integer vendorId = vendorPermission.getVendorId(); + return vendorId == null || !notAllowedVendorIds.contains(vendorId); + } + + private Map mapVendorPermission( + Collection vendorsForPurpose, + Collection publisherRestrictions) { + + return vendorsForPurpose.stream() + .collect(Collectors.toMap( + Function.identity(), + vendorPermissionWithGvl -> restrictionType(vendorPermissionWithGvl, publisherRestrictions))); + } + + private RestrictionType restrictionType(VendorPermissionWithGvl vendorPermissionWithGvl, + Collection publisherRestrictions) { + final VendorPermission vendorPermission = vendorPermissionWithGvl.getVendorPermission(); + final Integer vendorId = vendorPermission.getVendorId(); + + return publisherRestrictions.stream() + .filter(publisherRestriction -> publisherRestriction.getVendorIds().contains(vendorId)) + .map(PublisherRestriction::getRestrictionType) + .findFirst() + .orElse(RestrictionType.UNDEFINED); + } + + /** + * Purpose is flexible when {@link VendorV2} flexiblePurposes contains it id. + * When it is not flexible: + * We check purposeConsent and vendorConsent when it is contained in GVL purposes; + * We check purposesLITransparency and vendorLegitimateInterest when it is contained in GVL LegIntPurposes. + *


+ * If it flexible we check by {@link RestrictionType}: + *

  • For REQUIRE_CONSENT we check by purposeConsent and vendorConsent
  • + *
  • For REQUIRE_LEGITIMATE_INTEREST we check by purposesLITransparency and vendorLegitimateInterest
  • + *
  • For UNDEFINED we check by purposeConsent and vendorConsent + * or purposesLITransparency and vendorLegitimateInterest
  • + *

    + */ + private boolean isAllowedByPublisherRestrictionAndFlexible(int purposeId, + boolean isEnforceVendor, + VendorPermissionWithGvl vendorPermissionWithGvl, + TCString tcString, + RestrictionType restrictionType) { + if (restrictionType.equals(RestrictionType.NOT_ALLOWED)) { + return false; + } + + final Integer vendorId = vendorPermissionWithGvl.getVendorPermission().getVendorId(); + final VendorV2 vendorGvl = vendorPermissionWithGvl.getVendorV2(); + + final Set flexiblePurposes = vendorGvl.getFlexiblePurposes(); + final boolean isFlexible = CollectionUtils.isNotEmpty(flexiblePurposes) && flexiblePurposes.contains(purposeId); + + final Set gvlPurposes = vendorGvl.getPurposes(); + if (gvlPurposes != null && gvlPurposes.contains(purposeId)) { + return isFlexible + ? isAllowedByRestrictionTypePurpose(purposeId, vendorId, isEnforceVendor, tcString, restrictionType) + : isAllowedBySimpleConsent(purposeId, vendorId, isEnforceVendor, tcString); + } + + final Set legIntGvlPurposes = vendorGvl.getLegIntPurposes(); + if (legIntGvlPurposes != null && legIntGvlPurposes.contains(purposeId)) { + return isFlexible + ? isAllowedByRestrictionTypePurpose(purposeId, vendorId, isEnforceVendor, tcString, restrictionType) + : isAllowedByLegitimateInterest(purposeId, vendorId, isEnforceVendor, tcString); + } + return false; + } + + private boolean isAllowedByRestrictionTypePurpose(int purposeId, + Integer vendorId, + boolean isEnforceVendor, + TCString tcString, + RestrictionType restrictionType) { + switch (restrictionType) { + case REQUIRE_CONSENT: + return isAllowedBySimpleConsent(purposeId, vendorId, isEnforceVendor, tcString); + case REQUIRE_LEGITIMATE_INTEREST: + return isAllowedByLegitimateInterest(purposeId, vendorId, isEnforceVendor, tcString); + case UNDEFINED: + return isAllowedBySimpleConsentOrLegitimateInterest(purposeId, vendorId, isEnforceVendor, tcString); + default: + return false; + } + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/NoEnforcePurposeStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/NoEnforcePurposeStrategy.java new file mode 100644 index 00000000000..81465601924 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/NoEnforcePurposeStrategy.java @@ -0,0 +1,40 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public class NoEnforcePurposeStrategy extends EnforcePurposeStrategy { + + public Collection allowedByTypeStrategy(int purposeId, + TCString tcString, + Collection vendorsForPurpose, + Collection excludedVendors, + boolean isEnforceVendors) { + + final IntIterable vendorConsent = tcString.getVendorConsent(); + final IntIterable vendorLIConsent = tcString.getVendorLegitimateInterest(); + + final List allowedVendorPermissions = vendorsForPurpose.stream() + .map(VendorPermissionWithGvl::getVendorPermission) + .filter(vendorPermission -> vendorPermission.getVendorId() != null) + .filter(vendorPermission -> isAllowedByVendorConsent(vendorPermission.getVendorId(), isEnforceVendors, + vendorConsent, vendorLIConsent)) + .collect(Collectors.toList()); + + return CollectionUtils.union(allowedVendorPermissions, toVendorPermissions(excludedVendors)); + } + + private boolean isAllowedByVendorConsent(Integer vendorId, + boolean isEnforceVendors, + IntIterable vendorConsent, + IntIterable vendorLIConsent) { + return !isEnforceVendors || vendorConsent.contains(vendorId) || vendorLIConsent.contains(vendorId); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesOneStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesOneStrategy.java new file mode 100644 index 00000000000..005b10aaed3 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesOneStrategy.java @@ -0,0 +1,17 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature; + +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; + +public class SpecialFeaturesOneStrategy extends SpecialFeaturesStrategy { + + @Override + public int getSpecialFeatureId() { + return 1; + } + + @Override + public void allow(PrivacyEnforcementAction privacyEnforcementAction) { + privacyEnforcementAction.setMaskDeviceIp(false); + privacyEnforcementAction.setMaskGeo(false); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesStrategy.java b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesStrategy.java new file mode 100644 index 00000000000..33e6699adf6 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesStrategy.java @@ -0,0 +1,57 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.BooleanUtils; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.settings.model.SpecialFeature; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public abstract class SpecialFeaturesStrategy { + + public abstract int getSpecialFeatureId(); + + public abstract void allow(PrivacyEnforcementAction privacyEnforcementAction); + + public Collection processSpecialFeaturesStrategy(TCString vendorConsent, + SpecialFeature specialFeature, + Collection vendorPermissions) { + // Default True + if (BooleanUtils.isFalse(specialFeature.getEnforce())) { + return allowFor(vendorPermissions); + } + + final IntIterable specialFeatureOptIns = vendorConsent.getSpecialFeatureOptIns(); + final boolean isSpecialFeatureIsOptIn = specialFeatureOptIns.contains(getSpecialFeatureId()); + + return isSpecialFeatureIsOptIn + ? allowFor(vendorPermissions) + : allowOnlyExcluded(vendorPermissions, specialFeature); + } + + private Collection allowFor(Collection vendorPermissions) { + vendorPermissions.forEach(vendorPermission -> allow(vendorPermission.getPrivacyEnforcementAction())); + return vendorPermissions; + } + + private Collection allowOnlyExcluded(Collection vendorPermissions, + SpecialFeature specialFeature) { + excludedVendors(vendorPermissions, specialFeature) + .forEach(vendorPermission -> allow(vendorPermission.getPrivacyEnforcementAction())); + return vendorPermissions; + } + + protected Collection excludedVendors(Collection vendorPermissions, + SpecialFeature specialFeature) { + final List bidderNameExceptions = specialFeature.getVendorExceptions(); + return CollectionUtils.isEmpty(bidderNameExceptions) + ? Collections.emptyList() + : CollectionUtils.select(vendorPermissions, vendorPermission -> + bidderNameExceptions.contains(vendorPermission.getBidderName())); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListService.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListService.java index 728dc33fd90..fe0ade96e79 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListService.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListService.java @@ -1,6 +1,8 @@ package org.prebid.server.privacy.gdpr.vendorlist; +import com.github.benmanes.caffeine.cache.Caffeine; import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.FileProps; import io.vertx.core.file.FileSystem; @@ -9,27 +11,21 @@ import io.vertx.core.logging.LoggerFactory; import lombok.AllArgsConstructor; import lombok.Value; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.exception.PreBidException; -import org.prebid.server.privacy.gdpr.vendorlist.proto.Vendor; -import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorList; -import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; import org.prebid.server.vertx.http.HttpClient; import org.prebid.server.vertx.http.model.HttpClientResponse; import java.io.File; -import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Collections; -import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -44,70 +40,46 @@ * If request asks version that is absent in cache, we respond with failed result but start background process * to download new version and then put it to cache. */ -public class VendorListService { +public abstract class VendorListService { private static final Logger logger = LoggerFactory.getLogger(VendorListService.class); - private static final String JSON_SUFFIX = ".json"; private static final String VERSION_PLACEHOLDER = "{VERSION}"; + private static final Integer EXPIRE_DAY_CACHE_DURATION = 5; + /** + * This is memory/performance optimized model slice: + * map of vendor list version -> map of vendor ID -> Vendors + */ + protected final Map> cache; + private final FileSystem fileSystem; + private final HttpClient httpClient; private final String endpointTemplate; private final int defaultTimeoutMs; - private final Set knownVendorIds; private final String cacheDir; - private final FileSystem fileSystem; - private final HttpClient httpClient; - private final JacksonMapper mapper; - - /** - * This is memory/performance optimized {@link VendorList} model slice: - * map of vendor list version -> map of vendor ID -> set of purposes - */ - private final Map>> cache; - - private VendorListService(String cacheDir, - String endpointTemplate, - int defaultTimeoutMs, - Set knownVendorIds, - Map>> cache, - FileSystem fileSystem, - HttpClient httpClient, - JacksonMapper mapper) { - - this.cacheDir = cacheDir; - this.endpointTemplate = endpointTemplate; + protected Set knownVendorIds; + protected JacksonMapper mapper; + + public VendorListService(String cacheDir, + String endpointTemplate, + int defaultTimeoutMs, + Integer gdprHostVendorId, + BidderCatalog bidderCatalog, + FileSystem fileSystem, + HttpClient httpClient, + JacksonMapper mapper) { + + this.cacheDir = Objects.requireNonNull(cacheDir); + this.endpointTemplate = Objects.requireNonNull(endpointTemplate); this.defaultTimeoutMs = defaultTimeoutMs; - this.knownVendorIds = knownVendorIds; - this.cache = cache; - this.fileSystem = fileSystem; - this.httpClient = httpClient; - this.mapper = mapper; - } - - public static VendorListService create(String cacheDir, - String endpointTemplate, - int defaultTimeoutMs, - Integer gdprHostVendorId, - BidderCatalog bidderCatalog, - FileSystem fileSystem, - HttpClient httpClient, - JacksonMapper mapper) { - - Objects.requireNonNull(fileSystem); - Objects.requireNonNull(cacheDir); - Objects.requireNonNull(httpClient); - Objects.requireNonNull(endpointTemplate); - Objects.requireNonNull(bidderCatalog); - Objects.requireNonNull(mapper); + this.fileSystem = Objects.requireNonNull(fileSystem); + this.httpClient = Objects.requireNonNull(httpClient); + this.mapper = Objects.requireNonNull(mapper); createAndCheckWritePermissionsFor(fileSystem, cacheDir); - final Set knownVendorIds = knownVendorIds(gdprHostVendorId, bidderCatalog); - final Map>> cache = createCache( - fileSystem, cacheDir, knownVendorIds, mapper); - - return new VendorListService( - cacheDir, endpointTemplate, defaultTimeoutMs, knownVendorIds, cache, fileSystem, httpClient, mapper); + this.knownVendorIds = knownVendorIds(gdprHostVendorId, bidderCatalog); + this.cache = Objects.requireNonNull(createCache(fileSystem, cacheDir)); } /** @@ -127,37 +99,47 @@ private static void createAndCheckWritePermissionsFor(FileSystem fileSystem, Str } /** - * Fetches Vendor IDs from all known bidders + * Creates vendorList object from string content or throw {@link PreBidException}. + */ + protected abstract T toVendorList(String content); + + /** + * Returns a Map of vendor id to Vendors. + */ + protected abstract Map filterVendorIdToVendors(T vendorList); + + /** + * Verifies all significant fields of given {@link T} object. */ + protected abstract boolean isValid(T vendorList); + private static Set knownVendorIds(Integer gdprHostVendorId, BidderCatalog bidderCatalog) { - final Set vendorIds = bidderCatalog.names().stream() - .map(bidderCatalog::bidderInfoByName) - .map(bidderInfo -> bidderInfo.getGdpr().getVendorId()) - .collect(Collectors.toSet()); + final Set knownVendorIds = bidderCatalog.knownVendorIds(); // add host vendor ID (used in /setuid and /cookie_sync endpoint handlers) if (gdprHostVendorId != null) { - vendorIds.add(gdprHostVendorId); + knownVendorIds.add(gdprHostVendorId); } - return Collections.unmodifiableSet(vendorIds); + return Collections.unmodifiableSet(knownVendorIds); } /** - * Creates cache from previously downloaded vendor lists. + * Creates the cache from previously downloaded vendor lists. */ - private static Map>> createCache( - FileSystem fileSystem, String cacheDir, Set knownVendorIds, JacksonMapper mapper) { - + private Map> createCache(FileSystem fileSystem, String cacheDir) { final Map versionToFileContent = readFileSystemCache(fileSystem, cacheDir); - final Map>> cache = new ConcurrentHashMap<>(versionToFileContent.size()); - for (Map.Entry entry : versionToFileContent.entrySet()) { - final VendorList vendorList = toVendorList(entry.getValue(), mapper); - final Map> vendorIdToPurposes = mapVendorIdToPurposes(vendorList.getVendors(), - knownVendorIds); + final Map> cache = Caffeine.newBuilder() + .expireAfterWrite(EXPIRE_DAY_CACHE_DURATION, TimeUnit.DAYS) + .>build() + .asMap(); - cache.put(Integer.valueOf(entry.getKey()), vendorIdToPurposes); + for (Map.Entry versionAndFileContent : versionToFileContent.entrySet()) { + final T vendorList = toVendorList(versionAndFileContent.getValue()); + final Map vendorIdToVendors = filterVendorIdToVendors(vendorList); + + cache.put(Integer.valueOf(versionAndFileContent.getKey()), vendorIdToVendors); } return cache; } @@ -166,43 +148,20 @@ private static Map>> createCache( * Reads files with .json extension in configured directory and * returns a {@link Map} where key is a file name without .json extension and value is file content. */ - private static Map readFileSystemCache(FileSystem fileSystem, String dir) { + protected Map readFileSystemCache(FileSystem fileSystem, String dir) { return fileSystem.readDirBlocking(dir).stream() .filter(filepath -> filepath.endsWith(JSON_SUFFIX)) .collect(Collectors.toMap(filepath -> StringUtils.removeEnd(new File(filepath).getName(), JSON_SUFFIX), filename -> fileSystem.readFileBlocking(filename).toString())); } - /** - * Creates {@link VendorList} object from string content or throw {@link PreBidException}. - */ - private static VendorList toVendorList(String content, JacksonMapper mapper) { - try { - return mapper.mapper().readValue(content, VendorList.class); - } catch (IOException e) { - final String message = String.format("Cannot parse vendor list from: %s", content); - - logger.error(message, e); - throw new PreBidException(message, e); - } - } - - /** - * Returns a map with vendor ID as a key and set of purposes as a value from given list of {@link Vendor}s. - */ - private static Map> mapVendorIdToPurposes(List vendors, Set knownVendorIds) { - return vendors.stream() - .filter(vendor -> knownVendorIds.contains(vendor.getId())) // optimize cache to use only known vendors - .collect(Collectors.toMap(Vendor::getId, Vendor::combinedPurposes)); - } - /** * Returns a map with vendor ID as a key and a set of purposes as a value for given vendor list version. */ - public Future>> forVersion(int version) { - final Map> vendorIdToPurposes = cache.get(version); - if (vendorIdToPurposes != null) { - return Future.succeededFuture(vendorIdToPurposes); + public Future> forVersion(int version) { + final Map idToVendor = cache.get(version); + if (idToVendor != null) { + return Future.succeededFuture(idToVendor); } else { logger.info("Vendor list for version {0} not found, started downloading.", version); fetchNewVendorListFor(version); @@ -220,7 +179,7 @@ private void fetchNewVendorListFor(int version) { httpClient.get(url, defaultTimeoutMs) .compose(response -> processResponse(response, version)) - .compose(this::saveToFileAndUpdateCache) + .compose(vendorListResult -> saveToFileAndUpdateCache(vendorListResult, version)) .recover(exception -> failResponse(exception, version)); } @@ -229,19 +188,14 @@ private void fetchNewVendorListFor(int version) { * and creates {@link Future} with {@link VendorListResult} from body content * or throws {@link PreBidException} in case of errors. */ - private Future processResponse(HttpClientResponse response, int version) { + private Future> processResponse(HttpClientResponse response, int version) { final int statusCode = response.getStatusCode(); if (statusCode != 200) { throw new PreBidException(String.format("HTTP status code %d", statusCode)); } final String body = response.getBody(); - final VendorList vendorList; - try { - vendorList = mapper.decodeValue(body, VendorList.class); - } catch (DecodeException e) { - throw new PreBidException(String.format("Cannot parse response: %s", body), e); - } + final T vendorList = toVendorList(body); // we should care on obtained vendor list, because it'll be saved and never be downloaded again // while application is running @@ -252,25 +206,12 @@ private Future processResponse(HttpClientResponse response, in return Future.succeededFuture(VendorListResult.of(version, body, vendorList)); } - /** - * Verifies all significant fields of given {@link VendorList} object. - */ - private static boolean isValid(VendorList vendorList) { - return vendorList.getVendorListVersion() != null - && vendorList.getLastUpdated() != null - && CollectionUtils.isNotEmpty(vendorList.getVendors()) - && vendorList.getVendors().stream() - .allMatch(vendor -> vendor != null && vendor.getId() != null - && (vendor.getPurposeIds() != null || vendor.getLegIntPurposeIds() != null)); - } - - private Future saveToFileAndUpdateCache(VendorListResult vendorListResult) { - final VendorList vendorList = vendorListResult.getVendorList(); - final int version = vendorListResult.getVersion(); + private Future saveToFileAndUpdateCache(VendorListResult vendorListResult, int version) { + final T vendorList = vendorListResult.getVendorList(); saveToFile(vendorListResult.getVendorListAsString(), version) // add new entry to in-memory cache - .map(r -> cache.put(version, mapVendorIdToPurposes(vendorList.getVendors(), knownVendorIds))); + .map(ignored -> cache.put(version, filterVendorIdToVendors(vendorList))); return Future.succeededFuture(); } @@ -279,21 +220,21 @@ private Future saveToFileAndUpdateCache(VendorListResult vendorListResult) * Saves on file system given content as vendor list of specified version. */ private Future saveToFile(String content, int version) { - final Future future = Future.future(); + final Promise promise = Promise.promise(); final String filepath = new File(cacheDir, version + JSON_SUFFIX).getPath(); fileSystem.writeFile(filepath, Buffer.buffer(content), result -> { if (result.succeeded()) { logger.info("Created new vendor list for version {0}, file: {1}", version, filepath); - future.complete(); + promise.complete(); } else { logger.warn("Could not create new vendor list for version {0}, file: {1}", result.cause(), version, filepath); - future.fail(result.cause()); + promise.fail(result.cause()); } }); - return future; + return promise.future(); } /** @@ -308,12 +249,12 @@ private static Future failResponse(Throwable exception, int version) { @AllArgsConstructor(staticName = "of") @Value - private static class VendorListResult { + private static class VendorListResult { int version; String vendorListAsString; - VendorList vendorList; + T vendorList; } } diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV1.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV1.java new file mode 100644 index 00000000000..c2772a92d84 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV1.java @@ -0,0 +1,67 @@ +package org.prebid.server.privacy.gdpr.vendorlist; + +import io.vertx.core.file.FileSystem; +import io.vertx.core.logging.Logger; +import io.vertx.core.logging.LoggerFactory; +import org.apache.commons.collections4.CollectionUtils; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV1; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV1; +import org.prebid.server.vertx.http.HttpClient; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class VendorListServiceV1 extends VendorListService { + + private static final Logger logger = LoggerFactory.getLogger(VendorListServiceV1.class); + + public VendorListServiceV1(String cacheDir, + String endpointTemplate, + int defaultTimeoutMs, + Integer gdprHostVendorId, + BidderCatalog bidderCatalog, + FileSystem fileSystem, + HttpClient httpClient, + JacksonMapper mapper) { + super(cacheDir, endpointTemplate, defaultTimeoutMs, gdprHostVendorId, bidderCatalog, fileSystem, httpClient, + mapper); + } + + protected VendorListV1 toVendorList(String content) { + try { + return mapper.mapper().readValue(content, VendorListV1.class); + } catch (IOException e) { + final String message = String.format("Cannot parse vendor list from: %s", content); + + logger.error(message, e); + throw new PreBidException(message, e); + } + } + + protected Map filterVendorIdToVendors(VendorListV1 vendorList) { + return vendorList.getVendors().stream() + .filter(vendor -> knownVendorIds.contains(vendor.getId())) // optimize cache to use only known vendors + .collect(Collectors.toMap(VendorV1::getId, Function.identity())); + } + + protected boolean isValid(VendorListV1 vendorList) { + return vendorList.getVendorListVersion() != null + && vendorList.getLastUpdated() != null + && CollectionUtils.isNotEmpty(vendorList.getVendors()) + && isValidVendors(vendorList.getVendors()); + } + + private static boolean isValidVendors(Collection vendors) { + return vendors.stream() + .allMatch(vendor -> vendor != null + && vendor.getId() != null + && vendor.getPurposeIds() != null + && vendor.getLegIntPurposeIds() != null); + } +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV2.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV2.java new file mode 100644 index 00000000000..c3fdafa14df --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV2.java @@ -0,0 +1,70 @@ +package org.prebid.server.privacy.gdpr.vendorlist; + +import io.vertx.core.file.FileSystem; +import io.vertx.core.logging.Logger; +import io.vertx.core.logging.LoggerFactory; +import org.apache.commons.collections4.MapUtils; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.json.JacksonMapper; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV2; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.vertx.http.HttpClient; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; + +public class VendorListServiceV2 extends VendorListService { + + private static final Logger logger = LoggerFactory.getLogger(VendorListServiceV2.class); + + public VendorListServiceV2(String cacheDir, + String endpointTemplate, + int defaultTimeoutMs, + Integer gdprHostVendorId, + BidderCatalog bidderCatalog, + FileSystem fileSystem, + HttpClient httpClient, + JacksonMapper mapper) { + super(cacheDir, endpointTemplate, defaultTimeoutMs, gdprHostVendorId, bidderCatalog, fileSystem, httpClient, + mapper); + } + + protected VendorListV2 toVendorList(String content) { + try { + return mapper.mapper().readValue(content, VendorListV2.class); + } catch (IOException e) { + final String message = String.format("Cannot parse vendor list from: %s", content); + + logger.error(message, e); + throw new PreBidException(message, e); + } + } + + protected Map filterVendorIdToVendors(VendorListV2 vendorList) { + return vendorList.getVendors().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + protected boolean isValid(VendorListV2 vendorList) { + return vendorList.getVendorListVersion() != null + && vendorList.getLastUpdated() != null + && MapUtils.isNotEmpty(vendorList.getVendors()) + && isValidVendors(vendorList.getVendors().values()); + } + + private static boolean isValidVendors(Collection vendors) { + return vendors.stream() + .allMatch(vendor -> vendor != null + && vendor.getId() != null + && vendor.getPurposes() != null + && vendor.getLegIntPurposes() != null + && vendor.getFlexiblePurposes() != null + && vendor.getSpecialPurposes() != null + && vendor.getFeatures() != null + && vendor.getSpecialFeatures() != null); + } +} + diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorList.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorListV1.java similarity index 87% rename from src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorList.java rename to src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorListV1.java index 4db42cb45f4..270fd6c8b2c 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorList.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorListV1.java @@ -9,7 +9,7 @@ @AllArgsConstructor(staticName = "of") @Value -public class VendorList { +public class VendorListV1 { @JsonProperty("vendorListVersion") Integer vendorListVersion; @@ -17,5 +17,5 @@ public class VendorList { @JsonProperty("lastUpdated") Date lastUpdated; - List vendors; + List vendors; } diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorListV2.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorListV2.java new file mode 100644 index 00000000000..bda509024f0 --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorListV2.java @@ -0,0 +1,21 @@ +package org.prebid.server.privacy.gdpr.vendorlist.proto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Value; + +import java.util.Date; +import java.util.Map; + +@AllArgsConstructor(staticName = "of") +@Value +public class VendorListV2 { + + @JsonProperty("vendorListVersion") + Integer vendorListVersion; + + @JsonProperty("lastUpdated") + Date lastUpdated; + + Map vendors; +} diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/Vendor.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorV1.java similarity index 97% rename from src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/Vendor.java rename to src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorV1.java index c3ac80cff6b..aa960997936 100644 --- a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/Vendor.java +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorV1.java @@ -12,7 +12,7 @@ @AllArgsConstructor(staticName = "of") @Value -public class Vendor { +public class VendorV1 { Integer id; @@ -23,7 +23,6 @@ public class Vendor { Set legIntPurposeIds; public Set combinedPurposes() { - return Stream.of(purposeIds != null ? purposeIds : Collections.emptySet(), legIntPurposeIds != null ? legIntPurposeIds : Collections.emptySet()) .flatMap(Collection::stream) diff --git a/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorV2.java b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorV2.java new file mode 100644 index 00000000000..8c155e2e35e --- /dev/null +++ b/src/main/java/org/prebid/server/privacy/gdpr/vendorlist/proto/VendorV2.java @@ -0,0 +1,49 @@ +package org.prebid.server.privacy.gdpr.vendorlist.proto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Collections; +import java.util.Set; + +@AllArgsConstructor +@NoArgsConstructor +@Builder(toBuilder = true) +@Data +public class VendorV2 { + + Integer id; + + Set purposes; + + @JsonProperty("legIntPurposes") + Set legIntPurposes; + + @JsonProperty("flexiblePurposes") + Set flexiblePurposes; + + @JsonProperty("specialPurposes") + Set specialPurposes; + + @JsonProperty("features") + Set features; + + @JsonProperty("specialFeatures") + Set specialFeatures; + + public static VendorV2 empty(Integer id) { + return VendorV2.builder() + .id(id) + .purposes(Collections.emptySet()) + .legIntPurposes(Collections.emptySet()) + .flexiblePurposes(Collections.emptySet()) + .specialPurposes(Collections.emptySet()) + .features(Collections.emptySet()) + .specialFeatures(Collections.emptySet()) + .build(); + } +} + diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtImpPrebid.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtImpPrebid.java index c44d371ec31..8338e7e52cf 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtImpPrebid.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtImpPrebid.java @@ -38,5 +38,5 @@ public class ExtImpPrebid { /** * Defines the contract for bidrequest.imp[i].ext.prebid.is_rewarded_inventory */ - Boolean isRewardedInventory; + Integer isRewardedInventory; } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtCurrency.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestCurrency.java similarity index 76% rename from src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtCurrency.java rename to src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestCurrency.java index 6b3b0ae44f1..3e31cd7e7d7 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtCurrency.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestCurrency.java @@ -11,9 +11,9 @@ */ @AllArgsConstructor(staticName = "of") @Value -public class ExtCurrency { +public class ExtRequestCurrency { /** - * Defines the contract for bidrequest.ext.prebid.targeting.currency.rates + * Defines the contract for bidrequest.ext.prebid.currency.rates */ Map> rates; } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java index 920d6b4bc0a..a6b48e435a3 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestPrebid.java @@ -25,11 +25,21 @@ public class ExtRequestPrebid { */ Map aliases; + /** + * Defines the contract for bidrequest.ext.prebid.aliasgvlids + */ + Map aliasgvlids; + /** * Defines the contract for bidrequest.ext.prebid.bidadjustmentfactors */ Map bidadjustmentfactors; + /** + * Defines the contract for bidrequest.ext.prebid.currency + */ + ExtRequestCurrency currency; + /** * Defines the contract for bidrequest.ext.prebid.targeting */ @@ -50,11 +60,21 @@ public class ExtRequestPrebid { */ ExtRequestPrebidData data; + /** + * Defines the contract for bidrequest.ext.prebid.events + */ + ObjectNode events; + /** * Defines the contract for bidrequest.ext.prebid.schains */ List schains; + /** + * Defines the contract for bidrequest.ext.prebid.auctiontimestamp + */ + Long auctiontimestamp; + /** * Defines the contract for bidrequest.ext.prebid.bidders */ diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestTargeting.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestTargeting.java index 3493c65330e..5b876d92391 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestTargeting.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/ExtRequestTargeting.java @@ -24,11 +24,6 @@ public class ExtRequestTargeting { */ ExtMediaTypePriceGranularity mediatypepricegranularity; - /** - * Defines the contract for bidrequest.ext.prebid.targeting.currency - */ - ExtCurrency currency; - /** * Defines the contract for bidrequest.ext.prebid.targeting.includewinners */ diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/request/yieldone/ExtImpYieldone.java b/src/main/java/org/prebid/server/proto/openrtb/ext/request/yieldone/ExtImpYieldone.java new file mode 100644 index 00000000000..48ace41d819 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/request/yieldone/ExtImpYieldone.java @@ -0,0 +1,16 @@ +package org.prebid.server.proto.openrtb.ext.request.yieldone; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Value; + +/** + * Defines the contract for bidrequest.imp[i].ext.yieldone + */ +@AllArgsConstructor(staticName = "of") +@Value +public class ExtImpYieldone { + + @JsonProperty("placementId") + String placementId; +} diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java index 46168a89f0c..399a3cff405 100644 --- a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponse.java @@ -37,4 +37,8 @@ public class ExtBidResponse { */ Map usersync; + /** + * Defines the contract for bidresponse.ext.prebid + */ + ExtBidResponsePrebid prebid; } diff --git a/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponsePrebid.java b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponsePrebid.java new file mode 100644 index 00000000000..91a15109297 --- /dev/null +++ b/src/main/java/org/prebid/server/proto/openrtb/ext/response/ExtBidResponsePrebid.java @@ -0,0 +1,18 @@ +package org.prebid.server.proto.openrtb.ext.response; + +import lombok.AllArgsConstructor; +import lombok.Value; + +/** + * Defines the contract for bidresponse.ext + */ +@AllArgsConstructor(staticName = "of") +@Value +public class ExtBidResponsePrebid { + + /** + * Defines the contract for bidresponse.ext.prebid.auctiontimstamp + */ + Long auctiontimestamp; + +} diff --git a/src/main/java/org/prebid/server/proto/request/CookieSyncRequest.java b/src/main/java/org/prebid/server/proto/request/CookieSyncRequest.java index e80706afc8a..ce6f7d43c22 100644 --- a/src/main/java/org/prebid/server/proto/request/CookieSyncRequest.java +++ b/src/main/java/org/prebid/server/proto/request/CookieSyncRequest.java @@ -22,5 +22,7 @@ public class CookieSyncRequest { Boolean coopSync; Integer limit; + + String account; } diff --git a/src/main/java/org/prebid/server/settings/CachingApplicationSettings.java b/src/main/java/org/prebid/server/settings/CachingApplicationSettings.java index 718cc4d493d..b763e18dc03 100644 --- a/src/main/java/org/prebid/server/settings/CachingApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/CachingApplicationSettings.java @@ -1,6 +1,8 @@ package org.prebid.server.settings; import io.vertx.core.Future; +import io.vertx.core.logging.Logger; +import io.vertx.core.logging.LoggerFactory; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.Timeout; import org.prebid.server.settings.model.Account; @@ -21,6 +23,8 @@ */ public class CachingApplicationSettings implements ApplicationSettings { + private static final Logger logger = LoggerFactory.getLogger(CachingApplicationSettings.class); + private final ApplicationSettings delegate; private final Map accountCache; @@ -172,4 +176,9 @@ private static Map getFromCacheOrAddMissedIds(Set ids, M } return storedIdToJson; } + + public void invalidateAccountCache(String accountId) { + accountCache.remove(accountId); + logger.debug("Account with id {0} was invalidated", accountId); + } } diff --git a/src/main/java/org/prebid/server/settings/FileApplicationSettings.java b/src/main/java/org/prebid/server/settings/FileApplicationSettings.java index add01fb4f9b..4ba325e6c42 100644 --- a/src/main/java/org/prebid/server/settings/FileApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/FileApplicationSettings.java @@ -58,7 +58,7 @@ public FileApplicationSettings(FileSystem fileSystem, String settingsFileName, S configs = toMap(settingsFile.getConfigs(), AdUnitConfig::getId, - config -> ObjectUtils.firstNonNull(config.getConfig(), StringUtils.EMPTY)); + config -> ObjectUtils.defaultIfNull(config.getConfig(), StringUtils.EMPTY)); this.storedIdToRequest = readStoredData(fileSystem, Objects.requireNonNull(storedRequestsDir)); this.storedIdToImp = readStoredData(fileSystem, Objects.requireNonNull(storedImpsDir)); @@ -67,12 +67,12 @@ public FileApplicationSettings(FileSystem fileSystem, String settingsFileName, S @Override public Future getAccountById(String accountId, Timeout timeout) { - return mapValueToFuture(accounts, accountId); + return mapValueToFuture(accounts, accountId, "Account"); } @Override public Future getAdUnitConfigById(String adUnitConfigId, Timeout timeout) { - return mapValueToFuture(configs, adUnitConfigId); + return mapValueToFuture(configs, adUnitConfigId, "AdUnitConfig"); } /** @@ -145,18 +145,18 @@ private static Map readStoredData(FileSystem fileSystem, String filename -> fileSystem.readFileBlocking(filename).toString())); } - private static Future mapValueToFuture(Map map, String key) { - final T value = map.get(key); + private static Future mapValueToFuture(Map map, String id, String errorPrefix) { + final T value = map.get(id); return value != null ? Future.succeededFuture(value) - : Future.failedFuture(new PreBidException("Not found")); + : Future.failedFuture(new PreBidException(String.format("%s not found: %s", errorPrefix, id))); } /** * Returns corresponding stored id with json. */ private static Map existingStoredIdToJson(Set requestedIds, - Map storedIdToJson) { + Map storedIdToJson) { return requestedIds.stream() .filter(storedIdToJson::containsKey) .collect(Collectors.toMap(Function.identity(), storedIdToJson::get)); diff --git a/src/main/java/org/prebid/server/settings/JdbcApplicationSettings.java b/src/main/java/org/prebid/server/settings/JdbcApplicationSettings.java index 47440c924e6..121676c87ae 100644 --- a/src/main/java/org/prebid/server/settings/JdbcApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/JdbcApplicationSettings.java @@ -7,9 +7,12 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.Timeout; +import org.prebid.server.json.DecodeException; +import org.prebid.server.json.JacksonMapper; import org.prebid.server.settings.mapper.JdbcStoredDataResultMapper; import org.prebid.server.settings.mapper.JdbcStoredResponseResultMapper; import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountGdprConfig; import org.prebid.server.settings.model.StoredDataResult; import org.prebid.server.settings.model.StoredResponseDataResult; import org.prebid.server.vertx.jdbc.JdbcClient; @@ -38,6 +41,7 @@ public class JdbcApplicationSettings implements ApplicationSettings { private static final String RESPONSE_ID_PLACEHOLDER = "%RESPONSE_ID_LIST%"; private final JdbcClient jdbcClient; + private final JacksonMapper mapper; /** * Query to select stored requests and imps by ids, for example: @@ -73,9 +77,14 @@ public class JdbcApplicationSettings implements ApplicationSettings { */ private final String selectResponseQuery; - public JdbcApplicationSettings(JdbcClient jdbcClient, String selectQuery, String selectAmpQuery, + public JdbcApplicationSettings(JdbcClient jdbcClient, + JacksonMapper mapper, + String selectQuery, + String selectAmpQuery, String selectResponseQuery) { + this.jdbcClient = Objects.requireNonNull(jdbcClient); + this.mapper = Objects.requireNonNull(mapper); this.selectQuery = Objects.requireNonNull(selectQuery); this.selectAmpQuery = Objects.requireNonNull(selectAmpQuery); this.selectResponseQuery = Objects.requireNonNull(selectResponseQuery); @@ -88,7 +97,7 @@ public JdbcApplicationSettings(JdbcClient jdbcClient, String selectQuery, String @Override public Future getAccountById(String accountId, Timeout timeout) { return jdbcClient.executeQuery("SELECT uuid, price_granularity, banner_cache_ttl, video_cache_ttl," - + " events_enabled, enforce_gdpr, analytics_sampling_factor FROM accounts_account" + + " events_enabled, tcf_config, analytics_sampling_factor FROM accounts_account" + " where uuid = ? LIMIT 1", Collections.singletonList(accountId), result -> mapToModelOrError(result, row -> Account.builder() @@ -97,11 +106,11 @@ public Future getAccountById(String accountId, Timeout timeout) { .bannerCacheTtl(row.getInteger(2)) .videoCacheTtl(row.getInteger(3)) .eventsEnabled(row.getBoolean(4)) - .enforceGdpr(row.getBoolean(5)) + .gdpr(toAccountTcfConfig(row.getString(5))) .analyticsSamplingFactor(row.getInteger(6)) .build()), timeout) - .compose(JdbcApplicationSettings::failedIfNull); + .compose(result -> failedIfNull(result, accountId, "Account")); } /** @@ -114,7 +123,7 @@ public Future getAdUnitConfigById(String adUnitConfigId, Timeout timeout Collections.singletonList(adUnitConfigId), result -> mapToModelOrError(result, row -> row.getString(0)), timeout) - .compose(JdbcApplicationSettings::failedIfNull); + .compose(result -> failedIfNull(result, adUnitConfigId, "AdUnitConfig")); } /** @@ -133,10 +142,18 @@ private T mapToModelOrError(ResultSet result, Function mapper) * Returns succeeded {@link Future} if given value is not equal to NULL, * otherwise failed {@link Future} with {@link PreBidException}. */ - private static Future failedIfNull(T value) { + private static Future failedIfNull(T value, String id, String errorPrefix) { return value != null ? Future.succeededFuture(value) - : Future.failedFuture(new PreBidException("Not found")); + : Future.failedFuture(new PreBidException(String.format("%s not found: %s", errorPrefix, id))); + } + + private AccountGdprConfig toAccountTcfConfig(String tcfConfig) { + try { + return tcfConfig != null ? mapper.decodeValue(tcfConfig, AccountGdprConfig.class) : null; + } catch (DecodeException e) { + throw new PreBidException(e.getMessage()); + } } /** diff --git a/src/main/java/org/prebid/server/settings/model/Account.java b/src/main/java/org/prebid/server/settings/model/Account.java index 13a681252b2..102fb80c68f 100644 --- a/src/main/java/org/prebid/server/settings/model/Account.java +++ b/src/main/java/org/prebid/server/settings/model/Account.java @@ -17,8 +17,13 @@ public class Account { Boolean eventsEnabled; - Boolean enforceGdpr; + AccountGdprConfig gdpr; Integer analyticsSamplingFactor; -} + public static Account empty(String id) { + return Account.builder() + .id(id) + .build(); + } +} diff --git a/src/main/java/org/prebid/server/settings/model/AccountGdprConfig.java b/src/main/java/org/prebid/server/settings/model/AccountGdprConfig.java new file mode 100644 index 00000000000..2cf94cabd34 --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/AccountGdprConfig.java @@ -0,0 +1,24 @@ +package org.prebid.server.settings.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Data +public class AccountGdprConfig { + + Boolean enabled; + + Purposes purposes; + + @JsonProperty("special-features") + SpecialFeatures specialFeatures; + + @JsonProperty("purpose-one-treatment-interpretation") + PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation; +} diff --git a/src/main/java/org/prebid/server/settings/model/EnforcePurpose.java b/src/main/java/org/prebid/server/settings/model/EnforcePurpose.java new file mode 100644 index 00000000000..f4a97cbf386 --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/EnforcePurpose.java @@ -0,0 +1,12 @@ +package org.prebid.server.settings.model; + +import com.fasterxml.jackson.annotation.JsonCreator; + +public enum EnforcePurpose { + no, basic, full; + + @JsonCreator + public static EnforcePurpose forValue(String value) { + return EnforcePurpose.valueOf(value); + } +} diff --git a/src/main/java/org/prebid/server/settings/model/GdprConfig.java b/src/main/java/org/prebid/server/settings/model/GdprConfig.java new file mode 100644 index 00000000000..945d10bd88b --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/GdprConfig.java @@ -0,0 +1,31 @@ +package org.prebid.server.settings.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Data +public class GdprConfig { + + @JsonProperty("host-vendor-id") + String hostVendorId; + + Boolean enabled; + + @JsonProperty("default-value") + String defaultValue; + + Purposes purposes; + + @JsonProperty("special-features") + SpecialFeatures specialFeatures; + + @JsonProperty("purpose-one-treatment-interpretation") + PurposeOneTreatmentInterpretation purposeOneTreatmentInterpretation; +} + diff --git a/src/main/java/org/prebid/server/settings/model/Purpose.java b/src/main/java/org/prebid/server/settings/model/Purpose.java new file mode 100644 index 00000000000..4c0ea493dab --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/Purpose.java @@ -0,0 +1,23 @@ +package org.prebid.server.settings.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor(staticName = "of") +public class Purpose { + + @JsonProperty("enforce-purpose") + EnforcePurpose enforcePurpose; + + @JsonProperty("enforce-vendors") + Boolean enforceVendors; + + @JsonProperty("vendor-exceptions") + List vendorExceptions; +} diff --git a/src/main/java/org/prebid/server/settings/model/PurposeOneTreatmentInterpretation.java b/src/main/java/org/prebid/server/settings/model/PurposeOneTreatmentInterpretation.java new file mode 100644 index 00000000000..e3a6495d3b5 --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/PurposeOneTreatmentInterpretation.java @@ -0,0 +1,12 @@ +package org.prebid.server.settings.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum PurposeOneTreatmentInterpretation { + + ignore, + @JsonProperty("no-access-allowed") + noAccessAllowed, + @JsonProperty("access-allowed") + accessAllowed +} diff --git a/src/main/java/org/prebid/server/settings/model/Purposes.java b/src/main/java/org/prebid/server/settings/model/Purposes.java new file mode 100644 index 00000000000..16156e6cffb --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/Purposes.java @@ -0,0 +1,34 @@ +package org.prebid.server.settings.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Purposes { + + Purpose p1; + + Purpose p2; + + Purpose p3; + + Purpose p4; + + Purpose p5; + + Purpose p6; + + Purpose p7; + + Purpose p8; + + Purpose p9; + + Purpose p10; +} + diff --git a/src/main/java/org/prebid/server/settings/model/SpecialFeature.java b/src/main/java/org/prebid/server/settings/model/SpecialFeature.java new file mode 100644 index 00000000000..f17d61d7552 --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/SpecialFeature.java @@ -0,0 +1,21 @@ +package org.prebid.server.settings.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor(staticName = "of") +public class SpecialFeature { + + @JsonProperty(defaultValue = "true") + Boolean enforce; + + @JsonProperty("vendor-exceptions") + List vendorExceptions; +} + diff --git a/src/main/java/org/prebid/server/settings/model/SpecialFeatures.java b/src/main/java/org/prebid/server/settings/model/SpecialFeatures.java new file mode 100644 index 00000000000..f7974e444a7 --- /dev/null +++ b/src/main/java/org/prebid/server/settings/model/SpecialFeatures.java @@ -0,0 +1,18 @@ +package org.prebid.server.settings.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class SpecialFeatures { + + SpecialFeature sf1; + + SpecialFeature sf2; +} + diff --git a/src/main/java/org/prebid/server/spring/config/InitializationConfiguration.java b/src/main/java/org/prebid/server/spring/config/InitializationConfiguration.java index 7ea17e601ff..a0b0498e16b 100644 --- a/src/main/java/org/prebid/server/spring/config/InitializationConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/InitializationConfiguration.java @@ -35,9 +35,9 @@ public class InitializationConfiguration { @EventListener(ContextRefreshedEvent.class) public void initializeServices() { - contextRunner.runOnServiceContext(future -> { + contextRunner.runOnServiceContext(promise -> { initializables.forEach(Initializable::initialize); - future.complete(); + promise.complete(); }); } } diff --git a/src/main/java/org/prebid/server/spring/config/MetricsConfiguration.java b/src/main/java/org/prebid/server/spring/config/MetricsConfiguration.java index a1cd18655a1..08524749ebc 100644 --- a/src/main/java/org/prebid/server/spring/config/MetricsConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/MetricsConfiguration.java @@ -231,8 +231,8 @@ public void startPrometheusServer() { CollectorRegistry.defaultRegistry.register(new DropwizardExports(metricRegistry)); - contextRunner.runOnServiceContext(future -> - vertx.createHttpServer().requestHandler(router).listen(prometheusPort, future)); + contextRunner.runOnServiceContext(promise -> + vertx.createHttpServer().requestHandler(router).listen(prometheusPort, promise)); logger.info("Successfully started Prometheus Server"); } diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index 8278cc667b2..550981d9d42 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -6,7 +6,6 @@ import io.vertx.core.Vertx; import io.vertx.core.file.FileSystem; import io.vertx.core.http.HttpClientOptions; -import io.vertx.core.logging.LoggerFactory; import io.vertx.core.net.JksOptions; import org.prebid.server.auction.AmpRequestFactory; import org.prebid.server.auction.AmpResponsePostProcessor; @@ -34,16 +33,24 @@ import org.prebid.server.cookie.UidsCookieService; import org.prebid.server.currency.CurrencyConversionService; import org.prebid.server.events.EventsService; -import org.prebid.server.execution.LogModifier; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.geolocation.GeoLocationService; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.manager.AdminManager; import org.prebid.server.metric.Metrics; import org.prebid.server.optout.GoogleRecaptchaVerifier; import org.prebid.server.privacy.PrivacyExtractor; import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.vendorlist.VendorListService; +import org.prebid.server.privacy.gdpr.Tcf2Service; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.vendorlist.VendorListServiceV1; +import org.prebid.server.privacy.gdpr.vendorlist.VendorListServiceV2; import org.prebid.server.settings.ApplicationSettings; +import org.prebid.server.settings.model.GdprConfig; +import org.prebid.server.settings.model.Purpose; +import org.prebid.server.settings.model.Purposes; +import org.prebid.server.settings.model.SpecialFeature; +import org.prebid.server.settings.model.SpecialFeatures; import org.prebid.server.spring.config.model.CircuitBreakerProperties; import org.prebid.server.spring.config.model.ExternalConversionProperties; import org.prebid.server.spring.config.model.HttpClientProperties; @@ -68,8 +75,10 @@ import java.io.IOException; import java.time.Clock; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Properties; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -167,7 +176,8 @@ AuctionRequestFactory auctionRequestFactory( TimeoutResolver timeoutResolver, TimeoutFactory timeoutFactory, ApplicationSettings applicationSettings, - JacksonMapper mapper) { + JacksonMapper mapper, + AdminManager adminManager) { final List blacklistedApps = splitCommaSeparatedString(blacklistedAppsString); final List blacklistedAccounts = splitCommaSeparatedString(blacklistedAccountsString); @@ -349,37 +359,90 @@ UidsCookieService uidsCookieService( } @Bean - VendorListService vendorListService( - @Value("${gdpr.vendorlist.filesystem-cache-dir}") String cacheDir, - @Value("${gdpr.vendorlist.http-endpoint-template}") String endpointTemplate, - @Value("${gdpr.vendorlist.http-default-timeout-ms}") int defaultTimeoutMs, + VendorListServiceV1 vendorListServiceV1( + @Value("${gdpr.vendorlist.v1.cache-dir}") String cacheDir, + @Value("${gdpr.vendorlist.v1.http-endpoint-template}") String endpointTemplate, + @Value("${gdpr.vendorlist.v1.http-default-timeout-ms}") int defaultTimeoutMs, @Value("${gdpr.host-vendor-id:#{null}}") Integer hostVendorId, BidderCatalog bidderCatalog, FileSystem fileSystem, HttpClient httpClient, JacksonMapper mapper) { - return VendorListService.create( - cacheDir, - endpointTemplate, - defaultTimeoutMs, - hostVendorId, - bidderCatalog, - fileSystem, - httpClient, - mapper); + return new VendorListServiceV1(cacheDir, endpointTemplate, defaultTimeoutMs, hostVendorId, bidderCatalog, + fileSystem, httpClient, mapper); + } + + @Bean + VendorListServiceV2 vendorListServiceV2( + @Value("${gdpr.vendorlist.v2.cache-dir}") String cacheDir, + @Value("${gdpr.vendorlist.v2.http-endpoint-template}") String endpointTemplate, + @Value("${gdpr.vendorlist.v2.http-default-timeout-ms}") int defaultTimeoutMs, + @Value("${gdpr.host-vendor-id:#{null}}") Integer hostVendorId, + BidderCatalog bidderCatalog, + FileSystem fileSystem, + HttpClient httpClient, + JacksonMapper mapper) { + + return new VendorListServiceV2(cacheDir, endpointTemplate, defaultTimeoutMs, hostVendorId, bidderCatalog, + fileSystem, httpClient, mapper); + } + + @Bean + GdprService gdprService(VendorListServiceV1 vendorListServiceV1) { + return new GdprService(vendorListServiceV1); + } + + @Bean + Tcf2Service tcf2Service(GdprConfig gdprConfig, + VendorListServiceV2 vendorListServiceV2, + BidderCatalog bidderCatalog) { + + return new Tcf2Service(gdprConfig, vendorListServiceV2, bidderCatalog); } @Bean - GdprService gdprService( + TcfDefinerService tcfDefinerService( + GdprConfig gdprConfig, @Value("${gdpr.eea-countries}") String eeaCountriesAsString, - @Value("${gdpr.default-value}") String defaultValue, + GdprService gdprService, + Tcf2Service tcf2Service, @Autowired(required = false) GeoLocationService geoLocationService, - Metrics metrics, - VendorListService vendorListService) { + BidderCatalog bidderCatalog, + Metrics metrics) { - final List eeaCountries = Arrays.asList(eeaCountriesAsString.trim().split(",")); - return new GdprService(eeaCountries, defaultValue, geoLocationService, metrics, vendorListService); + final Set eeaCountries = new HashSet<>(Arrays.asList(eeaCountriesAsString.trim().split(","))); + + return new TcfDefinerService( + gdprConfig, eeaCountries, gdprService, tcf2Service, geoLocationService, bidderCatalog, metrics); + } + + @Bean + @ConfigurationProperties(prefix = "gdpr") + GdprConfig gdprConfig() { + return new GdprConfig(); + } + + @Bean + @ConfigurationProperties(prefix = "gdpr.purposes") + Purposes purposes() { + return new Purposes(); + } + + @Bean + Purpose purpose() { + return new Purpose(); + } + + @Bean + @ConfigurationProperties(prefix = "gdpr.special-features") + SpecialFeatures specialFeatures() { + return new SpecialFeatures(); + } + + @Bean + SpecialFeature specialFeature() { + return new SpecialFeature(); } @Bean @@ -464,13 +527,14 @@ StoredResponseProcessor storedResponseProcessor(ApplicationSettings applicationS @Bean PrivacyEnforcementService privacyEnforcementService( - GdprService gdprService, BidderCatalog bidderCatalog, + TcfDefinerService tcfDefinerService, Metrics metrics, @Value("${geolocation.enabled}") boolean useGeoLocation, @Value("${ccpa.enforce}") boolean ccpaEnforce, JacksonMapper mapper) { - return new PrivacyEnforcementService(gdprService, bidderCatalog, metrics, mapper, useGeoLocation, ccpaEnforce); + return new PrivacyEnforcementService( + bidderCatalog, tcfDefinerService, metrics, mapper, useGeoLocation, ccpaEnforce); } @Bean @@ -528,11 +592,6 @@ TimeoutFactory timeoutFactory(Clock clock) { return new TimeoutFactory(clock); } - @Bean - LogModifier logModifier() { - return new LogModifier(LoggerFactory.getLogger(ServiceConfiguration.class)); - } - @Bean BidResponsePostProcessor bidResponsePostProcessor() { return BidResponsePostProcessor.noOp(); @@ -562,4 +621,9 @@ ExternalConversionProperties externalConversionProperties( return new ExternalConversionProperties(currencyServerUrl, defaultTimeout, refreshPeriod, vertx, httpClient, mapper); } + + @Bean + AdminManager adminManager() { + return new AdminManager(); + } } diff --git a/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java b/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java index dd413e9d12a..d4c80580f46 100644 --- a/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/SettingsConfiguration.java @@ -75,10 +75,11 @@ JdbcApplicationSettings jdbcApplicationSettings( @Value("${settings.database.stored-requests-query}") String storedRequestsQuery, @Value("${settings.database.amp-stored-requests-query}") String ampStoredRequestsQuery, @Value("${settings.database.stored-responses-query}") String storedResponseQuery, - JdbcClient jdbcClient) { + JdbcClient jdbcClient, + JacksonMapper jacksonMapper) { - return new JdbcApplicationSettings(jdbcClient, storedRequestsQuery, ampStoredRequestsQuery, - storedResponseQuery); + return new JdbcApplicationSettings( + jdbcClient, jacksonMapper, storedRequestsQuery, ampStoredRequestsQuery, storedResponseQuery); } @Bean @@ -113,8 +114,7 @@ private static BasicJdbcClient createBasicJdbcClient( Vertx vertx, JDBCClient vertxJdbcClient, Metrics metrics, Clock clock, ContextRunner contextRunner) { final BasicJdbcClient basicJdbcClient = new BasicJdbcClient(vertx, vertxJdbcClient, metrics, clock); - contextRunner.runOnServiceContext( - future -> basicJdbcClient.initialize().compose(ignored -> future.complete(), future)); + contextRunner.runOnServiceContext(promise -> basicJdbcClient.initialize().setHandler(promise)); return basicJdbcClient; } @@ -321,7 +321,7 @@ static class ApplicationSettingsConfiguration { ApplicationSettings applicationSettings( @Autowired(required = false) CachingApplicationSettings cachingApplicationSettings, @Autowired(required = false) CompositeApplicationSettings compositeApplicationSettings) { - return ObjectUtils.firstNonNull(cachingApplicationSettings, compositeApplicationSettings); + return ObjectUtils.defaultIfNull(cachingApplicationSettings, compositeApplicationSettings); } } diff --git a/src/main/java/org/prebid/server/spring/config/WebConfiguration.java b/src/main/java/org/prebid/server/spring/config/WebConfiguration.java index 596eff981a0..f3c2d605585 100644 --- a/src/main/java/org/prebid/server/spring/config/WebConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/WebConfiguration.java @@ -9,7 +9,6 @@ import io.vertx.core.net.JksOptions; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; -import io.vertx.ext.web.handler.CookieHandler; import io.vertx.ext.web.handler.CorsHandler; import io.vertx.ext.web.handler.StaticHandler; import lombok.Data; @@ -28,8 +27,8 @@ import org.prebid.server.cache.CacheService; import org.prebid.server.cookie.UidsCookieService; import org.prebid.server.currency.CurrencyConversionService; -import org.prebid.server.execution.LogModifier; import org.prebid.server.execution.TimeoutFactory; +import org.prebid.server.handler.AccountCacheInvalidationHandler; import org.prebid.server.handler.AdminHandler; import org.prebid.server.handler.AuctionHandler; import org.prebid.server.handler.BidderParamHandler; @@ -52,11 +51,13 @@ import org.prebid.server.health.HealthChecker; import org.prebid.server.health.PeriodicHealthChecker; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.manager.AdminManager; import org.prebid.server.metric.Metrics; import org.prebid.server.optout.GoogleRecaptchaVerifier; import org.prebid.server.privacy.PrivacyExtractor; -import org.prebid.server.privacy.gdpr.GdprService; +import org.prebid.server.privacy.gdpr.TcfDefinerService; import org.prebid.server.settings.ApplicationSettings; +import org.prebid.server.settings.CachingApplicationSettings; import org.prebid.server.settings.SettingsCache; import org.prebid.server.util.HttpUtil; import org.prebid.server.validation.BidderParamValidator; @@ -109,11 +110,11 @@ public void startHttpServer() { logger.info("Starting {0} instances of Http Server to serve requests on port {1,number,#}", httpServerNum, httpPort); - contextRunner.runOnNewContext(httpServerNum, future -> + contextRunner.runOnNewContext(httpServerNum, promise -> vertx.createHttpServer(httpServerOptions) .exceptionHandler(exceptionHandler) .requestHandler(router) - .listen(httpPort, future)); + .listen(httpPort, promise)); logger.info("Successfully started {0} instances of Http Server", httpServerNum); } @@ -148,8 +149,7 @@ ExceptionHandler exceptionHandler(Metrics metrics) { } @Bean - Router router(CookieHandler cookieHandler, - BodyHandler bodyHandler, + Router router(BodyHandler bodyHandler, NoCacheHandler noCacheHandler, CorsHandler corsHandler, AuctionHandler auctionHandler, @@ -169,7 +169,6 @@ Router router(CookieHandler cookieHandler, StaticHandler staticHandler) { final Router router = Router.router(vertx); - router.route().handler(cookieHandler); router.route().handler(bodyHandler); router.route().handler(noCacheHandler); router.route().handler(corsHandler); @@ -194,11 +193,6 @@ Router router(CookieHandler cookieHandler, return router; } - @Bean - CookieHandler cookieHandler() { - return CookieHandler.create(); - } - @Bean NoCacheHandler noCacheHandler() { return NoCacheHandler.create(); @@ -226,7 +220,7 @@ AuctionHandler auctionHandler( Metrics metrics, HttpAdapterConnector httpAdapterConnector, Clock clock, - GdprService gdprService, + TcfDefinerService tcfDefinerService, PrivacyExtractor privacyExtractor, JacksonMapper mapper, @Value("${gdpr.host-vendor-id:#{null}}") Integer hostVendorId, @@ -240,7 +234,7 @@ AuctionHandler auctionHandler( metrics, httpAdapterConnector, clock, - gdprService, + tcfDefinerService, privacyExtractor, mapper, hostVendorId, @@ -254,11 +248,11 @@ org.prebid.server.handler.openrtb2.AuctionHandler openrtbAuctionHandler( CompositeAnalyticsReporter analyticsReporter, Metrics metrics, Clock clock, - LogModifier logModifier, + AdminManager adminManager, JacksonMapper mapper) { return new org.prebid.server.handler.openrtb2.AuctionHandler( - auctionRequestFactory, exchangeService, analyticsReporter, metrics, clock, logModifier, mapper); + auctionRequestFactory, exchangeService, analyticsReporter, metrics, clock, adminManager, mapper); } @Bean @@ -271,7 +265,7 @@ AmpHandler openrtbAmpHandler( BidderCatalog bidderCatalog, AmpProperties ampProperties, AmpResponsePostProcessor ampResponsePostProcessor, - LogModifier logModifier, + AdminManager adminManager, JacksonMapper mapper) { return new AmpHandler( @@ -283,7 +277,7 @@ AmpHandler openrtbAmpHandler( bidderCatalog, ampProperties.getCustomTargetingSet(), ampResponsePostProcessor, - logModifier, + adminManager, mapper); } @@ -315,9 +309,10 @@ CookieSyncHandler cookieSyncHandler( @Value("${external-url}") String externalUrl, @Value("${cookie-sync.default-timeout-ms}") int defaultTimeoutMs, UidsCookieService uidsCookieService, + ApplicationSettings applicationSettings, BidderCatalog bidderCatalog, CoopSyncPriorities coopSyncPriorities, - GdprService gdprService, + TcfDefinerService tcfDefinerService, PrivacyEnforcementService privacyEnforcementService, @Value("${gdpr.host-vendor-id:#{null}}") Integer hostVendorId, @Value("${geolocation.enabled}") boolean useGeoLocation, @@ -326,25 +321,26 @@ CookieSyncHandler cookieSyncHandler( Metrics metrics, TimeoutFactory timeoutFactory, JacksonMapper mapper) { - return new CookieSyncHandler(externalUrl, defaultTimeoutMs, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, hostVendorId, useGeoLocation, defaultCoopSync, - coopSyncPriorities.getPri(), analyticsReporter, metrics, timeoutFactory, mapper); + return new CookieSyncHandler(externalUrl, defaultTimeoutMs, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, hostVendorId, useGeoLocation, + defaultCoopSync, coopSyncPriorities.getPri(), analyticsReporter, metrics, timeoutFactory, mapper); } @Bean SetuidHandler setuidHandler( @Value("${setuid.default-timeout-ms}") int defaultTimeoutMs, UidsCookieService uidsCookieService, + ApplicationSettings applicationSettings, BidderCatalog bidderCatalog, - GdprService gdprService, + TcfDefinerService tcfDefinerService, @Value("${gdpr.host-vendor-id:#{null}}") Integer hostVendorId, @Value("${geolocation.enabled}") boolean useGeoLocation, CompositeAnalyticsReporter analyticsReporter, Metrics metrics, TimeoutFactory timeoutFactory) { - return new SetuidHandler(defaultTimeoutMs, uidsCookieService, bidderCatalog, gdprService, hostVendorId, - useGeoLocation, analyticsReporter, metrics, timeoutFactory); + return new SetuidHandler(defaultTimeoutMs, uidsCookieService, applicationSettings, bidderCatalog, + tcfDefinerService, hostVendorId, useGeoLocation, analyticsReporter, metrics, timeoutFactory); } @Bean @@ -355,6 +351,7 @@ GetuidsHandler getuidsHandler(UidsCookieService uidsCookieService, JacksonMapper @Bean VtrackHandler vtrackHandler( @Value("${vtrack.default-timeout-ms}") int defaultTimeoutMs, + @Value("${vtrack.allow-unkonwn-bidder}") boolean allowUnknownBidder, ApplicationSettings applicationSettings, BidderCatalog bidderCatalog, CacheService cacheService, @@ -362,7 +359,8 @@ VtrackHandler vtrackHandler( JacksonMapper mapper) { return new VtrackHandler( - defaultTimeoutMs, applicationSettings, bidderCatalog, cacheService, timeoutFactory, mapper); + defaultTimeoutMs, allowUnknownBidder, applicationSettings, bidderCatalog, cacheService, timeoutFactory, + mapper); } @Bean @@ -445,12 +443,15 @@ static class AdminServerConfiguration { @Autowired private VersionHandler versionHandler; - @Autowired(required = false) + @Autowired private AdminHandler adminHandler; @Autowired private CurrencyRatesHandler currencyRatesHandler; + @Autowired(required = false) + private AccountCacheInvalidationHandler accountCacheInvalidationHandler; + @Autowired(required = false) private SettingsCacheNotificationHandler cacheNotificationHandler; @@ -461,10 +462,11 @@ static class AdminServerConfiguration { private int adminPort; @Bean - @ConditionalOnProperty(prefix = "settings.in-memory-cache", name = "notification-endpoints-enabled", + @ConditionalOnProperty(prefix = "settings.in-memory-cache", name = "account-invalidation-enabled", havingValue = "true") - SettingsCacheNotificationHandler cacheNotificationHandler(SettingsCache settingsCache, JacksonMapper mapper) { - return new SettingsCacheNotificationHandler(settingsCache, mapper); + AccountCacheInvalidationHandler accountCacheInvalidationHandler( + CachingApplicationSettings cachingApplicationSettings) { + return new AccountCacheInvalidationHandler(cachingApplicationSettings); } @Bean @@ -476,15 +478,21 @@ SettingsCacheNotificationHandler ampCacheNotificationHandler( return new SettingsCacheNotificationHandler(ampSettingsCache, mapper); } + @Bean + @ConditionalOnProperty(prefix = "settings.in-memory-cache", name = "notification-endpoints-enabled", + havingValue = "true") + SettingsCacheNotificationHandler cacheNotificationHandler(SettingsCache settingsCache, JacksonMapper mapper) { + return new SettingsCacheNotificationHandler(settingsCache, mapper); + } + @Bean VersionHandler versionHandler(JacksonMapper mapper) { return VersionHandler.create("git-revision.json", mapper); } @Bean - @ConditionalOnProperty(prefix = "logger-level-modifier", name = "enabled", havingValue = "true") - AdminHandler adminHandler(LogModifier logModifier) { - return new AdminHandler(logModifier); + AdminHandler adminHandler(AdminManager adminManager) { + return new AdminHandler(adminManager); } @Bean @@ -514,9 +522,12 @@ public void startAdminServer() { if (ampCacheNotificationHandler != null) { router.route("/storedrequests/amp").handler(ampCacheNotificationHandler); } + if (accountCacheInvalidationHandler != null) { + router.route("/cache/invalidate").handler(accountCacheInvalidationHandler); + } - contextRunner.runOnServiceContext(future -> - vertx.createHttpServer().requestHandler(router).listen(adminPort, future)); + contextRunner.runOnServiceContext(promise -> + vertx.createHttpServer().requestHandler(router).listen(adminPort, promise)); logger.info("Successfully started Admin Server"); } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/BrightrollConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/BrightrollConfiguration.java index e90fb4efe1c..edf99957543 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/BrightrollConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/BrightrollConfiguration.java @@ -1,7 +1,12 @@ package org.prebid.server.spring.config.bidder; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import org.prebid.server.bidder.BidderDeps; import org.prebid.server.bidder.brightroll.BrightrollBidder; +import org.prebid.server.bidder.brightroll.model.PublisherOverride; 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,8 +20,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; +import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotBlank; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Configuration @PropertySource(value = "classpath:/bidder-config/brightroll.yaml", factory = YamlPropertySourceFactory.class) @@ -33,21 +43,63 @@ public class BrightrollConfiguration { @Autowired @Qualifier("brightrollConfigurationProperties") - private BidderConfigurationProperties configProperties; + private BrightrollConfigurationProperties configProperties; @Bean("brightrollConfigurationProperties") @ConfigurationProperties("adapters.brightroll") - BidderConfigurationProperties configurationProperties() { - return new BidderConfigurationProperties(); + BrightrollConfigurationProperties configurationProperties() { + return new BrightrollConfigurationProperties(); } @Bean BidderDeps brightrollBidderDeps() { + final Map publisherIdToOverride = configProperties.getAccounts() == null + ? Collections.emptyMap() + : configProperties.getAccounts().stream() + .collect(Collectors.toMap(BidderAccount::getId, this::toPublisherOverride)); return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(configProperties) .bidderInfo(BidderInfoCreator.create(configProperties)) .usersyncerCreator(UsersyncerCreator.create(configProperties.getUsersync(), externalUrl)) - .bidderCreator(() -> new BrightrollBidder(configProperties.getEndpoint(), mapper)) + .bidderCreator(() -> new BrightrollBidder(configProperties.getEndpoint(), mapper, + publisherIdToOverride)) .assemble(); } + + private PublisherOverride toPublisherOverride(BidderAccount bidderAccount) { + return PublisherOverride.of(bidderAccount.getBadv(), bidderAccount.getBcat(), bidderAccount.getImpBattr()); + } + + @Validated + @Data + @EqualsAndHashCode(callSuper = true) + @NoArgsConstructor + @AllArgsConstructor + public static class BrightrollConfigurationProperties extends BidderConfigurationProperties { + + private List accounts; + } + + @Data + @NoArgsConstructor + @AllArgsConstructor + public static class BidderAccount { + + private String id; + + /** + * Blocked advertisers. + */ + private List badv; + + /** + * Blocked advertisers. + */ + private List bcat; + + /** + * Blocked IAB categories. + */ + private List impBattr; + } } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/YieldoneConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/YieldoneConfiguration.java new file mode 100644 index 00000000000..d54ae67461d --- /dev/null +++ b/src/main/java/org/prebid/server/spring/config/bidder/YieldoneConfiguration.java @@ -0,0 +1,53 @@ +package org.prebid.server.spring.config.bidder; + +import org.prebid.server.bidder.BidderDeps; +import org.prebid.server.bidder.yieldone.YieldoneBidder; +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.BidderInfoCreator; +import org.prebid.server.spring.config.bidder.util.UsersyncerCreator; +import org.prebid.server.spring.env.YamlPropertySourceFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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; + +import javax.validation.constraints.NotBlank; + +@Configuration +@PropertySource(value = "classpath:/bidder-config/yieldone.yaml", factory = YamlPropertySourceFactory.class) +public class YieldoneConfiguration { + + private static final String BIDDER_NAME = "yieldone"; + + @Autowired + private JacksonMapper mapper; + + @Value("${external-url}") + @NotBlank + private String externalUrl; + + @Autowired + @Qualifier("yieldoneConfigurationProperties") + private BidderConfigurationProperties configProperties; + + @Bean("yieldoneConfigurationProperties") + @ConfigurationProperties("adapters.yieldone") + BidderConfigurationProperties configurationProperties() { + return new BidderConfigurationProperties(); + } + + @Bean + BidderDeps yieldoneBidderDeps() { + return BidderDepsAssembler.forBidder(BIDDER_NAME) + .withConfig(configProperties) + .bidderInfo(BidderInfoCreator.create(configProperties)) + .usersyncerCreator(UsersyncerCreator.create(configProperties.getUsersync(), externalUrl)) + .bidderCreator(() -> new YieldoneBidder(configProperties.getEndpoint(), mapper)) + .assemble(); + } +} diff --git a/src/main/java/org/prebid/server/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index 57c7d21937d..3cf372b089f 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -3,10 +3,10 @@ import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.MultiMap; +import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.Cookie; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.StringUtils; @@ -149,8 +149,8 @@ public static String getDomainFromUrl(String url) { } public static Map cookiesAsMap(RoutingContext context) { - return context.cookies().stream() - .collect(Collectors.toMap(Cookie::getName, Cookie::getValue)); + return context.cookieMap().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); } public static String toSetCookieHeaderValue(Cookie cookie) { diff --git a/src/main/java/org/prebid/server/validation/RequestValidator.java b/src/main/java/org/prebid/server/validation/RequestValidator.java index b24e6c7d38f..dfb5ac30206 100644 --- a/src/main/java/org/prebid/server/validation/RequestValidator.java +++ b/src/main/java/org/prebid/server/validation/RequestValidator.java @@ -452,7 +452,7 @@ private void validateUser(User user, Map aliases) throws Validat final ExtUserEid eid = eids.get(index); if (StringUtils.isBlank(eid.getSource())) { throw new ValidationException( - "request.user.ext.eids[%d].source missing required field: \"source\"", index); + "request.user.ext.eids[%d] missing required field: \"source\"", index); } final String eidId = eid.getId(); final List eidUids = eid.getUids(); diff --git a/src/main/java/org/prebid/server/vertx/CircuitBreaker.java b/src/main/java/org/prebid/server/vertx/CircuitBreaker.java index 00209a39f0e..cd16be04946 100644 --- a/src/main/java/org/prebid/server/vertx/CircuitBreaker.java +++ b/src/main/java/org/prebid/server/vertx/CircuitBreaker.java @@ -4,6 +4,7 @@ import io.vertx.circuitbreaker.CircuitBreakerState; import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; @@ -26,8 +27,13 @@ public class CircuitBreaker { private volatile long lastFailureTime; - public CircuitBreaker(String name, Vertx vertx, int openingThreshold, long openingIntervalMs, - long closingIntervalMs, Clock clock) { + public CircuitBreaker(String name, + Vertx vertx, + int openingThreshold, + long openingIntervalMs, + long closingIntervalMs, + Clock clock) { + breaker = io.vertx.circuitbreaker.CircuitBreaker.create( Objects.requireNonNull(name), Objects.requireNonNull(vertx), @@ -43,46 +49,46 @@ public CircuitBreaker(String name, Vertx vertx, int openingThreshold, long openi /** * Executes the given operation with the circuit breaker control. */ - public Future execute(Handler> command) { - return breaker.execute(future -> execute(command, future)); + public Future execute(Handler> command) { + return breaker.execute(promise -> execute(command, promise)); } /** - * Executes operation and handle result of it on given {@link Future}. + * Executes operation and handle result of it on given {@link Promise}. */ - private void execute(Handler> command, Future future) { - final Future passedFuture = Future.future(); - command.handle(passedFuture); + private void execute(Handler> command, Promise promise) { + final Promise passedPromise = Promise.promise(); + command.handle(passedPromise); - passedFuture - .compose(response -> succeedBreaker(response, future)) - .recover(exception -> failBreaker(exception, future)); + passedPromise.future() + .compose(response -> succeedBreaker(response, promise)) + .recover(exception -> failBreaker(exception, promise)); } /** - * Succeeds given {@link Future} and returns it. + * Succeeds given {@link Promise} and returns corresponding {@link Future}. */ - private static Future succeedBreaker(T result, Future future) { - future.complete(result); - return future; + private static Future succeedBreaker(T result, Promise promise) { + promise.complete(result); + return promise.future(); } /** - * Fails given {@link Future} and returns it. + * Fails given {@link Promise} and returns corresponding {@link Future}. */ - private Future failBreaker(Throwable exception, Future future) { - final Future ensureStateFuture = Future.future(); - vertx.executeBlocking(this::ensureState, false, ensureStateFuture); + private Future failBreaker(Throwable exception, Promise promise) { + final Promise ensureStatePromise = Promise.promise(); + vertx.executeBlocking(this::ensureState, false, ensureStatePromise); - return ensureStateFuture + return ensureStatePromise.future() .recover(throwable -> { logger.warn("Resetting circuit breaker state failed", throwable); - future.fail(throwable); - return future; + promise.fail(throwable); + return promise.future(); }) .compose(ignored -> { // ensuring state succeeded, propagate real error - future.fail(exception); - return future; + promise.fail(exception); + return promise.future(); }); } @@ -93,7 +99,7 @@ private Future failBreaker(Throwable exception, Future future) { * and {@link io.vertx.circuitbreaker.CircuitBreaker#reset()} can take a while, * so it is better to perform them on a worker thread. */ - private void ensureState(Future executeBlockingFuture) { + private void ensureState(Promise executeBlockingPromise) { final long currentTime = clock.millis(); if (breaker.state() == CircuitBreakerState.CLOSED && lastFailureTime > 0 && currentTime - lastFailureTime > openingIntervalMs) { @@ -101,7 +107,7 @@ private void ensureState(Future executeBlockingFuture) { } lastFailureTime = currentTime; - executeBlockingFuture.complete(); + executeBlockingPromise.complete(); } /** diff --git a/src/main/java/org/prebid/server/vertx/ContextRunner.java b/src/main/java/org/prebid/server/vertx/ContextRunner.java index d452a44d0f3..ed5ea8fdc20 100644 --- a/src/main/java/org/prebid/server/vertx/ContextRunner.java +++ b/src/main/java/org/prebid/server/vertx/ContextRunner.java @@ -1,8 +1,8 @@ package org.prebid.server.vertx; import io.vertx.core.Context; -import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; @@ -39,25 +39,26 @@ public ContextRunner(Vertx vertx, long timeoutMs) { * Runs provided action specified number of times each in a new context. This method is handy for * running several instances of {@link io.vertx.core.http.HttpServer} on different event loop threads. */ - public void runOnNewContext(int times, Handler> action) { + public void runOnNewContext(int times, Handler> action) { runOnContext(vertx::getOrCreateContext, times, action); } /** * Runs provided action on a dedicated service context. */ - public void runOnServiceContext(Handler> action) { + public void runOnServiceContext(Handler> action) { runOnContext(() -> serviceContext, 1, action); } - private void runOnContext(Supplier contextFactory, int times, Handler> action) { + private void runOnContext(Supplier contextFactory, int times, Handler> action) { final CountDownLatch completionLatch = new CountDownLatch(times); final AtomicBoolean actionFailed = new AtomicBoolean(false); for (int i = 0; i < times; i++) { final Context context = contextFactory.get(); - final Future future = Future.future().setHandler(ar -> { + final Promise promise = Promise.promise(); + promise.future().setHandler(ar -> { if (ar.failed()) { logger.fatal("Fatal error occurred while running action on Vertx context", ar.cause()); actionFailed.compareAndSet(false, true); @@ -67,9 +68,9 @@ private void runOnContext(Supplier contextFactory, int times, Handl context.runOnContext(v -> { try { - action.handle(future); + action.handle(promise); } catch (RuntimeException e) { - future.fail(e); + promise.fail(e); } }); } diff --git a/src/main/java/org/prebid/server/vertx/Initializable.java b/src/main/java/org/prebid/server/vertx/Initializable.java index 14d77b5a7c8..3c8bfd22c55 100644 --- a/src/main/java/org/prebid/server/vertx/Initializable.java +++ b/src/main/java/org/prebid/server/vertx/Initializable.java @@ -8,6 +8,7 @@ * Initialization is expected to be performed on Vert.x {@link io.vertx.core.Context} (event loop) thread, see * {@link io.vertx.core.Vertx#runOnContext(Handler)} and/or {@link io.vertx.core.Context#runOnContext(Handler)}. */ +@FunctionalInterface public interface Initializable { void initialize(); diff --git a/src/main/java/org/prebid/server/vertx/http/BasicHttpClient.java b/src/main/java/org/prebid/server/vertx/http/BasicHttpClient.java index 101f968cff6..0e6196584a9 100644 --- a/src/main/java/org/prebid/server/vertx/http/BasicHttpClient.java +++ b/src/main/java/org/prebid/server/vertx/http/BasicHttpClient.java @@ -2,6 +2,7 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.http.HttpClientRequest; import io.vertx.core.http.HttpMethod; @@ -30,21 +31,21 @@ public BasicHttpClient(Vertx vertx, io.vertx.core.http.HttpClient httpClient) { @Override public Future request(HttpMethod method, String url, MultiMap headers, String body, long timeoutMs) { - final Future future = Future.future(); + final Promise promise = Promise.promise(); if (timeoutMs <= 0) { - failResponse(new TimeoutException("Timeout has been exceeded"), future); + failResponse(new TimeoutException("Timeout has been exceeded"), promise); } else { final HttpClientRequest httpClientRequest = httpClient.requestAbs(method, url); // Vert.x HttpClientRequest timeout doesn't aware of case when a part of the response body is received, // but remaining part is delayed. So, overall request/response timeout is involved to fix it. - final long timerId = vertx.setTimer(timeoutMs, id -> handleTimeout(future, timeoutMs, httpClientRequest)); + final long timerId = vertx.setTimer(timeoutMs, id -> handleTimeout(promise, timeoutMs, httpClientRequest)); httpClientRequest .setFollowRedirects(true) - .handler(response -> handleResponse(response, future, timerId)) - .exceptionHandler(exception -> failResponse(exception, future, timerId)); + .handler(response -> handleResponse(response, promise, timerId)) + .exceptionHandler(exception -> failResponse(exception, promise, timerId)); if (headers != null) { httpClientRequest.headers().addAll(headers); @@ -57,13 +58,16 @@ public Future request(HttpMethod method, String url, MultiMa } } - return future; + return promise.future(); } - private void handleTimeout(Future future, long timeoutMs, HttpClientRequest httpClientRequest) { - if (!future.isComplete()) { + private void handleTimeout(Promise promise, + long timeoutMs, + HttpClientRequest httpClientRequest) { + + if (!promise.future().isComplete()) { failResponse(new TimeoutException( - String.format("Timeout period of %dms has been exceeded", timeoutMs)), future); + String.format("Timeout period of %dms has been exceeded", timeoutMs)), promise); // Explicitly close connection, inspired by https://github.com/eclipse-vertx/vert.x/issues/2745 httpClientRequest.reset(); @@ -71,28 +75,28 @@ private void handleTimeout(Future future, long timeoutMs, Ht } private void handleResponse(io.vertx.core.http.HttpClientResponse response, - Future future, long timerId) { + Promise promise, long timerId) { response - .bodyHandler(buffer -> successResponse(buffer.toString(), response, future, timerId)) - .exceptionHandler(exception -> failResponse(exception, future, timerId)); + .bodyHandler(buffer -> successResponse(buffer.toString(), response, promise, timerId)) + .exceptionHandler(exception -> failResponse(exception, promise, timerId)); } private void successResponse(String body, io.vertx.core.http.HttpClientResponse response, - Future future, long timerId) { + Promise promise, long timerId) { vertx.cancelTimer(timerId); - future.tryComplete(HttpClientResponse.of(response.statusCode(), response.headers(), body)); + promise.tryComplete(HttpClientResponse.of(response.statusCode(), response.headers(), body)); } - private void failResponse(Throwable exception, Future future, long timerId) { + private void failResponse(Throwable exception, Promise promise, long timerId) { vertx.cancelTimer(timerId); - failResponse(exception, future); + failResponse(exception, promise); } - private static void failResponse(Throwable exception, Future future) { + private static void failResponse(Throwable exception, Promise promise) { logger.warn("HTTP client error", exception); - future.tryFail(exception); + promise.tryFail(exception); } } diff --git a/src/main/java/org/prebid/server/vertx/http/CircuitBreakerSecuredHttpClient.java b/src/main/java/org/prebid/server/vertx/http/CircuitBreakerSecuredHttpClient.java index 12f7cb4e38e..cf6f965906d 100644 --- a/src/main/java/org/prebid/server/vertx/http/CircuitBreakerSecuredHttpClient.java +++ b/src/main/java/org/prebid/server/vertx/http/CircuitBreakerSecuredHttpClient.java @@ -7,6 +7,7 @@ import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import org.prebid.server.exception.PreBidException; +import org.prebid.server.log.ConditionalLogger; import org.prebid.server.metric.Metrics; import org.prebid.server.vertx.CircuitBreaker; import org.prebid.server.vertx.http.model.HttpClientResponse; @@ -17,6 +18,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.function.Function; /** @@ -25,6 +27,8 @@ public class CircuitBreakerSecuredHttpClient implements HttpClient { private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerSecuredHttpClient.class); + private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger); + private static final int LOG_PERIOD_SECONDS = 5; private final Function circuitBreakerCreator; private final Map circuitBreakerByName = new ConcurrentHashMap<>(); @@ -49,7 +53,8 @@ public CircuitBreakerSecuredHttpClient(Vertx vertx, HttpClient httpClient, Metri } private void circuitOpened(String name) { - logger.warn("Http client request to {0} is failed, circuit opened.", name); + conditionalLogger.warn(String.format("Http client request to %s is failed, circuit opened.", name), + LOG_PERIOD_SECONDS, TimeUnit.SECONDS); metrics.updateHttpClientCircuitBreakerMetric(true); } @@ -66,7 +71,7 @@ private void circuitClosed(String name) { public Future request(HttpMethod method, String url, MultiMap headers, String body, long timeoutMs) { return circuitBreakerByName.computeIfAbsent(nameFrom(url), circuitBreakerCreator) - .execute(future -> httpClient.request(method, url, headers, body, timeoutMs).setHandler(future)); + .execute(promise -> httpClient.request(method, url, headers, body, timeoutMs).setHandler(promise)); } private static String nameFrom(String urlAsString) { diff --git a/src/main/java/org/prebid/server/vertx/jdbc/BasicJdbcClient.java b/src/main/java/org/prebid/server/vertx/jdbc/BasicJdbcClient.java index 9f4bfca08a4..f536ca4b4b8 100644 --- a/src/main/java/org/prebid/server/vertx/jdbc/BasicJdbcClient.java +++ b/src/main/java/org/prebid/server/vertx/jdbc/BasicJdbcClient.java @@ -2,6 +2,7 @@ import io.vertx.core.AsyncResult; import io.vertx.core.Future; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.json.JsonArray; import io.vertx.core.logging.Logger; @@ -44,9 +45,9 @@ public BasicJdbcClient(Vertx vertx, JDBCClient jdbcClient, Metrics metrics, Cloc * Must be called on Vertx event loop thread. */ public Future initialize() { - final Future connectionFuture = Future.future(); - jdbcClient.getConnection(connectionFuture.completer()); - return connectionFuture + final Promise connectionPromise = Promise.promise(); + jdbcClient.getConnection(connectionPromise); + return connectionPromise.future() .recover(BasicJdbcClient::logConnectionError) .mapEmpty(); } @@ -59,30 +60,30 @@ public Future executeQuery(String query, List params, Function queryResultFuture = Future.future(); + final Promise queryResultPromise = Promise.promise(); // timeout implementation is inspired by this answer: // https://groups.google.com/d/msg/vertx/eSf3AQagGGU/K7pztnjLc_EJ - final long timerId = vertx.setTimer(remainingTimeout, id -> timedOutResult(queryResultFuture, startTime)); + final long timerId = vertx.setTimer(remainingTimeout, id -> timedOutResult(queryResultPromise, startTime)); - final Future connectionFuture = Future.future(); - jdbcClient.getConnection(connectionFuture.completer()); - connectionFuture + final Promise connectionPromise = Promise.promise(); + jdbcClient.getConnection(connectionPromise); + connectionPromise.future() .recover(BasicJdbcClient::logConnectionError) .compose(connection -> makeQuery(connection, query, params)) - .setHandler(result -> handleResult(result, queryResultFuture, timerId, startTime)); + .setHandler(result -> handleResult(result, queryResultPromise, timerId, startTime)); - return queryResultFuture.map(mapper); + return queryResultPromise.future().map(mapper); } /** - * Fails result {@link Future} with timeout exception. + * Fails result {@link Promise} with timeout exception. */ - private void timedOutResult(Future queryResultFuture, long startTime) { + private void timedOutResult(Promise queryResultPromise, long startTime) { // no need for synchronization since timer is fired on the same event loop thread - if (!queryResultFuture.isComplete()) { + if (!queryResultPromise.future().isComplete()) { metrics.updateDatabaseQueryTimeMetric(clock.millis() - startTime); - queryResultFuture.fail(timeoutException()); + queryResultPromise.fail(timeoutException()); } } @@ -95,26 +96,27 @@ private static Future logConnectionError(Throwable exception) { * Performs query to DB. */ private static Future makeQuery(SQLConnection connection, String query, List params) { - final Future resultSetFuture = Future.future(); + final Promise resultSetPromise = Promise.promise(); connection.queryWithParams(query, new JsonArray(params), ar -> { connection.close(); - resultSetFuture.handle(ar); + resultSetPromise.handle(ar); }); - return resultSetFuture; + return resultSetPromise.future(); } /** - * Propagates responded {@link ResultSet} (or failure) to result {@link Future}. + * Propagates responded {@link ResultSet} (or failure) to result {@link Promise}. */ - private void handleResult(AsyncResult result, Future queryResultFuture, long timerId, - long startTime) { + private void handleResult( + AsyncResult result, Promise queryResultPromise, long timerId, long startTime) { + vertx.cancelTimer(timerId); // check is to avoid harmless exception if timeout exceeds before successful result becomes ready - if (!queryResultFuture.isComplete()) { + if (!queryResultPromise.future().isComplete()) { metrics.updateDatabaseQueryTimeMetric(clock.millis() - startTime); - queryResultFuture.handle(result); + queryResultPromise.handle(result); } } diff --git a/src/main/java/org/prebid/server/vertx/jdbc/CircuitBreakerSecuredJdbcClient.java b/src/main/java/org/prebid/server/vertx/jdbc/CircuitBreakerSecuredJdbcClient.java index 4312299c66f..bacf262d672 100644 --- a/src/main/java/org/prebid/server/vertx/jdbc/CircuitBreakerSecuredJdbcClient.java +++ b/src/main/java/org/prebid/server/vertx/jdbc/CircuitBreakerSecuredJdbcClient.java @@ -6,12 +6,14 @@ import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.sql.ResultSet; import org.prebid.server.execution.Timeout; +import org.prebid.server.log.ConditionalLogger; import org.prebid.server.metric.Metrics; import org.prebid.server.vertx.CircuitBreaker; import java.time.Clock; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import java.util.function.Function; /** @@ -20,6 +22,8 @@ public class CircuitBreakerSecuredJdbcClient implements JdbcClient { private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerSecuredJdbcClient.class); + private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger); + private static final int LOG_PERIOD_SECONDS = 5; private final CircuitBreaker breaker; private final JdbcClient jdbcClient; @@ -42,7 +46,8 @@ public CircuitBreakerSecuredJdbcClient(Vertx vertx, JdbcClient jdbcClient, Metri } private void circuitOpened() { - logger.warn("Database is unavailable, circuit opened."); + conditionalLogger.warn("Database is unavailable, circuit opened.", + LOG_PERIOD_SECONDS, TimeUnit.SECONDS); metrics.updateDatabaseCircuitBreakerMetric(true); } @@ -58,6 +63,6 @@ private void circuitClosed() { @Override public Future executeQuery(String query, List params, Function mapper, Timeout timeout) { - return breaker.execute(future -> jdbcClient.executeQuery(query, params, mapper, timeout).setHandler(future)); + return breaker.execute(promise -> jdbcClient.executeQuery(query, params, mapper, timeout).setHandler(promise)); } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 85b80d522fb..46d42714fac 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -51,6 +51,7 @@ setuid: default-timeout-ms: 2000 vtrack: default-timeout-ms: 2000 + allow-unkonwn-bidder: true cookie-sync: coop-sync: default: true @@ -75,6 +76,7 @@ settings: cache-size: 10000 ttl-seconds: 360 notification-endpoints-enabled: false + account-invalidation-enabled: true recaptcha-url: https://www.google.com/recaptcha/api/siteverify recaptcha-secret: secret_value host-cookie: @@ -83,13 +85,55 @@ host-cookie: ttl-days: 90 max-cookie-size-bytes: 0 gdpr: + enabled: true default-value: 1 eea-countries: at,bg,be,cy,cz,dk,ee,fi,fr,de,gr,hu,ie,it,lv,lt,lu,mt,nl,pl,pt,ro,sk,si,es,se,gb,is,no,li,ai,aw,pt,bm,aq,io,vg,ic,ky,fk,re,mw,gp,gf,yt,pf,tf,gl,pt,ms,an,bq,cw,sx,nc,pn,sh,pm,gs,tc,uk,wf vendorlist: - http-endpoint-template: https://vendorlist.consensu.org/v-{VERSION}/vendorlist.json - http-default-timeout-ms: 2000 + v1: + http-endpoint-template: https://vendorlist.consensu.org/v-{VERSION}/vendorlist.json + http-default-timeout-ms: 2000 + v2: + http-endpoint-template: https://vendorlist.consensu.org/v2/archives/vendor-list-v{VERSION}.json + http-default-timeout-ms: 2000 + purposes: + p1: + enforce-purpose: full + enforce-vendors: true + p2: + enforce-purpose: full + enforce-vendors: true + p3: + enforce-purpose: full + enforce-vendors: true + p4: + enforce-purpose: full + enforce-vendors: true + p5: + enforce-purpose: full + enforce-vendors: true + p6: + enforce-purpose: full + enforce-vendors: true + p7: + enforce-purpose: full + enforce-vendors: true + p8: + enforce-purpose: full + enforce-vendors: true + p9: + enforce-purpose: full + enforce-vendors: true + p10: + enforce-purpose: full + enforce-vendors: true + special-features: + sf1: + enforce: true + sf2: + enforce: true + purpose-one-treatment-interpretation: ignore ccpa: - enforce: false + enforce: true geolocation: enabled: true type: maxmind diff --git a/src/main/resources/bidder-config/brightroll.yaml b/src/main/resources/bidder-config/brightroll.yaml index 6c65f240fca..cc20b56f6d0 100644 --- a/src/main/resources/bidder-config/brightroll.yaml +++ b/src/main/resources/bidder-config/brightroll.yaml @@ -1,13 +1,13 @@ adapters: brightroll: enabled: false - endpoint: http://east-bid.ybp.yahoo.com/bid/appnexuspbs + endpoint: http://east-bid.ybp.yahoo.com/bid/rubiconpbs pbs-enforces-gdpr: true modifying-vast-xml-allowed: true deprecated-names: aliases: meta-info: - maintainer-email: smithaa@oath.com + maintainer-email: x2@verizonmedia.com app-media-types: - banner - video @@ -15,9 +15,126 @@ adapters: - banner - video supported-vendors: + - businessinsider vendor-id: 25 + accounts: + - id: businessinsider + badv: + - 1smartpenny.com + - advantagegold.com + - beverlyhillsmd.com + - beyonddiet.com + - fisheradviser.com + - fisherinvestments.com + - fisherretirementtips.com + - fool.com + - freescore360.com + - gruener-fisher.de + - instantcheckmate.com + - intercreditreport.com + - king.com + - ladyfitnessandhealth.com + - ladyfitnessutah.com + - livecellresearch.com + - lowermybills.com + - promeritumgroup.com + - righttobear.com + - slendertone.com + - Squattypotty.com + - thebeverlyhillsmdsolution.com + - thecrux.com + - thehornnews.com + - ezmob.com + - mediasmart.io + - a4g.com + - servedbyadbutler.com + - adglobal.tech + - adfyre.co + - valo.ai + - metanetwork.mobi + - ato.mx + - avazutracking.net + - aztracking.net + - avidadserver.com + - avid-ad-server.com + - avid-adserver.com + - bidsopt.com + - bo-rtb.com + - bizzclick.com + - aibidsrv.com + - aibidauction.com + - brightmountainads.com + - bkserving.com + - bucksense.io + - ajillionmax.com + - decenterads.com + - digitaladsystems.com + - dspbox.io + - envisionx.co + - fmlabsonline.com + - gadmobe.com + - g2trk.com + - kds.media + - media-servers.net + - mediasmart.es + - motionspots.com + - nativeads.com + - niutux.com + - nuviad.com + - oxonux.com + - adx1.com + - plt7.com + - pltfrm.click + - plf1.net + - pfm.ninja + - readywind.com + - rklmstr.com + - reklamdsp.com + - revive-adserver.net + - adp3.net + - smrt-view.com + - vabilitytech.com + - bidderrtb.com + - doyour.bid + - dsptr.com + - howto5.io + - rtbadtrading.com + - trading-rtbg.com + - rtbsbengine.com + - uuidksinc.net + - rtbtradein.com + - mobuppsrtb.com + - vashoot.com + - psdwc.com + - cwkuki.com + - waardex.com + - webtradingspot.com + - wapstart.ru + - xapads.com + bcat: + - IAB7 + - IAB7-39 + - IAB7-44 + - IAB9-30 + - IAB11 + - IAB13-2 + - IAB14-1 + - IAB15-1 + - IAB15-5 + - IAB17-18 + - IAB18-1 + - IAB18-2 + - IAB7-19 + - IAB19-30 + - IAB23 + - IAB25-7 + - IAB26-1 + - IAB26-2 + - IAB26-3 + - IAB26-4 + imp_battr: [1, 3, 8, 9, 10, 13, 14, 17] usersync: - url: https://pr-bh.ybp.yahoo.com/sync/appnexuspbs?gdpr={{gdpr}}&euconsent={{gdpr_consent}}&us_privacy={{us_privacy}}&url= + url: https://pr-bh.ybp.yahoo.com/sync/rubiconprebidserver?gdpr={{gdpr}}&euconsent={{gdpr_consent}}&us_privacy={{us_privacy}}&url= redirect-url: /setuid?bidder=brightroll&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&uid=${UID} cookie-family-name: brightroll type: redirect diff --git a/src/main/resources/bidder-config/conversant.yaml b/src/main/resources/bidder-config/conversant.yaml index 3d019f8839c..e7f061630e0 100644 --- a/src/main/resources/bidder-config/conversant.yaml +++ b/src/main/resources/bidder-config/conversant.yaml @@ -17,7 +17,7 @@ adapters: supported-vendors: vendor-id: 24 usersync: - url: https://prebid-match.dotomi.com/prebid/match/bounce/current?rurl= + url: https://prebid-match.dotomi.com/match/bounce/current?rurl= redirect-url: /setuid?bidder=conversant&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&networkId=72582&version=1&uid= cookie-family-name: conversant type: redirect diff --git a/src/main/resources/bidder-config/ix.yaml b/src/main/resources/bidder-config/ix.yaml index 33f3a15870a..5c844e2d41c 100644 --- a/src/main/resources/bidder-config/ix.yaml +++ b/src/main/resources/bidder-config/ix.yaml @@ -1,7 +1,7 @@ adapters: ix: enabled: false - endpoint: http://appnexus-us-east.lb.indexww.com/transbidder?p=184932 + endpoint: http://rubicon-us-east.lb.indexww.com/transbidder?p=189517 pbs-enforces-gdpr: true modifying-vast-xml-allowed: true deprecated-names: indexExchange @@ -14,7 +14,7 @@ adapters: supported-vendors: vendor-id: 10 usersync: - url: https://ssum-sec.casalemedia.com/usermatchredir?s=184932&cb= + url: https://ssum.casalemedia.com/usermatchredir?s=189517&cb= redirect-url: /setuid?bidder=ix&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&uid= cookie-family-name: ix type: redirect diff --git a/src/main/resources/bidder-config/visx.yaml b/src/main/resources/bidder-config/visx.yaml index 1dd2106d60e..24e03c75656 100644 --- a/src/main/resources/bidder-config/visx.yaml +++ b/src/main/resources/bidder-config/visx.yaml @@ -9,6 +9,7 @@ adapters: meta-info: maintainer-email: service@yoc.com app-media-types: + - banner site-media-types: - banner supported-vendors: diff --git a/src/main/resources/bidder-config/yieldone.yaml b/src/main/resources/bidder-config/yieldone.yaml new file mode 100644 index 00000000000..df94686afc5 --- /dev/null +++ b/src/main/resources/bidder-config/yieldone.yaml @@ -0,0 +1,24 @@ +adapters: + yieldone: + enabled: false + endpoint: https://y.one.impact-ad.jp/hbs_imp + pbs-enforces-gdpr: true + modifying-vast-xml-allowed: true + deprecated-names: + aliases: + meta-info: + maintainer-email: y1dev@platform-one.co.jp + app-media-types: + - banner + - video + site-media-types: + - banner + - video + supported-vendors: + vendor-id: 0 + usersync: + url: https://y.one.impact-ad.jp/hbs_sc?gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&us_privacy={{us_privacy}}&redirectUri= + redirect-url: /setuid?bidder=yieldone&gdpr={{gdpr}}&gdpr_consent={{gdpr_consent}}&uid=$UID + cookie-family-name: yieldone + type: redirect + support-cors: false \ No newline at end of file diff --git a/src/main/resources/static/bidder-params/yieldone.json b/src/main/resources/static/bidder-params/yieldone.json new file mode 100644 index 00000000000..c60b149914e --- /dev/null +++ b/src/main/resources/static/bidder-params/yieldone.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Yieldone Adapter Params", + "description": "A schema which validates params accepted by the Yieldone adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "description": "Internal Yieldone Placement ID" + } + }, + "required": [ + "placementId" + ] +} \ No newline at end of file diff --git a/src/test/java/org/prebid/server/analytics/CompositeAnalyticsReporterTest.java b/src/test/java/org/prebid/server/analytics/CompositeAnalyticsReporterTest.java index ef36e1f5a97..7c24e814e8f 100644 --- a/src/test/java/org/prebid/server/analytics/CompositeAnalyticsReporterTest.java +++ b/src/test/java/org/prebid/server/analytics/CompositeAnalyticsReporterTest.java @@ -61,4 +61,4 @@ private static String captureEvent(AnalyticsReporter reporter) { verify(reporter).processEvent(auctionEventCaptor.capture()); return auctionEventCaptor.getValue(); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/assertion/FutureAssertion.java b/src/test/java/org/prebid/server/assertion/FutureAssertion.java new file mode 100644 index 00000000000..f8eb8f26fa2 --- /dev/null +++ b/src/test/java/org/prebid/server/assertion/FutureAssertion.java @@ -0,0 +1,54 @@ +package org.prebid.server.assertion; + +import io.vertx.core.Future; +import org.assertj.core.api.AbstractAssert; +import org.assertj.core.api.ThrowableAssert; +import org.assertj.core.internal.ComparisonStrategy; +import org.assertj.core.internal.StandardComparisonStrategy; +import org.assertj.core.util.Preconditions; + +public class FutureAssertion extends AbstractAssert, Future> { + + private ComparisonStrategy futureValueComparisonStrategy; + + private FutureAssertion(Future actual) { + super(actual, FutureAssertion.class); + this.futureValueComparisonStrategy = StandardComparisonStrategy.instance(); + } + + public static FutureAssertion assertThat(Future actual) { + return new FutureAssertion<>(actual); + } + + public FutureAssertion isSucceeded() { + isNotNull(); + if (!actual.succeeded()) { + failWithMessage("Expected future to be succeeded"); + } + return myself; + } + + public ThrowableAssert isFailed() { + isNotNull(); + if (!actual.failed()) { + failWithMessage("Expected future to be failed"); + } + return new ThrowableAssert(actual.cause()); + } + + public FutureAssertion succeededWith(VALUE expectedValue) { + isSucceeded(); + checkIsNotNull(expectedValue); + + final VALUE actualValue = actual.result(); + if (!futureValueComparisonStrategy.areEqual(actualValue, expectedValue)) { + failWithMessage("Expected future to contain <%s> but was <%s>", expectedValue, actualValue); + } + + return myself; + } + + private void checkIsNotNull(T expectedValue) { + Preconditions.checkArgument(expectedValue != null, "The expected value should not be ."); + } +} diff --git a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java index dff66573870..3e7bae2cdeb 100644 --- a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java @@ -290,7 +290,7 @@ public void shouldReturnBidRequestWithIncludeWinnersFromStoredBidRequest() { } @Test - public void shouldReturnBidRequestWithDefaultIncludeBidderKeysIfStoredBidRequestExtTargetingHasNoIncludeBidderKeys() { + public void shouldReturnBidRequestWithDefaultIncludeBidderKeysIfStoredRequestExtTargetingHasNoIncludeBidderKeys() { // given givenBidRequest( builder -> builder @@ -525,7 +525,6 @@ public void shouldReturnBidRequestWithSitePageContainingCurlParamValueWhenSitePr .containsOnly(tuple("overridden-site-page", mapper.valueToTree(ExtSite.of(1, null)))); } - @Test public void shouldReturnBidRequestWithSitePublisherIdOverriddenWithAccountParamValue() { // given diff --git a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java index a2d81cb1457..145575c88cb 100644 --- a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java @@ -15,6 +15,8 @@ import com.iab.openrtb.request.Video; import io.vertx.core.Future; import io.vertx.core.buffer.Buffer; +import io.vertx.core.http.CaseInsensitiveHeaders; +import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -104,6 +106,8 @@ public class AuctionRequestFactoryTest extends VertxTest { @Mock private RoutingContext routingContext; @Mock + private HttpServerRequest httpRequest; + @Mock private TimeoutResolver timeoutResolver; @Mock private TimeoutFactory timeoutFactory; @@ -112,6 +116,9 @@ public class AuctionRequestFactoryTest extends VertxTest { public void setUp() { given(interstitialProcessor.process(any())).will(invocationOnMock -> invocationOnMock.getArgument(0)); + given(routingContext.request()).willReturn(httpRequest); + given(httpRequest.headers()).willReturn(new CaseInsensitiveHeaders()); + given(timeoutResolver.resolve(any())).willReturn(2000L); given(timeoutResolver.adjustTimeout(anyLong())).willReturn(1900L); @@ -187,7 +194,6 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndIdIsNotProvided() { @Test public void shouldReturnFailedFutureIfAccountIsEnforcedAndFailedGetAccountById() { // given - factory = new AuctionRequestFactory( 1000, true, @@ -410,6 +416,7 @@ public void shouldNotSetSitePageIfDomainCouldNotBeDerived() { .site(Site.builder().domain("home.com").build()) .build()); + given(paramsExtractor.refererFrom(any())).willReturn("http://not-valid-site"); given(paramsExtractor.domainFrom(anyString())).willThrow(new PreBidException("Couldn't derive domain")); // when @@ -1266,7 +1273,7 @@ public void shouldReturnAuctionContextWithEmptyAccountIfNotFound() { } @Test - public void shouldReturnAuctionContextWithEmptyAccountIfExceptionOccured() { + public void shouldReturnAuctionContextWithEmptyAccountIfExceptionOccurred() { // given givenBidRequest(BidRequest.builder() .site(Site.builder() @@ -1309,13 +1316,13 @@ private void givenImplicitParams(String referer, String domain, String ip, Strin private void givenBidRequest(BidRequest bidRequest) { try { given(routingContext.getBody()).willReturn(Buffer.buffer(mapper.writeValueAsString(bidRequest))); - - given(storedRequestProcessor.processStoredRequests(any())).willReturn(Future.succeededFuture(bidRequest)); - - given(requestValidator.validate(any())).willReturn(ValidationResult.success()); } catch (JsonProcessingException e) { - e.printStackTrace(); + throw new RuntimeException(e); } + + given(storedRequestProcessor.processStoredRequests(any())).willReturn(Future.succeededFuture(bidRequest)); + + given(requestValidator.validate(any())).willReturn(ValidationResult.success()); } private void givenValidBidRequest() { diff --git a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java index 8696b2a186c..72a8b993858 100644 --- a/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java +++ b/src/test/java/org/prebid/server/auction/BidResponseCreatorTest.java @@ -37,6 +37,7 @@ import org.prebid.server.cache.model.CacheHttpResponse; import org.prebid.server.cache.model.CacheIdInfo; import org.prebid.server.cache.model.CacheServiceResult; +import org.prebid.server.events.EventsContext; import org.prebid.server.events.EventsService; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; @@ -53,6 +54,7 @@ import org.prebid.server.proto.openrtb.ext.response.Events; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidderError; import org.prebid.server.proto.openrtb.ext.response.ExtHttpCall; import org.prebid.server.proto.openrtb.ext.response.ExtResponseCache; @@ -65,6 +67,8 @@ import java.time.Instant; import java.time.ZoneId; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -79,6 +83,7 @@ import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; @@ -139,10 +144,10 @@ public void shouldPassOriginalTimeoutToCacheServiceIfCachingIsRequested() { givenCacheServiceResult(singletonMap(bid, CacheIdInfo.of(null, null))); // when - bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, timeout, false); + bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, false, 1000L, false, timeout); // then - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), same(timeout)); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), same(timeout)); } @Test @@ -172,14 +177,26 @@ public void shouldRequestCacheServiceWithExpectedArguments() { givenCacheServiceResult(singletonMap(bid1, CacheIdInfo.of(null, null))); // when - bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, timeout, false); + bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, false, 1000L, false, timeout); // then + Map> biddersToCacheBidIds = new HashMap<>(); + biddersToCacheBidIds.put("bidder1", Arrays.asList("bidId1", "bidId2")); + biddersToCacheBidIds.put("bidder2", Arrays.asList("bidId3", "bidId4")); verify(cacheService).cacheBidsOpenrtb( - argThat(t -> t.containsAll(asList(bid1, bid4, bid3, bid2))), eq(emptyList()), - eq(CacheContext.builder().shouldCacheBids(true).shouldCacheVideoBids(true).cacheBidsTtl(99) - .cacheVideoBidsTtl(101).videoBidIdsToModify(emptyList()).build()), - eq(Account.builder().id("accountId").build()), eq(timeout)); + argThat(t -> t.containsAll(asList(bid1, bid4, bid3, bid2))), + eq(emptyList()), + eq(CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .cacheBidsTtl(99) + .cacheVideoBidsTtl(101) + .bidderToVideoBidIdsToModify(emptyMap()) + .bidderToBidIds(biddersToCacheBidIds) + .build()), + eq(Account.builder().id("accountId").build()), + eq(EventsContext.builder().auctionTimestamp(1000L).build()), + eq(timeout)); } @Test @@ -204,14 +221,24 @@ public void shouldRequestCacheServiceWithWinningBidsOnlyWhenWinningonlyIsTrue() // just a stub to get through method call chain givenCacheServiceResult(singletonMap(bid1, CacheIdInfo.of(null, null))); - // when - bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, ACCOUNT, timeout, false); + // when\ + bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, ACCOUNT, false, 1000L, false, + timeout); // then + Map> biddersToCacheBidIds = new HashMap<>(); + biddersToCacheBidIds.put("bidder1", Arrays.asList("bidId1", "bidId2")); + biddersToCacheBidIds.put("bidder2", Arrays.asList("bidId3", "bidId4")); verify(cacheService).cacheBidsOpenrtb( - argThat(t -> t.containsAll(asList(bid1, bid2)) && t.size() == 2), eq(emptyList()), - eq(CacheContext.builder().videoBidIdsToModify(emptyList()).build()), - eq(Account.builder().id("accountId").build()), eq(timeout)); + argThat(t -> t.containsAll(asList(bid1, bid2)) && t.size() == 2), + eq(emptyList()), + eq(CacheContext.builder() + .bidderToVideoBidIdsToModify(emptyMap()) + .bidderToBidIds(biddersToCacheBidIds) + .build()), + eq(Account.builder().id("accountId").build()), + eq(EventsContext.builder().auctionTimestamp(1000L).build()), + eq(timeout)); } @Test @@ -239,14 +266,23 @@ public void shouldRequestCacheServiceWithVideoBidsToModifyWhenEventsEnabledAndFo given(bidderCatalog.isModifyingVastXmlAllowed(eq("bidder1"))).willReturn(true); // when - bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, account, timeout, false); + bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, account, true, 1000L, false, timeout); // then + Map> biddersToCacheBidIds = new HashMap<>(); + biddersToCacheBidIds.put("bidder1", Collections.singletonList("bidId1")); + biddersToCacheBidIds.put("bidder2", Collections.singletonList("bidId2")); verify(cacheService).cacheBidsOpenrtb( - argThat(t -> t.containsAll(asList(bid1, bid2))), eq(asList(imp1, imp2)), - eq(CacheContext.builder().shouldCacheVideoBids(true).videoBidIdsToModify(singletonList("bidId1")) + argThat(t -> t.containsAll(asList(bid1, bid2))), + eq(asList(imp1, imp2)), + eq(CacheContext.builder() + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder1", singletonList("bidId1"))) + .bidderToBidIds(biddersToCacheBidIds) .build()), - same(account), eq(timeout)); + same(account), + eq(EventsContext.builder().auctionTimestamp(1000L).build()), + eq(timeout)); } @Test @@ -263,13 +299,19 @@ public void shouldCallCacheServiceEvenRoundedCpmIsZero() { givenCacheServiceResult(singletonMap(bid1, CacheIdInfo.of(null, null))); // when - bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, timeout, false); + bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, false, 1000L, false, timeout); // then verify(cacheService).cacheBidsOpenrtb( - argThat(bids -> bids.contains(bid1)), eq(emptyList()), - eq(CacheContext.builder().videoBidIdsToModify(emptyList()).build()), - eq(Account.builder().id("accountId").build()), eq(timeout)); + argThat(bids -> bids.contains(bid1)), + eq(emptyList()), + eq(CacheContext.builder() + .bidderToVideoBidIdsToModify(emptyMap()) + .bidderToBidIds(singletonMap("bidder1", Collections.singletonList("bidId1"))) + .build()), + eq(Account.builder().id("accountId").build()), + eq(EventsContext.builder().auctionTimestamp(1000L).build()), + eq(timeout)); } @Test @@ -280,21 +322,23 @@ public void shouldSetExpectedConstantResponseFields() { final List bidderResponses = singletonList(BidderResponse.of("bidder1", givenSeatBid(), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, null, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, null, ACCOUNT, + false, 1000L, false, timeout).result(); // then final BidResponse responseWithExpectedFields = BidResponse.builder() .id("123") .cur("USD") .ext(mapper.valueToTree( - ExtBidResponse.of(null, null, singletonMap("bidder1", 100), 1000L, null))) + ExtBidResponse.of(null, null, singletonMap("bidder1", 100), 1000L, null, + ExtBidResponsePrebid.of(1000L)))) .build(); assertThat(bidResponse) .isEqualToIgnoringGivenFields(responseWithExpectedFields, "nbr", "seatbid"); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); + } @Test @@ -303,14 +347,14 @@ public void shouldSetNbrValueTwoAndEmptySeatbidWhenIncomingBidResponsesAreEmpty( final BidRequest bidRequest = givenBidRequest(); // when - final BidResponse bidResponse = bidResponseCreator.create(emptyList(), bidRequest, null, - null, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(emptyList(), bidRequest, null, null, ACCOUNT, false, + 0L, false, timeout).result(); // then assertThat(bidResponse).returns(0, BidResponse::getNbr); assertThat(bidResponse).returns(emptyList(), BidResponse::getSeatbid); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -321,14 +365,14 @@ public void shouldSetNbrValueTwoAndEmptySeatbidWhenIncomingBidResponsesDoNotCont final List bidderResponses = singletonList(BidderResponse.of("bidder1", givenSeatBid(), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, - null, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, null, ACCOUNT, + false, 1000L, false, timeout).result(); // then assertThat(bidResponse).returns(0, BidResponse::getNbr); assertThat(bidResponse).returns(emptyList(), BidResponse::getSeatbid); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -341,14 +385,14 @@ public void shouldSetNbrNullAndPopulateSeatbidWhenAtLeastOneBidIsPresent() { givenSeatBid(BidderBid.of(bid, null, null)), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, - CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getNbr()).isNull(); assertThat(bidResponse.getSeatbid()).hasSize(1); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -361,13 +405,13 @@ public void shouldSkipBidderResponsesWhereSeatBidContainEmptyBids() { BidderResponse.of("bidder2", givenSeatBid(BidderBid.of(Bid.builder().build(), banner, "USD")), 0)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -389,7 +433,7 @@ public void shouldOverwriteBidderIdToUUID() { storedRequestProcessor, jacksonMapper, true); // when final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, CACHE_INFO, ACCOUNT, timeout, false).result(); + null, CACHE_INFO, ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -401,7 +445,7 @@ public void shouldOverwriteBidderIdToUUID() { .hasSize(1) .doesNotContainNull(); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -415,8 +459,8 @@ public void shouldSetExpectedResponseSeatBidAndBidFields() { givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).containsOnly(SeatBid.builder() @@ -427,11 +471,12 @@ public void shouldSetExpectedResponseSeatBidAndBidFields() { .price(BigDecimal.ONE) .adm("adm") .ext(mapper.valueToTree(ExtPrebid.of( - ExtBidPrebid.of(null, banner, null, null, null, null, null), singletonMap("bidExt", 1)))) + ExtBidPrebid.of(null, banner, null, null, null, null, null), + singletonMap("bidExt", 1)))) .build())) .build()); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -470,8 +515,8 @@ public void shouldAddTypeToNativeBidAdm() throws JsonProcessingException { givenSeatBid(BidderBid.of(bid, xNative, "USD")), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -485,7 +530,7 @@ public void shouldAddTypeToNativeBidAdm() throws JsonProcessingException { .data(com.iab.openrtb.response.DataObject.builder().type(2).build()) .build()); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -503,8 +548,8 @@ public void shouldSetBidAdmToNullIfCacheIdIsPresentAndReturnCreativeBidsIsFalse( final BidRequestCacheInfo cacheInfo = BidRequestCacheInfo.builder().doCaching(true).build(); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -512,7 +557,7 @@ public void shouldSetBidAdmToNullIfCacheIdIsPresentAndReturnCreativeBidsIsFalse( .extracting(Bid::getAdm) .containsNull(); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -530,8 +575,8 @@ public void shouldSetBidAdmToNullIfVideoCacheIdIsPresentAndReturnCreativeVideoBi givenCacheServiceResult(singletonMap(bid, CacheIdInfo.of("id", null))); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -539,7 +584,7 @@ public void shouldSetBidAdmToNullIfVideoCacheIdIsPresentAndReturnCreativeVideoBi .extracting(Bid::getAdm) .containsNull(); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -552,8 +597,8 @@ public void shouldTolerateMissingExtInSeatBidAndBid() { givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -565,7 +610,7 @@ public void shouldTolerateMissingExtInSeatBidAndBid() { ExtPrebid.of(ExtBidPrebid.of(null, banner, null, null, null, null, null), null))) .build()); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -579,8 +624,8 @@ public void shouldPopulateTargetingKeywords() { givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + ACCOUNT, false, 1000L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -594,7 +639,7 @@ public void shouldPopulateTargetingKeywords() { tuple("hb_bidder", "bidder1"), tuple("hb_bidder_bidder1", "bidder1")); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -614,8 +659,8 @@ public void shouldPopulateTargetingKeywordsForWinningBidsAndWinningBidsByBidder( givenSeatBid(BidderBid.of(thirdBid, banner, null)), 111)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -630,7 +675,7 @@ public void shouldPopulateTargetingKeywordsForWinningBidsAndWinningBidsByBidder( tuple("bidId2", null, null, null), tuple("bidId3", "bidder2", null, "bidder2")); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -656,8 +701,8 @@ public void shouldPopulateTargetingKeywordsFromMediaTypePriceGranularities() { givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -671,7 +716,7 @@ public void shouldPopulateTargetingKeywordsFromMediaTypePriceGranularities() { tuple("hb_pb_bidder1", "5.000"), tuple("hb_bidder_bidder1", "bidder1")); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -688,8 +733,8 @@ public void shouldPopulateCacheIdHostPathAndUuidTargetingKeywords() { givenCacheServiceResult(singletonMap(bid, CacheIdInfo.of("cacheId", "videoId"))); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -711,7 +756,7 @@ public void shouldPopulateCacheIdHostPathAndUuidTargetingKeywords() { tuple("hb_cache_host_bidder1", "testHost"), tuple("hb_cache_path_bidder1", "testPath")); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -726,14 +771,14 @@ public void shouldPopulateTargetingKeywordsWithEventsUrl() { final Account account = Account.builder().id("accountId").eventsEnabled(true).build(); - given(eventsService.winUrlTargeting(anyString())).willReturn("http://win-url"); + given(eventsService.winUrlTargeting(anyString(), anyString(), anyLong())).willReturn("http://win-url"); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, CACHE_INFO, account, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + account, true, 0L, false, timeout).result(); // then - verify(eventsService).winUrlTargeting(eq("accountId")); + verify(eventsService).winUrlTargeting(eq("bidder1"), eq("accountId"), eq(0L)); assertThat(bidResponse.getSeatbid()) .flatExtracting(SeatBid::getBid).hasSize(1) .extracting(responseBid -> toExtPrebid(responseBid.getExt()).getPrebid().getTargeting()) @@ -748,7 +793,7 @@ public void shouldPopulateTargetingKeywordsWithEventsUrl() { tuple("hb_bidid", "bidId1"), tuple("hb_bidid_bidder1", "bidId1")); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -762,14 +807,14 @@ public void shouldAddExtPrebidEvents() { givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); final Events events = Events.of("http://event-type-win", "http://event-type-view"); - given(eventsService.createEvent(anyString(), anyString())).willReturn(events); - given(eventsService.winUrlTargeting(anyString())).willReturn("http://win-url"); + given(eventsService.createEvent(anyString(), anyString(), anyString(), anyLong())).willReturn(events); + given(eventsService.winUrlTargeting(anyString(), anyString(), anyLong())).willReturn("http://win-url"); final Account account = Account.builder().id("accountId").eventsEnabled(true).build(); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, CACHE_INFO, account, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + account, true, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).hasSize(1) @@ -777,7 +822,54 @@ public void shouldAddExtPrebidEvents() { .extracting(responseBid -> toExtPrebid(responseBid.getExt()).getPrebid().getEvents()) .containsOnly(events); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); + } + + @Test + public void shouldNotAddExtPrebidEventsIfEventsAreNotEnabled() { + // given + final BidRequest bidRequest = givenBidRequest(); + final ExtRequestTargeting targeting = givenTargeting(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(5.67)).build(); + final List bidderResponses = singletonList(BidderResponse.of("bidder1", + givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); + + final Account account = Account.builder().id("accountId").eventsEnabled(false).build(); + + // when + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + account, true, 0L, false, timeout).result(); + + // then + assertThat(bidResponse.getSeatbid()).hasSize(1) + .flatExtracting(SeatBid::getBid) + .extracting(responseBid -> toExtPrebid(responseBid.getExt()).getPrebid().getEvents()) + .containsNull(); + } + + @Test + public void shouldNotAddExtPrebidEventsIfExtRequestPrebidEventsNull() { + // given + final BidRequest bidRequest = givenBidRequest(); + final ExtRequestTargeting targeting = givenTargeting(); + + final Bid bid = Bid.builder().id("bidId1").price(BigDecimal.valueOf(5.67)).build(); + final List bidderResponses = singletonList(BidderResponse.of("bidder1", + givenSeatBid(BidderBid.of(bid, banner, "USD")), 100)); + + given(eventsService.winUrlTargeting(anyString(), anyString(), anyLong())).willReturn("http://win-url"); + final Account account = Account.builder().id("accountId").eventsEnabled(true).build(); + + // when + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, CACHE_INFO, + account, false, 0L, false, timeout).result(); + + // then + assertThat(bidResponse.getSeatbid()).hasSize(1) + .flatExtracting(SeatBid::getBid) + .extracting(responseBid -> toExtPrebid(responseBid.getExt()).getPrebid().getEvents()) + .containsNull(); } @Test @@ -799,8 +891,8 @@ public void shouldReturnCacheEntityInExt() { givenCacheServiceResult(singletonMap(bid, CacheIdInfo.of("cacheId", "videoId"))); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()) @@ -811,7 +903,7 @@ public void shouldReturnCacheEntityInExt() { CacheAsset.of("uuid=cacheId", "cacheId"), CacheAsset.of("uuid=videoId", "videoId"))); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -839,8 +931,8 @@ public void shouldNotPopulateWinningBidTargetingIfIncludeWinnersFlagIsFalse() { givenCacheServiceResult(singletonMap(bid, CacheIdInfo.of("cacheId", "videoId"))); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).flatExtracting(SeatBid::getBid) @@ -851,7 +943,7 @@ public void shouldNotPopulateWinningBidTargetingIfIncludeWinnersFlagIsFalse() { .containsOnly( tuple("bidId", null, "bidder1")); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -879,8 +971,8 @@ public void shouldNotPopulateBidderKeysTargetingIfIncludeBidderKeysFlagIsFalse() givenCacheServiceResult(singletonMap(bid, CacheIdInfo.of("cacheId", "videoId"))); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).flatExtracting(SeatBid::getBid) @@ -891,7 +983,7 @@ public void shouldNotPopulateBidderKeysTargetingIfIncludeBidderKeysFlagIsFalse() .containsOnly( tuple("bidId", "bidder1", null)); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -912,8 +1004,8 @@ public void shouldNotPopulateCacheIdTargetingKeywordsIfBidCpmIsZero() { givenCacheServiceResult(singletonMap(secondBid, CacheIdInfo.of("cacheId2", null))); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - targeting, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, targeting, cacheInfo, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getSeatbid()).flatExtracting(SeatBid::getBid).hasSize(2) @@ -925,7 +1017,7 @@ public void shouldNotPopulateCacheIdTargetingKeywordsIfBidCpmIsZero() { tuple("bidder1", null, null), tuple("bidder2", "cacheId2", "cacheId2")); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -948,8 +1040,8 @@ public void shouldPopulateBidResponseExtension() throws JsonProcessingException CacheHttpCall.of(null, null, 666), new RuntimeException("cacheError"), emptyMap())); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, cacheInfo, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, + false, 0L, false, timeout).result(); // then final ExtBidResponse responseExt = mapper.treeToValue(bidResponse.getExt(), ExtBidResponse.class); @@ -961,15 +1053,15 @@ public void shouldPopulateBidResponseExtension() throws JsonProcessingException assertThat(responseExt.getErrors()).hasSize(2).containsOnly( entry("bidder1", asList( ExtBidderError.of(2, "bad_input"), - ExtBidderError.of(3, "Failed to decode: Cannot deserialize instance of `com.iab." + - "openrtb.response.Response` out of START_ARRAY token\n at [Source: (String)\"[]\"; " + - "line: 1, column: 1]"))), + ExtBidderError.of(3, "Failed to decode: Cannot deserialize instance of `com.iab." + + "openrtb.response.Response` out of START_ARRAY token\n at [Source: (String)\"[]\"; " + + "line: 1, column: 1]"))), entry("prebid", singletonList(ExtBidderError.of(999, "cacheError")))); assertThat(responseExt.getResponsetimemillis()).hasSize(2) .containsOnly(entry("bidder1", 100), entry("cache", 666)); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -995,8 +1087,8 @@ public void impToStoredVideoJsonShouldTolerateWhenStoredVideoFetchIsFailed() { Future.failedFuture("Fetch failed")); // when - final Future result = - bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, ACCOUNT, timeout, false); + final Future result = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 0L, false, timeout); // then verify(storedRequestProcessor).videoStoredDataResult(eq(singletonList(imp)), any(), eq(timeout)); @@ -1046,8 +1138,8 @@ public void impToStoredVideoJsonShouldInjectStoredVideoWhenExtOptionsIsTrueAndVi VideoStoredDataResult.of(singletonMap("impId1", storedVideo), emptyList()))); // when - final Future result = - bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, ACCOUNT, timeout, false); + final Future result = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 0L, false, timeout); // then verify(storedRequestProcessor).videoStoredDataResult(eq(Arrays.asList(imp1, imp3)), any(), eq(timeout)); @@ -1081,8 +1173,8 @@ public void impToStoredVideoJsonShouldAddErrorsWithPrebidBidderWhenStoredVideoRe .willReturn(Future.failedFuture("Bad timeout")); // when - final Future result = - bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, ACCOUNT, timeout, false); + final Future result = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 0L, false, timeout); // then verify(storedRequestProcessor).videoStoredDataResult(eq(singletonList(imp1)), any(), eq(timeout)); @@ -1090,7 +1182,8 @@ public void impToStoredVideoJsonShouldAddErrorsWithPrebidBidderWhenStoredVideoRe assertThat(result.result().getExt()).isEqualTo( mapper.valueToTree(ExtBidResponse.of(null, singletonMap( "prebid", singletonList(ExtBidderError.of(BidderError.Type.generic.getCode(), - "Bad timeout"))), singletonMap("bidder1", 100), 1000L, null))); + "Bad timeout"))), singletonMap("bidder1", 100), 1000L, null, + ExtBidResponsePrebid.of(0L)))); } @Test @@ -1109,17 +1202,17 @@ public void shouldProcessRequestAndAddErrorAboutDeprecatedBidder() { "invalid has been deprecated and is no longer available. Use valid instead."); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, CACHE_INFO, ACCOUNT, timeout, false).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, CACHE_INFO, + ACCOUNT, false, 0L, false, timeout).result(); // then assertThat(bidResponse.getExt()).isEqualTo( mapper.valueToTree(ExtBidResponse.of(null, singletonMap( invalidBidderName, singletonList(ExtBidderError.of(BidderError.Type.bad_input.getCode(), "invalid has been deprecated and is no longer available. Use valid instead."))), - singletonMap("bidder1", 100), 1000L, null))); + singletonMap("bidder1", 100), 1000L, null, ExtBidResponsePrebid.of(0L)))); - verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService, never()).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } @Test @@ -1138,8 +1231,8 @@ public void shouldPopulateBidResponseDebugExtensionIfDebugIsEnabled() throws Jso singletonList(ExtHttpCall.builder().status(200).build()), null), 100)); // when - final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, - null, cacheInfo, ACCOUNT, timeout, true).result(); + final BidResponse bidResponse = bidResponseCreator.create(bidderResponses, bidRequest, null, cacheInfo, ACCOUNT, + false, 0L, true, timeout).result(); // then final ExtBidResponse responseExt = mapper.treeToValue(bidResponse.getExt(), ExtBidResponse.class); @@ -1152,7 +1245,7 @@ public void shouldPopulateBidResponseDebugExtensionIfDebugIsEnabled() throws Jso assertThat(responseExt.getDebug().getResolvedrequest()).isEqualTo(bidRequest); - verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any()); + verify(cacheService).cacheBidsOpenrtb(anyList(), anyList(), any(), any(), any(), any()); } private void givenCacheServiceResult(Map cacheBids) { @@ -1160,7 +1253,7 @@ private void givenCacheServiceResult(Map cacheBids) { } private void givenCacheServiceResult(CacheServiceResult cacheServiceResult) { - given(cacheService.cacheBidsOpenrtb(any(), any(), any(), any(), any())) + given(cacheService.cacheBidsOpenrtb(any(), any(), any(), any(), any(), any())) .willReturn(Future.succeededFuture(cacheServiceResult)); } diff --git a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java index ecb6c5fb4be..86a9375421d 100644 --- a/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java +++ b/src/test/java/org/prebid/server/auction/ExchangeServiceTest.java @@ -32,8 +32,8 @@ import org.prebid.server.VertxTest; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.BidRequestCacheInfo; +import org.prebid.server.auction.model.BidderPrivacyResult; import org.prebid.server.auction.model.BidderResponse; -import org.prebid.server.auction.model.PrivacyEnforcementResult; import org.prebid.server.auction.model.StoredResponseResult; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.BidderCatalog; @@ -56,6 +56,7 @@ import org.prebid.server.proto.openrtb.ext.request.ExtGranularityRange; import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; +import org.prebid.server.proto.openrtb.ext.request.ExtRequestCurrency; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidCache; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidCacheBids; @@ -86,6 +87,7 @@ import java.util.List; import java.util.Map; import java.util.function.Function; +import java.util.stream.Collectors; import static java.math.BigDecimal.TEN; import static java.util.Arrays.asList; @@ -99,6 +101,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.entry; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; @@ -153,22 +156,25 @@ public class ExchangeServiceTest extends VertxTest { @SuppressWarnings("unchecked") @Before public void setUp() { - given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), any(), anyBoolean())) + given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), anyBoolean(), anyLong(), anyBoolean(), + any())) .willReturn(Future.succeededFuture(givenBidResponseWithBids(singletonList(givenBid(identity()))))); given(bidderCatalog.isValidName(anyString())).willReturn(true); given(bidderCatalog.isActive(anyString())).willReturn(true); given(bidderCatalog.usersyncerByName(anyString())).willReturn(usersyncer); - given(privacyEnforcementService.mask(argThat(MapUtils::isNotEmpty), any(), any(), any(), any(), any(), any())) + given(privacyEnforcementService.mask(any(), argThat(MapUtils::isNotEmpty), any(), any(), any())) .willAnswer(inv -> - Future.succeededFuture(((Map) inv.getArgument(0)).entrySet().stream() - .collect(HashMap::new, (map, bidderToUserEntry) -> map.put(bidderToUserEntry.getKey(), - PrivacyEnforcementResult.of(bidderToUserEntry.getValue(), null)), - HashMap::putAll))); + Future.succeededFuture(((Map) inv.getArgument(1)).entrySet().stream() + .map(bidderAndUser -> BidderPrivacyResult.builder() + .requestBidder(bidderAndUser.getKey()) + .user(bidderAndUser.getValue()) + .build()) + .collect(Collectors.toList()))); - given(privacyEnforcementService.mask(argThat(MapUtils::isEmpty), any(), any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(emptyMap())); + given(privacyEnforcementService.mask(any(), argThat(MapUtils::isEmpty), any(), any(), any())) + .willReturn(Future.succeededFuture(emptyList())); given(responseBidValidator.validate(any())).willReturn(ValidationResult.success()); given(usersyncer.getCookieFamilyName()).willReturn("cookieFamily"); @@ -292,6 +298,49 @@ public void shouldExtractRequestWithBidderSpecificExtension() { .ext(mapper.valueToTree(ExtPrebid.of(0, 1))) .build())) .tmax(500L) + + .build()); + } + + @Test + public void shouldExtractRequestWithCurrencyRatesExtension() { + // given + givenBidder(givenEmptySeatBid()); + + final Map> currencyRates = doubleMap( + "GBP", singletonMap("EUR", BigDecimal.valueOf(1.15)), + "UAH", singletonMap("EUR", BigDecimal.valueOf(1.1565))); + + final BidRequest bidRequest = givenBidRequest(singletonList( + givenImp(doubleMap("prebid", 0, "someBidder", 1), builder -> builder + .id("impId") + .banner(Banner.builder() + .format(singletonList(Format.builder().w(400).h(300).build())) + .build()))), + builder -> builder + .id("requestId") + .ext(mapper.valueToTree( + ExtRequestPrebid.builder().currency(ExtRequestCurrency.of(currencyRates)).build())) + .tmax(500L)); + + // when + exchangeService.holdAuction(givenRequestContext(bidRequest)); + + // then + final BidRequest capturedBidRequest = captureBidRequest(); + assertThat(capturedBidRequest).isEqualTo(BidRequest.builder() + .id("requestId") + .cur(singletonList("USD")) + .imp(singletonList(Imp.builder() + .id("impId") + .banner(Banner.builder() + .format(singletonList(Format.builder().w(400).h(300).build())) + .build()) + .ext(mapper.valueToTree(ExtPrebid.of(0, 1))) + .build())) + .ext(mapper.valueToTree( + ExtRequestPrebid.builder().currency(ExtRequestCurrency.of(currencyRates)).build())) + .tmax(500L) .build()); } @@ -335,18 +384,19 @@ public void shouldPassRequestWithExtPrebidToDefinedBidder() { givenBidder(bidder1Name, bidder1, givenEmptySeatBid()); givenBidder(bidder2Name, bidder2, givenEmptySeatBid()); - final ObjectNode ext = mapper.valueToTree(ExtBidRequest.of( + final ObjectNode extBidRequest = mapper.valueToTree(ExtBidRequest.of( ExtRequestPrebid.builder() .bidders(mapper.createObjectNode() .putPOJO(bidder1Name, mapper.createObjectNode().put("test1", "test1")) .putPOJO(bidder2Name, mapper.createObjectNode().put("test2", "test2")) .putPOJO("spam", mapper.createObjectNode().put("spam", "spam"))) + .auctiontimestamp(1000L) .build())); final BidRequest bidRequest = givenBidRequest(asList( givenImp(singletonMap(bidder1Name, 1), identity()), givenImp(singletonMap(bidder2Name, 2), identity())), - reqBuilder -> reqBuilder.ext(ext)); + builder -> builder.ext(extBidRequest)); // when exchangeService.holdAuction(givenRequestContext(bidRequest)); @@ -392,16 +442,17 @@ public void shouldPassRequestWithInjectedSchainInSourceExt() { final ExtRequestPrebidSchain schain1 = ExtRequestPrebidSchain.of(Arrays.asList(bidder1Name, bidder2Name), schainObject); final ExtRequestPrebidSchain allSchain = ExtRequestPrebidSchain.of(singletonList("*"), allSchainObject); - final ObjectNode ext = mapper.valueToTree(ExtBidRequest.of( + final ObjectNode extBidRequest = mapper.valueToTree(ExtBidRequest.of( ExtRequestPrebid.builder() .schains(Arrays.asList(schain1, allSchain)) + .auctiontimestamp(1000L) .build())); final BidRequest bidRequest = givenBidRequest(asList( givenImp(singletonMap(bidder1Name, 1), identity()), givenImp(singletonMap(bidder2Name, 2), identity()), givenImp(singletonMap(bidder3Name, 3), identity())), - reqBuilder -> reqBuilder.ext(ext)); + builder -> builder.ext(extBidRequest)); // when exchangeService.holdAuction(givenRequestContext(bidRequest)); @@ -438,7 +489,7 @@ public void shouldReturnFailedFutureWithUnchangedMessageWhenPrivacyEnforcementSe final Bidder bidder = mock(Bidder.class); givenBidder("someBidder", bidder, givenEmptySeatBid()); - given(privacyEnforcementService.mask(any(), any(), any(), any(), any(), any(), any())) + given(privacyEnforcementService.mask(any(), any(), any(), any(), any())) .willReturn(Future.failedFuture("Error when retrieving allowed purpose ids")); final BidRequest bidRequest = givenBidRequest(givenSingleImp(singletonMap("someBidder", 1)), @@ -459,7 +510,7 @@ public void shouldReturnFailedFutureWithPrebidExceptionIfExtRegsCannotBeParsed() final Bidder bidder = mock(Bidder.class); givenBidder("someBidder", bidder, givenEmptySeatBid()); - given(privacyEnforcementService.mask(any(), any(), any(), any(), any(), any(), any())) + given(privacyEnforcementService.mask(any(), any(), any(), any(), any())) .willThrow(new PreBidException("Error decoding bidRequest.regs.ext:invalid")); final BidRequest bidRequest = givenBidRequest(givenSingleImp(singletonMap("someBidder", 1)), @@ -476,11 +527,18 @@ public void shouldReturnFailedFutureWithPrebidExceptionIfExtRegsCannotBeParsed() } @Test - public void shouldExtractRequestByAliasForCorrectBidder() { + public void shouldNotCreateRequestForBidderRestrictedByPrivacyEnforcement() { // given final Bidder bidder = mock(Bidder.class); givenBidder("bidder", bidder, givenEmptySeatBid()); + final BidderPrivacyResult restrictedPrivacy = BidderPrivacyResult.builder() + .requestBidder("bidderAlias") + .blockedRequestByTcf(true) + .build(); + given(privacyEnforcementService.mask(any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(singletonList(restrictedPrivacy))); + final BidRequest bidRequest = givenBidRequest(singletonList( givenImp(singletonMap("bidderAlias", 1), identity())), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() @@ -489,6 +547,26 @@ public void shouldExtractRequestByAliasForCorrectBidder() { // when exchangeService.holdAuction(givenRequestContext(bidRequest)); + // then + verifyZeroInteractions(httpBidderRequester); + } + + @Test + public void shouldExtractRequestByAliasForCorrectBidder() { + // given + final Bidder bidder = mock(Bidder.class); + givenBidder("bidder", bidder, givenEmptySeatBid()); + + final BidRequest bidRequest = givenBidRequest(singletonList( + givenImp(singletonMap("bidderAlias", 1), identity())), + builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .aliases(singletonMap("bidderAlias", "bidder")) + .auctiontimestamp(1000L) + .build())))); + + // when + exchangeService.holdAuction(givenRequestContext(bidRequest)); + // then final ArgumentCaptor bidRequestCaptor = ArgumentCaptor.forClass(BidRequest.class); verify(httpBidderRequester).requestBids(same(bidder), bidRequestCaptor.capture(), any(), anyBoolean()); @@ -506,7 +584,7 @@ public void shouldExtractMultipleRequestsForTheSameBidderIfAliasesWereUsed() { final BidRequest bidRequest = givenBidRequest(singletonList( givenImp(doubleMap("bidder", 1, "bidderAlias", 2), identity())), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() - .aliases(singletonMap("bidderAlias", "bidder")).build())))); + .aliases(singletonMap("bidderAlias", "bidder")).auctiontimestamp(1000L).build())))); // when exchangeService.holdAuction(givenRequestContext(bidRequest)); @@ -543,21 +621,26 @@ public void shouldReturnSeparateSeatBidsForTheSameBidderIfBiddersAliasAndBidderW // given given(httpBidderRequester.requestBids(any(), eq(givenBidRequest(givenSingleImp(singletonMap("bidder", 1)), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .auctiontimestamp(1000L) .aliases(singletonMap("bidderAlias", "bidder")).build()))))), any(), anyBoolean())) .willReturn(Future.succeededFuture(givenSeatBid(singletonList( givenBid(Bid.builder().price(BigDecimal.ONE).build()))))); given(httpBidderRequester.requestBids(any(), eq(givenBidRequest(givenSingleImp(singletonMap("bidder", 2)), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .auctiontimestamp(1000L) .aliases(singletonMap("bidderAlias", "bidder")).build()))))), any(), anyBoolean())) .willReturn(Future.succeededFuture(givenSeatBid(singletonList( givenBid(Bid.builder().price(BigDecimal.ONE).build()))))); final BidRequest bidRequest = givenBidRequest(givenSingleImp(doubleMap("bidder", 1, "bidderAlias", 2)), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() - .aliases(singletonMap("bidderAlias", "bidder")).build())))); + .aliases(singletonMap("bidderAlias", "bidder")) + .auctiontimestamp(1000L) + .build())))); - given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), any(), anyBoolean())) + given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), anyBoolean(), anyLong(), anyBoolean(), + any())) .willReturn(Future.succeededFuture(BidResponse.builder() .seatbid(asList( givenSeatBid(singletonList(givenBid(identity())), identity()), @@ -584,12 +667,15 @@ public void shouldCallBidResponseCreatorWithExpectedParams() { givenBidder("bidder2", mock(Bidder.class), givenSeatBid(singletonList(givenBid(thirdBid)))); final ExtRequestTargeting targeting = givenTargeting(true); + final ObjectNode events = mapper.createObjectNode(); final BidRequest bidRequest = givenBidRequest(asList( // imp ids are not really used for matching, included them here for clarity givenImp(singletonMap("bidder1", 1), builder -> builder.id("impId1")), givenImp(doubleMap("bidder1", 1, "bidder2", 2), builder -> builder.id("impId1"))), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(targeting) + .auctiontimestamp(1000L) + .events(events) .cache(ExtRequestPrebidCache.of(ExtRequestPrebidCacheBids.of(53, true), ExtRequestPrebidCacheVastxml.of(34, true), true)) .build())))); @@ -615,9 +701,9 @@ public void shouldCallBidResponseCreatorWithExpectedParams() { eq(bidRequest), eq(targeting), eq(expectedCacheInfo), - eq(Account.builder().id("accountId").eventsEnabled(false).build()), - eq(timeout), - eq(false)); + eq(Account.builder().id("accountId").eventsEnabled(true).build()), + eq(true), + eq(1000L), eq(false), eq(timeout)); assertThat(captor.getValue()).containsOnly( BidderResponse.of("bidder2", BidderSeatBid.of(singletonList( @@ -642,6 +728,7 @@ public void shouldCallBidResponseCreatorWithWinningOnlyTrueWhenIncludeBidderKeys builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(targeting) .cache(ExtRequestPrebidCache.of(null, null, true)) + .auctiontimestamp(1000L) .build())))); // when @@ -653,7 +740,7 @@ public void shouldCallBidResponseCreatorWithWinningOnlyTrueWhenIncludeBidderKeys eq(bidRequest), eq(targeting), eq(BidRequestCacheInfo.builder().doCaching(true).shouldCacheWinningBidsOnly(true).build()), - any(), any(), eq(false)); + any(), eq(false), anyLong(), eq(false), any()); } @Test @@ -673,6 +760,7 @@ public void shouldCallBidResponseCreatorWithWinningOnlyFalseWhenWinningOnlyIsNul builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(targeting) .cache(ExtRequestPrebidCache.of(null, null, null)) + .auctiontimestamp(1000L) .build())))); // when @@ -684,7 +772,7 @@ public void shouldCallBidResponseCreatorWithWinningOnlyFalseWhenWinningOnlyIsNul any(), eq(targeting), eq(BidRequestCacheInfo.builder().build()), - any(), any(), anyBoolean()); + any(), anyBoolean(), anyLong(), anyBoolean(), any()); } @Test @@ -708,7 +796,8 @@ public void shouldCallBidResponseCreatorWithEnabledDebugTrueIfTestFlagIsTrue() { exchangeService.holdAuction(givenRequestContext(bidRequest)).result(); // then - verify(bidResponseCreator).create(anyList(), eq(bidRequest), any(), any(), any(), any(), eq(true)); + verify(bidResponseCreator).create(anyList(), eq(bidRequest), any(), any(), any(), anyBoolean(), anyLong(), + eq(true), any()); } @Test @@ -727,13 +816,15 @@ public void shouldCallBidResponseCreatorWithEnabledDebugTrueIfExtPrebidDebugIsOn final BidRequest bidRequest = givenBidRequest( givenSingleImp(singletonMap("bidder1", 1)), builder -> builder.ext( - mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder().debug(1).build())))); + mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder().debug(1).auctiontimestamp(1000L) + .build())))); // when exchangeService.holdAuction(givenRequestContext(bidRequest)).result(); // then - verify(bidResponseCreator).create(anyList(), eq(bidRequest), any(), any(), any(), any(), eq(true)); + verify(bidResponseCreator).create(anyList(), eq(bidRequest), any(), any(), any(), eq(false), anyLong(), + eq(true), any()); } @Test @@ -776,7 +867,8 @@ public void shouldTolerateNullRequestExtPrebidTargeting() { final BidRequest bidRequest = givenBidRequest( givenSingleImp(singletonMap("someBidder", 1)), - builder -> builder.ext(mapper.valueToTree(singletonMap("prebid", singletonMap("someField", 1))))); + builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .data(ExtRequestPrebidData.of(singletonList("someBidder"))).auctiontimestamp(1000L).build())))); // when final BidResponse bidResponse = exchangeService.holdAuction(givenRequestContext(bidRequest)).result(); @@ -797,6 +889,7 @@ public void shouldTolerateResponseBidValidationErrors() throws JsonProcessingExc // imp ids are not really used for matching, included them here for clarity givenImp(singletonMap("bidder1", 1), builder -> builder.id("impId1"))), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .auctiontimestamp(1000L) .build())))); given(responseBidValidator.validate(any())) @@ -830,8 +923,7 @@ public void shouldCreateRequestsFromImpsReturnedByStoredResponseProcessor() { .id("impId2") .banner(Banner.builder() .format(singletonList(Format.builder().w(400).h(300).build())) - .build())) - ), + .build()))), builder -> builder.id("requestId").tmax(500L)); given(storedResponseProcessor.getStoredResponseResult(any(), any(), any())) @@ -905,7 +997,6 @@ public void shouldReturnFailedFutureWhenStoredResponseProcessorGetStoredResultRe .build()))), builder -> builder.id("requestId").tmax(500L)); - // when final Future result = exchangeService.holdAuction(givenRequestContext(bidRequest)); @@ -1040,6 +1131,7 @@ public void shouldCleanRequestExtPrebidDataBidders() { builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .data(ExtRequestPrebidData.of(asList("someBidder", "should_be_removed"))) .aliases(singletonMap("someBidder", "alias_should_stay")) + .auctiontimestamp(1000L) .build())))); // when @@ -1051,6 +1143,7 @@ public void shouldCleanRequestExtPrebidDataBidders() { ExtBidRequest.of(ExtRequestPrebid.builder() .aliases(singletonMap("someBidder", "alias_should_stay")) .data(ExtRequestPrebidData.of(singletonList("someBidder"))) + .auctiontimestamp(1000L) .build()))); } @@ -1067,6 +1160,7 @@ public void shouldPassUserExtDataOnlyForAllowedBidder() { final BidRequest bidRequest = givenBidRequest(givenSingleImp(bidderToGdpr), builder -> builder .ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .auctiontimestamp(1000L) .data(ExtRequestPrebidData.of(singletonList("someBidder"))).build()))) .user(User.builder() .ext(mapper.valueToTree(ExtUser.builder().data(dataNode).build())) @@ -1100,6 +1194,7 @@ public void shouldPassSiteExtDataOnlyForAllowedBidder() { final BidRequest bidRequest = givenBidRequest(givenSingleImp(bidderToGdpr), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() + .auctiontimestamp(1000L) .data(ExtRequestPrebidData.of(singletonList("someBidder"))).build()))) .site(Site.builder().ext(mapper.valueToTree(ExtSite.of(0, dataNode))).build())); @@ -1131,7 +1226,7 @@ public void shouldPassAppExtDataOnlyForAllowedBidder() { final BidRequest bidRequest = givenBidRequest(givenSingleImp(bidderToGdpr), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() - .data(ExtRequestPrebidData.of(singletonList("someBidder"))).build()))) + .data(ExtRequestPrebidData.of(singletonList("someBidder"))).auctiontimestamp(1000L).build()))) .app(App.builder().ext(mapper.valueToTree(ExtApp.of(null, dataNode))).build())); // when @@ -1224,6 +1319,7 @@ public void shouldPassReducedGlobalTimeoutToConnectorAndOriginalToBidResponseCre builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(givenTargeting(true)) .cache(ExtRequestPrebidCache.of(ExtRequestPrebidCacheBids.of(null, null), null, null)) + .auctiontimestamp(1000L) .build())))); // when @@ -1233,7 +1329,8 @@ public void shouldPassReducedGlobalTimeoutToConnectorAndOriginalToBidResponseCre final ArgumentCaptor timeoutCaptor = ArgumentCaptor.forClass(Timeout.class); verify(httpBidderRequester).requestBids(any(), any(), timeoutCaptor.capture(), anyBoolean()); assertThat(timeoutCaptor.getValue().remaining()).isEqualTo(400L); - verify(bidResponseCreator).create(anyList(), any(), any(), any(), any(), same(timeout), anyBoolean()); + verify(bidResponseCreator).create(anyList(), any(), any(), any(), any(), anyBoolean(), anyLong(), anyBoolean(), + same(timeout)); } @Test @@ -1302,12 +1399,13 @@ public void shouldDropBidIfPrebidExceptionWasThrownDuringCurrencyConversion() { // then final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), any(), anyBoolean()); + verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), anyBoolean(), anyLong(), + anyBoolean(), any()); assertThat(argumentCaptor.getValue()).hasSize(1); - final BidderError expectedError = BidderError.generic("Unable to covert bid currency CUR to desired ad" + - " server currency USD. no currency conversion available"); + final BidderError expectedError = BidderError.generic("Unable to covert bid currency CUR to desired ad" + + " server currency USD. no currency conversion available"); final BidderSeatBid firstSeatBid = argumentCaptor.getValue().get(0).getSeatBid(); assertThat(firstSeatBid.getBids()).isEmpty(); assertThat(firstSeatBid.getErrors()).containsOnly(expectedError); @@ -1325,6 +1423,7 @@ public void shouldUpdateBidPriceWithCurrencyConversionAndPriceAdjustmentFactor() builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .aliases(emptyMap()) .bidadjustmentfactors(singletonMap("bidder", BigDecimal.valueOf(10.0))) + .auctiontimestamp(1000L) .build())))); given(currencyService.convertCurrency(any(), any(), any(), any())).willReturn(BigDecimal.valueOf(10.0)); @@ -1334,7 +1433,8 @@ public void shouldUpdateBidPriceWithCurrencyConversionAndPriceAdjustmentFactor() // then final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), any(), anyBoolean()); + verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), anyBoolean(), anyLong(), + anyBoolean(), any()); assertThat(argumentCaptor.getValue()).hasSize(1); @@ -1369,7 +1469,8 @@ public void shouldUpdatePriceForOneBidAndDropAnotherIfPrebidExceptionHappensForS // then final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), any(), anyBoolean()); + verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), anyBoolean(), anyLong(), + anyBoolean(), any()); verify(currencyService).convertCurrency(eq(firstBidderPrice), eq(null), any(), eq("CUR1")); verify(currencyService).convertCurrency(eq(secondBidderPrice), eq(null), any(), eq("CUR2")); @@ -1377,8 +1478,8 @@ public void shouldUpdatePriceForOneBidAndDropAnotherIfPrebidExceptionHappensForS final Bid expectedBid = Bid.builder().price(updatedPrice).build(); final BidderBid expectedBidderBid = BidderBid.of(expectedBid, banner, "CUR1"); - final BidderError expectedError = BidderError.generic("Unable to covert bid currency CUR2 to desired ad" + - " server currency USD. no currency conversion available"); + final BidderError expectedError = BidderError.generic("Unable to covert bid currency CUR2 to desired ad" + + " server currency USD. no currency conversion available"); final BidderSeatBid firstSeatBid = argumentCaptor.getValue().get(0).getSeatBid(); assertThat(firstSeatBid.getBids()).containsOnly(expectedBidderBid); @@ -1410,7 +1511,8 @@ public void shouldRespondWithOneBidAndErrorWhenBidResponseContainsOneUnsupported // then final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), any(), anyBoolean()); + verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), anyBoolean(), anyLong(), + anyBoolean(), any()); verify(currencyService).convertCurrency(eq(firstBidderPrice), eq(null), eq("BAD"), eq("USD")); verify(currencyService).convertCurrency(eq(secondBidderPrice), eq(null), eq("BAD"), eq("CUR")); @@ -1423,8 +1525,8 @@ public void shouldRespondWithOneBidAndErrorWhenBidResponseContainsOneUnsupported .flatExtracting(BidderSeatBid::getBids) .containsOnly(expectedBidderBid); - final BidderError expectedError = BidderError.generic("Unable to covert bid currency CUR to desired ad" + - " server currency BAD. no currency conversion available"); + final BidderError expectedError = BidderError.generic("Unable to covert bid currency CUR to desired ad" + + " server currency BAD. no currency conversion available"); assertThat(argumentCaptor.getValue()) .extracting(BidderResponse::getSeatBid) .flatExtracting(BidderSeatBid::getErrors) @@ -1451,13 +1553,14 @@ public void shouldUpdateBidPriceWithCurrencyConversionAndAddErrorAboutMultipleCu // then final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), any(), anyBoolean()); + verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), anyBoolean(), anyLong(), + anyBoolean(), any()); verify(currencyService).convertCurrency(eq(bidderPrice), eq(null), eq("CUR1"), eq("USD")); assertThat(argumentCaptor.getValue()).hasSize(1); - final BidderError expectedError = BidderError.badInput("Cur parameter contains more than one currency." + - " CUR1 will be used"); + final BidderError expectedError = BidderError.badInput("Cur parameter contains more than one currency." + + " CUR1 will be used"); final BidderSeatBid firstSeatBid = argumentCaptor.getValue().get(0).getSeatBid(); assertThat(firstSeatBid.getBids()) .extracting(BidderBid::getBid) @@ -1496,7 +1599,8 @@ public void shouldUpdateBidPriceWithCurrencyConversionForMultipleBid() { // then final ArgumentCaptor> argumentCaptor = ArgumentCaptor.forClass(List.class); - verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), any(), anyBoolean()); + verify(bidResponseCreator).create(argumentCaptor.capture(), any(), any(), any(), any(), anyBoolean(), anyLong(), + anyBoolean(), any()); verify(currencyService).convertCurrency(eq(bidder1Price), eq(null), eq("USD"), eq("EUR")); verify(currencyService).convertCurrency(eq(bidder2Price), eq(null), eq("USD"), eq("GBP")); verify(currencyService).convertCurrency(eq(bidder3Price), eq(null), eq("USD"), eq("USD")); @@ -1643,7 +1747,7 @@ public void shouldPassResponseToPostProcessor() { // then verify(bidResponsePostProcessor).postProcess(any(), same(uidsCookie), same(bidRequest), any(), - eq(Account.builder().id("accountId").eventsEnabled(false).build())); + eq(Account.builder().id("accountId").eventsEnabled(true).build())); } @Test @@ -1657,6 +1761,7 @@ public void shouldReturnBidsWithAdjustedPricesWhenAdjustmentFactorPresent() { builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .aliases(emptyMap()) .bidadjustmentfactors(singletonMap("bidder", BigDecimal.valueOf(2.468))) + .auctiontimestamp(1000L) .build())))); givenBidResponseCreator(singletonList(Bid.builder().price(BigDecimal.valueOf(4.936)).build())); @@ -1682,6 +1787,7 @@ public void shouldReturnBidsWithoutAdjustingPricesWhenAdjustmentFactorNotPresent final BidRequest bidRequest = givenBidRequest(singletonList(givenImp(singletonMap("bidder", 2), identity())), builder -> builder.ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .aliases(emptyMap()) + .auctiontimestamp(1000L) .bidadjustmentfactors(singletonMap("some-other-bidder", BigDecimal.TEN)) .build())))); @@ -1696,7 +1802,7 @@ public void shouldReturnBidsWithoutAdjustingPricesWhenAdjustmentFactorNotPresent } private AuctionContext givenRequestContext(BidRequest bidRequest) { - return givenRequestContext(bidRequest, Account.builder().id("accountId").eventsEnabled(false).build()); + return givenRequestContext(bidRequest, Account.builder().id("accountId").eventsEnabled(true).build()); } private AuctionContext givenRequestContext(BidRequest bidRequest, Account account) { @@ -1745,6 +1851,14 @@ private void givenBidder(String bidderName, Bidder bidder, BidderSeatBid resp .willReturn(Future.succeededFuture(response)); } + private static SeatBid givenSeatBid(List bids, + Function seatBidCustomizer) { + return seatBidCustomizer.apply(SeatBid.builder() + .seat("someBidder") + .bid(bids)) + .build(); + } + private static BidderSeatBid givenSeatBid(List bids) { return BidderSeatBid.of(bids, emptyList(), emptyList()); } @@ -1799,12 +1913,14 @@ private static ExtRequestTargeting givenTargeting(boolean includebidderkeys) { } private void givenBidResponseCreator(List bids) { - given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), any(), anyBoolean())) + given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), anyBoolean(), anyLong(), anyBoolean(), + any())) .willReturn(Future.succeededFuture(givenBidResponseWithBids(bids))); } private void givenBidResponseCreator(Map> errors) { - given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), any(), anyBoolean())) + given(bidResponseCreator.create(anyList(), any(), any(), any(), any(), anyBoolean(), anyLong(), anyBoolean(), + any())) .willReturn(Future.succeededFuture(givenBidResponseWithError(errors))); } @@ -1815,18 +1931,10 @@ private static BidResponse givenBidResponseWithBids(List bids) { .build(); } - private static SeatBid givenSeatBid(List bids, - Function seatBidCustomizer) { - return seatBidCustomizer.apply(SeatBid.builder() - .seat("someBidder") - .bid(bids)) - .build(); - } - private static BidResponse givenBidResponseWithError(Map> errors) { return BidResponse.builder() .seatbid(emptyList()) - .ext(mapper.valueToTree(ExtBidResponse.of(null, errors, null, null, null))) + .ext(mapper.valueToTree(ExtBidResponse.of(null, errors, null, null, null, null))) .build(); } } diff --git a/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java b/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java index 6bb12539bd7..5d39546db4c 100644 --- a/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java +++ b/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java @@ -166,7 +166,6 @@ public void secureFromShouldReturnOneIfXForwardedProtoIsHttps() { assertThat(extractor.secureFrom(httpRequest)).isEqualTo(1); } - @Test public void secureFromShouldReturnOneIfConnectedViaSSL() { // given diff --git a/src/test/java/org/prebid/server/auction/InterstitialProcessorTest.java b/src/test/java/org/prebid/server/auction/InterstitialProcessorTest.java index de1a45dc210..a97d975ab23 100644 --- a/src/test/java/org/prebid/server/auction/InterstitialProcessorTest.java +++ b/src/test/java/org/prebid/server/auction/InterstitialProcessorTest.java @@ -225,8 +225,8 @@ public void processShouldThrowInvalidRequestExceptionWhenCantFindMaxWidthOrMaxHe // when and then assertThatThrownBy(() -> interstitialProcessor.process(bidRequest)) .isExactlyInstanceOf(InvalidRequestException.class) - .hasMessageEndingWith("Unable to read max interstitial size for Imp id=impId (No Device sizes and no " + - "Format objects)"); + .hasMessageEndingWith("Unable to read max interstitial size for Imp id=impId (No Device sizes and no " + + "Format objects)"); } @Test diff --git a/src/test/java/org/prebid/server/auction/PrivacyEnforcementServiceTest.java b/src/test/java/org/prebid/server/auction/PrivacyEnforcementServiceTest.java index 42ea2f5bcf7..9093c2925a2 100644 --- a/src/test/java/org/prebid/server/auction/PrivacyEnforcementServiceTest.java +++ b/src/test/java/org/prebid/server/auction/PrivacyEnforcementServiceTest.java @@ -14,7 +14,8 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.VertxTest; -import org.prebid.server.auction.model.PrivacyEnforcementResult; +import org.prebid.server.auction.model.AuctionContext; +import org.prebid.server.auction.model.BidderPrivacyResult; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.PreBidException; @@ -22,21 +23,27 @@ import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.metric.Metrics; import org.prebid.server.privacy.ccpa.Ccpa; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; -import org.prebid.server.proto.response.BidderInfo; +import org.prebid.server.proto.openrtb.ext.request.ExtUserDigiTrust; +import org.prebid.server.proto.openrtb.ext.request.ExtUserEid; +import org.prebid.server.proto.openrtb.ext.request.ExtUserPrebid; +import org.prebid.server.settings.model.Account; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; -import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.function.Function; +import java.util.Set; +import java.util.function.UnaryOperator; +import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.Collections.singleton; @@ -44,22 +51,19 @@ import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.entry; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anySet; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; public class PrivacyEnforcementServiceTest extends VertxTest { - private final static String BIDDER_NAME = "someBidder"; - private final static String BUYER_UID = "uidval"; + private static final String BIDDER_NAME = "someBidder"; + private static final String BUYER_UID = "uidval"; @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); @@ -67,54 +71,127 @@ public class PrivacyEnforcementServiceTest extends VertxTest { @Mock private BidderCatalog bidderCatalog; @Mock - private Metrics metrics; + private TcfDefinerService tcfDefinerService; @Mock - private GdprService gdprService; + private Metrics metrics; - private Timeout timeout; private PrivacyEnforcementService privacyEnforcementService; + private Timeout timeout; + @Before public void setUp() { - given(bidderCatalog.bidderInfoByName(anyString())).willReturn(givenBidderInfo(15, true)); - - given(gdprService.isGdprEnforced(any(), any(), any())).willReturn(true); - given(gdprService.resultByVendor(any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, singletonMap(15, false), null))); + given(tcfDefinerService.resultForBidderNames(anySet(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, restrictDeviceAndUser()), null))); timeout = new TimeoutFactory(Clock.fixed(Instant.now(), ZoneId.systemDefault())).create(500); - privacyEnforcementService = new PrivacyEnforcementService(gdprService, bidderCatalog, metrics, jacksonMapper, - false, false - ); + privacyEnforcementService = new PrivacyEnforcementService( + bidderCatalog, tcfDefinerService, metrics, jacksonMapper, false, false); + } + + @Test + public void shouldMaskForCoppaWhenDeviceLmtIsOneAndRegsCoppaIsOneAndDoesNotCallTcfServices() { + // given + final ExtUser extUser = ExtUser.builder().build(); + final User user = notMaskedUser(); + final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); + final Regs regs = Regs.of(1, mapper.valueToTree(ExtRegs.of(1, null))); + final Map bidderToUser = singletonMap(BIDDER_NAME, user); + + final BidRequest bidRequest = givenBidRequest(givenSingleImp( + singletonMap(BIDDER_NAME, 1)), + bidRequestBuilder -> bidRequestBuilder + .user(user) + .device(device) + .regs(regs)); + + final AuctionContext context = auctionContext(bidRequest); + + // when + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) + .result(); + + // then + final BidderPrivacyResult expected = BidderPrivacyResult.builder() + .requestBidder(BIDDER_NAME) + .user(userCoppaMasked()) + .device(givenCoppaMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1))) + .build(); + assertThat(result).isEqualTo(singletonList(expected)); + + verifyZeroInteractions(tcfDefinerService); + } + + @Test + public void shouldMaskForCcpaWhenUsPolicyIsValidAndCoppaIsZeroAndDoesNotCallTcfServices() { + // given + privacyEnforcementService = new PrivacyEnforcementService(bidderCatalog, tcfDefinerService, metrics, + jacksonMapper, false, + true); + final ExtUser extUser = ExtUser.builder().build(); + final User user = notMaskedUser(); + final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); + final Regs regs = Regs.of(0, mapper.valueToTree(ExtRegs.of(1, "1YYY"))); + final Map bidderToUser = singletonMap(BIDDER_NAME, user); + + final BidRequest bidRequest = givenBidRequest(givenSingleImp( + singletonMap(BIDDER_NAME, 1)), + bidRequestBuilder -> bidRequestBuilder + .user(user) + .device(device) + .regs(regs)); + + final AuctionContext context = auctionContext(bidRequest); + + // when + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) + .result(); + + // then + final BidderPrivacyResult expected = BidderPrivacyResult.builder() + .requestBidder(BIDDER_NAME) + .user(userTcfMasked()) + .device(givenTcfMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1))) + .build(); + assertThat(result).isEqualTo(singletonList(expected)); + + verifyZeroInteractions(tcfDefinerService); } @Test - public void shouldTolerateEmptyBidderToUserMap() { - // given and when + public void shouldTolerateEmptyBidderToBidderPrivacyResultList() { + // given final BidRequest bidRequest = givenBidRequest(emptyList(), bidRequestBuilder -> bidRequestBuilder .user(null) .device(null) .regs(null)); - final Map result = privacyEnforcementService - .mask(emptyMap(), null, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout) + final AuctionContext context = auctionContext(bidRequest); + + // when + final List result = privacyEnforcementService + .mask(context, emptyMap(), null, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(isNull(), eq(true), eq(singleton(15))); - verify(gdprService).resultByVendor(eq(singleton(15)), isNull(), any(), any(), eq(timeout)); - verifyNoMoreInteractions(gdprService); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); + verifyNoMoreInteractions(tcfDefinerService); - assertThat(result).isEqualTo(emptyMap()); + assertThat(result).isEqualTo(emptyList()); } @Test - public void shouldNotMaskWhenDeviceLmtIsNullAndExtRegsGdprIsOneAndGdprEnforcedIsTrueAndResultByVendorWithoutEnforcement() { + public void shouldNotMaskWhenDeviceLmtIsNullAndExtRegsGdprIsOneAndNotGdprEnforcedAndResultByVendorNoEnforcement() { // given - given(gdprService.resultByVendor(any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, singletonMap(15, true), null))); + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, PrivacyEnforcementAction.allowAll()), null))); final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); @@ -122,65 +199,81 @@ public void shouldNotMaskWhenDeviceLmtIsNullAndExtRegsGdprIsOneAndGdprEnforcedIs final Regs regs = Regs.of(null, mapper.valueToTree(ExtRegs.of(1, null))); final Map bidderToUser = singletonMap(BIDDER_NAME, user); - final BidRequest bidRequest = givenBidRequest(givenSingleImp( - singletonMap(BIDDER_NAME, 1)), + final BidRequest bidRequest = givenBidRequest( + givenSingleImp(singletonMap(BIDDER_NAME, 1)), bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) .regs(regs)); + final AuctionContext context = auctionContext(bidRequest); + // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(eq("1"), eq(true), eq(singleton(15))); - verify(gdprService).resultByVendor(eq(singleton(15)), eq("1"), any(), any(), eq(timeout)); - verifyNoMoreInteractions(gdprService); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(notMaskedUser()) + .device(notMaskedDevice()) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(user, device); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), eq("1"), any(), any(), any(), eq(timeout)); } @Test - public void shouldNotMaskWhenExtDeviceLmtIsNullAndGdprServiceRespondIsGdprEnforcedWithFalse() { + public void shouldNotMaskWhenDeviceLmtIsZeroAndRegsCoppaIsZeroAndExtRegsGdprIsZeroAndTcfDefinerServiceAllowAll() { // given - given(gdprService.isGdprEnforced(any(), any(), any())).willReturn(false); + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, PrivacyEnforcementAction.allowAll()), null))); + final Regs regs = Regs.of(0, mapper.valueToTree(ExtRegs.of(0, null))); final User user = notMaskedUser(); - final Device device = notMaskedDevice(); + final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(0)); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( singletonMap(BIDDER_NAME, 1)), bidRequestBuilder -> bidRequestBuilder .user(user) - .device(device)); + .device(device) + .regs(regs)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Map result = privacyEnforcementService - .mask(bidderToUser, null, singletonList(BIDDER_NAME), emptyMap(), bidRequest, false, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, null, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(isNull(), eq(false), eq(singleton(15))); - verifyNoMoreInteractions(gdprService); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(notMaskedUser()) + .device(givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(0))) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(user, device); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), eq("0"), any(), any(), any(), eq(timeout)); } @Test - public void shouldNotMaskWhenExtRegsGdprIsOneDeviceLmtIsNullAndGdprServiceRespondIsGdprEnforcedWithFalse() { + public void shouldMaskForTcfWhenTcfServiceAllowAllAndDeviceLmtIsOne() { // given - given(gdprService.isGdprEnforced(any(), any(), any())).willReturn(false); + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, PrivacyEnforcementAction.allowAll()), null))); + final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); - final Device device = notMaskedDevice(); - final Regs regs = Regs.of(null, mapper.valueToTree(ExtRegs.of(1, null))); + final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); + final Regs regs = Regs.of(0, null); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( @@ -190,28 +283,31 @@ public void shouldNotMaskWhenExtRegsGdprIsOneDeviceLmtIsNullAndGdprServiceRespon .device(device) .regs(regs)); + final AuctionContext context = auctionContext(bidRequest); + // when - final Map result = privacyEnforcementService - .mask(bidderToUser, null, singletonList(BIDDER_NAME), emptyMap(), bidRequest, false, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(eq("1"), eq(false), eq(singleton(15))); - verifyNoMoreInteractions(gdprService); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(userTcfMasked()) + .device(givenTcfMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1))) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(user, device); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldNotMaskWhenDeviceLmtIsZeroAndRegsCoppaIsZeroAndExtRegsGdprIsZeroAndGdprEnforcedIsFalse() { + public void shouldMaskForTcfWhenTcfDefinerServiceRestrictDeviceAndUser() { // given - given(gdprService.isGdprEnforced(any(), any(), any())).willReturn(false); - - final Regs regs = Regs.of(0, mapper.valueToTree(ExtRegs.of(0, null))); + final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); - final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(0)); + final Device device = notMaskedDevice(); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( @@ -219,99 +315,126 @@ public void shouldNotMaskWhenDeviceLmtIsZeroAndRegsCoppaIsZeroAndExtRegsGdprIsZe bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) - .regs(regs)); + .regs(null)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Map result = privacyEnforcementService - .mask(bidderToUser, null, singletonList(BIDDER_NAME), emptyMap(), bidRequest, false, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(eq("0"), eq(false), eq(singleton(15))); - verifyNoMoreInteractions(gdprService); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(userTcfMasked()) + .device(deviceTcfMasked()) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(user, device); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldResolveBidderNameByAliases() { + public void shouldMaskUserIdsWhenTcfDefinerServiceRestrictUserIds() { // given - final User user = notMaskedUser(); + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.allowAll(); + privacyEnforcementAction.setRemoveUserIds(true); + + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, privacyEnforcementAction), null))); + + final ExtUser extUser = notMaskedExtUser(); + final User user = notMaskedUser(extUser); final Device device = notMaskedDevice(); - final Regs regs = Regs.of(null, mapper.valueToTree(ExtRegs.of(1, null))); - final String alias = "alias"; - final Map bidderToUser = singletonMap(alias, user); - final Map aliases = singletonMap(alias, BIDDER_NAME); + final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( singletonMap(BIDDER_NAME, 1)), bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) - .regs(regs)); + .regs(null)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Map result = privacyEnforcementService - .mask(bidderToUser, null, singletonList(BIDDER_NAME), aliases, bidRequest, true, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(bidderCatalog, times(2)).bidderInfoByName(BIDDER_NAME); - verifyNoMoreInteractions(bidderCatalog); - verify(gdprService).isGdprEnforced(eq("1"), eq(true), eq(singleton(15))); - verify(gdprService).resultByVendor(eq(singleton(15)), eq("1"), any(), any(), eq(timeout)); - verifyNoMoreInteractions(gdprService); - verify(metrics).updateGdprMaskedMetric(BIDDER_NAME); - verifyNoMoreInteractions(metrics); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(givenNotMaskedUser(userBuilder -> userBuilder.buyeruid(null) + .ext(mapper.valueToTree(extUserTcfMasked())))) + .device(notMaskedDevice()) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(userGdprMasked(), deviceGdprMasked()); - assertThat(result).hasSize(1) - .containsOnly(entry(alias, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldMaskForGdprWhenGdprEnforcedIsTrueAndResultByVendorWithEnforcementResponse() { + public void shouldMaskUserIdsWhenTcfDefinerServiceRestrictUserIdsAndReturnNullWhenAllValuesMasked() { // given - final ExtUser extUser = ExtUser.builder().build(); - final User user = notMaskedUser(); - final Device device = notMaskedDevice(); + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.allowAll(); + privacyEnforcementAction.setRemoveUserIds(true); + + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, privacyEnforcementAction), null))); + + final ExtUser extUser = ExtUser.builder() + .eids(singletonList(ExtUserEid.of("Test", "id", emptyList(), null))) + .digitrust(ExtUserDigiTrust.of("idDigit", 12, 23)) + .build(); + final User user = User.builder() + .buyeruid(BUYER_UID) + .ext(mapper.valueToTree(extUser)) + .build(); + final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( singletonMap(BIDDER_NAME, 1)), bidRequestBuilder -> bidRequestBuilder .user(user) - .device(device) .regs(null)); + final AuctionContext context = auctionContext(bidRequest); + // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(isNull(), eq(true), eq(singleton(15))); - verify(gdprService).resultByVendor(eq(singleton(15)), isNull(), any(), any(), eq(timeout)); - verifyNoMoreInteractions(gdprService); - verify(metrics).updateGdprMaskedMetric(eq(BIDDER_NAME)); - verifyNoMoreInteractions(metrics); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(userGdprMasked(), deviceGdprMasked()); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldMaskForGdprWhenGdprServiceRespondIsGdprEnforcedWithFalseAndDeviceLmtIsOne() { + public void shouldMaskGeoWhenTcfDefinerServiceRestrictGeo() { // given - given(gdprService.isGdprEnforced(any(), any(), any())).willReturn(false); + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.allowAll(); + privacyEnforcementAction.setMaskGeo(true); + + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, privacyEnforcementAction), null))); final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); - final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final Regs regs = Regs.of(0, null); + final Device device = notMaskedDevice(); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( @@ -319,34 +442,40 @@ public void shouldMaskForGdprWhenGdprServiceRespondIsGdprEnforcedWithFalseAndDev bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) - .regs(regs)); + .regs(null)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, false, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(isNull(), eq(false), eq(singleton(15))); - verifyNoMoreInteractions(gdprService); - verify(metrics).updateGdprMaskedMetric(eq(BIDDER_NAME)); - verifyNoMoreInteractions(metrics); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(givenNotMaskedUser(userBuilder -> userBuilder.geo(userTcfMasked().getGeo()))) + .device(givenNotMaskedDevice(deviceBuilder -> deviceBuilder.geo(deviceTcfMasked().getGeo()))) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - final Device expectedDevice = givenGdprMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(userGdprMasked(), expectedDevice); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldMaskForGdprAndCoppaWhenGdprEnforcedIsFalseAndDeviceLmtIsOne() { + public void shouldMaskDeviceIpWhenTcfDefinerServiceRestrictDeviceIp() { // given - given(gdprService.isGdprEnforced(any(), any(), any())).willReturn(false); + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.allowAll(); + privacyEnforcementAction.setMaskDeviceIp(true); + + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, privacyEnforcementAction), null))); final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); - final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final Regs regs = Regs.of(0, null); + final Device device = notMaskedDevice(); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( @@ -354,63 +483,85 @@ public void shouldMaskForGdprAndCoppaWhenGdprEnforcedIsFalseAndDeviceLmtIsOne() bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) - .regs(regs)); + .regs(null)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, false, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verify(gdprService).isGdprEnforced(isNull(), eq(false), eq(singleton(15))); - verifyNoMoreInteractions(gdprService); - verify(metrics).updateGdprMaskedMetric(eq(BIDDER_NAME)); - verifyNoMoreInteractions(metrics); + final Device deviceTcfMasked = deviceTcfMasked(); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(notMaskedUser()) + .device(givenNotMaskedDevice( + deviceBuilder -> deviceBuilder.ip(deviceTcfMasked.getIp()).ipv6(deviceTcfMasked.getIpv6()))) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); - //Coppa includes all masked fields for Gdpr - final Device expectedDevice = givenGdprMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(userGdprMasked(), expectedDevice); - assertThat(result).hasSize(1) - .containsOnly(entry(BIDDER_NAME, expected)); + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldNotReturnUserIfMaskingAppliedAndUserBecameEmptyObject() { + public void shouldMaskDeviceInfoWhenTcfDefinerServiceRestrictDeviceInfo() { // given - final User user = User.builder() - .buyeruid("buyeruid") - .build(); - final Regs regs = Regs.of(1, null); + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.allowAll(); + privacyEnforcementAction.setMaskDeviceInfo(true); + + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, privacyEnforcementAction), null))); + + final ExtUser extUser = ExtUser.builder().build(); + final User user = notMaskedUser(); + final Device device = notMaskedDevice(); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( singletonMap(BIDDER_NAME, 1)), bidRequestBuilder -> bidRequestBuilder .user(user) - .regs(regs)); + .device(device) + .regs(null)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Map result = privacyEnforcementService - .mask(bidderToUser, null, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - assertThat(result.values()).hasSize(1) - .extracting(PrivacyEnforcementResult::getUser) - .containsNull(); + final Device deviceInfoMasked = givenNotMaskedDevice(deviceBuilder -> deviceBuilder + .ifa(null) + .macsha1(null).macmd5(null) + .dpidsha1(null).dpidmd5(null) + .didsha1(null).didmd5(null)); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .user(notMaskedUser()) + .device(deviceInfoMasked) + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); + + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldReturnFailedFutureWhenGdprServiceIsReturnFailedFuture() { + public void shouldRerunEmptyResultWhenTcfDefinerServiceRestrictRequest() { // given - given(gdprService.resultByVendor(any(), any(), any(), any(), any())) - .willReturn(Future.failedFuture(new InvalidRequestException( - "Error when retrieving allowed purpose ids in a reason of invalid consent string"))); + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(BIDDER_NAME, PrivacyEnforcementAction.restrictAll()), null))); final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); - final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final Regs regs = Regs.of(0, null); + final Device device = notMaskedDevice(); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( @@ -418,74 +569,152 @@ public void shouldReturnFailedFutureWhenGdprServiceIsReturnFailedFuture() { bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) - .regs(regs)); + .regs(null)); + + final AuctionContext context = auctionContext(bidRequest); // when - final Future> firstFuture = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout); + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) + .result(); // then - verify(gdprService).isGdprEnforced(isNull(), eq(true), eq(singleton(15))); - verify(gdprService).resultByVendor(eq(singleton(15)), isNull(), any(), any(), eq(timeout)); - verifyNoMoreInteractions(gdprService); - verifyZeroInteractions(metrics); - assertThat(firstFuture.failed()).isTrue(); - assertThat(firstFuture.cause().getMessage()) - .isEqualTo("Error when retrieving allowed purpose ids in a reason of invalid consent string"); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .requestBidder(BIDDER_NAME) + .blockedRequestByTcf(true) + .blockedAnalyticsByTcf(true) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); + + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); } @Test - public void shouldThrowPrebidExceptionWhenExtRegsCannotBeParsed() { + public void shouldResolveBidderNameAndVendorIdsByAliases() { // given - final BidRequest bidRequest = givenBidRequest(givenSingleImp(singletonMap("someBidder", 1)), + final String requestBidder1Name = "bidder1"; + final String requestBidder1Alias = "bidder1Alias"; + final String bidder2Name = "bidder2NotInRequest"; + final String bidder2Alias = "bidder2Alias"; + final Integer bidder2AliasVendorId = 220; + final String requestBidder3Name = "bidder3"; + + final User user = notMaskedUser(); + final Device device = notMaskedDevice(); + final Regs regs = Regs.of(0, mapper.valueToTree(ExtRegs.of(1, null))); + final HashMap bidderToId = new HashMap<>(); + bidderToId.put(requestBidder1Name, 1); + bidderToId.put(requestBidder1Alias, 2); + bidderToId.put(bidder2Alias, 3); + bidderToId.put(requestBidder3Name, 4); + final BidRequest bidRequest = givenBidRequest( + givenSingleImp(bidderToId), bidRequestBuilder -> bidRequestBuilder - .regs(Regs.of(null, mapper.createObjectNode().put("gdpr", "invalid")))); + .user(user) + .device(device) + .regs(regs)); - // when and then - assertThatExceptionOfType(PreBidException.class) - .isThrownBy(() -> privacyEnforcementService.mask(emptyMap(), null, singletonList(BIDDER_NAME), - emptyMap(), bidRequest, true, timeout)) - .withMessageStartingWith("Error decoding bidRequest.regs.ext:"); + final AuctionContext context = auctionContext(bidRequest); + + final Map bidderToUser = new HashMap<>(); + bidderToUser.put(requestBidder1Name, notMaskedUser()); + bidderToUser.put(requestBidder1Alias, notMaskedUser()); + bidderToUser.put(bidder2Alias, notMaskedUser()); + bidderToUser.put(requestBidder3Name, notMaskedUser()); + final Map aliases = new HashMap<>(); + final Map aliasgvlids = new HashMap<>(); + aliases.put(requestBidder1Alias, requestBidder1Name); + aliases.put(bidder2Alias, bidder2Name); + aliasgvlids.put(bidder2Alias, bidder2AliasVendorId); + + final Map bidderNameToTcfEnforcement = new HashMap<>(); + bidderNameToTcfEnforcement.put(requestBidder1Name, PrivacyEnforcementAction.restrictAll()); + bidderNameToTcfEnforcement.put(requestBidder1Alias, PrivacyEnforcementAction.restrictAll()); + bidderNameToTcfEnforcement.put(bidder2Alias, restrictDeviceAndUser()); + bidderNameToTcfEnforcement.put(requestBidder3Name, PrivacyEnforcementAction.allowAll()); + + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, bidderNameToTcfEnforcement, null))); + + // when + final List bidders = + asList(requestBidder1Name, requestBidder1Alias, bidder2Alias, requestBidder3Name); + final List result = privacyEnforcementService + .mask(context, bidderToUser, null, bidders, BidderAliases.of(aliases, aliasgvlids)) + .result(); + + // then + final BidderPrivacyResult expectedBidder1Masked = BidderPrivacyResult.builder() + .requestBidder(requestBidder1Name) + .blockedAnalyticsByTcf(true) + .blockedRequestByTcf(true) + .build(); + final BidderPrivacyResult expectedBidderAlias1Masked = BidderPrivacyResult.builder() + .requestBidder(requestBidder1Alias) + .blockedAnalyticsByTcf(true) + .blockedRequestByTcf(true) + .build(); + final BidderPrivacyResult expectedBidderAlias2Masked = BidderPrivacyResult.builder() + .requestBidder(bidder2Alias) + .user(userTcfMasked()) + .device(deviceTcfMasked()) + .build(); + final BidderPrivacyResult expectedBidder3Masked = BidderPrivacyResult.builder() + .requestBidder(requestBidder3Name) + .user(notMaskedUser()) + .device(notMaskedDevice()) + .build(); + assertThat(result).containsOnly( + expectedBidder1Masked, expectedBidderAlias1Masked, expectedBidderAlias2Masked, expectedBidder3Masked); + + final Set bidderNames = new HashSet<>(asList( + requestBidder1Name, requestBidder1Alias, bidder2Alias, requestBidder3Name)); + verify(tcfDefinerService) + .resultForBidderNames(eq(bidderNames), any(), eq("1"), any(), any(), isNull(), eq(timeout)); } @Test - public void shouldMaskForCoppaWhenDeviceLmtIsOneAndRegsCoppaIsOneAndDoesNotCallGdprServices() { + public void shouldNotReturnUserIfMaskingAppliedAndUserBecameEmptyObject() { // given - final ExtUser extUser = ExtUser.builder().build(); - final User user = notMaskedUser(); - final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final Regs regs = Regs.of(1, mapper.valueToTree(ExtRegs.of(1, null))); + final User user = User.builder() + .buyeruid("buyeruid") + .build(); + final Regs regs = Regs.of(1, null); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( singletonMap(BIDDER_NAME, 1)), bidRequestBuilder -> bidRequestBuilder .user(user) - .device(device) .regs(regs)); + final AuctionContext context = auctionContext(bidRequest); + // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, null, singletonList(BIDDER_NAME), BidderAliases.of(null, null)) .result(); // then - verifyZeroInteractions(gdprService); - final Device expectedDevice = givenCoppaMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(userCoppaMasked(), expectedDevice); - assertThat(result).hasSize(1).containsOnly(entry(BIDDER_NAME, expected)); + final BidderPrivacyResult expectedBidderPrivacy = BidderPrivacyResult.builder() + .requestBidder(BIDDER_NAME) + .build(); + assertThat(result).containsOnly(expectedBidderPrivacy); } @Test - public void shouldMaskForCcpaAndDoesNotCallGdprServicesWhenUsPolicyIsValidAndGdprIsEnforcedAndCOPPAIsZero() { + public void shouldReturnFailedFutureWhenTcfServiceIsReturnFailedFuture() { // given - privacyEnforcementService = new PrivacyEnforcementService(gdprService, bidderCatalog, metrics, jacksonMapper, - false, true); + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.failedFuture(new InvalidRequestException( + "Error when retrieving allowed purpose ids in a reason of invalid consent string"))); + final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); final Device device = givenNotMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final Regs regs = Regs.of(0, mapper.valueToTree(ExtRegs.of(1, "1YYY"))); + final Regs regs = Regs.of(0, null); final Map bidderToUser = singletonMap(BIDDER_NAME, user); final BidRequest bidRequest = givenBidRequest(givenSingleImp( @@ -495,16 +724,36 @@ public void shouldMaskForCcpaAndDoesNotCallGdprServicesWhenUsPolicyIsValidAndGdp .device(device) .regs(regs)); + final AuctionContext context = auctionContext(bidRequest); + // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, singletonList(BIDDER_NAME), emptyMap(), bidRequest, true, timeout) - .result(); + final Future> firstFuture = privacyEnforcementService + .mask(context, bidderToUser, extUser, singletonList(BIDDER_NAME), BidderAliases.of(null, null)); // then - verifyZeroInteractions(gdprService); - final Device expectedDevice = givenGdprMaskedDevice(deviceBuilder -> deviceBuilder.lmt(1)); - final PrivacyEnforcementResult expected = PrivacyEnforcementResult.of(userGdprMasked(), expectedDevice); - assertThat(result).hasSize(1).containsOnly(entry(BIDDER_NAME, expected)); + assertThat(firstFuture.failed()).isTrue(); + assertThat(firstFuture.cause().getMessage()) + .isEqualTo("Error when retrieving allowed purpose ids in a reason of invalid consent string"); + + verify(tcfDefinerService) + .resultForBidderNames(eq(singleton(BIDDER_NAME)), any(), isNull(), any(), any(), any(), eq(timeout)); + verifyNoMoreInteractions(tcfDefinerService); + } + + @Test + public void shouldThrowPrebidExceptionWhenExtRegsCannotBeParsed() { + // given + final BidRequest bidRequest = givenBidRequest(givenSingleImp(singletonMap("someBidder", 1)), + bidRequestBuilder -> bidRequestBuilder + .regs(Regs.of(null, mapper.createObjectNode().put("gdpr", "invalid")))); + + final AuctionContext context = auctionContext(bidRequest); + + // when and then + assertThatExceptionOfType(PreBidException.class) + .isThrownBy(() -> privacyEnforcementService.mask( + context, emptyMap(), null, singletonList(BIDDER_NAME), BidderAliases.of(null, null))) + .withMessageStartingWith("Error decoding bidRequest.regs.ext:"); } @Test @@ -519,21 +768,21 @@ public void isCcpaEnforcedShouldReturnFalseWhenEnforcedPropertyIsFalse() { @Test public void isCcpaEnforcedShouldReturnFalseWhenEnforcedPropertyIsTrue() { // given - privacyEnforcementService = new PrivacyEnforcementService(gdprService, bidderCatalog, metrics, jacksonMapper, - false, true); + privacyEnforcementService = new PrivacyEnforcementService(bidderCatalog, tcfDefinerService, metrics, + jacksonMapper, false, + true); final Ccpa ccpa = Ccpa.of("1YNY"); // when and then assertThat(privacyEnforcementService.isCcpaEnforced(ccpa)).isFalse(); } - @Test public void isCcpaEnforcedShouldReturnTrueWhenEnforcedPropertyIsTrueAndCcpaReturnsTrue() { // given - privacyEnforcementService = new PrivacyEnforcementService(gdprService, bidderCatalog, metrics, jacksonMapper, - false, true - ); + privacyEnforcementService = new PrivacyEnforcementService(bidderCatalog, tcfDefinerService, metrics, + jacksonMapper, false, + true); final Ccpa ccpa = Ccpa.of("1YYY"); // when and then @@ -546,17 +795,14 @@ public void shouldReturnCorrectMaskedForMultipleBidders() { final String bidder1Name = "bidder1"; final String bidder2Name = "bidder2"; final String bidder3Name = "bidder3"; - given(bidderCatalog.bidderInfoByName(bidder1Name)).willReturn(givenBidderInfo(1, true)); - given(bidderCatalog.bidderInfoByName(bidder2Name)).willReturn(givenBidderInfo(2, true)); - given(bidderCatalog.bidderInfoByName(bidder3Name)).willReturn(givenBidderInfo(3, false)); - - final HashMap vendorIdToGdprEnforce = new HashMap<>(); - vendorIdToGdprEnforce.put(1, false); - vendorIdToGdprEnforce.put(2, false); - vendorIdToGdprEnforce.put(3, true); - given(gdprService.resultByVendor(any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, vendorIdToGdprEnforce, null))); + final Map vendorIdToTcfEnforcement = new HashMap<>(); + vendorIdToTcfEnforcement.put(bidder1Name, PrivacyEnforcementAction.restrictAll()); + vendorIdToTcfEnforcement.put(bidder2Name, restrictDeviceAndUser()); + vendorIdToTcfEnforcement.put(bidder3Name, PrivacyEnforcementAction.allowAll()); + given(tcfDefinerService.resultForBidderNames(any(), any(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, vendorIdToTcfEnforcement, null))); final ExtUser extUser = ExtUser.builder().build(); final User user = notMaskedUser(); @@ -566,37 +812,56 @@ public void shouldReturnCorrectMaskedForMultipleBidders() { bidderToUser.put(bidder1Name, notMaskedUser()); bidderToUser.put(bidder2Name, notMaskedUser()); bidderToUser.put(bidder3Name, notMaskedUser()); - final List bidders = Arrays.asList(bidder1Name, bidder2Name, bidder3Name); - - final BidRequest bidRequest = givenBidRequest(givenSingleImp( - singletonMap(BIDDER_NAME, 1)), + final List bidders = asList(bidder1Name, bidder2Name, bidder3Name); + + final HashMap bidderToId = new HashMap<>(); + bidderToId.put(bidder1Name, 1); + bidderToId.put(bidder2Name, 2); + bidderToId.put(bidder3Name, 3); + final BidRequest bidRequest = givenBidRequest( + givenSingleImp(bidderToId), bidRequestBuilder -> bidRequestBuilder .user(user) .device(device) .regs(regs)); + final AuctionContext context = auctionContext(bidRequest); + // when - final Map result = privacyEnforcementService - .mask(bidderToUser, extUser, bidders, emptyMap(), bidRequest, true, timeout) + final List result = privacyEnforcementService + .mask(context, bidderToUser, extUser, bidders, BidderAliases.of(null, null)) .result(); // then - final PrivacyEnforcementResult expectedMasked = PrivacyEnforcementResult.of( - userGdprMasked(), deviceGdprMasked()); - final PrivacyEnforcementResult expectedNotMasked = PrivacyEnforcementResult.of(user, device); + final BidderPrivacyResult expectedBidder1Masked = BidderPrivacyResult.builder() + .requestBidder(bidder1Name) + .blockedAnalyticsByTcf(true) + .blockedRequestByTcf(true) + .build(); + final BidderPrivacyResult expectedBidder2Masked = BidderPrivacyResult.builder() + .requestBidder(bidder2Name) + .user(userTcfMasked()) + .device(deviceTcfMasked()) + .build(); + final BidderPrivacyResult expectedBidder3Masked = BidderPrivacyResult.builder() + .requestBidder(bidder3Name) + .user(notMaskedUser()) + .device(notMaskedDevice()) + .build(); + assertThat(result).hasSize(3).containsOnly(expectedBidder1Masked, expectedBidder2Masked, expectedBidder3Masked); - verify(gdprService).isGdprEnforced(eq("1"), eq(true), anySet()); - verify(gdprService).resultByVendor(anySet(), eq("1"), isNull(), isNull(), eq(timeout)); - verifyNoMoreInteractions(gdprService); - verify(metrics).updateGdprMaskedMetric(bidder1Name); - verify(metrics).updateGdprMaskedMetric(bidder2Name); - verifyNoMoreInteractions(metrics); + final HashSet bidderNames = new HashSet<>(asList(bidder1Name, bidder2Name, bidder3Name)); + verify(tcfDefinerService).resultForBidderNames(eq(bidderNames), any(), eq("1"), isNull(), isNull(), + any(), + eq(timeout)); + } - assertThat(result).hasSize(3) - .contains( - entry(bidder1Name, expectedMasked), - entry(bidder2Name, expectedMasked), - entry(bidder3Name, expectedNotMasked)); + private AuctionContext auctionContext(BidRequest bidRequest) { + return AuctionContext.builder() + .account(Account.builder().build()) + .bidRequest(bidRequest) + .timeout(timeout) + .build(); } private static Device notMaskedDevice() { @@ -612,7 +877,6 @@ private static Device notMaskedDevice() { .dpidsha1("dpidsha1") .dpidmd5("dpidmd5") .build(); - } private static User notMaskedUser() { @@ -621,7 +885,22 @@ private static User notMaskedUser() { .geo(Geo.builder().lon(-85.1245F).lat(189.9531F).country("US").build()) .ext(mapper.valueToTree(ExtUser.builder().consent("consent").build())) .build(); + } + + private static User notMaskedUser(ExtUser extUser) { + return User.builder() + .buyeruid(BUYER_UID) + .geo(Geo.builder().lon(-85.1245F).lat(189.9531F).country("US").build()) + .ext(mapper.valueToTree(extUser)) + .build(); + } + private static ExtUser notMaskedExtUser() { + return ExtUser.builder() + .eids(singletonList(ExtUserEid.of("Test", "id", emptyList(), null))) + .digitrust(ExtUserDigiTrust.of("idDigit", 12, 23)) + .prebid(ExtUserPrebid.of(emptyMap())) + .build(); } private static Device deviceCoppaMasked() { @@ -639,7 +918,7 @@ private static User userCoppaMasked() { .build(); } - private static Device deviceGdprMasked() { + private static Device deviceTcfMasked() { return Device.builder() .ip("192.168.0.0") .ipv6("2001:0db8:85a3:0000:0000:8a2e:0370:0") @@ -647,45 +926,63 @@ private static Device deviceGdprMasked() { .build(); } - private static User userGdprMasked() { + private static User userTcfMasked() { return User.builder() .buyeruid(null) + .geo(Geo.builder().lon(-85.12F).lat(189.95F).country("US").build()) .ext(mapper.valueToTree(ExtUser.builder().consent("consent").build())) + .build(); + } + + private static User userTcfMasked(ExtUser extUser) { + return User.builder() + .buyeruid(null) .geo(Geo.builder().lon(-85.12F).lat(189.95F).country("US").build()) + .ext(mapper.valueToTree(extUser)) + .build(); + } + + private static ExtUser extUserTcfMasked() { + return ExtUser.builder() + .prebid(ExtUserPrebid.of(emptyMap())) .build(); } - private static BidRequest givenBidRequest( - List imp, - Function bidRequestBuilderCustomizer) { + private static BidRequest givenBidRequest(List imp, + UnaryOperator bidRequestBuilderCustomizer) { return bidRequestBuilderCustomizer.apply(BidRequest.builder().cur(singletonList("USD")).imp(imp)).build(); } - private static Device givenNotMaskedDevice( - Function deviceBuilderCustomizer) { + private static Device givenNotMaskedDevice(UnaryOperator deviceBuilderCustomizer) { return deviceBuilderCustomizer.apply(notMaskedDevice().toBuilder()).build(); } - private static Device givenGdprMaskedDevice( - Function deviceBuilderCustomizer) { - return deviceBuilderCustomizer.apply(deviceGdprMasked().toBuilder()).build(); + private static User givenNotMaskedUser(UnaryOperator deviceBuilderCustomizer) { + return deviceBuilderCustomizer.apply(notMaskedUser().toBuilder()).build(); } - private static Device givenCoppaMaskedDevice( - Function deviceBuilderCustomizer) { + private static Device givenTcfMaskedDevice(UnaryOperator deviceBuilderCustomizer) { + return deviceBuilderCustomizer.apply(deviceTcfMasked().toBuilder()).build(); + } + + private static Device givenCoppaMaskedDevice(UnaryOperator deviceBuilderCustomizer) { return deviceBuilderCustomizer.apply(deviceCoppaMasked().toBuilder()).build(); } private static List givenSingleImp(T ext) { - return singletonList(givenImp(ext, Function.identity())); + return singletonList(givenImp(ext, UnaryOperator.identity())); } - private static Imp givenImp(T ext, Function impBuilderCustomizer) { + private static Imp givenImp(T ext, UnaryOperator impBuilderCustomizer) { return impBuilderCustomizer.apply(Imp.builder().ext(mapper.valueToTree(ext))).build(); } - private static BidderInfo givenBidderInfo(int gdprVendorId, boolean enforceGdpr) { - return new BidderInfo(true, null, null, null, - new BidderInfo.GdprInfo(gdprVendorId, enforceGdpr), false); + private static PrivacyEnforcementAction restrictDeviceAndUser() { + return PrivacyEnforcementAction.builder() + .maskDeviceInfo(true) + .maskDeviceIp(true) + .maskGeo(true) + .removeUserIds(true) + .build(); } } diff --git a/src/test/java/org/prebid/server/auction/StoredRequestProcessorTest.java b/src/test/java/org/prebid/server/auction/StoredRequestProcessorTest.java index ab75a38f7fe..90543a7ef37 100644 --- a/src/test/java/org/prebid/server/auction/StoredRequestProcessorTest.java +++ b/src/test/java/org/prebid/server/auction/StoredRequestProcessorTest.java @@ -161,9 +161,9 @@ public void shouldReturnMergedBidRequest() throws IOException { public void shouldReturnAmpRequest() throws IOException { // given given(applicationSettings.getAmpStoredData(anySet(), anySet(), any())) - .willReturn((Future.succeededFuture(StoredDataResult.of( + .willReturn(Future.succeededFuture(StoredDataResult.of( singletonMap("123", mapper.writeValueAsString( - BidRequest.builder().id("test-request-id").build())), emptyMap(), emptyList())))); + BidRequest.builder().id("test-request-id").build())), emptyMap(), emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processAmpRequest("123"); @@ -184,8 +184,8 @@ public void shouldReturnFailedFutureWhenStoredBidRequestJsonIsNotValid() { .storedrequest(ExtStoredRequest.of("123")).build())))); final Map storedRequestFetchResult = singletonMap("123", "{{}"); - given(applicationSettings.getStoredData(anySet(), anySet(), any())).willReturn((Future - .succeededFuture(StoredDataResult.of(storedRequestFetchResult, emptyMap(), emptyList())))); + given(applicationSettings.getStoredData(anySet(), anySet(), any())).willReturn(Future + .succeededFuture(StoredDataResult.of(storedRequestFetchResult, emptyMap(), emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -206,8 +206,8 @@ public void shouldReturnFailedFutureWhenMergedResultCouldNotBeConvertedToBidRequ final Map storedRequestFetchResult = singletonMap("123", mapper.writeValueAsString( mapper.createObjectNode().put("tmax", "stringValue"))); - given(applicationSettings.getStoredData(anySet(), anySet(), any())).willReturn((Future - .succeededFuture(StoredDataResult.of(storedRequestFetchResult, emptyMap(), emptyList())))); + given(applicationSettings.getStoredData(anySet(), anySet(), any())).willReturn(Future + .succeededFuture(StoredDataResult.of(storedRequestFetchResult, emptyMap(), emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -273,8 +273,8 @@ public void shouldReturnBidRequestWithMergedImp() throws IOException { .build()); given(applicationSettings.getStoredData(anySet(), anySet(), any())) - .willReturn((Future.succeededFuture( - StoredDataResult.of(emptyMap(), singletonMap("123", storedRequestImpJson), emptyList())))); + .willReturn(Future.succeededFuture( + StoredDataResult.of(emptyMap(), singletonMap("123", storedRequestImpJson), emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -316,8 +316,8 @@ public void shouldReturnFailedFutureWhenJsonBodyWasNotFoundByFetcher() { null))))))); given(applicationSettings.getStoredData(anySet(), anySet(), any())) - .willReturn((Future.succeededFuture( - StoredDataResult.of(emptyMap(), emptyMap(), singletonList("No config found for id: 123"))))); + .willReturn(Future.succeededFuture( + StoredDataResult.of(emptyMap(), emptyMap(), singletonList("No config found for id: 123")))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -360,8 +360,8 @@ public void shouldReturnChangedImpWithStoredRequestAndNotModifiedImpWithoutStore .format(singletonList(Format.builder().w(300).h(250).build())).build()).build()); given(applicationSettings.getStoredData(anySet(), anySet(), any())) - .willReturn((Future.succeededFuture( - StoredDataResult.of(emptyMap(), singletonMap("123", storedRequestImpJson), emptyList())))); + .willReturn(Future.succeededFuture( + StoredDataResult.of(emptyMap(), singletonMap("123", storedRequestImpJson), emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -427,7 +427,7 @@ public void shouldReturnFailedFutureIfStoredRequestFetcherReturnsFailedFuture() null))))))); given(applicationSettings.getStoredData(anySet(), anySet(), any())) - .willReturn((Future.failedFuture(new Exception("Error during file fetching")))); + .willReturn(Future.failedFuture(new Exception("Error during file fetching"))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -449,8 +449,8 @@ public void shouldReturnFailedFutureWhenStoredImpJsonIsNotValid() { null))))))); given(applicationSettings.getStoredData(anySet(), anySet(), any())) - .willReturn((Future.succeededFuture( - StoredDataResult.of(emptyMap(), singletonMap("123", "{{}"), emptyList())))); + .willReturn(Future.succeededFuture( + StoredDataResult.of(emptyMap(), singletonMap("123", "{{}"), emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); @@ -473,8 +473,8 @@ public void shouldReturnFailedFutureWhenMergedResultCantBeConvertedToImp() throw final Map storedImpFetchResult = singletonMap("123", mapper.writeValueAsString( mapper.createObjectNode().put("secure", "stringValue"))); - given(applicationSettings.getStoredData(anySet(), anySet(), any())).willReturn((Future - .succeededFuture(StoredDataResult.of(emptyMap(), storedImpFetchResult, emptyList())))); + given(applicationSettings.getStoredData(anySet(), anySet(), any())) + .willReturn(Future.succeededFuture(StoredDataResult.of(emptyMap(), storedImpFetchResult, emptyList()))); // when final Future bidRequestFuture = storedRequestProcessor.processStoredRequests(bidRequest); diff --git a/src/test/java/org/prebid/server/auction/StoredResponseProcessorTest.java b/src/test/java/org/prebid/server/auction/StoredResponseProcessorTest.java index 43ea37f7b59..305e803726c 100644 --- a/src/test/java/org/prebid/server/auction/StoredResponseProcessorTest.java +++ b/src/test/java/org/prebid/server/auction/StoredResponseProcessorTest.java @@ -41,7 +41,6 @@ import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; @@ -90,7 +89,7 @@ public void getStoredResponseResultShouldReturnSeatBidsForAuctionResponseId() th // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.result()).isEqualTo(StoredResponseResult.of(emptyList(), @@ -108,7 +107,7 @@ public void getStoredResponseResultShouldNotChangeImpsAndReturnSeatBidsWhenThere // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.result()).isEqualTo(StoredResponseResult.of( @@ -121,20 +120,20 @@ public void getStoredResponseResultShouldNotChangeImpsAndReturnSeatBidsWhenThere public void getStoredResponseResultShouldAddImpToRequiredRequestWhenItsStoredBidResponseIsEmpty() { // given final List imps = singletonList(Imp.builder().id("impId1") - .ext(mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder(). - storedBidResponse(emptyList()) + .ext(mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder() + .storedBidResponse(emptyList()) .build(), null))) .build()); // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.result()).isEqualTo(StoredResponseResult.of( singletonList(Imp.builder().id("impId1") - .ext(mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder(). - storedBidResponse(emptyList()) + .ext(mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder() + .storedBidResponse(emptyList()) .build(), null))) .build()), emptyList())); @@ -155,7 +154,7 @@ public void getStoredResponseResultShouldReturnFailedFutureWhenErrorHappenedDuri // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.failed()).isTrue(); @@ -171,8 +170,8 @@ public void getStoredResponseResultShouldReturnSeatBidsForBidStoredResponseId() .ext(mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder() .storedBidResponse(asList(ExtStoredBidResponse.of("rubicon", "storedBidResponseId1"), ExtStoredBidResponse.of("appnexus", "storedBidResponseId2"))) - .build() - , null))) + .build(), + null))) .build()); final Map storedResponse = new HashMap<>(); @@ -183,13 +182,12 @@ public void getStoredResponseResultShouldReturnSeatBidsForBidStoredResponseId() SeatBid.builder().seat("appnexus").bid(singletonList(Bid.builder().id("id2").build())) .build()))); - given(applicationSettings.getStoredResponses(any(), any())).willReturn( Future.succeededFuture(StoredResponseDataResult.of(storedResponse, emptyList()))); // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.result()).isEqualTo(StoredResponseResult.of(emptyList(), @@ -230,7 +228,7 @@ public void getStoredResponseResultShouldReturnSeatBidsForBidAndAuctionStoredRes // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.result()).isEqualTo(StoredResponseResult.of(emptyList(), @@ -263,7 +261,7 @@ public void getStoredResponseResultShouldRemoveMockedBiddersFromImps() throws Js // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then final ObjectNode impExtResult = mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder() @@ -308,7 +306,7 @@ public void getStoredResponseResultShouldMergeStoredSeatBidsForTheSameBidder() t // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.result()).isEqualTo(StoredResponseResult.of(emptyList(), @@ -342,7 +340,7 @@ public void getStoredResponseResultShouldSupportAliasesWhenDecidingIfImpRequired // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - singletonMap("appnexusAlias", "appnexus"), timeout); + BidderAliases.of(singletonMap("appnexusAlias", "appnexus"), singletonMap("appnexusAlias", 1)), timeout); // then final ObjectNode impExtResult = mapper.valueToTree(ExtImp.of(ExtImpPrebid.builder() @@ -364,7 +362,7 @@ public void getStoredResponseResultShouldReturnFailedFutureWhenImpExtIsNotValid( // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.failed()).isTrue(); @@ -382,7 +380,7 @@ public void getStoredResponseResultShouldReturnFailedFutureWhenBidderIsMissedInS // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.failed()).isTrue(); @@ -399,7 +397,7 @@ public void getStoredResponseResultShouldReturnFailedFutureWhenIdIsMissedInStore // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.failed()).isTrue(); @@ -425,7 +423,7 @@ public void getStoredResponseResultShouldReturnFailedFutureWhenSeatIsEmptyInStor // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.failed()).isTrue(); @@ -447,7 +445,7 @@ public void getStoredResponseResultShouldReturnFailedFutureSeatBidsCantBeParsed( // when final Future result = storedResponseProcessor.getStoredResponseResult(imps, - emptyMap(), timeout); + BidderAliases.of(null, null), timeout); // then assertThat(result.failed()).isTrue(); diff --git a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java index 3c51252a71f..2cc5e1e140f 100644 --- a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java @@ -1,5 +1,6 @@ package org.prebid.server.auction; +import com.fasterxml.jackson.core.JsonProcessingException; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Content; import com.iab.openrtb.request.Imp; @@ -11,7 +12,6 @@ import io.vertx.core.Future; import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.json.Json; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -66,7 +66,13 @@ public void setUp() { given(routingContext.request()).willReturn(httpServerRequest); given(httpServerRequest.getParam(anyString())).willReturn("test"); - factory = new VideoRequestFactory(Integer.MAX_VALUE, false, videoStoredRequestProcessor, auctionRequestFactory, timeoutResolver, jacksonMapper); + factory = new VideoRequestFactory( + Integer.MAX_VALUE, + false, + videoStoredRequestProcessor, + auctionRequestFactory, + timeoutResolver, + jacksonMapper); } @Test @@ -85,10 +91,17 @@ public void shouldReturnFailedFutureIfRequestBodyIsMissing() { } @Test - public void shouldReturnFailedFutureIfStoredRequestIsEnforcedAndIdIsNotProvided() { + public void shouldReturnFailedFutureIfStoredRequestIsEnforcedAndIdIsNotProvided() throws JsonProcessingException { // given - given(routingContext.getBody()).willReturn(Json.encodeToBuffer(BidRequestVideo.builder().build())); - factory = new VideoRequestFactory(Integer.MAX_VALUE, true, videoStoredRequestProcessor, auctionRequestFactory, timeoutResolver, jacksonMapper); + given(routingContext.getBody()) + .willReturn(Buffer.buffer(mapper.writeValueAsBytes(BidRequestVideo.builder().build()))); + factory = new VideoRequestFactory( + Integer.MAX_VALUE, + true, + videoStoredRequestProcessor, + auctionRequestFactory, + timeoutResolver, + jacksonMapper); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -103,7 +116,13 @@ public void shouldReturnFailedFutureIfStoredRequestIsEnforcedAndIdIsNotProvided( @Test public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { // given - factory = new VideoRequestFactory(2, true, videoStoredRequestProcessor, auctionRequestFactory, timeoutResolver, jacksonMapper); + factory = new VideoRequestFactory( + 2, + true, + videoStoredRequestProcessor, + auctionRequestFactory, + timeoutResolver, + jacksonMapper); given(routingContext.getBody()).willReturn(Buffer.buffer("body")); @@ -133,7 +152,7 @@ public void shouldReturnFailedFutureIfRequestBodyCouldNotBeParsed() { } @Test - public void shouldReturnExpectedResultAndReturnErrors() { + public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingException { // given final Content content = Content.builder() .len(900) @@ -141,16 +160,24 @@ public void shouldReturnExpectedResultAndReturnErrors() { .build(); final Imp expectedImp1 = Imp.builder() .id("123_0") - .video(Video.builder().mimes(singletonList("mime")).maxduration(100).protocols(singletonList(123)).build()) + .video(Video.builder() + .mimes(singletonList("mime")) + .maxduration(100) + .protocols(singletonList(123)) + .build()) .build(); final Imp expectedImp2 = Imp.builder() .id("123_1") - .video(Video.builder().mimes(singletonList("mime")).maxduration(100).protocols(singletonList(123)).build()) + .video(Video.builder() + .mimes(singletonList("mime")) + .maxduration(100) + .protocols(singletonList(123)) + .build()) .build(); final ExtRequestPrebid ext = ExtRequestPrebid.builder() .cache(ExtRequestPrebidCache.of(null, ExtRequestPrebidCacheVastxml.of(null, null), null)) .targeting(ExtRequestTargeting.builder() - .pricegranularity(Json.mapper.valueToTree(PriceGranularity.createFromString("med"))) + .pricegranularity(mapper.valueToTree(PriceGranularity.createFromString("med"))) .includebidderkeys(true) .includebrandcategory(ExtIncludeBrandCategory.of(null, null, false)) .build()) @@ -164,16 +191,19 @@ public void shouldReturnExpectedResultAndReturnErrors() { .badv(singletonList("badv")) .cur(singletonList("USD")) .tmax(0L) - .ext(Json.mapper.valueToTree(ExtBidRequest.of(ext))) + .ext(mapper.valueToTree(ExtBidRequest.of(ext))) .build(); - final WithPodErrors mergedBidRequest = WithPodErrors.of(bidRequest, singletonList(PodError.of(1, 1, singletonList("TEST")))); + final WithPodErrors mergedBidRequest = WithPodErrors.of( + bidRequest, singletonList(PodError.of(1, 1, singletonList("TEST")))); final BidRequestVideo requestVideo = BidRequestVideo.builder().build(); - given(routingContext.getBody()).willReturn(Json.encodeToBuffer(requestVideo)); - given(videoStoredRequestProcessor.processVideoRequest(any(), any(), any())).willReturn(Future.succeededFuture(mergedBidRequest)); + given(routingContext.getBody()).willReturn(Buffer.buffer(mapper.writeValueAsBytes(requestVideo))); + given(videoStoredRequestProcessor.processVideoRequest(any(), any(), any())) + .willReturn(Future.succeededFuture(mergedBidRequest)); given(auctionRequestFactory.validateRequest(any())).willAnswer(invocation -> invocation.getArgument(0)); - given(auctionRequestFactory.fillImplicitParameters(any(), any(), any())).willAnswer(invocation -> invocation.getArgument(0)); + given(auctionRequestFactory.fillImplicitParameters(any(), any(), any())) + .willAnswer(invocation -> invocation.getArgument(0)); given(auctionRequestFactory.toAuctionContext(any(), any(), anyLong(), any())) .willReturn(Future.succeededFuture()); diff --git a/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java b/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java index cc18484f07d..1e2a6b945e0 100644 --- a/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/VideoResponseFactoryTest.java @@ -54,7 +54,8 @@ public void shouldReturnExpectedVideoResponse() { final Bid bid2 = Bid.builder() .impid("2_1") .ext(mapper.valueToTree( - ExtPrebid.of(ExtBidPrebid.of(null, null, null, null, null, null, null), mapper.createObjectNode()))) + ExtPrebid.of(ExtBidPrebid.of(null, null, null, null, null, null, null), + mapper.createObjectNode()))) .build(); final BidResponse bidResponse = BidResponse.builder() diff --git a/src/test/java/org/prebid/server/auction/VideoStoredRequestProcessorTest.java b/src/test/java/org/prebid/server/auction/VideoStoredRequestProcessorTest.java index c62278b98cb..b252d3acb17 100644 --- a/src/test/java/org/prebid/server/auction/VideoStoredRequestProcessorTest.java +++ b/src/test/java/org/prebid/server/auction/VideoStoredRequestProcessorTest.java @@ -14,7 +14,6 @@ import com.iab.openrtb.request.video.VideoUser; import com.iab.openrtb.request.video.VideoVideo; import io.vertx.core.Future; -import io.vertx.core.json.Json; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -37,7 +36,6 @@ import org.prebid.server.validation.VideoRequestValidator; import java.util.Arrays; -import java.util.List; import java.util.function.UnaryOperator; import static java.util.Collections.emptyList; @@ -56,7 +54,6 @@ public class VideoStoredRequestProcessorTest extends VertxTest { - private static final List BLACKLISTED_ACCOUNTS = singletonList("bad_acc"); private static final String STORED_REQUEST_ID = "storedReqId"; private static final String STORED_POD_ID = "storedPodId"; @Rule @@ -121,7 +118,7 @@ public void shouldReturnFutureWithMergedStoredAndDefaultRequest() { podconfigBuilder -> podconfigBuilder.pods(singletonList(Pod.of(123, 20, STORED_POD_ID)))); final StoredDataResult storedDataResult = StoredDataResult.of( - singletonMap(STORED_REQUEST_ID, Json.encode(storedVideo)), + singletonMap(STORED_REQUEST_ID, jacksonMapper.encode(storedVideo)), singletonMap(STORED_POD_ID, "{}"), emptyList()); @@ -156,7 +153,7 @@ public void shouldReturnFutureWithMergedStoredAndDefaultRequest() { final ExtRequestPrebid ext = ExtRequestPrebid.builder() .cache(ExtRequestPrebidCache.of(null, ExtRequestPrebidCacheVastxml.of(null, null), null)) .targeting(ExtRequestTargeting.builder() - .pricegranularity(Json.mapper.valueToTree(PriceGranularity.createFromString("med"))) + .pricegranularity(mapper.valueToTree(PriceGranularity.createFromString("med"))) .includebidderkeys(true) .includebrandcategory(ExtIncludeBrandCategory.of(null, null, false)) .build()) @@ -170,7 +167,7 @@ public void shouldReturnFutureWithMergedStoredAndDefaultRequest() { .badv(singletonList("badv")) .cur(singletonList("USD")) .tmax(0L) - .ext(Json.mapper.valueToTree(ExtBidRequest.of(ext))) + .ext(mapper.valueToTree(ExtBidRequest.of(ext))) .build(); assertThat(result.result()).isEqualTo(WithPodErrors.of(expectedMergedRequest, emptyList())); diff --git a/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java b/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java index 87338cdd3a8..cd21e535381 100644 --- a/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java +++ b/src/test/java/org/prebid/server/bidder/BidderCatalogTest.java @@ -206,6 +206,26 @@ public void bidderByNameShouldReturnBidderForKnownBidder() { assertThat(bidderCatalog.bidderByName(BIDDER)).isSameAs(bidder); } + @Test + public void nameByVendorIdShouldReturnBidderNameForVendorId() { + // given + final BidderInfo bidderInfo = BidderInfo.create(true, "test@email.com", + singletonList("banner"), singletonList("video"), null, 99, true, false); + + bidderDeps = BidderDeps.builder() + .name(BIDDER) + .deprecatedNames(emptyList()) + .aliases(emptyList()) + .bidder(bidder) + .bidderInfo(bidderInfo) + .build(); + + bidderCatalog = new BidderCatalog(singletonList(bidderDeps)); + + // when and then + assertThat(bidderCatalog.nameByVendorId(99)).isEqualTo(BIDDER); + } + @Test public void bidderByNameShouldReturnNullForUnknownBidder() { // given diff --git a/src/test/java/org/prebid/server/bidder/HttpAdapterConnectorTest.java b/src/test/java/org/prebid/server/bidder/HttpAdapterConnectorTest.java index 23ee9691e46..60736cfab66 100644 --- a/src/test/java/org/prebid/server/bidder/HttpAdapterConnectorTest.java +++ b/src/test/java/org/prebid/server/bidder/HttpAdapterConnectorTest.java @@ -410,8 +410,7 @@ public void callShouldReturnBidderResultWithoutErrorIfBidsArePresent() throws Js } @Test - public void - callShouldReturnAdapterResponseWithErrorIfAtLeastOneErrorOccursWhileHttpRequestForNotToleratedErrorsAdapter() + public void callShouldReturnAdapterResponseWithErrorIfErrorsOccurWhileHttpRequestForNotToleratedErrorsAdapter() throws JsonProcessingException { // given givenHttpClientReturnsResponse(200, null); @@ -443,8 +442,7 @@ public void callShouldReturnBidderResultWithoutErrorIfBidsArePresent() throws Js } @Test - public void - callShouldReturnAdapterResponseWithoutErrorIfAtLeastOneBidIsPresentWhileHttpRequestForToleratedErrorsAdapter() + public void callShouldReturnAdapterResponseWithoutErrorIfBidsArePresentWhileHttpRequestForToleratedErrorsAdapter() throws JsonProcessingException { // given willReturn(asList(givenHttpRequest(), givenHttpRequest())).given(adapter).makeHttpRequests(any(), any()); @@ -475,8 +473,7 @@ public void callShouldReturnBidderResultWithoutErrorIfBidsArePresent() throws Js } @Test - public void - callShouldReturnAdapterResponseWithErrorIfAtLeastOneErrorOccursWhileExtractingForNotToleratedErrorsAdapter() + public void callShouldReturnAdapterResponseWithErrorIfErrorsOccurWhileExtractingForNotToleratedErrorsAdapter() throws JsonProcessingException { // given willReturn(asList(givenHttpRequest(), givenHttpRequest())).given(adapter).makeHttpRequests(any(), any()); @@ -503,8 +500,7 @@ public void callShouldReturnBidderResultWithoutErrorIfBidsArePresent() throws Js } @Test - public void - callShouldReturnAdapterResponseWithoutErrorIfAtLeastOneBidIsPresentWhileExtractingForToleratedErrorsAdapter() + public void callShouldReturnAdapterResponseWithoutErrorIfBidsArePresentWhileExtractingForToleratedErrorsAdapter() throws JsonProcessingException { // given willReturn(asList(givenHttpRequest(), givenHttpRequest())).given(adapter).makeHttpRequests(any(), any()); diff --git a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java index 8a43cb8ee51..d7a670fcf59 100644 --- a/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java +++ b/src/test/java/org/prebid/server/bidder/HttpBidderRequesterTest.java @@ -84,8 +84,8 @@ public void shouldReturnFailedToRequestBidsErrorWhenBidderReturnsEmptyHttpReques assertThat(bidderSeatBid.getBids()).isEmpty(); assertThat(bidderSeatBid.getHttpCalls()).isEmpty(); assertThat(bidderSeatBid.getErrors()) - .containsOnly(BidderError.failedToRequestBids("The bidder failed to generate any bid " + - "requests, but also failed to generate an error")); + .containsOnly(BidderError.failedToRequestBids( + "The bidder failed to generate any bid requests, but also failed to generate an error")); } @Test @@ -378,7 +378,6 @@ public void shouldTolerateMultipleErrors() { .build()), singletonList(BidderError.badInput("makeHttpRequestsError")))); - given(httpClient.request(any(), anyString(), any(), any(), anyLong())) // simulate response error for the first request .willReturn(Future.failedFuture(new RuntimeException("Response exception"))) diff --git a/src/test/java/org/prebid/server/bidder/adform/AdformBidderTest.java b/src/test/java/org/prebid/server/bidder/adform/AdformBidderTest.java index d8270420bbe..7447e4bf5b3 100644 --- a/src/test/java/org/prebid/server/bidder/adform/AdformBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adform/AdformBidderTest.java @@ -85,8 +85,8 @@ public void makeHttpRequestsShouldReturnHttpRequestWithoutErrors() { + "&rp=4&stid=tid&bWlkPTE1JnJjdXI9VVNEJm1rdj1jb2xvcjpyZWQmbWt3PXJlZA"); assertThat(result.getValue()).extracting(HttpRequest::getMethod).containsExactly(HttpMethod.GET); - assertThat(result.getValue()). - flatExtracting(res -> res.getHeaders().entries()) + assertThat(result.getValue()) + .flatExtracting(res -> res.getHeaders().entries()) .extracting(Map.Entry::getKey, Map.Entry::getValue) .containsOnly(tuple(HttpUtil.CONTENT_TYPE_HEADER.toString(), HttpUtil.APPLICATION_JSON_CONTENT_TYPE), tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString()), diff --git a/src/test/java/org/prebid/server/bidder/adform/AdformHttpUtilTest.java b/src/test/java/org/prebid/server/bidder/adform/AdformHttpUtilTest.java index f2bbe65008e..558dbc24b91 100644 --- a/src/test/java/org/prebid/server/bidder/adform/AdformHttpUtilTest.java +++ b/src/test/java/org/prebid/server/bidder/adform/AdformHttpUtilTest.java @@ -49,8 +49,8 @@ public void buildAdformHeadersShouldReturnAllHeaders() { tuple(HttpUtil.REFERER_HEADER.toString(), "www.example.com"), tuple(HttpUtil.COOKIE_HEADER.toString(), // Base64 encoded {"id":"id","version":1,"keyv":123,"privacy":{"optout":true}} - "uid=buyeruid;DigiTrust.v1.identity=eyJpZCI6ImlkIiwidmVyc2lvbiI6MSwia2V5diI6MTIzLC" + - "Jwcml2YWN5Ijp7Im9wdG91dCI6dHJ1ZX19")); + "uid=buyeruid;DigiTrust.v1.identity=eyJpZCI6ImlkIiwidmVyc2lvbiI6MSwia2V5diI6MTIzLC" + + "Jwcml2YWN5Ijp7Im9wdG91dCI6dHJ1ZX19")); } @Test @@ -141,8 +141,8 @@ public void buildAdformUrlShouldReturnCorrectUrl() { // bWlkPTE1 is Base64 encoded mid=15 and bWlkPTE2 encoded mid=16, so bWlkPTE1&bWlkPTE2 = mid=15&mid=16 assertThat(url).isEqualTo( "http://adx.adform.net/adx?CC=1&adid=adId&fd=1&gdpr=1&gdpr_consent=consent&ip=ip&pt=gross&rp=4" - + "&stid=tid&bWlkPTE1JnJjdXI9VVNEJm1rdj1jb2xvcjpyZWQmbWt3PXJlZA" + - "&bWlkPTE2JnJjdXI9VVNEJm1rdj1hZ2U6MzAtNDAmbWt3PWJsdWU"); + + "&stid=tid&bWlkPTE1JnJjdXI9VVNEJm1rdj1jb2xvcjpyZWQmbWt3PXJlZA" + + "&bWlkPTE2JnJjdXI9VVNEJm1rdj1hZ2U6MzAtNDAmbWt3PWJsdWU"); } @Test diff --git a/src/test/java/org/prebid/server/bidder/adkerneladn/AdkernelAdnBidderTest.java b/src/test/java/org/prebid/server/bidder/adkerneladn/AdkernelAdnBidderTest.java index 402fcaf2b22..a71ae2901d0 100644 --- a/src/test/java/org/prebid/server/bidder/adkerneladn/AdkernelAdnBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adkerneladn/AdkernelAdnBidderTest.java @@ -448,7 +448,8 @@ public void extractTargetingShouldReturnEmptyMap() { private static BidRequest givenBidRequest( Function bidRequestCustomizer, Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { return bidRequestCustomizer.apply(BidRequest.builder() .imp(singletonList(givenImp(impCustomizer, extCustomizer)))) @@ -461,14 +462,16 @@ private static BidRequest givenBidRequest(Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { return givenBidRequest(identity(), impCustomizer, extCustomizer); } private static Imp givenImp( Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { return impCustomizer.apply(Imp.builder() .id("123") diff --git a/src/test/java/org/prebid/server/bidder/adtelligent/AdtelligentBidderTest.java b/src/test/java/org/prebid/server/bidder/adtelligent/AdtelligentBidderTest.java index d7ba3af80ad..9a899f014c8 100644 --- a/src/test/java/org/prebid/server/bidder/adtelligent/AdtelligentBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adtelligent/AdtelligentBidderTest.java @@ -22,7 +22,6 @@ 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.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; @@ -407,9 +406,9 @@ public void makeBidsShouldReturnEmptyBidderWithErrorWhenResponseCantBeParsed() { // then assertThat(result.getErrors()).hasSize(1) .containsExactly(BidderError.badServerResponse( - "Failed to decode: Unexpected end-of-input: expected close marker for Object (start marker at" + - " [Source: (String)\"{\"; line: 1, column: 1])\n at [Source: (String)\"{\"; line: 1, " + - "column: 3]")); + "Failed to decode: Unexpected end-of-input: expected close marker for Object (start marker at" + + " [Source: (String)\"{\"; line: 1, column: 1])\n at [Source: (String)\"{\"; line: 1, " + + "column: 3]")); } private static HttpCall givenHttpCall(String body) { diff --git a/src/test/java/org/prebid/server/bidder/applogy/ApplogyBidderTest.java b/src/test/java/org/prebid/server/bidder/applogy/ApplogyBidderTest.java index 61ef53f2a9f..7c78749f48e 100644 --- a/src/test/java/org/prebid/server/bidder/applogy/ApplogyBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/applogy/ApplogyBidderTest.java @@ -1,6 +1,5 @@ package org.prebid.server.bidder.applogy; - import com.fasterxml.jackson.core.JsonProcessingException; import com.iab.openrtb.request.Audio; import com.iab.openrtb.request.Banner; diff --git a/src/test/java/org/prebid/server/bidder/appnexus/AppnexusAdapterTest.java b/src/test/java/org/prebid/server/bidder/appnexus/AppnexusAdapterTest.java index 7115027b1d4..91b999265b1 100644 --- a/src/test/java/org/prebid/server/bidder/appnexus/AppnexusAdapterTest.java +++ b/src/test/java/org/prebid/server/bidder/appnexus/AppnexusAdapterTest.java @@ -642,12 +642,16 @@ public void extractBidsShouldReturnMultipleBidBuildersIfMultipleAdUnitsInPreBidR Bid.builder() .impid("adUnitCode1") .ext(mapper.valueToTree(AppnexusBidExt.of( - AppnexusBidExtAppnexus.builder().bidAdType(BANNER_TYPE).build()))) + AppnexusBidExtAppnexus.builder() + .bidAdType(BANNER_TYPE) + .build()))) .build(), Bid.builder() .impid("adUnitCode2") .ext(mapper.valueToTree(AppnexusBidExt.of( - AppnexusBidExtAppnexus.builder().bidAdType(BANNER_TYPE).build()))) + AppnexusBidExtAppnexus.builder() + .bidAdType(BANNER_TYPE) + .build()))) .build())) .build()))); diff --git a/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java b/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java index 0115c3b9d40..9dd13238820 100644 --- a/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java @@ -17,7 +17,6 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; -import io.vertx.core.json.Json; import org.assertj.core.groups.Tuple; import org.junit.Before; import org.junit.Test; @@ -298,7 +297,9 @@ public void makeHttpRequestsShouldNotModifyImpDisplaymanagerverIfItExists() { public void makeHttpRequestsShouldSetRequestExtAppnexusTrueWhenPrimaryAdserverIsOne() { // given final ExtRequestPrebid requestPrebid = ExtRequestPrebid.builder() - .targeting(ExtRequestTargeting.builder().includebrandcategory(ExtIncludeBrandCategory.of(1, null, null)).build()) + .targeting(ExtRequestTargeting.builder() + .includebrandcategory(ExtIncludeBrandCategory.of(1, null, null)) + .build()) .build(); final BidRequest bidRequest = givenBidRequest( @@ -315,7 +316,7 @@ public void makeHttpRequestsShouldSetRequestExtAppnexusTrueWhenPrimaryAdserverIs assertThat(result.getValue()).hasSize(1) .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .extracting(BidRequest::getExt) - .extracting(ext -> Json.mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() + .extracting(ext -> mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() .extracting(AppnexusReqExt::getAppnexus) .containsOnly(AppnexusReqExtAppnexus.of(true, true)); } @@ -324,7 +325,9 @@ public void makeHttpRequestsShouldSetRequestExtAppnexusTrueWhenPrimaryAdserverIs public void makeHttpRequestsShouldUpdateRequestExtAppnexusTrueWhenPrimaryAdserverIsNotZero() { // given final ExtRequestPrebid requestPrebid = ExtRequestPrebid.builder() - .targeting(ExtRequestTargeting.builder().includebrandcategory(ExtIncludeBrandCategory.of(-120, null, null)).build()) + .targeting(ExtRequestTargeting.builder() + .includebrandcategory(ExtIncludeBrandCategory.of(-120, null, null)) + .build()) .build(); final BidRequest bidRequest = givenBidRequest( @@ -341,7 +344,7 @@ public void makeHttpRequestsShouldUpdateRequestExtAppnexusTrueWhenPrimaryAdserve assertThat(result.getValue()).hasSize(1) .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .extracting(BidRequest::getExt) - .extracting(ext -> Json.mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() + .extracting(ext -> mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() .extracting(AppnexusReqExt::getAppnexus) .containsOnly(AppnexusReqExtAppnexus.of(true, true)); } @@ -350,12 +353,15 @@ public void makeHttpRequestsShouldUpdateRequestExtAppnexusTrueWhenPrimaryAdserve public void makeHttpRequestsShouldNotUpdateRequestExtAppnexusWhenPrimaryAdserverIsZero() { // given final ExtRequestPrebid requestPrebid = ExtRequestPrebid.builder() - .targeting(ExtRequestTargeting.builder().includebrandcategory(ExtIncludeBrandCategory.of(0, null, null)).build()) + .targeting(ExtRequestTargeting.builder() + .includebrandcategory(ExtIncludeBrandCategory.of(0, null, null)) + .build()) .build(); final BidRequest bidRequest = givenBidRequest( bidRequestBuilder -> bidRequestBuilder - .ext(mapper.valueToTree(AppnexusReqExt.of(AppnexusReqExtAppnexus.of(false, true), requestPrebid))), + .ext(mapper.valueToTree(AppnexusReqExt.of(AppnexusReqExtAppnexus.of(false, true), + requestPrebid))), impBuilder -> impBuilder.banner(Banner.builder().build()), extImpAppnexusBuilder -> extImpAppnexusBuilder.placementId(20)); @@ -367,7 +373,7 @@ public void makeHttpRequestsShouldNotUpdateRequestExtAppnexusWhenPrimaryAdserver assertThat(result.getValue()).hasSize(1) .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .extracting(BidRequest::getExt) - .extracting(ext -> Json.mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() + .extracting(ext -> mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() .extracting(AppnexusReqExt::getAppnexus) .containsOnly(AppnexusReqExtAppnexus.of(false, true)); } @@ -381,7 +387,8 @@ public void makeHttpRequestsShouldNotUpdateRequestExtAppnexusWhenIncludeBrandCat final BidRequest bidRequest = givenBidRequest( bidRequestBuilder -> bidRequestBuilder - .ext(mapper.valueToTree(AppnexusReqExt.of(AppnexusReqExtAppnexus.of(false, true), requestPrebid))), + .ext(mapper.valueToTree(AppnexusReqExt.of( + AppnexusReqExtAppnexus.of(false, true), requestPrebid))), impBuilder -> impBuilder.banner(Banner.builder().build()), extImpAppnexusBuilder -> extImpAppnexusBuilder.placementId(20)); @@ -393,7 +400,7 @@ public void makeHttpRequestsShouldNotUpdateRequestExtAppnexusWhenIncludeBrandCat assertThat(result.getValue()).hasSize(1) .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .extracting(BidRequest::getExt) - .extracting(ext -> Json.mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() + .extracting(ext -> mapper.treeToValue(ext, AppnexusReqExt.class)).isNotNull() .extracting(AppnexusReqExt::getAppnexus) .containsOnly(AppnexusReqExtAppnexus.of(false, true)); } @@ -476,7 +483,10 @@ public void makeHttpRequestsShouldSetImpTagidAndImpBidFloorIfExtImpAppnexusHasIn final BidRequest bidRequest = givenBidRequest( identity(), identity(), - extImpAppnexusBuilder -> extImpAppnexusBuilder.placementId(20).invCode("tagid").reserve(BigDecimal.TEN)); + extImpAppnexusBuilder -> extImpAppnexusBuilder + .placementId(20) + .invCode("tagid") + .reserve(BigDecimal.TEN)); // when final Result>> result = appnexusBidder.makeHttpRequests(bidRequest); @@ -552,9 +562,13 @@ public void makeHttpRequestsShouldSetBannerSizesFromExistingFirstFormatElement() // given final BidRequest bidRequest = givenBidRequest( identity(), - impBuilder -> impBuilder.banner(Banner.builder().format(singletonList(Format.builder().w(100).h(200).build())) + impBuilder -> impBuilder.banner(Banner.builder() + .format(singletonList(Format.builder().w(100).h(200).build())) .build()), - extImpAppnexusBuilder -> extImpAppnexusBuilder.placementId(20).invCode("tagid").reserve(BigDecimal.TEN)); + extImpAppnexusBuilder -> extImpAppnexusBuilder + .placementId(20) + .invCode("tagid") + .reserve(BigDecimal.TEN)); // when final Result>> result = appnexusBidder.makeHttpRequests(bidRequest); @@ -749,7 +763,8 @@ public void makeBidsShouldReturnBannerBidIfBidTypeFromResponseIsBanner() throws // then assertThat(result.getErrors()).isEmpty(); - final AppnexusBidExtAppnexus expectedExtAppnexus = AppnexusBidExtAppnexus.builder().bidAdType(BANNER_TYPE).build(); + final AppnexusBidExtAppnexus expectedExtAppnexus = + AppnexusBidExtAppnexus.builder().bidAdType(BANNER_TYPE).build(); assertThat(result.getValue()).containsOnly(BidderBid.of(Bid.builder() .ext(mapper.valueToTree(AppnexusBidExt.of( expectedExtAppnexus))).impid("impId").build(), BidType.banner, null)); @@ -758,7 +773,8 @@ public void makeBidsShouldReturnBannerBidIfBidTypeFromResponseIsBanner() throws @Test public void makeBidsShouldReturnVideoBidIfBidTypeFromResponseIsVideo() throws JsonProcessingException { // given - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.id("impId").video(Video.builder().build())); + final BidRequest bidRequest = + givenBidRequest(impBuilder -> impBuilder.id("impId").video(Video.builder().build())); final HttpCall httpCall = givenHttpCall(givenBidResponse(VIDEO_TYPE)); // when @@ -767,7 +783,8 @@ public void makeBidsShouldReturnVideoBidIfBidTypeFromResponseIsVideo() throws Js // then assertThat(result.getErrors()).isEmpty(); - final AppnexusBidExtAppnexus expectedExtAppnexus = AppnexusBidExtAppnexus.builder().bidAdType(VIDEO_TYPE).build(); + final AppnexusBidExtAppnexus expectedExtAppnexus = + AppnexusBidExtAppnexus.builder().bidAdType(VIDEO_TYPE).build(); assertThat(result.getValue()).containsOnly(BidderBid.of(Bid.builder() .ext(mapper.valueToTree(AppnexusBidExt.of( expectedExtAppnexus))).impid("impId").build(), BidType.video, null)); @@ -785,7 +802,8 @@ public void makeBidsShouldReturnAudioBidIfBidTypeFromResponseIsAudio() throws Js // then assertThat(result.getErrors()).isEmpty(); - final AppnexusBidExtAppnexus expectedExtAppnexus = AppnexusBidExtAppnexus.builder().bidAdType(AUDIO_TYPE).build(); + final AppnexusBidExtAppnexus expectedExtAppnexus = + AppnexusBidExtAppnexus.builder().bidAdType(AUDIO_TYPE).build(); assertThat(result.getValue()).containsOnly(BidderBid.of(Bid.builder() .ext(mapper.valueToTree(AppnexusBidExt.of( expectedExtAppnexus))).impid("impId").build(), BidType.audio, null)); @@ -803,7 +821,8 @@ public void makeBidsShouldReturnNativeBidIfBidTypeFromResponseBidExtIsNative() t // then assertThat(result.getErrors()).isEmpty(); - final AppnexusBidExtAppnexus expectedExtAppnexus = AppnexusBidExtAppnexus.builder().bidAdType(NATIVE_TYPE).build(); + final AppnexusBidExtAppnexus expectedExtAppnexus = + AppnexusBidExtAppnexus.builder().bidAdType(NATIVE_TYPE).build(); assertThat(result.getValue()).containsOnly(BidderBid.of(Bid.builder() .ext(mapper.valueToTree(AppnexusBidExt.of( expectedExtAppnexus))).impid("impId").build(), BidType.xNative, null)); @@ -813,7 +832,8 @@ public void makeBidsShouldReturnNativeBidIfBidTypeFromResponseBidExtIsNative() t public void makeBidsShouldSetBidCatWhenBrandCategoryIdIsMatch() throws JsonProcessingException { // given final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.id("impId")); - final AppnexusBidExtAppnexus bidExtAppnexus = AppnexusBidExtAppnexus.builder().brandCategoryId(10).bidAdType(1).build(); + final AppnexusBidExtAppnexus bidExtAppnexus = + AppnexusBidExtAppnexus.builder().brandCategoryId(10).bidAdType(1).build(); final HttpCall httpCall = givenHttpCall(givenBidResponse(AppnexusBidExt.of(bidExtAppnexus))); // when @@ -828,10 +848,12 @@ public void makeBidsShouldSetBidCatWhenBrandCategoryIdIsMatch() throws JsonProce } @Test - public void makeBidsShouldClearBidCatWhenBrandCategoryIdIsNotMatchAndBidCatIsNotEmpty() throws JsonProcessingException { + public void makeBidsShouldClearBidCatWhenBrandCategoryIdIsNotMatchAndBidCatIsNotEmpty() + throws JsonProcessingException { // given final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.id("impId")); - final AppnexusBidExtAppnexus bidExtAppnexus = AppnexusBidExtAppnexus.builder().brandCategoryId(350).bidAdType(1).build(); + final AppnexusBidExtAppnexus bidExtAppnexus = + AppnexusBidExtAppnexus.builder().brandCategoryId(350).bidAdType(1).build(); final HttpCall httpCall = givenHttpCall(givenBidResponse( bidBuilder -> bidBuilder.cat(singletonList("CLEAR")), AppnexusBidExt.of(bidExtAppnexus))); @@ -912,7 +934,8 @@ public void makeBidsShouldReturnErrorIfBidExtAppnexusBidTypeNotDefined() throws .seatbid(singletonList(SeatBid.builder() .bid(singletonList(Bid.builder() .impid("impId") - .ext(mapper.valueToTree(AppnexusBidExt.of(AppnexusBidExtAppnexus.builder().bidAdType(null).build()))) + .ext(mapper.valueToTree(AppnexusBidExt.of( + AppnexusBidExtAppnexus.builder().bidAdType(null).build()))) .build())) .build())) .build())); @@ -962,7 +985,8 @@ private static String givenBidResponse(Integer bidType) throws JsonProcessingExc .seatbid(singletonList(SeatBid.builder() .bid(singletonList(Bid.builder() .impid("impId") - .ext(mapper.valueToTree(AppnexusBidExt.of(AppnexusBidExtAppnexus.builder().bidAdType(bidType).build()))) + .ext(mapper.valueToTree(AppnexusBidExt.of( + AppnexusBidExtAppnexus.builder().bidAdType(bidType).build()))) .build())) .build())) .build()); @@ -972,7 +996,9 @@ private static String givenBidResponse(Function AppnexusBidExt extCustomizer) throws JsonProcessingException { return mapper.writeValueAsString(BidResponse.builder() .seatbid(singletonList(SeatBid.builder() - .bid(singletonList(bidCustomizer.apply(Bid.builder().ext(mapper.valueToTree(extCustomizer))).build())) + .bid(singletonList(bidCustomizer.apply(Bid.builder() + .ext(mapper.valueToTree(extCustomizer))) + .build())) .build())) .build()); } diff --git a/src/test/java/org/prebid/server/bidder/brightroll/BrightrollBidderTest.java b/src/test/java/org/prebid/server/bidder/brightroll/BrightrollBidderTest.java index 2501a40e5a0..63f413a92cd 100644 --- a/src/test/java/org/prebid/server/bidder/brightroll/BrightrollBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/brightroll/BrightrollBidderTest.java @@ -17,13 +17,13 @@ import org.junit.Before; import org.junit.Test; import org.prebid.server.VertxTest; +import org.prebid.server.bidder.brightroll.model.PublisherOverride; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderError; import org.prebid.server.bidder.model.HttpCall; 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.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; @@ -33,24 +33,36 @@ import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; public class BrightrollBidderTest extends VertxTest { private static final String ENDPOINT_URL = "http://brightroll.com"; + private static final List BLOCKED_CREATIVETYPES = Arrays.asList(1, 2, 3, 6, 9, 10); + private static final List BLOCKED_CATEGORIES = Arrays.asList("IAB8-5", "IAB8-18", "IAB15-1", "IAB7-30"); + private static final List BLOCKED_ADVERTISERS = Arrays.asList("adv1", "adv2", "adv3"); private BrightrollBidder brightrollBidder; @Before public void setUp() { - brightrollBidder = new BrightrollBidder(ENDPOINT_URL, jacksonMapper); + Map testPublisher = singletonMap("testPublisher", + PublisherOverride.of(BLOCKED_ADVERTISERS, BLOCKED_CATEGORIES, BLOCKED_CREATIVETYPES)); + Map publisher = singletonMap("publisher", + PublisherOverride.of(null, null, null)); + Map publisherIdToOverride = new HashMap<>(); + publisherIdToOverride.putAll(testPublisher); + publisherIdToOverride.putAll(publisher); + brightrollBidder = new BrightrollBidder(ENDPOINT_URL, jacksonMapper, publisherIdToOverride); } @Test @@ -60,7 +72,7 @@ public void makeHttpRequestsShouldReturnHttpRequestWithCorrectBodyHeadersAndMeth final BidRequest bidRequest = BidRequest.builder() .imp(singletonList(Imp.builder() .banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("publisher")))).build())) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("testPublisher")))).build())) .device(Device.builder().ua("ua").ip("192.168.0.1").language("en").dnt(1).build()) .user(User.builder().ext(mapper.valueToTree(ExtUser.builder().consent("consent").build())).build()) .regs(Regs.of(0, mapper.valueToTree(ExtRegs.of(1, null)))) @@ -73,7 +85,7 @@ public void makeHttpRequestsShouldReturnHttpRequestWithCorrectBodyHeadersAndMeth assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1).extracting(HttpRequest::getMethod).containsExactly(HttpMethod.POST); assertThat(result.getValue()).extracting(HttpRequest::getUri) - .containsExactly("http://brightroll.com?publisher=publisher"); + .containsExactly("http://brightroll.com?publisher=testPublisher"); assertThat(result.getValue()).flatExtracting(httpRequest -> httpRequest.getHeaders().entries()) .extracting(Map.Entry::getKey, Map.Entry::getValue) .containsOnly( @@ -86,13 +98,16 @@ public void makeHttpRequestsShouldReturnHttpRequestWithCorrectBodyHeadersAndMeth tuple("x-openrtb-version", "2.5")); assertThat(result.getValue()).extracting(HttpRequest::getBody).containsExactly(mapper.writeValueAsString( BidRequest.builder() - .imp(singletonList(Imp.builder().banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("publisher")))) + .imp(singletonList(Imp.builder() + .banner(Banner.builder().battr(BLOCKED_CREATIVETYPES).build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("testPublisher")))) .build())) .device(Device.builder().ua("ua").ip("192.168.0.1").language("en").dnt(1).build()) .user(User.builder() .ext(mapper.valueToTree(ExtUser.builder().consent("consent").build())) .build()) + .bcat(BLOCKED_CATEGORIES) + .badv(BLOCKED_ADVERTISERS) .regs(Regs.of(0, mapper.valueToTree(ExtRegs.of(1, null)))) .at(1) .build())); @@ -193,16 +208,16 @@ public void makeHttpRequestShouldUpdateBannerWhenWAndHMissedAndFormatIsPresent() } @Test - public void makeHttpRequestsShouldUpdateEachImpIfExtPublisherIsAdthrive() { + public void makeHttpRequestsShouldOverrideBadvAndBcatWhenPublisherIsInBidderAccounts() { // given final BidRequest bidRequest = BidRequest.builder() .imp(Arrays.asList(Imp.builder() .banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("adthrive")))) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("publisher")))) .build(), Imp.builder() .video(Video.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("adthrive")))) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("publisher")))) .build())) .build(); @@ -210,24 +225,27 @@ public void makeHttpRequestsShouldUpdateEachImpIfExtPublisherIsAdthrive() { final Result>> result = brightrollBidder.makeHttpRequests(bidRequest); // then - final List expectedBattr = Arrays.asList(1, 2, 3, 6, 9, 10); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .flatExtracting(BidRequest::getImp).hasSize(2) .extracting(Imp::getBanner, Imp::getVideo) .containsOnly( - tuple(Banner.builder().battr(expectedBattr).build(), null), - tuple(null, Video.builder().battr(expectedBattr).build())); + tuple(Banner.builder().build(), null), + tuple(null, Video.builder().build())); + assertThat(result.getValue()).hasSize(1) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .extracting(BidRequest::getBcat, BidRequest::getBadv) + .containsOnly(tuple(null, null)); } @Test - public void makeHttpRequestsShouldSetRequestBcatIfExtPublisherIsAdthrive() { + public void makeHttpRequestsShouldNotSetRequestBcatIfExtPublisherIsNotInTheBidderAccountList() { // given final BidRequest bidRequest = BidRequest.builder() .imp(Collections.singletonList(Imp.builder() .banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("adthrive")))) + .ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpBrightroll.of("publisher")))) .build())) .build(); @@ -238,8 +256,8 @@ public void makeHttpRequestsShouldSetRequestBcatIfExtPublisherIsAdthrive() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) - .flatExtracting(BidRequest::getBcat) - .hasSize(42); + .extracting(BidRequest::getBcat) + .containsNull(); } @Test diff --git a/src/test/java/org/prebid/server/bidder/consumable/ConsumableBidderTest.java b/src/test/java/org/prebid/server/bidder/consumable/ConsumableBidderTest.java index e272de74039..83559793703 100644 --- a/src/test/java/org/prebid/server/bidder/consumable/ConsumableBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/consumable/ConsumableBidderTest.java @@ -355,14 +355,17 @@ private static Imp givenImp(Function impCustomiz } private static ConsumableDecision givenDecision( - Function decision) { + Function decision) { + return decision.apply(ConsumableDecision.builder()) .build(); } private static HttpCall givenHttpCall( Function bidResponse, - Function decision) + Function decision) throws JsonProcessingException { final String body = mapper.writeValueAsString( diff --git a/src/test/java/org/prebid/server/bidder/conversant/ConversantBidderTest.java b/src/test/java/org/prebid/server/bidder/conversant/ConversantBidderTest.java index e0a52dfc4fb..283eccb7730 100644 --- a/src/test/java/org/prebid/server/bidder/conversant/ConversantBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/conversant/ConversantBidderTest.java @@ -544,7 +544,9 @@ public void extractTargetingShouldReturnEmptyMap() { private static BidRequest givenBidRequest( Function bidRequestCustomizer, Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { + return bidRequestCustomizer.apply(BidRequest.builder() .imp(singletonList(givenImp(impCustomizer, extCustomizer)))) .build(); @@ -556,14 +558,16 @@ private static BidRequest givenBidRequest(Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { return givenBidRequest(identity(), impCustomizer, extCustomizer); } private static Imp givenImp( Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { return impCustomizer.apply(Imp.builder() .id("123") diff --git a/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java b/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java index e3eed4669f6..5e59adf0f4a 100644 --- a/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/cpmstar/CpmStarBidderTest.java @@ -1,6 +1,5 @@ package org.prebid.server.bidder.cpmstar; - import com.fasterxml.jackson.core.JsonProcessingException; import com.iab.openrtb.request.Audio; import com.iab.openrtb.request.Banner; diff --git a/src/test/java/org/prebid/server/bidder/engagebdr/EngagebdrBidderTest.java b/src/test/java/org/prebid/server/bidder/engagebdr/EngagebdrBidderTest.java index 769556a6d13..e60534c3e0c 100644 --- a/src/test/java/org/prebid/server/bidder/engagebdr/EngagebdrBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/engagebdr/EngagebdrBidderTest.java @@ -60,8 +60,8 @@ public void makeHttpRequestsShouldReturnErrorWhenImpContainsAudio() { // then assertThat(result.getErrors()).hasSize(1).containsOnly( - BidderError.badInput("Ignoring imp id=123, invalid MediaType EngageBDR only supports Banner, " + - "Video and Native")); + BidderError.badInput("Ignoring imp id=123, invalid MediaType EngageBDR only supports Banner, " + + "Video and Native")); assertThat(result.getValue()).isEmpty(); } @@ -235,7 +235,6 @@ public void extractTargetingShouldReturnEmptyMap() { assertThat(engagebdrBidder.extractTargeting(mapper.createObjectNode())).isEqualTo(emptyMap()); } - private static BidRequest givenBidRequest(Function impCustomizer) { return givenBidRequest(identity(), impCustomizer); } diff --git a/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java b/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java index 261928171b1..1a4a9cf6e9a 100644 --- a/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java @@ -23,7 +23,6 @@ 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.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.eplanning.ExtImpEplanning; import org.prebid.server.proto.openrtb.ext.response.BidType; @@ -227,8 +226,8 @@ public void makeHttpRequestsShouldSetCorrectUriWithSizeString() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) - .containsOnly( - "https://eplanning.com/clientId/1/FILE/ROS?ct=1&r=pbs&ncb=1&ur=FILE&e=testadun_itco_de:300x200"); + .containsOnly("https://eplanning.com/clientId/1/FILE/ROS?ct=1&r=pbs&ncb=1&ur=FILE&e=testadun_itco_de" + + ":300x200"); } @Test @@ -246,8 +245,8 @@ public void makeHttpRequestsShouldSetCorrectUriWithUserId() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) - .containsOnly("https://eplanning.com/clientId/1/FILE/ROS?ct=1&r=pbs&ncb=1&ur=FILE&e=testadun_itco_de:1x1" - + "&uid=Buyer-ID"); + .containsOnly("https://eplanning.com/clientId/1/FILE/ROS?ct=1&r=pbs&ncb=1&ur=FILE&e=testadun_itco_de" + + ":1x1&uid=Buyer-ID"); } @Test @@ -265,8 +264,8 @@ public void makeHttpRequestsShouldSetCorrectUriWithDeviceIp() { assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) - .containsOnly("https://eplanning.com/clientId/1/FILE/ROS?ct=1&r=pbs&ncb=1&ur=FILE&e=testadun_itco_de:1x1" - + "&ip=123.321.321.123"); + .containsOnly("https://eplanning.com/clientId/1/FILE/ROS?ct=1&r=pbs&ncb=1&ur=FILE&e=testadun_itco_de" + + ":1x1&ip=123.321.321.123"); } @Test diff --git a/src/test/java/org/prebid/server/bidder/facebook/FacebookBidderTest.java b/src/test/java/org/prebid/server/bidder/facebook/FacebookBidderTest.java index 7e51a971cf8..2a588d3bd2d 100644 --- a/src/test/java/org/prebid/server/bidder/facebook/FacebookBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/facebook/FacebookBidderTest.java @@ -381,7 +381,7 @@ public void makeHttpRequestsShouldThrowErrorIfFormatHeightIsInvalid() { // then assertThat(result.getErrors()).hasSize(1) - .containsOnly(BidderError.badInput("imp #imp1: banner height required")); + .containsOnly(BidderError.badInput("imp #imp1: banner height required")); assertThat(result.getValue()).isEmpty(); } @@ -720,7 +720,8 @@ private static Imp givenImp(Function impCustomiz return impCustomizer.apply(Imp.builder() .id("imp1") .banner(Banner.builder().h(50).format(singletonList(Format.builder().build())).build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, impExtCustomizer.apply(ExtImpFacebook.of("placementId", "pubId")))))) + .ext(mapper.valueToTree(ExtPrebid.of( + null, impExtCustomizer.apply(ExtImpFacebook.of("placementId", "pubId")))))) .build(); } diff --git a/src/test/java/org/prebid/server/bidder/gamma/GammaBidderTest.java b/src/test/java/org/prebid/server/bidder/gamma/GammaBidderTest.java index 41a6430faf6..f5d4f1ddd13 100644 --- a/src/test/java/org/prebid/server/bidder/gamma/GammaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/gamma/GammaBidderTest.java @@ -184,9 +184,11 @@ public void makeHttpRequestsShouldFillMethodAndUrlAndExpectedHeadersWhenDeviceAn assertThat(result.getValue()).doesNotContainNull() .hasSize(1).element(0) .returns(HttpMethod.GET, HttpRequest::getMethod) - .returns("https://test.endpoint.com/?id=id&zid=zid&wid=wid&bidid=&hb=pbmobile" + - "&device_ip=123.123.123.12&device_model=Model&device_os=OS&device_ua=userAgent" + - "&device_ifa=ifa&app_id=appId&app_bundle=bundle&app_name=appName", HttpRequest::getUri); + .returns( + "https://test.endpoint.com/?id=id&zid=zid&wid=wid&bidid=&hb=pbmobile" + + "&device_ip=123.123.123.12&device_model=Model&device_os=OS&device_ua=userAgent" + + "&device_ifa=ifa&app_id=appId&app_bundle=bundle&app_name=appName", + HttpRequest::getUri); assertThat(result.getValue().get(0).getHeaders()).isNotNull() .extracting(Map.Entry::getKey, Map.Entry::getValue) .containsOnly( diff --git a/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java b/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java index 43d422d381c..6708d8d6217 100644 --- a/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/ix/IxBidderTest.java @@ -221,7 +221,6 @@ public void makeHttpRequestsShouldCreateOneRequestPerImp() { .format(singletonList(Format.builder().w(600).h(400).build())).build())))) .build(); - // when final Result>> result = ixBidder.makeHttpRequests(bidRequest); diff --git a/src/test/java/org/prebid/server/bidder/lifestreet/LifestreetBidderTest.java b/src/test/java/org/prebid/server/bidder/lifestreet/LifestreetBidderTest.java index 751593df28b..3dffcd363cc 100644 --- a/src/test/java/org/prebid/server/bidder/lifestreet/LifestreetBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/lifestreet/LifestreetBidderTest.java @@ -299,7 +299,6 @@ public void makeBidsShouldReturnVideoBidIfRequestImpHasVideo() throws JsonProces .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), video, "USD")); } - @Test public void extractTargetingShouldReturnEmptyMap() { assertThat(lifestreetBidder.extractTargeting(mapper.createObjectNode())).isEqualTo(emptyMap()); diff --git a/src/test/java/org/prebid/server/bidder/marsmedia/MarsmediaBidderTest.java b/src/test/java/org/prebid/server/bidder/marsmedia/MarsmediaBidderTest.java index 39ab82a1cef..54382dc9be3 100644 --- a/src/test/java/org/prebid/server/bidder/marsmedia/MarsmediaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/marsmedia/MarsmediaBidderTest.java @@ -12,7 +12,6 @@ import com.iab.openrtb.response.SeatBid; import io.netty.handler.codec.http.HttpHeaderValues; import io.vertx.core.MultiMap; -import io.vertx.core.json.Json; import org.junit.Before; import org.junit.Test; import org.prebid.server.VertxTest; @@ -143,7 +142,7 @@ public void makeHttpRequestsShouldReplaceBannerWidthAndHeightWithValuesFromFirst // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) - .extracting(httpRequest -> Json.mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .flatExtracting(BidRequest::getImp) .extracting(Imp::getBanner) .extracting(Banner::getW, Banner::getH) @@ -161,7 +160,7 @@ public void makeHttpRequestsShouldAlwaysSetRequestAtToOne() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) - .extracting(httpRequest -> Json.mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) .flatExtracting(BidRequest::getAt) .containsOnly(1); } diff --git a/src/test/java/org/prebid/server/bidder/mgid/MgidBidderTest.java b/src/test/java/org/prebid/server/bidder/mgid/MgidBidderTest.java index 5e1716a5259..2bbcc5ab955 100644 --- a/src/test/java/org/prebid/server/bidder/mgid/MgidBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/mgid/MgidBidderTest.java @@ -16,7 +16,6 @@ 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.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.mgid.ExtImpMgid; @@ -86,7 +85,7 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { public void makeHttpRequestsShouldReturnErrorIfImpExtAccIdIsBlank() { // given final String currency = "GRP"; - final BigDecimal bidFloor = new BigDecimal(10.3); + final BigDecimal bidFloor = new BigDecimal("10.3"); final String placementId = "placID"; final String accId = ""; final BidRequest bidRequest = BidRequest.builder() @@ -158,10 +157,12 @@ public void makeHttpRequestsShouldSetTagidToIncomingRequestWhenImpExtHasNotBlank } @Test - public void makeHttpRequestsShouldSetBidFloorCurAndBidFloorToIncomingRequestWhenImpExtHasNotBlankCurAndBidfloor() throws JsonProcessingException { + public void makeHttpRequestsShouldSetBidFloorCurAndBidFloorToIncomingRequestWhenImpExtHasNotBlankCurAndBidfloor() + throws JsonProcessingException { + // given final String currency = "GRP"; - final BigDecimal bidFloor = new BigDecimal(10.3); + final BigDecimal bidFloor = new BigDecimal("10.3"); final String placementId = "placID"; final String accId = "accId"; final BidRequest bidRequest = BidRequest.builder() @@ -196,10 +197,11 @@ public void makeHttpRequestsShouldSetBidFloorCurAndBidFloorToIncomingRequestWhen } @Test - public void makeHttpRequestsShouldSetBidFloorCurAndBidFloorToIncomingRequestWhenImpExtHasNotBlankCurencyAndBidFloor() throws JsonProcessingException { + public void makeHttpRequestsShouldSetBidFloorCurAndBidFloorToRequestWhenImpExtHasNotBlankCurrencyAndBidFloor() + throws JsonProcessingException { // given final String currency = "GRP"; - final BigDecimal bidFloor = new BigDecimal(10.3); + final BigDecimal bidFloor = new BigDecimal("10.3"); final String placementId = "placID"; final String accId = "accId"; final BidRequest bidRequest = BidRequest.builder() @@ -234,7 +236,8 @@ public void makeHttpRequestsShouldSetBidFloorCurAndBidFloorToIncomingRequestWhen } @Test - public void makeHttpRequestsShouldNotModifyIncomingRequestWhenImpExtNotContainsParamters() throws JsonProcessingException { + public void makeHttpRequestsShouldNotModifyIncomingRequestWhenImpExtNotContainsParameters() + throws JsonProcessingException { // given final String placementId = "placID"; final String impId = "impId"; @@ -270,7 +273,6 @@ public void makeHttpRequestsShouldNotModifyIncomingRequestWhenImpExtNotContainsP .containsOnly(mapper.writeValueAsString(expected)); } - @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given diff --git a/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java b/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java index 23f2526e62e..1f9e0f51300 100644 --- a/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/openx/OpenxBidderTest.java @@ -23,7 +23,6 @@ import org.prebid.server.bidder.model.HttpResponse; import org.prebid.server.bidder.model.Result; import org.prebid.server.bidder.openx.proto.OpenxRequestExt; -import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; @@ -238,7 +237,6 @@ public void makeHttpRequestsShouldReturnResultWithExpectedFieldsSet() { .delDomain("se-demo-d.openx.net") .unit("unitId").build()))).build(), - Imp.builder().id("impId1").audio(Audio.builder().build()).build())) .user(User.builder().ext(mapper.valueToTree(ExtUser.builder().consent("consent").build())).build()) .regs(Regs.of(0, mapper.valueToTree(ExtRegs.of(1, null)))) diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticAdapterTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticAdapterTest.java index ee12ed4568c..ddc76619545 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticAdapterTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticAdapterTest.java @@ -55,7 +55,6 @@ import static java.util.function.Function.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatNullPointerException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.eq; @@ -85,12 +84,6 @@ public void setUp() { adapter = new PubmaticAdapter(COOKIE_FAMILY, ENDPOINT_URL, jacksonMapper); } - @Test - public void creationShouldFailOnNullArguments() { - assertThatNullPointerException().isThrownBy(() -> new PubmaticAdapter(null, null, jacksonMapper)); - assertThatNullPointerException().isThrownBy(() -> new PubmaticAdapter(COOKIE_FAMILY, null, jacksonMapper)); - } - @Test public void creationShouldFailOnInvalidEndpointUrl() { assertThatIllegalArgumentException() diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java index 22a30fa32a5..3b5e488913a 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -170,8 +170,8 @@ public void makeHttpRequestsShouldReturnErrorIfKeywordsAreInvalid() { // then assertThat(result.getErrors()).hasSize(1); - assertThat(result.getErrors().get(0).getMessage()).startsWith("Failed to create keywords with error: " + - "Unexpected character"); + assertThat(result.getErrors().get(0).getMessage()) + .startsWith("Failed to create keywords with error: Unexpected character"); assertThat(result.getValue()).isEmpty(); } @@ -567,7 +567,9 @@ private static BidRequest givenBidRequest( } private static Imp givenImp(Function impCustomizer, - Function extCustomizer) { + Function extCustomizer) { + return impCustomizer.apply(Imp.builder() .id("123") .banner(Banner.builder().build()) diff --git a/src/test/java/org/prebid/server/bidder/rhythmone/RhythmoneBidderTest.java b/src/test/java/org/prebid/server/bidder/rhythmone/RhythmoneBidderTest.java index bf5545364cd..d413170d5aa 100644 --- a/src/test/java/org/prebid/server/bidder/rhythmone/RhythmoneBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/rhythmone/RhythmoneBidderTest.java @@ -80,8 +80,8 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtBidderCouldNotBeParsed() { // then assertThat(result.getErrors()).hasSize(1) - .containsOnly(BidderError.badInput("placementId | zone | path not provided in imp id=123. Abort all " + - "Request")); + .containsOnly(BidderError.badInput( + "placementId | zone | path not provided in imp id=123. Abort all Request")); assertThat(result.getValue()).isEmpty(); } diff --git a/src/test/java/org/prebid/server/bidder/rubicon/RubiconAdapterTest.java b/src/test/java/org/prebid/server/bidder/rubicon/RubiconAdapterTest.java index a79b8ccde60..e7ff8dca125 100644 --- a/src/test/java/org/prebid/server/bidder/rubicon/RubiconAdapterTest.java +++ b/src/test/java/org/prebid/server/bidder/rubicon/RubiconAdapterTest.java @@ -489,7 +489,7 @@ public void makeHttpRequestsShouldReturnBidRequestsWithInventoryDataFromPreBidRe // given final ObjectNode inventory = mapper.createObjectNode(); inventory.set("rating", mapper.createArrayNode().add(new TextNode("5-star"))); - inventory.set("prodtype", mapper.createArrayNode().add((new TextNode("tech")))); + inventory.set("prodtype", mapper.createArrayNode().add(new TextNode("tech"))); adapterRequest = givenBidderCustomizable(identity(), builder -> builder.inventory(inventory)); @@ -508,7 +508,7 @@ public void makeHttpRequestsShouldReturnBidRequestsWithVisitorDataFromPreBidRequ // given final ObjectNode visitor = mapper.createObjectNode(); visitor.set("ucat", mapper.createArrayNode().add(new TextNode("new"))); - visitor.set("search", mapper.createArrayNode().add((new TextNode("iphone")))); + visitor.set("search", mapper.createArrayNode().add(new TextNode("iphone"))); adapterRequest = givenBidderCustomizable(identity(), builder -> builder.visitor(visitor)); @@ -641,8 +641,7 @@ public void makeHttpRequestsShouldReturnListWithMultipleRequestsIfMultipleAdUnit } @Test - public void makeHttpRequestsShouldReturnBidRequestsWithoutVideoExtWhenMediaTypeIsVideoAndRubiconParamsVideoIsNull - () { + public void makeHttpRequestsShouldReturnRequestsWithoutVideoExtWhenMediaTypeIsVideoAndRubiconParamsVideoIsNull() { // given adapterRequest = AdapterRequest.of(BIDDER, singletonList( givenAdUnitBidCustomizable(builder -> builder diff --git a/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java b/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java index cec303a8b1b..c4b5300159d 100644 --- a/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/rubicon/RubiconBidderTest.java @@ -339,7 +339,7 @@ public void makeHttpRequestsShouldFillVideoExt() { public void makeHttpRequestsShouldTransferRewardedVideoFlagIntoRewardedVideoObject() { // given final ExtImpPrebid prebid = - ExtImpPrebid.builder().isRewardedInventory(true).build(); + ExtImpPrebid.builder().isRewardedInventory(1).build(); final ExtImpRubicon rubicon = ExtImpRubicon.builder() .video(RubiconVideoParams.builder().skip(5).skipdelay(10).sizeId(14).build()) .build(); @@ -390,6 +390,33 @@ public void makeHttpRequestsShouldIgnoreRewardedVideoLogic() { .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); } + @Test + public void makeHttpRequestsShouldIgnoreRewardedVideoLogicIfRewardedInventoryIsNotOne() { + // given + final ExtImpPrebid prebid = ExtImpPrebid.builder().isRewardedInventory(2).build(); + final ExtImpRubicon rubicon = ExtImpRubicon.builder() + .video(RubiconVideoParams.builder().skip(5).skipdelay(10).sizeId(14).build()) + .build(); + + final ExtPrebid ext = ExtPrebid.of(prebid, rubicon); + + final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.video(Video.builder().build()) + .ext(mapper.valueToTree(ext))); + + // when + final Result>> result = rubiconBidder.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1).doesNotContainNull() + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp).doesNotContainNull() + .extracting(Imp::getVideo).doesNotContainNull() + .extracting(Video::getExt).doesNotContainNull() + .extracting(ex -> mapper.treeToValue(ex, RubiconVideoExt.class)) + .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); + } + @Test public void makeHttpRequestsShouldNotFailIfVideoParamIsNull() { // given @@ -414,7 +441,7 @@ public void makeHttpRequestsShouldNotFailIfVideoParamIsNull() { @Test public void makeHttpRequestsShouldIgnoreRewardedVideoFlag() { // given - final ExtImpPrebid prebid = ExtImpPrebid.builder().isRewardedInventory(false).build(); + final ExtImpPrebid prebid = ExtImpPrebid.builder().isRewardedInventory(0).build(); final ExtImpRubicon rubicon = ExtImpRubicon.builder() .video(RubiconVideoParams.builder().skip(5).skipdelay(10).sizeId(14).build()) .build(); @@ -438,7 +465,6 @@ public void makeHttpRequestsShouldIgnoreRewardedVideoFlag() { .containsOnly(RubiconVideoExt.of(5, 10, RubiconVideoExtRp.of(14), null)); } - @Test public void makeHttpRequestsShouldFillUserExtIfUserAndVisitorPresent() { // given @@ -1643,12 +1669,12 @@ public void makeBidsShouldNotReturnImpIfPriceLessOrEqualToZero() throws JsonProc public void makeBidsShouldReturnBidWithBidIdFieldFromBidResponseIfZero() throws JsonProcessingException { // given final HttpCall httpCall = givenHttpCall(givenBidRequest(identity()), - mapper.writeValueAsString((BidResponse.builder() + mapper.writeValueAsString(BidResponse.builder() .bidid("bidid1") // returned bidid from XAPI .seatbid(singletonList(SeatBid.builder() .bid(singletonList(Bid.builder().id("0").price(ONE).build())) .build())) - .build()))); + .build())); // when final Result> result = rubiconBidder.makeBids(httpCall, null); @@ -1663,12 +1689,12 @@ public void makeBidsShouldReturnBidWithBidIdFieldFromBidResponseIfZero() throws public void makeBidsShouldReturnBidWithOriginalBidIdFieldFromBidResponseIfNotZero() throws JsonProcessingException { // given final HttpCall httpCall = givenHttpCall(givenBidRequest(identity()), - mapper.writeValueAsString((BidResponse.builder() + mapper.writeValueAsString(BidResponse.builder() .bidid("bidid1") // returned bidid from XAPI .seatbid(singletonList(SeatBid.builder() .bid(singletonList(Bid.builder().id("non-zero").price(ONE).build())) .build())) - .build()))); + .build())); // when final Result> result = rubiconBidder.makeBids(httpCall, null); @@ -1686,11 +1712,11 @@ public void makeBidsShouldReturnBidWithRandomlyGeneratedId() throws JsonProcessi ENDPOINT_URL, USERNAME, PASSWORD, SUPPORTED_VENDORS, true, jacksonMapper); final HttpCall httpCall = givenHttpCall(givenBidRequest(identity()), - mapper.writeValueAsString((BidResponse.builder() + mapper.writeValueAsString(BidResponse.builder() .seatbid(singletonList(SeatBid.builder() .bid(singletonList(Bid.builder().id("bidid1").price(ONE).build())) .build())) - .build()))); + .build())); // when final Result> result = rubiconBidder.makeBids(httpCall, null); diff --git a/src/test/java/org/prebid/server/bidder/sharethrough/HttpUserAgentUtilTest.java b/src/test/java/org/prebid/server/bidder/sharethrough/HttpUserAgentUtilTest.java index 43aaf1dce8d..dd84f0cec81 100644 --- a/src/test/java/org/prebid/server/bidder/sharethrough/HttpUserAgentUtilTest.java +++ b/src/test/java/org/prebid/server/bidder/sharethrough/HttpUserAgentUtilTest.java @@ -9,11 +9,11 @@ public class HttpUserAgentUtilTest { @Test public void isAndroidShouldReturnTrueWhenDeviceOcIsAndroid() { // given - final String firstUaAndroid = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + - "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; + final String firstUaAndroid = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + + "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; - final String secondUaAndroid = "Mozilla/5.0 (Linux; android 4.4; Nexus 5 Build/_BuildID_) " + - "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"; + final String secondUaAndroid = "Mozilla/5.0 (Linux; android 4.4; Nexus 5 Build/_BuildID_) " + + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"; // when and then assertThat(HttpUserAgentUtil.isAndroid(firstUaAndroid)).isTrue(); @@ -23,12 +23,12 @@ public void isAndroidShouldReturnTrueWhenDeviceOcIsAndroid() { @Test public void isIosShouldReturnTrueWhenDeviceIsIphoneOrIpadORIpod() { // given - final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1"; - final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; - final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; + final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1"; + final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; + final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; // when and then assertThat(HttpUserAgentUtil.isIos(uaIphone)).isTrue(); @@ -39,10 +39,10 @@ public void isIosShouldReturnTrueWhenDeviceIsIphoneOrIpadORIpod() { @Test public void isAtMinChromeIosVersionShouldReturnFalseWhenVersionIsNotSetup() { // given - final String uaWithoutCriOsVersion = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/ Mobile/14E5239e Safari/602.1"; - final String uaWithoutCriOs = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14E5239e Safari/602.1"; + final String uaWithoutCriOsVersion = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/ Mobile/14E5239e Safari/602.1"; + final String uaWithoutCriOs = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/602.1.50 (KHTML, like Gecko) Mobile/14E5239e Safari/602.1"; // when and then assertThat(HttpUserAgentUtil.isAtMinChromeIosVersion(uaWithoutCriOsVersion, 2)).isFalse(); @@ -51,14 +51,13 @@ public void isAtMinChromeIosVersionShouldReturnFalseWhenVersionIsNotSetup() { assertThat(HttpUserAgentUtil.isAtMinChromeIosVersion(uaWithoutCriOs, 100)).isFalse(); } - @Test public void isAtMinChromeVersionShouldReturnFalseWhenVersionIsNotSetup() { // given - final String uaWithoutChromeVersion = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + - "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/ Mobile Safari/535.19"; - final String uaWithoutChrome = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + - "AppleWebKit/535.19 (KHTML, like Gecko)Mobile Safari/535.19"; + final String uaWithoutChromeVersion = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + + "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/ Mobile Safari/535.19"; + final String uaWithoutChrome = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + + "AppleWebKit/535.19 (KHTML, like Gecko)Mobile Safari/535.19"; // when and then assertThat(HttpUserAgentUtil.isAtMinChromeVersion(uaWithoutChromeVersion, 2)).isFalse(); @@ -70,10 +69,10 @@ public void isAtMinChromeVersionShouldReturnFalseWhenVersionIsNotSetup() { @Test public void isAtMinSafariVersionShouldReturnFalseWhenVersionIsNotSetup() { // given - final String uaWithoutSafariVersion = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/ Mobile/14E5239e Safari/602.1"; - final String uaWithoutSafari = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/603.1.23 (KHTML, like Gecko) Mobile/14E5239e Safari/602.1"; + final String uaWithoutSafariVersion = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/ Mobile/14E5239e Safari/602.1"; + final String uaWithoutSafari = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/603.1.23 (KHTML, like Gecko) Mobile/14E5239e Safari/602.1"; // when and then assertThat(HttpUserAgentUtil.isAtMinSafariVersion(uaWithoutSafariVersion, 2)).isFalse(); @@ -82,14 +81,13 @@ public void isAtMinSafariVersionShouldReturnFalseWhenVersionIsNotSetup() { assertThat(HttpUserAgentUtil.isAtMinSafariVersion(uaWithoutSafari, 100)).isFalse(); } - @Test public void isAtMinChromeVersionShouldReturnFalseWhenVersionIsLessThanMinVersion() { // given - final String firstUaAndroid = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + - "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; - final String secondUaAndroid = "Mozilla/5.0 (Linux; android 4.4; Nexus 5 Build/_BuildID_) " + - "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"; + final String firstUaAndroid = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + + "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; + final String secondUaAndroid = "Mozilla/5.0 (Linux; android 4.4; Nexus 5 Build/_BuildID_) " + + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"; // when and then assertThat(HttpUserAgentUtil.isAtMinSafariVersion(firstUaAndroid, 19)).isFalse(); @@ -103,12 +101,12 @@ public void isAtMinChromeVersionShouldReturnFalseWhenVersionIsLessThanMinVersion @Test public void isAtMinChromeIosVersionShouldReturnFalseWhenVersionIsLessThanMinVersion() { // given - final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e "; - final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/23.0.2924.75 Mobile/7B314 "; - final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/13.0.2924.75 Mobile/7B314 "; + final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e "; + final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/23.0.2924.75 Mobile/7B314 "; + final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/13.0.2924.75 Mobile/7B314 "; // when and then assertThat(HttpUserAgentUtil.isAtMinChromeIosVersion(uaIphone, 57)).isFalse(); @@ -125,12 +123,12 @@ public void isAtMinChromeIosVersionShouldReturnFalseWhenVersionIsLessThanMinVers @Test public void isAtMinSafariVersionShouldReturnFalseWhenVersionIsLessThanMinVersion() { // given - final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1"; - final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; - final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; + final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1"; + final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; + final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10"; // when and then assertThat(HttpUserAgentUtil.isIos(uaIphone)).isTrue(); @@ -141,10 +139,10 @@ public void isAtMinSafariVersionShouldReturnFalseWhenVersionIsLessThanMinVersion @Test public void isAtMinChromeVersionShouldReturnTrueWhenVersionIsGreaterEqualMinVersion() { // given - final String firstUaAndroid = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + - "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; - final String secondUaAndroid = "Mozilla/5.0 (Linux; android 4.4; Nexus 5 Build/_BuildID_) " + - "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"; + final String firstUaAndroid = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) " + + "AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; + final String secondUaAndroid = "Mozilla/5.0 (Linux; android 4.4; Nexus 5 Build/_BuildID_) " + + "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"; // when and then assertThat(HttpUserAgentUtil.isAtMinSafariVersion(firstUaAndroid, 18)).isFalse(); @@ -158,12 +156,12 @@ public void isAtMinChromeVersionShouldReturnTrueWhenVersionIsGreaterEqualMinVers @Test public void isAtMinChromeIosVersionShouldReturnTrueWhenVersionIsGreaterEqualMinVersion() { // given - final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e "; - final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/23.0.2924.75 Mobile/7B314 "; - final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + - "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/13.0.2924.75 Mobile/7B314 "; + final String uaIphone = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e "; + final String uaIpad = "Mozilla/5.0(iPad; U; like Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/23.0.2924.75 Mobile/7B314 "; + final String uaIpod = "Mozilla/5.0(iPod; U; Mac OS X; en-us) " + + "AppleWebKit/531.21.10 (KHTML, like Gecko) CriOS/13.0.2924.75 Mobile/7B314 "; // when and then assertThat(HttpUserAgentUtil.isAtMinChromeIosVersion(uaIphone, 56)).isTrue(); @@ -180,8 +178,8 @@ public void isAtMinChromeIosVersionShouldReturnTrueWhenVersionIsGreaterEqualMinV @Test public void isAtMinSafariVersionShouldReturnTrueWhenVersionIsGreaterEqualMinVersion() { // given - final String uaSafari = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + - "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1"; + final String uaSafari = "Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) " + + "AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1"; // when and then assertThat(HttpUserAgentUtil.isAtMinSafariVersion(uaSafari, 10)).isTrue(); @@ -189,4 +187,3 @@ public void isAtMinSafariVersionShouldReturnTrueWhenVersionIsGreaterEqualMinVers assertThat(HttpUserAgentUtil.isAtMinSafariVersion(uaSafari, 1)).isTrue(); } } - diff --git a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java index d75aadd4bd5..fd549c36389 100644 --- a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughBidderTest.java @@ -23,7 +23,6 @@ import org.prebid.server.bidder.sharethrough.model.bidresponse.ExtImpSharethroughCreative; import org.prebid.server.bidder.sharethrough.model.bidresponse.ExtImpSharethroughCreativeMetadata; import org.prebid.server.bidder.sharethrough.model.bidresponse.ExtImpSharethroughResponse; -import org.prebid.server.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtUser; import org.prebid.server.proto.openrtb.ext.request.ExtUserEid; @@ -136,9 +135,9 @@ public void makeHttpRequestsShouldReturnRequestWithCorrectUriAndHeaders() throws bidRequest); // then - final String expectedParameters = "?placement_key=pkey&bidId=abc&consent_required=false&consent_string=" + - "&instant_play_capable=true&stayInIframe=false&height=10&width=20" + - "&adRequestAt=" + URLENCODED_TEST_FORMATTED_TIME + "&supplyId=FGMrCMMc&strVersion=7"; + final String expectedParameters = "?placement_key=pkey&bidId=abc&consent_required=false&consent_string=" + + "&instant_play_capable=true&stayInIframe=false&height=10&width=20" + + "&adRequestAt=" + URLENCODED_TEST_FORMATTED_TIME + "&supplyId=FGMrCMMc&strVersion=7"; final SharethroughRequestBody expectedPayload = SharethroughRequestBody.of(singletonList("testBlocked"), 2000L, DEADLINE_FORMATTED_TIME, true, BigDecimal.ONE); @@ -161,7 +160,8 @@ public void makeHttpRequestsShouldReturnRequestWithCorrectUriAndHeaders() throws } @Test - public void makeHttpRequestsShouldReturnRequestWithCorrectUriAndHeadersDefaultParameters() throws JsonProcessingException { + public void makeHttpRequestsShouldReturnRequestWithCorrectUriAndHeadersDefaultParameters() + throws JsonProcessingException { // given final List uids = Arrays.asList( ExtUserEidUid.of("first", null), @@ -188,8 +188,8 @@ public void makeHttpRequestsShouldReturnRequestWithCorrectUriAndHeadersDefaultPa bidRequest); // then - final String expectedParameters = "?placement_key=pkey&bidId&consent_required=false&consent_string=consent" + - "&instant_play_capable=false&stayInIframe=false&height=1&width=1" + final String expectedParameters = "?placement_key=pkey&bidId&consent_required=false&consent_string=consent" + + "&instant_play_capable=false&stayInIframe=false&height=1&width=1" + "&adRequestAt=" + URLENCODED_TEST_FORMATTED_TIME + "&supplyId=FGMrCMMc&strVersion=7&ttduid=first&stxuid=buyer"; final SharethroughRequestBody expectedPayload = SharethroughRequestBody.of(null, 2000L, @@ -230,26 +230,31 @@ public void makeBidsShouldReturnCorrectBidderBid() throws JsonProcessingExceptio final Result> result = sharethroughBidder.makeBids(httpCall, null); // then - final String adm = "\n" + - "\t\t
    \n" + - //Decoded: {"adserverRequestId":"arid","bidId":"bid","creatives":[{"cpm":10,"creative":{"campaign_key":"cmpKey","creative_key":"creaKey","deal_id":"dealId"}]} - "\t\t\n" + - "\t\t\t\n" + - "\t \t\n"; + final String adm = "\n" + + "\t\t
    \n" + // Decoded: {"adserverRequestId":"arid","bidId":"bid","creatives":[{"cpm":10, + // "creative":{"campaign_key":"cmpKey","creative_key":"creaKey","deal_id":"dealId"}]} + + "\t\t\n\t\t\t\n" + + "\t \t\n"; final BidderBid expected = BidderBid.of( Bid.builder() diff --git a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughMarkupUtilTest.java b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughMarkupUtilTest.java index 06b2426343f..a32accb7ae4 100644 --- a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughMarkupUtilTest.java +++ b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughMarkupUtilTest.java @@ -30,11 +30,12 @@ public void getAdMarkupShouldReturnScriptWithParametersFromImpResponseAndUriPara final String result = SharethroughMarkupUtil.getAdMarkup(strResponse, impResponse, uriParameters, TEST_TIME); // then - final String expected = "\n" + - "\t\t
    \n" + + final String expected = "\n" + + "\t\t
    \n" // Encoded {"adserverRequestId":"arid","bidId":"bid"} - "\t\t"; + + "\t\t"; assertThat(result.contains(expected)).isTrue(); } @@ -76,7 +77,8 @@ public void getAdMarkupShouldContainsScriptWhenIframeItFalse() { final String result = SharethroughMarkupUtil.getAdMarkup("", impResponse, uriParameters, new Date()); // then - final String expectedContains = ""; + final String expectedContains = ""; assertThat(result.contains(expectedContains)).isTrue(); } } diff --git a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtilTest.java b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtilTest.java index f6b5a441849..78041402646 100644 --- a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtilTest.java +++ b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughRequestUtilTest.java @@ -70,7 +70,6 @@ public void getHostShouldReturnHostWhenStringUri() { assertThat(requestUtil.getHost(thirdUri)).isEqualTo("http://a.domain.com"); } - @Test public void retrieveFromUserInfoShouldReturnEmptyStringWhenUserInfoOrParameterIsNull() { // given diff --git a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughUriBuilderUtilTest.java b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughUriBuilderUtilTest.java index 8b5f0a81914..6ee4285d59a 100644 --- a/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughUriBuilderUtilTest.java +++ b/src/test/java/org/prebid/server/bidder/sharethrough/SharethroughUriBuilderUtilTest.java @@ -63,7 +63,7 @@ public void buildSharethroughUrlParametersShouldConsentRequiredBeFalseWhenConsen } @Test - public void buildSharethroughUrlParametersShouldReturnOptionalParametersWithEmptyStringWhenUriNotContainsOptionalParameters() { + public void buildSharethroughUrlParametersShouldReturnOptionalParametersWithEmptyStringWhenUriHasNoOptParameters() { // given final String uriWithoutOptionalParameters = "http://uri.com?height=30&width=30"; @@ -79,8 +79,8 @@ public void buildSharethroughUrlParametersShouldReturnOptionalParametersWithEmpt @Test public void buildSharethroughUrlParametersShouldPopulateWithParametersWhenUriContainsParameters() { // given - final String uriWithoutOptionalParameters = "http://uri.com?placement_key=pkey&bidId=bidid&height=30&width=30" + - "&consent_required=true&stayInIframe=true&consent_string=123&"; + final String uriWithoutOptionalParameters = "http://uri.com?placement_key=pkey&bidId=bidid&height=30&width=30" + + "&consent_required=true&stayInIframe=true&consent_string=123&"; // when and then assertThat(SharethroughUriBuilderUtil.buildSharethroughUrlParameters(uriWithoutOptionalParameters)) @@ -116,9 +116,9 @@ public void buildSharethroughUrlShouldReturnUriWithParametersFromStrUriParameter final String strVersion = "version"; // when - final String expected = "http://uri.com?placement_key=3pkey3&bidId=2bidId2&consent_required=true&" + - "consent_string=1consentString1&instant_play_capable=true&stayInIframe=true&height=100&width=200&" + - "adRequestAt=testDate&supplyId=suId&strVersion=version&ttduid=ttd123&stxuid=uuid"; + final String expected = "http://uri.com?placement_key=3pkey3&bidId=2bidId2&consent_required=true&" + + "consent_string=1consentString1&instant_play_capable=true&stayInIframe=true&height=100&width=200&" + + "adRequestAt=testDate&supplyId=suId&strVersion=version&ttduid=ttd123&stxuid=uuid"; final String result = SharethroughUriBuilderUtil.buildSharethroughUrl(baseUri, supplyId, strVersion, "testDate", strUriParameters); diff --git a/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java b/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java index 45d43e99394..8d34e38e070 100644 --- a/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/smartrtb/SmartrtbBidderTest.java @@ -11,9 +11,6 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.netty.handler.codec.http.HttpHeaderValues; -import java.util.List; -import java.util.Map; -import java.util.function.Function; import org.junit.Before; import org.junit.Test; import org.prebid.server.VertxTest; @@ -28,6 +25,10 @@ import org.prebid.server.proto.openrtb.ext.request.smartrtb.ExtImpSmartrtb; import org.prebid.server.util.HttpUtil; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; @@ -124,7 +125,6 @@ public void makeHttpRequestsShouldSetExpectedRequestUrlAndDefaultHeaders() { tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString())); } - @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given @@ -148,7 +148,8 @@ public void makeBidsShouldReturnErrorWhenBidExtIsEmpty() throws JsonProcessingEx final Result> result = smartrtbBidder.makeBids(httpCall, null); // then - assertThat(result.getErrors()).containsOnly(BidderError.badServerResponse("Invalid bid extension from endpoint.")); + assertThat(result.getErrors()).containsOnly( + BidderError.badServerResponse("Invalid bid extension from endpoint.")); assertThat(result.getValue()).isEmpty(); } @@ -180,7 +181,8 @@ public void makeBidsShouldReturnTypeBannerWhenResponseExtCreativeTypeEmpty() thr final Result> result = smartrtbBidder.makeBids(httpCall, null); // then - assertThat(result.getErrors()).containsOnly(BidderError.badServerResponse("Unsupported creative type wrong type.")); + assertThat(result.getErrors()).containsOnly( + BidderError.badServerResponse("Unsupported creative type wrong type.")); } @Test diff --git a/src/test/java/org/prebid/server/bidder/somoaudience/SomoaudienceBidderTest.java b/src/test/java/org/prebid/server/bidder/somoaudience/SomoaudienceBidderTest.java index b449ee90f6e..7de3b44ace1 100644 --- a/src/test/java/org/prebid/server/bidder/somoaudience/SomoaudienceBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/somoaudience/SomoaudienceBidderTest.java @@ -442,9 +442,9 @@ public void makeBidsShouldReturnEmptyBidderWithErrorWhenResponseCantBeParsed() { // then assertThat(result.getErrors()).hasSize(1) .containsExactly(BidderError.badServerResponse( - "Failed to decode: Unexpected end-of-input: expected close marker for Object (start marker at" + - " [Source: (String)\"{\"; line: 1, column: 1])\n at [Source: (String)\"{\"; line: 1, " + - "column: 3]")); + "Failed to decode: Unexpected end-of-input: expected close marker for Object (start marker at" + + " [Source: (String)\"{\"; line: 1, column: 1])\n at [Source: (String)\"{\"; line: 1, " + + "column: 3]")); } private static HttpCall givenHttpCall(String body) { diff --git a/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java b/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java index cdfb58c5946..b7904c390d6 100644 --- a/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java @@ -23,7 +23,6 @@ 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.json.JacksonMapper; import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRegs; import org.prebid.server.proto.openrtb.ext.request.ExtUser; diff --git a/src/test/java/org/prebid/server/bidder/synacormedia/SynacormediaBidderTest.java b/src/test/java/org/prebid/server/bidder/synacormedia/SynacormediaBidderTest.java index 3023d156da8..92e14f32e43 100644 --- a/src/test/java/org/prebid/server/bidder/synacormedia/SynacormediaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/synacormedia/SynacormediaBidderTest.java @@ -10,8 +10,6 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; -import java.util.List; -import java.util.function.Function; import org.junit.Before; import org.junit.Test; import org.prebid.server.VertxTest; @@ -24,6 +22,9 @@ import org.prebid.server.proto.openrtb.ext.ExtPrebid; import org.prebid.server.proto.openrtb.ext.request.synacormedia.ExtImpSynacormedia; +import java.util.List; +import java.util.function.Function; + import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; @@ -94,7 +95,8 @@ public void makeHttpRequestsShouldExcludeInvalidImpAndReturnExpectedResult() { public void makeHttpRequestsShouldReturnErrorIfFirstValidImpHasEmptySeatId() { // given final BidRequest bidRequest = givenBidRequest( - impBuilder -> impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpSynacormedia.of(" ", "tagId")))), + impBuilder -> impBuilder.ext(mapper.valueToTree( + ExtPrebid.of(null, ExtImpSynacormedia.of(" ", "tagId")))), identity()); // when @@ -110,7 +112,8 @@ public void makeHttpRequestsShouldReturnErrorIfFirstValidImpHasEmptySeatId() { public void makeHttpRequestsShouldReturnErrorIfFirstValidImpHasEmptyTagId() { // given final BidRequest bidRequest = givenBidRequest( - impBuilder -> impBuilder.ext(mapper.valueToTree(ExtPrebid.of(null, ExtImpSynacormedia.of("seadId", " ")))), + impBuilder -> impBuilder.ext(mapper.valueToTree( + ExtPrebid.of(null, ExtImpSynacormedia.of("seadId", " ")))), identity()); // when diff --git a/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java b/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java index 66433067ea5..b99d60276d1 100644 --- a/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/tripleliftnative/TripleliftNativeBidderTest.java @@ -270,9 +270,11 @@ public void extractTargetingShouldReturnEmptyMap() { assertThat(tripleliftNativeBidder.extractTargeting(mapper.createObjectNode())).isEqualTo(emptyMap()); } - private static BidRequest givenBidRequest(Function bidRequestCustomizer, - Function impCustomizer, - ExtImpTriplelift extImpTriplelift) { + private static BidRequest givenBidRequest( + Function bidRequestCustomizer, + Function impCustomizer, + ExtImpTriplelift extImpTriplelift) { + return bidRequestCustomizer.apply(BidRequest.builder() .imp(singletonList(givenImp(impCustomizer, extImpTriplelift)))) .build(); diff --git a/src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java b/src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java index 9b6b6be4877..85431dbc164 100644 --- a/src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/ttx/TtxBidderTest.java @@ -105,7 +105,6 @@ public void makeHttpRequestsShouldGetDetailsOnlyFromFirstImpExt() { .containsOnly("siteId"); } - @Test public void makeHttpRequestsShouldChangeOnlyFirstImpExt() { // given diff --git a/src/test/java/org/prebid/server/bidder/yieldone/YieldoneBidderTest.java b/src/test/java/org/prebid/server/bidder/yieldone/YieldoneBidderTest.java new file mode 100644 index 00000000000..7bdbaa285ae --- /dev/null +++ b/src/test/java/org/prebid/server/bidder/yieldone/YieldoneBidderTest.java @@ -0,0 +1,243 @@ +package org.prebid.server.bidder.yieldone; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.iab.openrtb.request.Audio; +import com.iab.openrtb.request.Banner; +import com.iab.openrtb.request.BidRequest; +import com.iab.openrtb.request.Format; +import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.Video; +import com.iab.openrtb.response.Bid; +import com.iab.openrtb.response.BidResponse; +import com.iab.openrtb.response.SeatBid; +import org.junit.Before; +import org.junit.Test; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.model.BidderBid; +import org.prebid.server.bidder.model.BidderError; +import org.prebid.server.bidder.model.HttpCall; +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.proto.openrtb.ext.ExtPrebid; +import org.prebid.server.proto.openrtb.ext.request.yieldone.ExtImpYieldone; +import org.prebid.server.proto.openrtb.ext.response.BidType; + +import java.util.Arrays; +import java.util.List; +import java.util.function.Function; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.singletonList; +import static java.util.function.Function.identity; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.api.Assertions.tuple; + +public class YieldoneBidderTest extends VertxTest { + + private static final String ENDPOINT_URL = "https://test.endpoint.com"; + + private YieldoneBidder yieldoneBidder; + + @Before + public void setUp() { + yieldoneBidder = new YieldoneBidder(ENDPOINT_URL, jacksonMapper); + } + + @Test + public void creationShouldFailOnInvalidEndpointUrl() { + assertThatIllegalArgumentException().isThrownBy(() -> new YieldoneBidder("invalid_url", jacksonMapper)); + } + + @Test + public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { + // given + final BidRequest bidRequest = BidRequest.builder() + .imp(singletonList(Imp.builder() + .banner(Banner.builder().format(singletonList(Format.builder().w(300).h(500).build())).build()) + .ext(mapper.valueToTree(ExtPrebid.of(null, mapper.createArrayNode()))).build())) + .build(); + // when + final Result>> result = yieldoneBidder.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).hasSize(1); + assertThat(result.getErrors().get(0).getMessage()).startsWith("Cannot deserialize instance"); + } + + @Test + public void makeHttpRequestsShouldNotChangeBannerWidthAndHeightIfPresent() { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder + .banner(Banner.builder() + .format(singletonList(Format.builder().w(300).h(500).build())) + .w(200) + .h(150) + .build())); + + // when + final Result>> result = yieldoneBidder.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .extracting(Banner::getW, Banner::getH) + .containsOnly(tuple(200, 150)); + } + + @Test + public void makeHttpRequestsShouldSetBannerWidthAndHeightFromFirstFormatIfEmpty() { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder + .banner(Banner.builder() + .format(Arrays.asList(Format.builder().w(300).h(500).build(), + Format.builder().w(450).h(150).build())) + .build())); + + // when + final Result>> result = yieldoneBidder.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .extracting(Banner::getW, Banner::getH) + .containsOnly(tuple(300, 500)); + } + + @Test + public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { + // given + final HttpCall httpCall = givenHttpCall("false"); + + // when + final Result> result = yieldoneBidder.makeBids(httpCall, null); + + // then + assertThat(result.getErrors().get(0).getType()).isEqualTo(BidderError.Type.bad_input); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeBidsShouldReturnBannerBidIfBannerIsPresentInRequestImp() throws JsonProcessingException { + // given + final HttpCall httpCall = givenHttpCall( + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + + // when + final Result> result = yieldoneBidder.makeBids(httpCall, + BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").banner(Banner.builder().build()).build())) + .build()); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), BidType.banner, "USD")); + } + + @Test + public void makeHttpRequestsShouldReturnExpectedBidRequest() { + // given + final BidRequest bidRequest = givenBidRequest(identity()); + + // when + final Result>> result = yieldoneBidder.makeHttpRequests(bidRequest); + + // then + final BidRequest expectedRequest = bidRequest.toBuilder() + .imp(singletonList(bidRequest.getImp().get(0).toBuilder().build())) + .build(); + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1) + .extracting(httpRequest -> mapper.readValue(httpRequest.getBody(), BidRequest.class)) + .containsOnly(expectedRequest); + } + + @Test + public void makeBidsShouldReturnBannerBidIfVideoIsPresentInRequestImp() throws JsonProcessingException { + // given + final HttpCall httpCall = givenHttpCall( + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + + // when + final Result> result = yieldoneBidder.makeBids(httpCall, + BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").video(Video.builder().build()).build())) + .build()); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .containsOnly(BidderBid.of(Bid.builder().impid("123").build(), BidType.video, "USD")); + } + + @Test + public void makeBidsShouldReturnErrorWithUnknownBidTypeIfNotSupportedBidType() throws JsonProcessingException { + // given + final HttpCall httpCall = givenHttpCall( + mapper.writeValueAsString( + givenBidResponse(bidBuilder -> bidBuilder.impid("123")))); + + // when + final Result> result = yieldoneBidder.makeBids(httpCall, + BidRequest.builder() + .imp(singletonList(Imp.builder().id("123").audio(Audio.builder().build()).build())) + .build()); + + // then + assertThat(result.getErrors()).hasSize(1) + .containsOnly(BidderError.badInput("Failed to find impression 123")); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void extractTargetingShouldReturnEmptyMap() { + assertThat(yieldoneBidder.extractTargeting(mapper.createObjectNode())).isEqualTo(emptyMap()); + } + + private static BidRequest givenBidRequest( + Function bidRequestCustomizer, + Function impCustomizer) { + + return bidRequestCustomizer.apply(BidRequest.builder() + .imp(singletonList(givenImp(impCustomizer)))) + .build(); + } + + private static BidRequest givenBidRequest(Function impCustomizer) { + return givenBidRequest(identity(), impCustomizer); + } + + private static Imp givenImp(Function impCustomizer) { + return impCustomizer.apply(Imp.builder() + .id("123") + .banner(Banner.builder().id("banner_id").build()).ext(mapper.valueToTree(ExtPrebid.of(null, + ExtImpYieldone.of("placementId"))))) + .build(); + } + + private static BidResponse givenBidResponse(Function bidCustomizer) { + return BidResponse.builder() + .seatbid(singletonList(SeatBid.builder().bid(singletonList(bidCustomizer.apply(Bid.builder()).build())) + .build())) + .build(); + } + + private static HttpCall givenHttpCall(String body) { + return HttpCall.success( + HttpRequest.builder().payload(null).build(), + HttpResponse.of(200, null, body), + null); + } +} diff --git a/src/test/java/org/prebid/server/cache/CacheServiceTest.java b/src/test/java/org/prebid/server/cache/CacheServiceTest.java index ae4aae5a282..a57a2d6b911 100644 --- a/src/test/java/org/prebid/server/cache/CacheServiceTest.java +++ b/src/test/java/org/prebid/server/cache/CacheServiceTest.java @@ -26,6 +26,7 @@ import org.prebid.server.cache.proto.request.PutObject; import org.prebid.server.cache.proto.response.BidCacheResponse; import org.prebid.server.cache.proto.response.CacheObject; +import org.prebid.server.events.EventsContext; import org.prebid.server.events.EventsService; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.Timeout; @@ -44,7 +45,6 @@ import java.time.Instant; import java.time.ZoneId; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.TimeoutException; import java.util.function.Function; @@ -54,6 +54,7 @@ import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static java.util.function.Function.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; @@ -61,6 +62,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; @@ -84,12 +86,14 @@ public class CacheServiceTest extends VertxTest { private CacheService cacheService; + private Account account; + + private EventsContext eventsContext; + private Timeout timeout; private Timeout expiredTimeout; - private Account account; - @Before public void setUp() throws MalformedURLException, JsonProcessingException { clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); @@ -104,13 +108,15 @@ public void setUp() throws MalformedURLException, JsonProcessingException { clock, jacksonMapper); + account = Account.builder().build(); + + eventsContext = EventsContext.builder().build(); + final TimeoutFactory timeoutFactory = new TimeoutFactory(clock); timeout = timeoutFactory.create(500L); expiredTimeout = timeoutFactory.create(clock.instant().minusMillis(1500L).toEpochMilli(), 1000L); - account = Account.builder().build(); - given(httpClient.post(anyString(), any(), any(), anyLong())).willReturn(Future.succeededFuture( HttpClientResponse.of(200, null, mapper.writeValueAsString( BidCacheResponse.of(singletonList(CacheObject.of("uuid1"))))))); @@ -294,8 +300,7 @@ public void cacheBidsShouldPerformHttpRequestWithExpectedBody() throws Exception PutObject.builder().type("json").value( mapper.valueToTree(BannerValue.of("adm2", "nurl2", 400, 300))).build(), PutObject.builder().type("xml").value(new TextNode(adm3)).build(), - PutObject.builder().type("xml").value(new TextNode(adm4)).build() - ); + PutObject.builder().type("xml").value(new TextNode(adm4)).build()); } @Test @@ -340,7 +345,7 @@ public void cacheBidsVideoOnlyShouldReturnExpectedResult() { @Test public void cacheBidsOpenrtbShouldNeverCallCacheServiceIfNoBidsPassed() { // when - cacheService.cacheBidsOpenrtb(emptyList(), emptyList(), null, null, null); + cacheService.cacheBidsOpenrtb(emptyList(), emptyList(), null, null, null, null); // then verifyZeroInteractions(httpClient); @@ -350,7 +355,11 @@ public void cacheBidsOpenrtbShouldNeverCallCacheServiceIfNoBidsPassed() { public void cacheBidsOpenrtbShouldPerformHttpRequestWithExpectedTimeout() { // when cacheService.cacheBidsOpenrtb(singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then verify(httpClient).post(anyString(), any(), any(), eq(500L)); @@ -361,7 +370,11 @@ public void cacheBidsOpenrtbShouldTolerateGlobalTimeoutAlreadyExpired() { // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), account, expiredTimeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, expiredTimeout); // then final CacheServiceResult result = future.result(); @@ -370,6 +383,24 @@ public void cacheBidsOpenrtbShouldTolerateGlobalTimeoutAlreadyExpired() { assertThat(result.getHttpCall()).isNull(); } + @Test + public void cacheBidsOpenrtbShouldStoreWinUrl() { + // given + final com.iab.openrtb.response.Bid bid = givenBidOpenrtb(builder -> builder.id("bidId1").impid("impId1")); + + // when + cacheService.cacheBidsOpenrtb( + singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + Account.builder().id("accountId").eventsEnabled(true).build(), eventsContext, timeout); + + // then + verify(eventsService).winUrl(eq("bidId1"), eq("bidder"), eq("accountId"), isNull()); + } + @Test public void cacheBidsOpenrtbShouldTolerateReadingHttpResponseFails() throws JsonProcessingException { // given @@ -380,7 +411,11 @@ public void cacheBidsOpenrtbShouldTolerateReadingHttpResponseFails() throws Json // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then final CacheServiceResult result = future.result(); @@ -400,7 +435,11 @@ public void cacheBidsOpenrtbShouldTolerateResponseCodeIsNot200() throws JsonProc // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then final CacheServiceResult result = future.result(); @@ -421,7 +460,11 @@ public void cacheBidsOpenrtbShouldTolerateResponseBodyCouldNotBeParsed() throws // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then final CacheServiceResult result = future.result(); @@ -433,7 +476,8 @@ public void cacheBidsOpenrtbShouldTolerateResponseBodyCouldNotBeParsed() throws } @Test - public void cacheBidsOpenrtbShouldTolerateCacheEntriesNumberDoesNotMatchBidsNumber() throws JsonProcessingException { + public void cacheBidsOpenrtbShouldTolerateCacheEntriesNumberDoesNotMatchBidsNumber() + throws JsonProcessingException { // given givenHttpClientReturnsResponse(200, "{}"); @@ -442,7 +486,11 @@ public void cacheBidsOpenrtbShouldTolerateCacheEntriesNumberDoesNotMatchBidsNumb // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then final CacheServiceResult result = future.result(); @@ -462,7 +510,11 @@ public void cacheBidsOpenrtbShouldReturnExpectedDebugInfo() throws JsonProcessin // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then final CacheServiceResult result = future.result(); @@ -479,7 +531,11 @@ public void cacheBidsOpenrtbShouldReturnExpectedCacheBids() { // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(builder -> builder.id("impId1"))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then final CacheServiceResult result = future.result(); @@ -490,15 +546,21 @@ public void cacheBidsOpenrtbShouldReturnExpectedCacheBids() { @Test public void cacheBidsOpenrtbShouldPerformHttpRequestWithExpectedBody() throws IOException { // given - final com.iab.openrtb.response.Bid bid1 = givenBidOpenrtb(builder -> builder.impid("impId1")); - final com.iab.openrtb.response.Bid bid2 = givenBidOpenrtb(builder -> builder.impid("impId2").adm("adm2")); + final com.iab.openrtb.response.Bid bid1 = givenBidOpenrtb(builder -> builder.id("bid1").impid("impId1")); + final com.iab.openrtb.response.Bid bid2 = givenBidOpenrtb(builder -> builder.id("bid2").impid("impId2") + .adm("adm2")); final Imp imp1 = givenImp(identity()); final Imp imp2 = givenImp(builder -> builder.id("impId2").video(Video.builder().build())); // when cacheService.cacheBidsOpenrtb( asList(bid1, bid2), asList(imp1, imp2), - CacheContext.builder().shouldCacheBids(true).shouldCacheVideoBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder2", singletonList("bid2"))) + .bidderToBidIds(singletonMap("bidder1", asList("bid1", "bid2"))) + .build(), account, EventsContext.builder().auctionTimestamp(1000L).build(), timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -515,7 +577,11 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithExpectedTtlFromBid() throw cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(builder -> builder.impid("impId1").exp(10))), singletonList(givenImp(buider -> buider.id("impId1").exp(20))), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -529,7 +595,12 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithExpectedTtlFromImp() throw // when cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(buider -> buider.exp(10))), - CacheContext.builder().shouldCacheBids(true).cacheBidsTtl(20).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .cacheBidsTtl(20) + .build(), + account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -543,7 +614,12 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithExpectedTtlFromRequest() t // when cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).cacheBidsTtl(10).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .cacheBidsTtl(10) + .build(), + account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -568,8 +644,11 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithExpectedTtlFromAccountBann // when cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), - Account.builder().bannerCacheTtl(10).build(), timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + Account.builder().bannerCacheTtl(10).eventsEnabled(false).build(), eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -594,7 +673,11 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithExpectedTtlFromMediaTypeTt // when cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -619,7 +702,11 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithTtlFromMediaTypeWhenAccoun // when cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -633,7 +720,11 @@ public void cacheBidsOpenrtbShouldSendCacheRequestWithNoTtl() throws IOException // when cacheService.cacheBidsOpenrtb( singletonList(givenBidOpenrtb(identity())), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -650,7 +741,11 @@ public void cacheBidsOpenrtbShouldReturnExpectedResultForBids() { // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(givenImp(identity())), - CacheContext.builder().shouldCacheBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + account, eventsContext, timeout); // then assertThat(future.result().getCacheBids()).hasSize(1) @@ -666,7 +761,11 @@ public void cacheBidsOpenrtbShouldReturnExpectedResultForVideoBids() { // when final Future future = cacheService.cacheBidsOpenrtb( singletonList(bid), singletonList(imp), - CacheContext.builder().shouldCacheVideoBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder1", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then assertThat(future.result().getCacheBids()).hasSize(1) @@ -688,7 +787,13 @@ public void cacheBidsOpenrtbShouldReturnExpectedResultForBidsAndVideoBids() thro // when final Future future = cacheService.cacheBidsOpenrtb( asList(bid1, bid2), asList(imp1, imp2), - CacheContext.builder().shouldCacheBids(true).shouldCacheVideoBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder1", singletonList("bidId1"))) + .bidderToBidIds(singletonMap("bidder2", singletonList("bidId2"))) + .build(), + account, eventsContext, timeout); // then assertThat(future.result().getCacheBids()).hasSize(2) @@ -708,7 +813,11 @@ public void cacheBidsOpenrtbShouldNotCacheVideoBidWithMissingImpId() { // when final Future future = cacheService.cacheBidsOpenrtb( asList(bid1, bid2), asList(imp1, imp2), - CacheContext.builder().shouldCacheVideoBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder1", singletonList("bidId1"))) + .build(), + account, eventsContext, timeout); // then assertThat(future.result().getCacheBids()).hasSize(1) @@ -718,14 +827,21 @@ public void cacheBidsOpenrtbShouldNotCacheVideoBidWithMissingImpId() { @Test public void cacheBidsOpenrtbShouldWrapEmptyAdMFieldUsingNurlFieldValue() throws IOException { // given - final com.iab.openrtb.response.Bid bid1 = givenBidOpenrtb(builder -> builder.impid("impId1").adm("adm1")); - final com.iab.openrtb.response.Bid bid2 = givenBidOpenrtb(builder -> builder.impid("impId1").nurl("adm2")); + final com.iab.openrtb.response.Bid bid1 = givenBidOpenrtb(builder -> builder.id("bid1").impid("impId1") + .adm("adm1")); + final com.iab.openrtb.response.Bid bid2 = givenBidOpenrtb(builder -> builder.id("bid2").impid("impId1") + .nurl("adm2")); final Imp imp1 = givenImp(builder -> builder.id("impId1").video(Video.builder().build())); // when cacheService.cacheBidsOpenrtb( asList(bid1, bid2), singletonList(imp1), - CacheContext.builder().shouldCacheBids(true).shouldCacheVideoBids(true).build(), account, timeout); + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder1", singletonList("bid1"))) + .bidderToBidIds(singletonMap("bidder1", asList("bid1", "bid2"))) + .build(), account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -735,23 +851,27 @@ public void cacheBidsOpenrtbShouldWrapEmptyAdMFieldUsingNurlFieldValue() throws PutObject.builder().type("json").value(mapper.valueToTree(bid2)).build(), PutObject.builder().type("xml").value(new TextNode("adm1")).build(), PutObject.builder().type("xml").value(new TextNode( - "prebid.org wrapper" + - "" + - "")) + "prebid.org wrapper" + + "" + + "")) .build()); } @Test public void cacheBidsOpenrtbShouldNotModifyVastXmlWhenBidIdIsNotInToModifyList() throws IOException { // given - final com.iab.openrtb.response.Bid bid = givenBidOpenrtb(builder -> builder.id("bid1").impid("impId1") - .adm("adm")); + final com.iab.openrtb.response.Bid bid = givenBidOpenrtb(builder -> + builder.id("bid1").impid("impId1").adm("adm")); final Imp imp1 = givenImp(builder -> builder.id("impId1").video(Video.builder().build())); // when - cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), CacheContext.builder() - .shouldCacheBids(true).shouldCacheVideoBids(true).videoBidIdsToModify(singletonList("bid2")) - .build(), Account.builder().id("accountId").build(), timeout); + cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder", singletonList("bid2"))) + .bidderToBidIds(singletonMap("bidder", singletonList("bid1"))) + .build(), account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -764,14 +884,18 @@ public void cacheBidsOpenrtbShouldNotModifyVastXmlWhenBidIdIsNotInToModifyList() @Test public void cacheBidsOpenrtbShouldNotAddTrackingImpToBidAdmWhenXmlDoesNotContainImpTag() throws IOException { // given - final com.iab.openrtb.response.Bid bid = givenBidOpenrtb(builder -> builder.id("bid1").impid("impId1") - .adm("no impression tag")); + final com.iab.openrtb.response.Bid bid = givenBidOpenrtb(builder -> + builder.id("bid1").impid("impId1").adm("no impression tag")); final Imp imp1 = givenImp(builder -> builder.id("impId1").video(Video.builder().build())); // when - cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), CacheContext.builder() - .shouldCacheBids(true).shouldCacheVideoBids(true).videoBidIdsToModify(singletonList("bid1")) - .build(), account, timeout); + cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder", singletonList("bid2"))) + .bidderToBidIds(singletonMap("bidder", singletonList("bid1"))) + .build(), account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -788,13 +912,17 @@ public void cacheBidsOpenrtbShouldAddTrackingLinkToImpTagWhenItIsEmpty() throws .adm("")); final Imp imp1 = givenImp(builder -> builder.id("impId1").video(Video.builder().build())); - given(eventsService.vastUrlTracking(any(), any())) + given(eventsService.vastUrlTracking(anyString(), anyString(), any(), any())) .willReturn("https://test-event.com/event?t=imp&b=bid1&f=b&a=accountId"); // when - cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), CacheContext.builder() - .shouldCacheBids(true).shouldCacheVideoBids(true).videoBidIdsToModify(singletonList("bid1")) - .build(), Account.builder().id("accountId").build(), timeout); + cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder", singletonList("bid1"))) + .bidderToBidIds(singletonMap("bidder", singletonList("bid1"))) + .build(), account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -806,8 +934,8 @@ public void cacheBidsOpenrtbShouldAddTrackingLinkToImpTagWhenItIsEmpty() throws .build(), PutObject.builder() .type("xml") - .value(new TextNode("")) + .value(new TextNode("")) .build()); } @@ -819,14 +947,17 @@ public void cacheBidsOpenrtbShouldAddTrackingImpToBidAdmXmlWhenThatBidShouldBeMo .adm("http:/test.com")); final Imp imp1 = givenImp(builder -> builder.id("impId1").video(Video.builder().build())); - given(eventsService.vastUrlTracking(any(), any())) + given(eventsService.vastUrlTracking(any(), any(), any(), any())) .willReturn("https://test-event.com/event?t=imp&b=bid1&f=b&a=accountId"); // when - cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), CacheContext.builder() - .shouldCacheBids(true).shouldCacheVideoBids(true).videoBidIdsToModify(singletonList("bid1")) - .build(), - Account.builder().id("accountId").build(), timeout); + cacheService.cacheBidsOpenrtb(singletonList(bid), singletonList(imp1), + CacheContext.builder() + .shouldCacheBids(true) + .shouldCacheVideoBids(true) + .bidderToVideoBidIdsToModify(singletonMap("bidder", singletonList("bid1"))) + .bidderToBidIds(singletonMap("bidder", singletonList("bid1"))) + .build(), account, eventsContext, timeout); // then final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); @@ -838,8 +969,8 @@ public void cacheBidsOpenrtbShouldAddTrackingImpToBidAdmXmlWhenThatBidShouldBeMo .build(), PutObject.builder() .type("xml") - .value(new TextNode("http:/test.com" + - "" + .value(new TextNode("http:/test.com" + + "" + "")) .build()); } @@ -870,34 +1001,65 @@ public void cachePutObjectsShouldModifyVastAndCachePutObjects() throws IOExcepti // given final PutObject firstPutObject = PutObject.builder() .type("xml") - .bidid("biddid1") + .bidid("bidId1") .bidder("bidder1") - .value(new TextNode("" + - "prebid.org wrapper" + - "")).build(); + .timestamp(1L) + .value(new TextNode("" + + "prebid.org wrapper" + + "")) + .build(); final PutObject secondPutObject = PutObject.builder() .type("xml") - .value(new TextNode("VAST")) - .bidid("biddid2") + .bidid("bidId2") .bidder("bidder2") + .timestamp(1L) + .value(new TextNode("VAST")) .build(); - given(eventsService.vastUrlTracking(any(), any())) - .willReturn("https://test-event.com/event?t=imp&b=biddid1&f=b&a=account"); + given(eventsService.vastUrlTracking(any(), any(), any(), any())) + .willReturn("http://external-url/event"); // when - cacheService.cachePutObjects(Arrays.asList(firstPutObject, secondPutObject), singleton("bidder1"), "account", + cacheService.cachePutObjects(asList(firstPutObject, secondPutObject), singleton("bidder1"), "account", timeout); // then - final PutObject modifiedSecondPutObject = firstPutObject.toBuilder() - .value(new TextNode("" + - "prebid.org wrapper" + - "" + - "")) + final PutObject modifiedFirstPutObject = firstPutObject.toBuilder() + .bidid(null) + .bidder(null) + .timestamp(null) + .value(new TextNode("" + + "prebid.org wrapper" + + "" + + "")) .build(); - final BidCacheRequest bidCacheRequest = captureBidCacheRequest(); - assertThat(bidCacheRequest.getPuts()).hasSize(2).containsOnly(modifiedSecondPutObject, secondPutObject); + final PutObject modifiedSecondPutObject = secondPutObject.toBuilder() + .bidid(null) + .bidder(null) + .timestamp(null) + .build(); + + assertThat(captureBidCacheRequest().getPuts()).hasSize(2) + .containsOnly(modifiedFirstPutObject, modifiedSecondPutObject); + } + + @Test + public void cachePutObjectsShouldCallEventsServiceWithExpectedArguments() { + // given + final PutObject firstPutObject = PutObject.builder() + .type("xml") + .bidid("bidId1") + .bidder("bidder1") + .timestamp(1000L) + .value(new TextNode("")) + .build(); + + // when + cacheService.cachePutObjects(singletonList(firstPutObject), singleton("bidder1"), "account", timeout); + + // then + verify(eventsService).vastUrlTracking(eq("bidId1"), eq("bidder1"), eq("account"), eq(1000L)); } private static List singleBidList() { @@ -917,7 +1079,8 @@ private static Imp givenImp(Function impCustomiz return impCustomizer.apply(Imp.builder()).build(); } - private static CacheHttpRequest givenCacheHttpRequest(com.iab.openrtb.response.Bid... bids) throws JsonProcessingException { + private static CacheHttpRequest givenCacheHttpRequest(com.iab.openrtb.response.Bid... bids) + throws JsonProcessingException { final List putObjects; if (bids != null) { putObjects = new ArrayList<>(); diff --git a/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java b/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java index ed60c6e5ebb..a8543f2e43f 100644 --- a/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java +++ b/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java @@ -1,7 +1,7 @@ package org.prebid.server.cookie; import com.fasterxml.jackson.core.JsonProcessingException; -import io.vertx.ext.web.Cookie; +import io.vertx.core.http.Cookie; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -20,16 +20,12 @@ import java.time.temporal.ChronoUnit; import java.util.Base64; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import static java.util.Arrays.asList; import static java.util.Collections.emptyMap; -import static java.util.Collections.singleton; import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.within; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verifyZeroInteractions; @@ -78,7 +74,8 @@ public void shouldReturnNonEmptyUidsCookieFromCookiesMap() { public void shouldReturnNonEmptyUidsCookie() { // given // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}} - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("uids", + given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie( + "uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ=="))); // when @@ -102,7 +99,7 @@ public void shouldReturnNonNullUidsCookieIfUidsCookieIsMissing() { @Test public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonBase64() { // given - given(routingContext.getCookie(eq("uids"))).willReturn(Cookie.cookie("uids", "abcde")); + given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie("uids", "abcde"))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -115,7 +112,7 @@ public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonBase64() { public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonJson() { // given // this uids cookie value stands for "abcde" - given(routingContext.getCookie(eq("uids"))).willReturn(Cookie.cookie("uids", "bm9uLWpzb24=")); + given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie("uids", "bm9uLWpzb24="))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -138,7 +135,8 @@ public void shouldReturnNewUidsCookieWithBday() throws IOException { @Test public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsMissingAndOptoutCookieHasExpectedValue() { // given - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE))); + given(routingContext.cookieMap()).willReturn( + singletonMap(OPT_OUT_COOKIE_NAME, Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -150,10 +148,13 @@ public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsMissingAndOptoutCo @Test public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsPresentAndOptoutCookieHasExpectedValue() { // given + final Map cookies = new HashMap<>(); // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}} - given(routingContext.cookies()).willReturn(new HashSet<>(asList( - Cookie.cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ=="), - Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE)))); + cookies.put("uids", Cookie.cookie("uids", + "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ==")); + cookies.put(OPT_OUT_COOKIE_NAME, Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE)); + + given(routingContext.cookieMap()).willReturn(cookies); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -167,10 +168,13 @@ public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsPresentAndOptoutCo @Test public void shouldReturnUidsCookieWithOptoutFalseIfOptoutCookieHasNotExpectedValue() { // given + final Map cookies = new HashMap<>(); // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}} - given(routingContext.cookies()).willReturn(new HashSet<>(asList( - Cookie.cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ=="), - Cookie.cookie(OPT_OUT_COOKIE_NAME, "dummy")))); + cookies.put("uids", Cookie.cookie("uids", + "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ==")); + cookies.put(OPT_OUT_COOKIE_NAME, Cookie.cookie(OPT_OUT_COOKIE_NAME, "dummy")); + + given(routingContext.cookieMap()).willReturn(cookies); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -186,7 +190,8 @@ public void shouldReturnUidsCookieWithOptoutFalseIfOptoutCookieNameNotSpecified( // given uidsCookieService = new UidsCookieService( null, "true", null, null, "cookie-domain", 90, MAX_COOKIE_SIZE_BYTES, jacksonMapper); - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("trp_optout", "true"))); + given(routingContext.cookieMap()).willReturn( + singletonMap(OPT_OUT_COOKIE_NAME, Cookie.cookie("trp_optout", "true"))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -200,7 +205,8 @@ public void shouldReturnUidsCookieWithOptoutFalseIfOptoutCookieValueNotSpecified // given uidsCookieService = new UidsCookieService( "trp_optout", null, null, null, "cookie-domain", 90, MAX_COOKIE_SIZE_BYTES, jacksonMapper); - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("trp_optout", "true"))); + given(routingContext.cookieMap()).willReturn( + singletonMap(OPT_OUT_COOKIE_NAME, Cookie.cookie("trp_optout", "true"))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -214,7 +220,7 @@ public void shouldReturnRubiconCookieValueFromHostCookieWhenUidValueIsAbsent() { // given uidsCookieService = new UidsCookieService( "trp_optout", "true", "rubicon", "khaos", "cookie-domain", 90, MAX_COOKIE_SIZE_BYTES, jacksonMapper); - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("khaos", "abc123"))); + given(routingContext.cookieMap()).willReturn(singletonMap("khaos", Cookie.cookie("khaos", "abc123"))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -229,10 +235,13 @@ public void shouldReturnRubiconCookieValueFromHostCookieWhenUidValueIsPresentBut uidsCookieService = new UidsCookieService( "trp_optout", "true", "rubicon", "khaos", "cookie-domain", 90, MAX_COOKIE_SIZE_BYTES, jacksonMapper); + final Map cookies = new HashMap<>(); // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}} - given(routingContext.cookies()).willReturn(new HashSet<>(asList( - Cookie.cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ=="), - Cookie.cookie("khaos", "abc123")))); + cookies.put("uids", Cookie.cookie("uids", + "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ==")); + cookies.put("khaos", Cookie.cookie("khaos", "abc123")); + + given(routingContext.cookieMap()).willReturn(cookies); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -250,7 +259,7 @@ public void shouldSkipFacebookSentinelFromUidsCookie() throws JsonProcessingExce final Uids uids = Uids.builder().uids(uidsWithExpiry).build(); final String encodedUids = encodeUids(uids); - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("uids", encodedUids))); + given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie("uids", encodedUids))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); @@ -261,7 +270,6 @@ public void shouldSkipFacebookSentinelFromUidsCookie() throws JsonProcessingExce assertThat(uidsCookie.uidFrom("audienceNetwork")).isNull(); } - @Test public void toCookieShouldEnforceMaxCookieSizeAndRemoveAUidWithCloserExpirationDate() throws IOException { // given @@ -341,9 +349,10 @@ public void shouldCreateUidsFromLegacyUidsIfUidsAreMissed() { // given // this uids cookie value stands for // {"uids":{"rubicon":"J5VLCWQP-26-CWFT"},"tempUIDs":{}},"bday":"2017-08-15T19:47:59.523908376Z"} - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("uids", - "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIn0sInRlbXBVSURzIjp7fX0sImJkYXkiOiIyMDE3LTA" + - "4LTE1VDE5OjQ3OjU5LjUyMzkwODM3NloifQ=="))); + given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie( + "uids", + "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIn0sInRlbXBVSURzIjp7fX0sImJkYXkiOiIyMDE3LTA" + + "4LTE1VDE5OjQ3OjU5LjUyMzkwODM3NloifQ=="))); // when final UidsCookie uidsCookie = uidsCookieService.parseFromRequest(routingContext); diff --git a/src/test/java/org/prebid/server/cookie/UidsCookieTest.java b/src/test/java/org/prebid/server/cookie/UidsCookieTest.java index 1906b8ebad0..0ab3b31300f 100644 --- a/src/test/java/org/prebid/server/cookie/UidsCookieTest.java +++ b/src/test/java/org/prebid/server/cookie/UidsCookieTest.java @@ -243,7 +243,7 @@ public void toJsonShouldReturnCookieInValidJsonFormat() { jacksonMapper); // when and then - assertThat(uidsCookie.toJson()).isEqualTo("{\"tempUIDs\":{\"rubicon\":{\"uid\":\"J5VLCWQP-26-CWFT\"," + - "\"expires\":\"2017-12-30T12:30:40.123456789Z\"}},\"bday\":\"2017-08-15T19:47:59.523908376Z\"}"); + assertThat(uidsCookie.toJson()).isEqualTo("{\"tempUIDs\":{\"rubicon\":{\"uid\":\"J5VLCWQP-26-CWFT\"," + + "\"expires\":\"2017-12-30T12:30:40.123456789Z\"}},\"bday\":\"2017-08-15T19:47:59.523908376Z\"}"); } } diff --git a/src/test/java/org/prebid/server/events/EventUtilTest.java b/src/test/java/org/prebid/server/events/EventUtilTest.java index b0761d49796..34e077d55cb 100644 --- a/src/test/java/org/prebid/server/events/EventUtilTest.java +++ b/src/test/java/org/prebid/server/events/EventUtilTest.java @@ -30,13 +30,11 @@ public class EventUtilTest { public void setUp() { given(routingContext.request()).willReturn(httpRequest); given(httpRequest.headers()).willReturn(new CaseInsensitiveHeaders()); + given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap()); } @Test public void validateTypeShouldFailWhenTypeIsMissing() { - // given - given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap()); - // when and then assertThatIllegalArgumentException().isThrownBy(() -> EventUtil.validateType(routingContext)) .withMessage("Type 't' is required query parameter. Possible values are win and imp, but was null"); @@ -76,25 +74,28 @@ public void validateTypeShouldSucceedWhenTypeIsImp() { } @Test - public void validateBidIdShouldFailWhenBidIdIsMissing() { - // given - given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() - .add("t", "win")); + public void validateAccountIdShouldFailWhenAccountIsMissing() { + // when and then + assertThatIllegalArgumentException().isThrownBy(() -> EventUtil.validateAccountId(routingContext)) + .withMessage("Account 'a' is required query parameter and can't be empty"); + } + @Test + public void validateBidIdShouldFailWhenBidIdIsMissing() { // when and then assertThatIllegalArgumentException().isThrownBy(() -> EventUtil.validateBidId(routingContext)) .withMessage("BidId 'b' is required query parameter and can't be empty"); } @Test - public void validateAccountIdShouldFailWhenAccountIsMissing() { + public void validateTimestampShouldFailWhenTimestampIsInvalid() { // given given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() - .add("b", "bidId")); + .add("ts", "invalid")); // when and then - assertThatIllegalArgumentException().isThrownBy(() -> EventUtil.validateAccountId(routingContext)) - .withMessage("Account 'a' is required query parameter and can't be empty"); + assertThatIllegalArgumentException().isThrownBy(() -> EventUtil.validateTimestamp(routingContext)) + .withMessage("Timestamp 'ts' query parameter is not valid number: invalid"); } @Test @@ -168,8 +169,10 @@ public void fromShouldReturnExpectedEventRequest() { // given given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() .add("t", "win") - .add("b", "bidId") .add("a", "accountId") + .add("bidder", "bidder") + .add("b", "bidId") + .add("ts", "1000") .add("f", "i") .add("x", "0")); @@ -179,8 +182,10 @@ public void fromShouldReturnExpectedEventRequest() { // then assertThat(result).isEqualTo(EventRequest.builder() .type(EventRequest.Type.win) - .bidId("bidId") .accountId("accountId") + .bidder("bidder") + .bidId("bidId") + .timestamp(1000L) .format(EventRequest.Format.image) .analytics(EventRequest.Analytics.disabled) .build()); @@ -191,8 +196,10 @@ public void fromShouldReturnExpectedEventRequestWithDefaultFormatAndAnalytics() // given given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() .add("t", "win") + .add("a", "accountId") + .add("bidder", "bidder") .add("b", "bidId") - .add("a", "accountId")); + .add("ts", "1000")); // when final EventRequest result = EventUtil.from(routingContext); @@ -200,10 +207,12 @@ public void fromShouldReturnExpectedEventRequestWithDefaultFormatAndAnalytics() // then assertThat(result).isEqualTo(EventRequest.builder() .type(EventRequest.Type.win) - .bidId("bidId") .accountId("accountId") + .bidder("bidder") + .bidId("bidId") .format(EventRequest.Format.blank) .analytics(EventRequest.Analytics.enabled) + .timestamp(1000L) .build()); } @@ -212,17 +221,20 @@ public void toUrlShouldReturnExpectedUrl() { // given final EventRequest eventRequest = EventRequest.builder() .type(EventRequest.Type.win) - .bidId("bidId") .accountId("accountId") + .bidder("bidder") + .bidId("bidId") .format(EventRequest.Format.blank) .analytics(EventRequest.Analytics.enabled) + .timestamp(1000L) .build(); // when final String result = EventUtil.toUrl("http://external-url", eventRequest); // then - assertThat(result).isEqualTo("http://external-url/event?t=win&b=bidId&a=accountId&f=b&x=1"); + assertThat(result) + .isEqualTo("http://external-url/event?t=win&b=bidId&a=accountId&ts=1000&bidder=bidder&f=b&x=1"); } @Test @@ -230,14 +242,34 @@ public void toUrlShouldReturnExpectedUrlWithoutFormatAndAnalytics() { // given final EventRequest eventRequest = EventRequest.builder() .type(EventRequest.Type.win) + .accountId("accountId") + .bidder("bidder") .bidId("bidId") + .timestamp(1000L) + .build(); + + // when + final String result = EventUtil.toUrl("http://external-url", eventRequest); + + // then + assertThat(result).isEqualTo("http://external-url/event?t=win&b=bidId&a=accountId&ts=1000&bidder=bidder"); + } + + @Test + public void toUrlShouldReturnExpectedUrlWithoutTimestamp() { + // given + final EventRequest eventRequest = EventRequest.builder() + .type(EventRequest.Type.win) .accountId("accountId") + .bidder("bidder") + .bidId("bidId") + .timestamp(null) .build(); // when final String result = EventUtil.toUrl("http://external-url", eventRequest); // then - assertThat(result).isEqualTo("http://external-url/event?t=win&b=bidId&a=accountId"); + assertThat(result).isEqualTo("http://external-url/event?t=win&b=bidId&a=accountId&bidder=bidder"); } } diff --git a/src/test/java/org/prebid/server/events/EventsServiceTest.java b/src/test/java/org/prebid/server/events/EventsServiceTest.java index db9df25f3a2..2ee78221ba7 100644 --- a/src/test/java/org/prebid/server/events/EventsServiceTest.java +++ b/src/test/java/org/prebid/server/events/EventsServiceTest.java @@ -24,29 +24,38 @@ public void setUp() { @Test public void createEventsShouldReturnExpectedEvent() { // when - final Events events = eventsService.createEvent("bidId", "accountId"); + final Events events = eventsService.createEvent("bidId", "bidder", "accountId", 1000L); // then assertThat(events).isEqualTo(Events.of( - "http://external-url/event?t=win&b=bidId&a=accountId&f=i", - "http://external-url/event?t=imp&b=bidId&a=accountId&f=i")); + "http://external-url/event?t=win&b=bidId&a=accountId&ts=1000&bidder=bidder&f=i", + "http://external-url/event?t=imp&b=bidId&a=accountId&ts=1000&bidder=bidder&f=i")); } @Test public void winUrlTargetingShouldReturnExpectedUrl() { // when - final String winUrlTargeting = eventsService.winUrlTargeting("accountId"); + final String winUrlTargeting = eventsService.winUrlTargeting("bidder", "accountId", 1000L); // then - assertThat(winUrlTargeting).isEqualTo("http://external-url/event?t=win&b=BIDID&a=accountId&f=i"); + assertThat(winUrlTargeting).isEqualTo("http://external-url/event?t=win&b=BIDID&a=accountId&ts=1000&bidder=bidder&f=i"); } @Test - public void vastUrlTrackingShouldReturnExpectedUrl() { + public void winUrlShouldReturnExpectedUrl() { // when - final String winUrlTargeting = eventsService.vastUrlTracking("bidId", "accountId"); + final String winUrl = eventsService.winUrl("bidId", "bidder", "accountId", 1000L); // then - assertThat(winUrlTargeting).isEqualTo("http://external-url/event?t=imp&b=bidId&a=accountId&f=b"); + assertThat(winUrl).isEqualTo("http://external-url/event?t=win&b=bidId&a=accountId&ts=1000&bidder=bidder&f=i"); + } + + @Test + public void vastUrlShouldReturnExpectedUrl() { + // when + final String vastUrl = eventsService.vastUrlTracking("bidId", "bidder", "accountId", 1000L); + + // then + assertThat(vastUrl).isEqualTo("http://external-url/event?t=imp&b=bidId&a=accountId&ts=1000&bidder=bidder&f=b"); } } diff --git a/src/test/java/org/prebid/server/execution/LogModifierTest.java b/src/test/java/org/prebid/server/execution/LogModifierTest.java deleted file mode 100644 index e71004baab3..00000000000 --- a/src/test/java/org/prebid/server/execution/LogModifierTest.java +++ /dev/null @@ -1,77 +0,0 @@ -package org.prebid.server.execution; - -import io.vertx.core.logging.Logger; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.function.BiConsumer; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; - -public class LogModifierTest { - - @Rule - public final MockitoRule mockitoRule = MockitoJUnit.rule(); - - @Mock - private Logger logger; - - private LogModifier logModifier; - - @Before - public void setUp() { - given(logger.isInfoEnabled()).willReturn(true); - - logModifier = new LogModifier(logger); - } - - @Test - public void shouldUseDefaultLogModifierWhenNothingWasSet() { - // given and when - logModifier.get().accept(logger, "test"); - - // then - verify(logger).info(any()); - } - - @Test - public void shouldUseDefaultLogModifierWhenErrorLevelCountIsZero() { - // given and when - logModifier.set(Logger::error, 0); - logModifier.get().accept(logger, "test"); - - // then - verify(logger).info(any()); - } - - @Test - public void shouldUseDefaultLogModifierWhenErrorLevelCountIsNegative() { - // given and when - logModifier.set(Logger::error, -123); - logModifier.get().accept(logger, "test"); - - // then - verify(logger).info(any()); - } - - @Test - public void shouldReturnLogModifierWhenErrorLevelCountIsPositive() { - // given - final BiConsumer loggingLevelModifier = Logger::error; - logModifier.set(loggingLevelModifier, 123); - - // when - final BiConsumer result = logModifier.get(); - - // then - assertThat(result).isEqualTo(loggingLevelModifier); - } -} - diff --git a/src/test/java/org/prebid/server/execution/RemoteFileSyncerTest.java b/src/test/java/org/prebid/server/execution/RemoteFileSyncerTest.java index f7ebf46b7ac..157d4cdc717 100644 --- a/src/test/java/org/prebid/server/execution/RemoteFileSyncerTest.java +++ b/src/test/java/org/prebid/server/execution/RemoteFileSyncerTest.java @@ -41,7 +41,6 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; - @SuppressWarnings("ResultOfMethodCallIgnored") public class RemoteFileSyncerTest extends VertxTest { @@ -94,11 +93,14 @@ public void shouldThrowNullPointerExceptionWhenIllegalArgumentsWhenNullArguments () -> RemoteFileSyncer.create(SOURCE_URL, null, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, TIMEOUT, UPDATE_INTERVAL, httpClient, vertx, fileSystem)); assertThatNullPointerException().isThrownBy( - () -> RemoteFileSyncer.create(SOURCE_URL, FILE_PATH, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, TIMEOUT, UPDATE_INTERVAL, null, vertx, fileSystem)); + () -> RemoteFileSyncer.create(SOURCE_URL, FILE_PATH, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, + TIMEOUT, UPDATE_INTERVAL, null, vertx, fileSystem)); assertThatNullPointerException().isThrownBy( - () -> RemoteFileSyncer.create(SOURCE_URL, FILE_PATH, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, TIMEOUT, UPDATE_INTERVAL, httpClient, null, fileSystem)); + () -> RemoteFileSyncer.create(SOURCE_URL, FILE_PATH, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, + TIMEOUT, UPDATE_INTERVAL, httpClient, null, fileSystem)); assertThatNullPointerException().isThrownBy( - () -> RemoteFileSyncer.create(SOURCE_URL, FILE_PATH, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, TIMEOUT, UPDATE_INTERVAL, httpClient, vertx, null)); + () -> RemoteFileSyncer.create(SOURCE_URL, FILE_PATH, TMP_FILE_PATH, RETRY_COUNT, RETRY_INTERVAL, + TIMEOUT, UPDATE_INTERVAL, httpClient, vertx, null)); } @Test diff --git a/src/test/java/org/prebid/server/execution/TimeoutFactoryTest.java b/src/test/java/org/prebid/server/execution/TimeoutFactoryTest.java index 27231bdea0e..0504b8fa5f1 100644 --- a/src/test/java/org/prebid/server/execution/TimeoutFactoryTest.java +++ b/src/test/java/org/prebid/server/execution/TimeoutFactoryTest.java @@ -50,4 +50,4 @@ public void createShouldReturnTimeoutStartedFromSpecifiedMoment() { // then assertThat(timeout.remaining()).isEqualTo(500L); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/execution/TimeoutTest.java b/src/test/java/org/prebid/server/execution/TimeoutTest.java index b28f10cf721..69aa867d1cc 100644 --- a/src/test/java/org/prebid/server/execution/TimeoutTest.java +++ b/src/test/java/org/prebid/server/execution/TimeoutTest.java @@ -31,4 +31,4 @@ public void remainingShouldReturnZeroIfTimeoutAlreadyExpired() { // when and then assertThat(timeout.remaining()).isZero(); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/handler/AccountCacheInvalidationHandlerTest.java b/src/test/java/org/prebid/server/handler/AccountCacheInvalidationHandlerTest.java new file mode 100644 index 00000000000..175075a0e35 --- /dev/null +++ b/src/test/java/org/prebid/server/handler/AccountCacheInvalidationHandlerTest.java @@ -0,0 +1,76 @@ +package org.prebid.server.handler; + +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import io.vertx.ext.web.RoutingContext; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.VertxTest; +import org.prebid.server.settings.CachingApplicationSettings; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +public class AccountCacheInvalidationHandlerTest extends VertxTest { + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private CachingApplicationSettings cachingApplicationSettings; + + private AccountCacheInvalidationHandler handler; + @Mock + private RoutingContext routingContext; + @Mock + private HttpServerRequest httpRequest; + @Mock + private HttpServerResponse httpResponse; + + @Before + public void setUp() { + handler = new AccountCacheInvalidationHandler(cachingApplicationSettings); + + given(routingContext.request()).willReturn(httpRequest); + given(routingContext.response()).willReturn(httpResponse); + given(routingContext.response().setStatusCode(anyInt())).willReturn(httpResponse); + } + + @Test + public void shouldReturnBadRequestWhenAccountParamIsMissing() { + // given + given(httpRequest.getParam(any())).willReturn(null); + + // when + handler.handle(routingContext); + + // then + verify(httpResponse).setStatusCode(eq(400)); + verify(httpResponse).end(eq("Account id is not defined")); + + verify(httpRequest).getParam("account"); + } + + @Test + public void shouldReturnOkAndTriggerInvalidateWhenAccountIdIsPresent() { + // given + given(httpRequest.getParam(any())).willReturn("123"); + + // when + handler.handle(routingContext); + + // then + verify(httpResponse).setStatusCode(eq(200)); + verify(cachingApplicationSettings).invalidateAccountCache("123"); + + verify(httpRequest).getParam("account"); + } +} + diff --git a/src/test/java/org/prebid/server/handler/AdminHandlerTest.java b/src/test/java/org/prebid/server/handler/AdminHandlerTest.java index 5820a68bc61..0e8e2040146 100644 --- a/src/test/java/org/prebid/server/handler/AdminHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/AdminHandlerTest.java @@ -3,7 +3,6 @@ import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.RoutingContext; -import org.apache.commons.lang3.StringUtils; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -11,10 +10,7 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.VertxTest; -import org.prebid.server.execution.LogModifier; - -import java.util.stream.Collectors; -import java.util.stream.IntStream; +import org.prebid.server.manager.AdminManager; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -29,7 +25,7 @@ public class AdminHandlerTest extends VertxTest { public final MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock - private LogModifier logModifier; + private AdminManager adminManager; @Mock private RoutingContext routingContext; @Mock @@ -45,7 +41,7 @@ public void setUp() { given(routingContext.request()).willReturn(httpRequest); given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); - adminHandler = new AdminHandler(logModifier); + adminHandler = new AdminHandler(adminManager); } @Test @@ -57,23 +53,23 @@ public void shouldRespondWithErrorWhenLoggingParamIsMissing() { adminHandler.handle(routingContext); // then - verify(httpResponse).end(eq("Invalid LoggingLevel: null")); + verify(httpResponse).end(eq("Logging level cannot be empty")); verify(httpResponse).setStatusCode(eq(400)); - verifyZeroInteractions(logModifier); + verifyZeroInteractions(adminManager); } @Test public void shouldRespondWithErrorWhenLoggingIsInvalid() { // given - given(httpRequest.getParam(eq("logging"))).willReturn("spam"); + given(httpRequest.getParam(eq("logging"))).willReturn("invalid"); // when adminHandler.handle(routingContext); // then - verify(httpResponse).end(eq("Invalid LoggingLevel: spam")); + verify(httpResponse).end(eq("Invalid logging level: invalid")); verify(httpResponse).setStatusCode(eq(400)); - verifyZeroInteractions(logModifier); + verifyZeroInteractions(adminManager); } @Test @@ -88,7 +84,7 @@ public void shouldRespondWithErrorWhenRecordsIsMissing() { // then verify(httpResponse).end(eq("Invalid records parameter: null")); verify(httpResponse).setStatusCode(eq(400)); - verifyZeroInteractions(logModifier); + verifyZeroInteractions(adminManager); } @Test @@ -103,7 +99,7 @@ public void shouldRespondWithErrorWhenRecordsIsInvalid() { // then verify(httpResponse).end(eq("Invalid records parameter: spam")); verify(httpResponse).setStatusCode(eq(400)); - verifyZeroInteractions(logModifier); + verifyZeroInteractions(adminManager); } @Test @@ -118,7 +114,7 @@ public void shouldRespondWithErrorWhenRecordsIsNegative() { // then verify(httpResponse).end(eq("Invalid records parameter: -123")); verify(httpResponse).setStatusCode(eq(400)); - verifyZeroInteractions(logModifier); + verifyZeroInteractions(adminManager); } @Test @@ -132,7 +128,6 @@ public void shouldRespondWithOkAndSetErrorOnBadRequestCount() { // then verify(httpResponse).end(eq("Logging level was changed to error, for 123 requests")); - verify(logModifier).set(any(), eq(123)); + verify(adminManager).setupByCounter(eq(AdminManager.COUNTER_KEY), eq(123), any(), any()); } } - diff --git a/src/test/java/org/prebid/server/handler/AuctionHandlerTest.java b/src/test/java/org/prebid/server/handler/AuctionHandlerTest.java index 7d9af2f5eaf..567679ae12c 100644 --- a/src/test/java/org/prebid/server/handler/AuctionHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/AuctionHandlerTest.java @@ -36,8 +36,9 @@ import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.privacy.PrivacyExtractor; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; import org.prebid.server.proto.request.AdUnit; import org.prebid.server.proto.request.PreBidRequest; import org.prebid.server.proto.request.PreBidRequest.PreBidRequestBuilder; @@ -73,6 +74,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anySet; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willReturn; @@ -112,7 +114,7 @@ public class AuctionHandlerTest extends VertxTest { private Clock clock; @Mock - private GdprService gdprService; + private TcfDefinerService tcfDefinerService; private PrivacyExtractor privacyExtractor; private AuctionHandler auctionHandler; @@ -151,8 +153,8 @@ public void setUp() { clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); - given(gdprService.resultByVendor(any(), any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, emptyMap(), null))); + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, emptyMap(), null))); privacyExtractor = new PrivacyExtractor(jacksonMapper); @@ -164,7 +166,7 @@ public void setUp() { metrics, httpAdapterConnector, clock, - gdprService, + tcfDefinerService, privacyExtractor, jacksonMapper, null, @@ -591,8 +593,8 @@ public void shouldIncrementSafariAndNoCookieMetrics() { // given givenPreBidRequestContext(identity(), builder -> builder.noLiveUids(true)); - httpRequest.headers().add(HttpUtil.USER_AGENT_HEADER, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " + - "AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"); + httpRequest.headers().add(HttpUtil.USER_AGENT_HEADER, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " + + "AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"); // when auctionHandler.handle(routingContext); @@ -757,8 +759,9 @@ public void shouldRespondWithNoUsersyncInfoForAllBiddersIfHostVendorDeniesGdpr() // given givenPreBidRequestContextWith2AdUnitsAnd2BidsEach(identity()); - given(gdprService.resultByVendor(any(), any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, singletonMap(1, false), null))); + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(1, actionWithUserSync(true)), null))); given(httpAdapterConnector.call(any(), any(), any(), any())) .willReturn(Future.succeededFuture(AdapterResponse.of( @@ -783,12 +786,12 @@ public void shouldRespondWithNoUsersyncInfoForBidderRestrictedByGdpr() throws IO // given givenPreBidRequestContextWith2AdUnitsAnd2BidsEach(identity()); - final Map vendorsToGdpr = new HashMap<>(); - vendorsToGdpr.put(1, true); // host vendor id from app config - vendorsToGdpr.put(15, true); // Rubicon bidder - vendorsToGdpr.put(20, false); // Appnexus bidder - given(gdprService.resultByVendor(any(), any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, vendorsToGdpr, null))); + final Map vendorToAction = new HashMap<>(); + vendorToAction.put(1, actionWithUserSync(false)); // host vendor id from app config + vendorToAction.put(15, actionWithUserSync(false)); // Rubicon bidder + vendorToAction.put(20, actionWithUserSync(true)); // Appnexus bidder + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, vendorToAction, null))); given(httpAdapterConnector.call(any(), any(), any(), any())) .willReturn(Future.succeededFuture(AdapterResponse.of( @@ -813,11 +816,11 @@ public void shouldRespondWithUsersyncInfoForBiddersButNotForHostVendor() throws // given givenPreBidRequestContextWith1AdUnitAndOneBid(identity()); - final Map vendorsToGdpr = new HashMap<>(); - vendorsToGdpr.put(1, true); // host vendor id from app config - vendorsToGdpr.put(15, true); // Rubicon bidder - given(gdprService.resultByVendor(any(), any(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, vendorsToGdpr, null))); + final Map vendorToAction = new HashMap<>(); + vendorToAction.put(1, actionWithUserSync(false)); // host vendor id from app config + vendorToAction.put(15, actionWithUserSync(false)); // Rubicon bidder + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, vendorToAction, null))); given(httpAdapterConnector.call(any(), any(), any(), any())) .willReturn(Future.succeededFuture(AdapterResponse.of( @@ -832,8 +835,10 @@ public void shouldRespondWithUsersyncInfoForBiddersButNotForHostVendor() throws cacheService, metrics, httpAdapterConnector, - clock, gdprService, - privacyExtractor, jacksonMapper, + clock, + tcfDefinerService, + privacyExtractor, + jacksonMapper, 1, false); @@ -918,4 +923,8 @@ private static BidderInfo givenBidderInfo(int gdprVendorId, boolean enforceGdpr) return new BidderInfo(true, null, null, null, new BidderInfo.GdprInfo(gdprVendorId, enforceGdpr), false); } + + private static PrivacyEnforcementAction actionWithUserSync(boolean blockPixelSync) { + return PrivacyEnforcementAction.builder().blockPixelSync(blockPixelSync).build(); + } } diff --git a/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java b/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java index ad2ce5b9e8d..30080cc14e7 100644 --- a/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java @@ -25,13 +25,17 @@ import org.prebid.server.cookie.proto.Uids; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.metric.Metrics; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; import org.prebid.server.proto.request.CookieSyncRequest; import org.prebid.server.proto.response.BidderInfo; import org.prebid.server.proto.response.BidderUsersyncStatus; import org.prebid.server.proto.response.CookieSyncResponse; import org.prebid.server.proto.response.UsersyncInfo; +import org.prebid.server.settings.ApplicationSettings; +import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountGdprConfig; import java.io.IOException; import java.time.Clock; @@ -42,17 +46,22 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; +import static java.util.function.Function.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anySet; @@ -60,6 +69,7 @@ import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; public class CookieSyncHandlerTest extends VertxTest { @@ -76,9 +86,11 @@ public class CookieSyncHandlerTest extends VertxTest { @Mock private UidsCookieService uidsCookieService; @Mock + private ApplicationSettings applicationSettings; + @Mock private BidderCatalog bidderCatalog; @Mock - private GdprService gdprService; + private TcfDefinerService tcfDefinerService; @Mock private PrivacyEnforcementService privacyEnforcementService; @Mock @@ -103,9 +115,9 @@ public void setUp() { given(routingContext.response()).willReturn(httpResponse); given(httpResponse.putHeader(any(CharSequence.class), any(CharSequence.class))).willReturn(httpResponse); - cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, 1, false, false, emptyList(), analyticsReporter, metrics, - timeoutFactory, jacksonMapper); + cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, 1, false, false, emptyList(), + analyticsReporter, metrics, timeoutFactory, jacksonMapper); } @Test @@ -125,7 +137,7 @@ public void shouldRespondWithErrorIfOptedOut() { verify(httpResponse).setStatusMessage(eq("User has opted out")); verify(httpResponse).end(); verify(routingContext, never()).getBody(); - verifyNoMoreInteractions(httpResponse, gdprService); + verifyNoMoreInteractions(httpResponse, tcfDefinerService); } @Test @@ -134,14 +146,16 @@ public void shouldRespondWithErrorIfRequestBodyIsMissing() { given(routingContext.getBody()).willReturn(null); given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); + given(httpResponse.setStatusMessage(anyString())).willReturn(httpResponse); // when cookieSyncHandler.handle(routingContext); // then verify(httpResponse).setStatusCode(eq(400)); + verify(httpResponse).setStatusMessage(eq("Request has no body")); verify(httpResponse).end(); - verifyNoMoreInteractions(httpResponse, gdprService); + verifyNoMoreInteractions(httpResponse, tcfDefinerService); } @Test @@ -157,16 +171,16 @@ public void shouldRespondWithErrorIfRequestBodyCouldNotBeParsed() { // then verify(httpResponse).setStatusCode(eq(400)); - verify(httpResponse).setStatusMessage(eq("JSON parse failed")); + verify(httpResponse).setStatusMessage(eq("Request body cannot be parsed")); verify(httpResponse).end(); - verifyNoMoreInteractions(httpResponse, gdprService); + verifyNoMoreInteractions(httpResponse, tcfDefinerService); } @Test public void shouldRespondWithErrorIfGdprConsentIsMissing() { // given given(routingContext.getBody()) - .willReturn(givenRequestBody(CookieSyncRequest.of(emptyList(), 1, null, null, null, null))); + .willReturn(givenRequestBody(CookieSyncRequest.of(emptyList(), 1, null, null, null, null, null))); given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); given(httpResponse.setStatusMessage(anyString())).willReturn(httpResponse); @@ -178,16 +192,16 @@ public void shouldRespondWithErrorIfGdprConsentIsMissing() { verify(httpResponse).setStatusCode(eq(400)); verify(httpResponse).setStatusMessage(eq("gdpr_consent is required if gdpr is 1")); verify(httpResponse).end(); - verifyNoMoreInteractions(httpResponse, gdprService); + verifyNoMoreInteractions(httpResponse, tcfDefinerService); } @Test public void shouldNotSendResponseIfClientClosedConnection() { // given given(routingContext.getBody()).willReturn( - givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null))); + givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null, null))); - givenGdprServiceReturningResult(emptyMap()); + givenTcfServiceReturningVendorIdResult(emptySet()); given(routingContext.response().closed()).willReturn(true); @@ -202,9 +216,9 @@ public void shouldNotSendResponseIfClientClosedConnection() { public void shouldRespondWithExpectedHeaders() { // given given(routingContext.getBody()).willReturn( - givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null))); + givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null, null))); - givenGdprServiceReturningResult(emptyMap()); + givenTcfServiceReturningVendorIdResult(emptySet()); // when cookieSyncHandler.handle(routingContext); @@ -214,6 +228,48 @@ public void shouldRespondWithExpectedHeaders() { .putHeader(eq(new AsciiString("Content-Type")), eq(new AsciiString("application/json"))); } + @Test + public void shouldPassAccountToTcfWhenAccountIsFound() { + // given + given(routingContext.getBody()).willReturn( + givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null, "account"))); + + final AccountGdprConfig accountGdprConfig = AccountGdprConfig.builder().enabled(true).build(); + final Account account = Account.builder().gdpr(accountGdprConfig).build(); + given(applicationSettings.getAccountById(any(), any())).willReturn(Future.succeededFuture(account)); + + givenTcfServiceReturningVendorIdResult(singleton(1)); + + // when + cookieSyncHandler.handle(routingContext); + + // then + verify(applicationSettings).getAccountById(eq("account"), any()); + + verify(tcfDefinerService).resultForVendorIds(anySet(), any(), any(), any(), eq(accountGdprConfig), any()); + verify(tcfDefinerService).resultForBidderNames(anySet(), any(), any(), any(), eq(accountGdprConfig), any()); + } + + @Test + public void shouldPassAccountToTcfWhenAccountIsNotFound() { + // given + given(routingContext.getBody()).willReturn( + givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null, "account"))); + + given(applicationSettings.getAccountById(any(), any())).willReturn(Future.failedFuture("bad")); + + givenTcfServiceReturningVendorIdResult(singleton(1)); + + // when + cookieSyncHandler.handle(routingContext); + + // then + verify(applicationSettings).getAccountById(eq("account"), any()); + + verify(tcfDefinerService).resultForVendorIds(anySet(), any(), any(), any(), isNull(), any()); + verify(tcfDefinerService).resultForBidderNames(anySet(), any(), any(), any(), isNull(), any()); + } + @Test public void shouldRespondWithSomeBidderStatusesIfSomeUidsMissingInCookies() throws IOException { // given @@ -223,7 +279,7 @@ public void shouldRespondWithSomeBidderStatusesIfSomeUidsMissingInCookies() thro given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -231,7 +287,8 @@ public void shouldRespondWithSomeBidderStatusesIfSomeUidsMissingInCookies() thro rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -255,19 +312,21 @@ public void shouldRespondWithAllActiveBiddersWhenRequestCoopSyncTrueAndNoPriorit given(bidderCatalog.isActive(anyString())).willReturn(true); given(bidderCatalog.isActive(disabledBidder)).willReturn(false); - cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, 1, false, false, emptyList(), analyticsReporter, metrics, - timeoutFactory, jacksonMapper); + cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, 1, false, false, emptyList(), + analyticsReporter, metrics, timeoutFactory, jacksonMapper); given(routingContext.getBody()) .willReturn( - givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, true, null))); + givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, true, null, + null))); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "http://adnxsexample.com", null, null, "redirect", false); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -291,19 +350,21 @@ public void shouldRespondWithCoopBiddersWhenRequestCoopSyncTrue() throws IOExcep final List> coopBidders = asList(singletonList(RUBICON), singletonList(disabledBidder)); - cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, 1, false, false, coopBidders, analyticsReporter, metrics, - timeoutFactory, jacksonMapper); + cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, 1, false, false, coopBidders, + analyticsReporter, metrics, timeoutFactory, jacksonMapper); given(routingContext.getBody()) .willReturn( - givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, true, null))); + givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, true, null, + null))); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "http://adnxsexample.com", null, null, "redirect", false); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -327,18 +388,20 @@ public void shouldRespondWithPrioritisedCoopBidderWhenRequestCoopDefaultTrueAndL final List> priorityBidders = asList(singletonList(APPNEXUS), singletonList(RUBICON), asList("bidder1", "bidder2"), singletonList("spam")); - cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, 1, false, true, priorityBidders, analyticsReporter, metrics, - timeoutFactory, jacksonMapper); + cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, 1, false, true, priorityBidders, + analyticsReporter, metrics, timeoutFactory, jacksonMapper); given(routingContext.getBody()) - .willReturn(givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, null, 2))); + .willReturn(givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, null, 2, + null))); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "http://adnxsexample.com", null, null, "redirect", false); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -356,7 +419,7 @@ public void shouldRespondWithPrioritisedCoopBidderWhenRequestCoopDefaultTrueAndL public void shouldRespondWithBidderStatusForAllBiddersIfBiddersListOmittedInRequest() throws IOException { // given given(routingContext.getBody()) - .willReturn(givenRequestBody(CookieSyncRequest.of(null, null, null, null, null, null))); + .willReturn(givenRequestBody(CookieSyncRequest.of(null, null, null, null, null, null, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -365,15 +428,16 @@ public void shouldRespondWithBidderStatusForAllBiddersIfBiddersListOmittedInRequ given(bidderCatalog.names()).willReturn(new HashSet<>(asList(APPNEXUS, RUBICON, disabledBidder))); - cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, 1, false, false, emptyList(), analyticsReporter, metrics, - timeoutFactory, jacksonMapper); + cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, 1, false, false, emptyList(), + analyticsReporter, metrics, timeoutFactory, jacksonMapper); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "http://adnxsexample.com", null, null, "redirect", false); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -400,14 +464,14 @@ public void shouldRespondWithNoBidderStatusesIfAllUidsPresentInCookies() throws given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "", null, null, null, false); givenUsersyncersReturningFamilyName(); - - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -426,7 +490,7 @@ public void shouldTolerateUnsupportedBidder() throws IOException { given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, "unsupported"), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, "unsupported"), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); givenUsersyncersReturningFamilyName(); @@ -434,7 +498,8 @@ public void shouldTolerateUnsupportedBidder() throws IOException { given(bidderCatalog.isActive(RUBICON)).willReturn(true); given(bidderCatalog.isValidName("unsupported")).willReturn(false); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(RUBICON)); // when cookieSyncHandler.handle(routingContext); @@ -456,7 +521,7 @@ public void shouldTolerateDisabledBidder() throws IOException { given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, "disabled"), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, "disabled"), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); givenUsersyncersReturningFamilyName(); @@ -467,7 +532,8 @@ public void shouldTolerateDisabledBidder() throws IOException { given(bidderCatalog.isActive(RUBICON)).willReturn(true); given(bidderCatalog.isActive("disabled")).willReturn(false); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(RUBICON)); // when cookieSyncHandler.handle(routingContext); @@ -484,7 +550,7 @@ public void shouldTolerateDisabledBidder() throws IOException { } @Test - public void shouldTolerateRejectedBidderByGdpr() throws IOException { + public void shouldTolerateRejectedBidderByTcf() throws IOException { // given given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), @@ -492,7 +558,7 @@ public void shouldTolerateRejectedBidderByGdpr() throws IOException { given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "", null, null, null, false); @@ -505,7 +571,8 @@ public void shouldTolerateRejectedBidderByGdpr() throws IOException { .willReturn(BidderInfo.create(true, null, null, null, null, 2, true, false)); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(RUBICON)); // when cookieSyncHandler.handle(routingContext); @@ -515,15 +582,15 @@ public void shouldTolerateRejectedBidderByGdpr() throws IOException { assertThat(cookieSyncResponse.getStatus()).isEqualTo("ok"); assertThat(cookieSyncResponse.getBidderStatus()).hasSize(1) .extracting(BidderUsersyncStatus::getBidder, BidderUsersyncStatus::getError) - .containsOnly(tuple(APPNEXUS, "Rejected by GDPR")); + .containsOnly(tuple(APPNEXUS, "Rejected by TCF")); } @Test - public void shouldUpdateCookieSyncSetAndRejectByGdprMetricForEachRejectedAndSyncedBidder() { + public void shouldUpdateCookieSyncSetAndRejectByTcfMetricForEachRejectedAndSyncedBidder() { // given given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "", null, null, null, false); @@ -536,13 +603,14 @@ public void shouldUpdateCookieSyncSetAndRejectByGdprMetricForEachRejectedAndSync .willReturn(BidderInfo.create(true, null, null, null, null, 2, true, false)); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(RUBICON)); // when cookieSyncHandler.handle(routingContext); // then - verify(metrics).updateCookieSyncGdprPreventMetric(APPNEXUS); + verify(metrics).updateCookieSyncTcfBlockedMetric(APPNEXUS); verify(metrics).updateCookieSyncGenMetric(RUBICON); } @@ -555,7 +623,7 @@ public void shouldUpdateCookieSyncMatchesMetricForEachAlreadySyncedBidder() { given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "", null, null, null, false); @@ -564,10 +632,8 @@ public void shouldUpdateCookieSyncMatchesMetricForEachAlreadySyncedBidder() { given(bidderCatalog.isActive(RUBICON)).willReturn(true); given(bidderCatalog.isActive(APPNEXUS)).willReturn(true); - Map bidderToGdprVendorId = new HashMap<>(); - bidderToGdprVendorId.put(RUBICON, 1); - bidderToGdprVendorId.put(APPNEXUS, 2); - givenGdprServiceReturningResult(bidderToGdprVendorId); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -578,18 +644,18 @@ public void shouldUpdateCookieSyncMatchesMetricForEachAlreadySyncedBidder() { } @Test - public void shouldRespondWithNoCookieStatusIfHostVendorRejectedByGdpr() throws IOException { + public void shouldRespondWithNoCookieStatusIfHostVendorRejectedByTcf() throws IOException { // given - cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, bidderCatalog, - gdprService, privacyEnforcementService, null, false, false, emptyList(), analyticsReporter, metrics, - timeoutFactory, jacksonMapper); + cookieSyncHandler = new CookieSyncHandler("http://external-url", 2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, privacyEnforcementService, null, false, false, emptyList(), + analyticsReporter, metrics, timeoutFactory, jacksonMapper); given(uidsCookieService.parseFromRequest(any())) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "", null, null, null, false); @@ -598,7 +664,8 @@ gdprService, privacyEnforcementService, null, false, false, emptyList(), analyti given(bidderCatalog.isActive(RUBICON)).willReturn(true); given(bidderCatalog.isActive(APPNEXUS)).willReturn(true); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -609,8 +676,8 @@ gdprService, privacyEnforcementService, null, false, false, emptyList(), analyti assertThat(cookieSyncResponse.getBidderStatus()).hasSize(2) .extracting(BidderUsersyncStatus::getBidder, BidderUsersyncStatus::getError) .containsOnly( - tuple(RUBICON, "Rejected by GDPR"), - tuple(APPNEXUS, "Rejected by GDPR")); + tuple(RUBICON, "Rejected by TCF"), + tuple(APPNEXUS, "Rejected by TCF")); } @Test @@ -622,14 +689,16 @@ public void shouldRespondWithNoCookieStatusIfNoLiveUids() throws IOException { given(routingContext.getBody()) .willReturn( - givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, null, null))); + givenRequestBody(CookieSyncRequest.of(singletonList(APPNEXUS), null, null, null, null, null, + null))); given(bidderCatalog.isActive(anyString())).willReturn(true); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "http://adnxsexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -648,7 +717,7 @@ public void shouldRespondWithNoCookieStatusIfNoLiveUids() throws IOException { public void shouldRespondWithExpectedUsersyncInfo() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList(APPNEXUS), 1, "gdpr_consent1", null, null, null))); + CookieSyncRequest.of(singletonList(APPNEXUS), 1, "gdpr_consent1", null, null, null, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -657,7 +726,8 @@ public void shouldRespondWithExpectedUsersyncInfo() throws IOException { "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -673,13 +743,14 @@ public void shouldRespondWithExpectedUsersyncInfo() throws IOException { public void shouldRespondWithUpdatedUsersyncInfoIfHostCookieAndUidsDiffers() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList(RUBICON), null, null, null, null, null))); + CookieSyncRequest.of(singletonList(RUBICON), null, null, null, null, null, null))); given(bidderCatalog.isActive(RUBICON)).willReturn(true); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(RUBICON)); given(uidsCookieService.getHostCookieFamily()).willReturn(RUBICON); given(uidsCookieService.parseHostCookie(any())).willReturn("host/cookie/value"); @@ -702,7 +773,7 @@ public void shouldRespondWithUpdatedUsersyncInfoIfHostCookieAndUidsDiffers() thr public void shouldRespondWithOriginalUsersyncInfoIfNoHostCookieFamilyInBiddersCookieFamily() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList(APPNEXUS), 1, "gdpr_consent1", "YNN", null, null))); + CookieSyncRequest.of(singletonList(APPNEXUS), 1, "gdpr_consent1", "YNN", null, null, null))); given(bidderCatalog.isActive(APPNEXUS)).willReturn(true); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, @@ -710,7 +781,8 @@ public void shouldRespondWithOriginalUsersyncInfoIfNoHostCookieFamilyInBiddersCo null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(APPNEXUS)); given(uidsCookieService.getHostCookieFamily()).willReturn(RUBICON); @@ -730,14 +802,15 @@ public void shouldRespondWithOriginalUsersyncInfoIfNoHostCookieFamilyInBiddersCo public void shouldRespondWithOriginalUsersyncInfoIfNoHostCookieInRequest() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList(RUBICON), null, null, null, null, null))); + CookieSyncRequest.of(singletonList(RUBICON), null, null, null, null, null, null))); given(bidderCatalog.isActive(RUBICON)).willReturn(true); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(RUBICON)); given(uidsCookieService.getHostCookieFamily()).willReturn(RUBICON); given(uidsCookieService.parseHostCookie(any())).willReturn(null); @@ -757,14 +830,15 @@ public void shouldRespondWithOriginalUsersyncInfoIfNoHostCookieInRequest() throw public void shouldRespondWithOriginalUsersyncInfoIfHostCookieAndUidsAreEqual() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList(RUBICON), null, null, null, null, null))); + CookieSyncRequest.of(singletonList(RUBICON), null, null, null, null, null, null))); given(bidderCatalog.isActive(RUBICON)).willReturn(true); rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); given(uidsCookieService.getHostCookieFamily()).willReturn(RUBICON); given(uidsCookieService.parseHostCookie(any())).willReturn("cookie-value"); @@ -785,7 +859,7 @@ public void shouldRespondWithOriginalUsersyncInfoIfHostCookieAndUidsAreEqual() t public void shouldRespondWithExpectedUsersyncInfoForBidderAlias() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList("rubiconAlias"), 0, null, null, null, null))); + CookieSyncRequest.of(singletonList("rubiconAlias"), 0, null, null, null, null, null))); given(bidderCatalog.isActive(RUBICON)).willReturn(true); given(bidderCatalog.isAlias("rubiconAlias")).willReturn(true); @@ -793,7 +867,9 @@ public void shouldRespondWithExpectedUsersyncInfoForBidderAlias() throws IOExcep rubiconUsersyncer = new Usersyncer(RUBICON, "http://rubiconexample.com", null, null, "redirect", false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(singletonMap(RUBICON, 1)); + + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(emptySet()); // when cookieSyncHandler.handle(routingContext); @@ -806,10 +882,10 @@ public void shouldRespondWithExpectedUsersyncInfoForBidderAlias() throws IOExcep } @Test - public void shouldTolerateMissingGdprParamsInRequestForUsersyncInfo() throws IOException { + public void shouldTolerateMissingTcfParamsInRequestForUsersyncInfo() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(singletonList(APPNEXUS), null, "", null, null, null))); + CookieSyncRequest.of(singletonList(APPNEXUS), null, "", null, null, null, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); given(bidderCatalog.names()).willReturn(singleton(APPNEXUS)); @@ -819,7 +895,8 @@ public void shouldTolerateMissingGdprParamsInRequestForUsersyncInfo() throws IOE false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -829,13 +906,15 @@ public void shouldTolerateMissingGdprParamsInRequestForUsersyncInfo() throws IOE assertThat(cookieSyncResponse.getBidderStatus()) .extracting(bidderStatus -> bidderStatus.getUsersync().getUrl()) .containsOnly("http://adnxsexample.com/sync?gdpr=&gdpr_consent="); + + verifyZeroInteractions(applicationSettings); } @Test public void shouldLimitBidderStatuses() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), 0, null, null, null, 1))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), 0, null, null, null, 1, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -846,7 +925,8 @@ public void shouldLimitBidderStatuses() throws IOException { false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -865,7 +945,7 @@ public void shouldLimitBidderStatusesWithLiveUids() throws IOException { Uids.builder().uids(liveUids).build(), jacksonMapper)); given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), 0, null, null, null, 1))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), 0, null, null, null, 1, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -876,7 +956,8 @@ public void shouldLimitBidderStatusesWithLiveUids() throws IOException { false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -890,7 +971,7 @@ public void shouldLimitBidderStatusesWithLiveUids() throws IOException { public void shouldNotLimitBidderStatusesIfLimitIsBiggerThanBiddersList() throws IOException { // given given(routingContext.getBody()).willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), 0, null, null, null, 3))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), 0, null, null, null, 3, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -901,7 +982,8 @@ public void shouldNotLimitBidderStatusesIfLimitIsBiggerThanBiddersList() throws false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(singleton(APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -915,9 +997,9 @@ public void shouldNotLimitBidderStatusesIfLimitIsBiggerThanBiddersList() throws public void shouldIncrementMetrics() { // given given(routingContext.getBody()).willReturn( - givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null))); + givenRequestBody(CookieSyncRequest.of(emptyList(), null, null, null, null, null, null))); - givenGdprServiceReturningResult(emptyMap()); + givenTcfServiceReturningVendorIdResult(emptySet()); // when cookieSyncHandler.handle(routingContext); @@ -939,7 +1021,7 @@ public void shouldPassUnauthorizedEventToAnalyticsReporterIfOptedOut() { // then final CookieSyncEvent cookieSyncEvent = captureCookieSyncEvent(); - assertThat(cookieSyncEvent).isEqualTo(CookieSyncEvent.error(401, "user has opted out")); + assertThat(cookieSyncEvent).isEqualTo(CookieSyncEvent.error(401, "User has opted out")); } @Test @@ -948,13 +1030,14 @@ public void shouldPassBadRequestEventToAnalyticsReporterIfRequestBodyIsMissing() given(routingContext.getBody()).willReturn(null); given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); + given(httpResponse.setStatusMessage(anyString())).willReturn(httpResponse); // when cookieSyncHandler.handle(routingContext); // then final CookieSyncEvent cookieSyncEvent = captureCookieSyncEvent(); - assertThat(cookieSyncEvent).isEqualTo(CookieSyncEvent.error(400, "request has no body")); + assertThat(cookieSyncEvent).isEqualTo(CookieSyncEvent.error(400, "Request has no body")); } @Test @@ -970,7 +1053,7 @@ public void shouldPassBadRequestEventToAnalyticsReporterIfRequestBodyCouldNotBeP // then final CookieSyncEvent cookieSyncEvent = captureCookieSyncEvent(); - assertThat(cookieSyncEvent).isEqualTo(CookieSyncEvent.error(400, "JSON parse failed")); + assertThat(cookieSyncEvent).isEqualTo(CookieSyncEvent.error(400, "Request body cannot be parsed")); } @Test @@ -982,7 +1065,7 @@ public void shouldPassSuccessfulEventToAnalyticsReporter() { given(routingContext.getBody()) .willReturn(givenRequestBody( - CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null))); + CookieSyncRequest.of(asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -990,7 +1073,8 @@ public void shouldPassSuccessfulEventToAnalyticsReporter() { rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); givenUsersyncersReturningFamilyName(); - givenGdprServiceReturningResult(doubleMap(RUBICON, 1, APPNEXUS, 2)); + givenTcfServiceReturningVendorIdResult(singleton(1)); + givenTcfServiceReturningBidderNamesResult(set(RUBICON, APPNEXUS)); // when cookieSyncHandler.handle(routingContext); @@ -1014,8 +1098,8 @@ public void handleShouldRespondWithNoCookieWhenCcpaIsEnforced() throws IOExcepti Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(routingContext.getBody()) - .willReturn(givenRequestBody(CookieSyncRequest.of - (asList(RUBICON, APPNEXUS), null, null, null, null, null))); + .willReturn(givenRequestBody(CookieSyncRequest.of( + asList(RUBICON, APPNEXUS), null, null, null, null, null, null))); rubiconUsersyncer = new Usersyncer(RUBICON, "", null, null, null, false); appnexusUsersyncer = new Usersyncer(APPNEXUS_COOKIE, "", null, null, null, false); @@ -1042,19 +1126,21 @@ public void handleShouldRespondWithNoCookieWhenCcpaIsEnforced() throws IOExcepti .containsOnly(tuple(APPNEXUS, "Rejected by CCPA"), tuple(RUBICON, "Rejected by CCPA")); } - private void givenGdprServiceReturningResult(Map bidderToGdprVendorId) { - final Map vendorToGdprResult = new HashMap<>(); - - for (Map.Entry entry : bidderToGdprVendorId.entrySet()) { - given(bidderCatalog.bidderInfoByName(entry.getKey())) - .willReturn(BidderInfo.create(true, null, null, - null, null, entry.getValue(), true, false)); + private void givenTcfServiceReturningVendorIdResult(Set vendorIds) { + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, actions(vendorIds), null))); + } - vendorToGdprResult.put(entry.getValue(), true); - } + private void givenTcfServiceReturningBidderNamesResult(Set bidderNames) { + given(tcfDefinerService.resultForBidderNames(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, actions(bidderNames), null))); + } - given(gdprService.resultByVendor(anySet(), anySet(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, vendorToGdprResult, null))); + private static Map actions(Set keys) { + return keys.stream() + .collect(Collectors.toMap( + identity(), + vendorId -> PrivacyEnforcementAction.builder().blockPixelSync(false).build())); } private static Buffer givenRequestBody(CookieSyncRequest request) { @@ -1092,4 +1178,9 @@ private static Map doubleMap(K key1, V value1, K key2, V value2) { map.put(key2, value2); return map; } + + @SafeVarargs + private static Set set(T... elements) { + return new HashSet<>(asList(elements)); + } } diff --git a/src/test/java/org/prebid/server/handler/CurrencyRatesHandlerTest.java b/src/test/java/org/prebid/server/handler/CurrencyRatesHandlerTest.java index e1563152e41..7a4c07ba4c1 100644 --- a/src/test/java/org/prebid/server/handler/CurrencyRatesHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/CurrencyRatesHandlerTest.java @@ -72,4 +72,4 @@ private static class Response { String lastUpdate; } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java b/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java index 85da4d005af..9c34321dc99 100644 --- a/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java @@ -100,4 +100,4 @@ private String getResponseBody() { verify(httpServerResponse).end(bodyCaptor.capture()); return bodyCaptor.getValue(); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/handler/NotificationEventHandlerTest.java b/src/test/java/org/prebid/server/handler/NotificationEventHandlerTest.java index 4309fdea693..c7b023e9c2e 100644 --- a/src/test/java/org/prebid/server/handler/NotificationEventHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/NotificationEventHandlerTest.java @@ -118,6 +118,24 @@ public void shouldReturnBadRequestWhenBidIdIsMissing() { assertThat(captureResponseStatusCode()).isEqualTo(400); } + @Test + public void shouldReturnBadRequestWhenTimestampIsInvalid() { + // given + given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() + .add("t", "win") + .add("b", "bidId") + .add("bidder", "bidder") + .add("ts", "invalid")); + + // when + notificationHandler.handle(routingContext); + + // then + verifyZeroInteractions(analyticsReporter); + + assertThat(captureResponseStatusCode()).isEqualTo(400); + } + @Test public void shouldReturnUnauthorizedWhenAccountIsMissing() { // given @@ -306,6 +324,46 @@ public void shouldRespondWithNoContentWhenRequestFormatIsNotDefined() { verifyNoMoreInteractions(httpResponse); } + @Test + public void shouldPassExpectedEventToAnalyticsReporter() { + // given + given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() + .add("t", "win") + .add("b", "bidId") + .add("a", "accountId") + .add("bidder", "bidder") + .add("ts", "1000")); + + final Account account = Account.builder().eventsEnabled(true).build(); + given(applicationSettings.getAccountById(anyString(), any())) + .willReturn(Future.succeededFuture(account)); + + // when + notificationHandler.handle(routingContext); + + // then + final Map queryParams = new HashMap<>(); + queryParams.put("t", "win"); + queryParams.put("b", "bidId"); + queryParams.put("a", "accountId"); + queryParams.put("bidder", "bidder"); + queryParams.put("ts", "1000"); + final HttpContext expectedHttpContext = HttpContext.builder() + .queryParams(queryParams) + .headers(Collections.emptyMap()) + .cookies(Collections.emptyMap()) + .build(); + + assertThat(captureAnalyticEvent()).isEqualTo(NotificationEvent.builder() + .type(NotificationEvent.Type.win) + .bidId("bidId") + .account(account) + .bidder("bidder") + .timestamp(1000L) + .httpContext(expectedHttpContext) + .build()); + } + private Integer captureResponseStatusCode() { final ArgumentCaptor captor = ArgumentCaptor.forClass(Integer.class); verify(httpResponse).setStatusCode(captor.capture()); diff --git a/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java b/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java index 4d8133bc7ff..30b88e086b9 100644 --- a/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java @@ -2,9 +2,9 @@ import io.netty.util.AsciiString; import io.vertx.core.Future; +import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.Cookie; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; diff --git a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java index 344149b3919..4addf151892 100644 --- a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java @@ -3,9 +3,9 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.http.CaseInsensitiveHeaders; +import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.ext.web.Cookie; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -26,8 +26,12 @@ import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.metric.Metrics; -import org.prebid.server.privacy.gdpr.GdprService; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.TcfDefinerService; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TcfResponse; +import org.prebid.server.settings.ApplicationSettings; +import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountGdprConfig; import java.io.IOException; import java.time.Clock; @@ -44,6 +48,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anySet; @@ -63,9 +68,11 @@ public class SetuidHandlerTest extends VertxTest { @Mock private UidsCookieService uidsCookieService; @Mock + private ApplicationSettings applicationSettings; + @Mock private BidderCatalog bidderCatalog; @Mock - private GdprService gdprService; + private TcfDefinerService tcfDefinerService; @Mock private AnalyticsReporter analyticsReporter; @Mock @@ -81,8 +88,10 @@ public class SetuidHandlerTest extends VertxTest { @Before public void setUp() { - given(gdprService.resultByVendor(anySet(), anySet(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, singletonMap(null, true), null))); + final Map vendorIdToGdpr = singletonMap(null, + PrivacyEnforcementAction.allowAll()); + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(true, vendorIdToGdpr, null))); given(routingContext.request()).willReturn(httpRequest); given(routingContext.response()).willReturn(httpResponse); @@ -97,8 +106,8 @@ public void setUp() { final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); final TimeoutFactory timeoutFactory = new TimeoutFactory(clock); - setuidHandler = new SetuidHandler(2000, uidsCookieService, bidderCatalog, gdprService, - null, false, analyticsReporter, metrics, timeoutFactory); + setuidHandler = new SetuidHandler(2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, null, false, analyticsReporter, metrics, timeoutFactory); } @Test @@ -152,8 +161,10 @@ public void shouldRespondWithErrorIfBidderParamIsInvalid() { @Test public void shouldRespondWithoutCookieIfGdprProcessingPreventsCookieSetting() { // given - given(gdprService.resultByVendor(anySet(), anySet(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(true, singletonMap(null, false), null))); + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture( + TcfResponse.of(true, singletonMap(null, privacyEnforcementAction), null))); given(uidsCookieService.parseFromRequest(any())) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); @@ -166,7 +177,7 @@ public void shouldRespondWithoutCookieIfGdprProcessingPreventsCookieSetting() { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).setStatusCode(eq(200)); verify(httpResponse).end(eq("The gdpr_consent param prevents cookies from being saved")); } @@ -174,7 +185,7 @@ public void shouldRespondWithoutCookieIfGdprProcessingPreventsCookieSetting() { @Test public void shouldRespondWithBadRequestStatusIfGdprProcessingFailsWithInvalidRequestException() { // given - given(gdprService.resultByVendor(anySet(), anySet(), any(), any(), any(), any())) + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) .willReturn(Future.failedFuture(new InvalidRequestException("gdpr exception"))); given(uidsCookieService.parseFromRequest(any())) @@ -188,7 +199,7 @@ public void shouldRespondWithBadRequestStatusIfGdprProcessingFailsWithInvalidReq setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).setStatusCode(eq(400)); verify(httpResponse).end(eq("GDPR processing failed with error: gdpr exception")); } @@ -196,7 +207,7 @@ public void shouldRespondWithBadRequestStatusIfGdprProcessingFailsWithInvalidReq @Test public void shouldRespondWithInternalServerErrorStatusIfGdprProcessingFailsWithUnexpectedException() { // given - given(gdprService.resultByVendor(anySet(), anySet(), any(), any(), any(), any())) + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) .willReturn(Future.failedFuture("unexpected error")); given(uidsCookieService.parseFromRequest(any())) @@ -211,18 +222,18 @@ public void shouldRespondWithInternalServerErrorStatusIfGdprProcessingFailsWithU // then verify(httpResponse, never()).sendFile(any()); - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).setStatusCode(eq(500)); verify(httpResponse).end(eq("Unexpected GDPR processing error")); } @Test - public void shouldPassIpAddressToGdprServiceIfGeoLocationEnabled() { + public void shouldPassIpAddressToTcfDefinerServiceIfGeoLocationEnabled() { // given final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); final TimeoutFactory timeoutFactory = new TimeoutFactory(clock); - setuidHandler = new SetuidHandler(2000, uidsCookieService, bidderCatalog, gdprService, - null, true, analyticsReporter, metrics, timeoutFactory); + setuidHandler = new SetuidHandler(2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, null, true, analyticsReporter, metrics, timeoutFactory); given(uidsCookieService.parseFromRequest(any())) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); @@ -239,7 +250,52 @@ public void shouldPassIpAddressToGdprServiceIfGeoLocationEnabled() { setuidHandler.handle(routingContext); // then - verify(gdprService).resultByVendor(anySet(), anySet(), any(), any(), eq("192.168.144.1"), any()); + verify(tcfDefinerService).resultForVendorIds(anySet(), any(), any(), eq("192.168.144.1"), any(), any()); + } + + @Test + public void shouldPassAccountToTcfDefinerServiceWhenAccountIsFound() { + // given + given(uidsCookieService.parseFromRequest(any())) + .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); + + given(httpRequest.getParam("bidder")).willReturn(RUBICON); + given(httpRequest.getParam("account")).willReturn("accId"); + + final AccountGdprConfig accountGdprConfig = AccountGdprConfig.builder().enabled(true).build(); + final Account account = Account.builder().gdpr(accountGdprConfig).build(); + final Future accountFuture = Future.succeededFuture(account); + given(applicationSettings.getAccountById(any(), any())).willReturn(accountFuture); + + given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); + + // when + setuidHandler.handle(routingContext); + + // then + verify(applicationSettings).getAccountById(eq("accId"), any()); + verify(tcfDefinerService).resultForVendorIds(anySet(), any(), any(), any(), eq(accountGdprConfig), any()); + } + + @Test + public void shouldPassAccountToTcfDefinerServiceWhenAccountIsNotFound() { + // given + given(uidsCookieService.parseFromRequest(any())) + .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); + + given(httpRequest.getParam("bidder")).willReturn(RUBICON); + given(httpRequest.getParam("account")).willReturn("accId"); + + given(applicationSettings.getAccountById(any(), any())).willReturn(Future.failedFuture("bad req")); + + given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); + + // when + setuidHandler.handle(routingContext); + + // then + verify(applicationSettings).getAccountById(eq("accId"), any()); + verify(tcfDefinerService).resultForVendorIds(anySet(), any(), any(), any(), isNull(), any()); } @Test @@ -262,7 +318,7 @@ public void shouldRemoveUidFromCookieIfMissingInRequest() throws IOException { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).sendFile(any()); final String uidsCookie = getUidsCookie(); @@ -289,14 +345,14 @@ public void shouldIgnoreFacebookSentinel() throws IOException { final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); final TimeoutFactory timeoutFactory = new TimeoutFactory(clock); - setuidHandler = new SetuidHandler(2000, uidsCookieService, bidderCatalog, gdprService, - null, false, analyticsReporter, metrics, timeoutFactory); + setuidHandler = new SetuidHandler(2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, null, false, analyticsReporter, metrics, timeoutFactory); // when setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).end(); verify(httpResponse, never()).sendFile(any()); @@ -326,7 +382,7 @@ public void shouldRespondWithCookieFromRequestParam() throws IOException { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).sendFile(any()); final String uidsCookie = getUidsCookie(); @@ -357,7 +413,7 @@ public void shouldUpdateUidInCookieWithRequestValue() throws IOException { // then verify(httpResponse).end(); - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); final String uidsCookie = getUidsCookie(); final Uids decodedUids = decodeUids(uidsCookie); @@ -369,8 +425,8 @@ public void shouldUpdateUidInCookieWithRequestValue() throws IOException { @Test public void shouldRespondWithCookieIfUserIsNotInGdprScope() throws IOException { // given - given(gdprService.resultByVendor(anySet(), anySet(), any(), any(), any(), any())) - .willReturn(Future.succeededFuture(GdprResponse.of(false, emptyMap(), null))); + given(tcfDefinerService.resultForVendorIds(anySet(), any(), any(), any(), any(), any())) + .willReturn(Future.succeededFuture(TcfResponse.of(false, emptyMap(), null))); given(uidsCookieService.parseFromRequest(any())) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); @@ -388,7 +444,7 @@ public void shouldRespondWithCookieIfUserIsNotInGdprScope() throws IOException { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any()); + verify(routingContext, never()).addCookie(any(Cookie.class)); verify(httpResponse).end(); final String uidsCookie = getUidsCookie(); @@ -528,8 +584,8 @@ public void shouldPassUnsuccessfulEventToAnalyticsReporterIfFacebookSentinel() { final Clock clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); final TimeoutFactory timeoutFactory = new TimeoutFactory(clock); - setuidHandler = new SetuidHandler(2000, uidsCookieService, bidderCatalog, gdprService, - null, false, analyticsReporter, metrics, timeoutFactory); + setuidHandler = new SetuidHandler(2000, uidsCookieService, applicationSettings, + bidderCatalog, tcfDefinerService, null, false, analyticsReporter, metrics, timeoutFactory); // when setuidHandler.handle(routingContext); diff --git a/src/test/java/org/prebid/server/handler/VersionHandlerTest.java b/src/test/java/org/prebid/server/handler/VersionHandlerTest.java index a35e3540aa2..335469b495e 100644 --- a/src/test/java/org/prebid/server/handler/VersionHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/VersionHandlerTest.java @@ -15,7 +15,6 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; - public class VersionHandlerTest extends VertxTest { @Rule @@ -54,7 +53,6 @@ public void handleShouldRespondWithInternalServerErrorWhenPropertyIsNotInFile() verify(httpResponse).end(mapper.writeValueAsString(RevisionResponse.of("not-set"))); } - @Test public void handleShouldRespondWithHashWhenPropertyIsInFile() throws JsonProcessingException { // given diff --git a/src/test/java/org/prebid/server/handler/VtrackHandlerTest.java b/src/test/java/org/prebid/server/handler/VtrackHandlerTest.java index 254555718e3..38a3605e0e5 100644 --- a/src/test/java/org/prebid/server/handler/VtrackHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/VtrackHandlerTest.java @@ -25,6 +25,7 @@ import org.prebid.server.settings.model.Account; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.function.Function; @@ -42,7 +43,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; - public class VtrackHandlerTest extends VertxTest { @Rule @@ -69,11 +69,13 @@ public class VtrackHandlerTest extends VertxTest { public void setUp() { given(routingContext.request()).willReturn(httpRequest); given(routingContext.response()).willReturn(httpResponse); + given(httpRequest.getParam("a")).willReturn("accountId"); + given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); handler = new VtrackHandler( - 2000, applicationSettings, bidderCatalog, cacheService, timeoutFactory, jacksonMapper); + 2000, true, applicationSettings, bidderCatalog, cacheService, timeoutFactory, jacksonMapper); } @Test @@ -234,16 +236,90 @@ public void shouldSendToCacheEmptyUpdatableBiddersIfAccountEventsEnabledIsNull() } @Test - public void shouldSendToCacheExpectedPutsAndUpdatableBidders() throws JsonProcessingException { + public void shouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastNotAllowed() + throws JsonProcessingException { // given + handler = new VtrackHandler( + 2000, false, applicationSettings, bidderCatalog, cacheService, timeoutFactory, jacksonMapper); + final List putObjects = asList( PutObject.builder().bidid("bidId1").bidder("bidder").value(new TextNode("value1")).build(), PutObject.builder().bidid("bidId2").bidder("updatable_bidder").value(new TextNode("value2")).build()); given(routingContext.getBody()) .willReturn(givenVtrackRequest(putObjects)); + given(bidderCatalog.isValidName("bidder")).willReturn(true); + given(bidderCatalog.isModifyingVastXmlAllowed("bidder")).willReturn(false); + given(bidderCatalog.isValidName("updatable_bidder")).willReturn(true); given(bidderCatalog.isModifyingVastXmlAllowed("updatable_bidder")).willReturn(true); + given(applicationSettings.getAccountById(any(), any())) + .willReturn(Future.succeededFuture(Account.builder().eventsEnabled(true).build())); + given(cacheService.cachePutObjects(any(), any(), any(), any())) + .willReturn(Future.succeededFuture(BidCacheResponse.of( + singletonList(CacheObject.of("uuid1"))))); + + // when + handler.handle(routingContext); + + // then + verify(cacheService).cachePutObjects(eq(putObjects), eq(singleton("updatable_bidder")), eq("accountId"), + any()); + + verify(httpResponse).end(eq("{\"responses\":[{\"uuid\":\"uuid1\"}]}")); + } + + @Test + public void shouldSendToCacheExpectedPutsAndUpdatableBiddersWhenBidderVastAllowed() throws JsonProcessingException { + // given + handler = new VtrackHandler( + 2000, false, applicationSettings, bidderCatalog, cacheService, timeoutFactory, jacksonMapper); + + final List putObjects = asList( + PutObject.builder().bidid("bidId1").bidder("bidder").value(new TextNode("value1")).build(), + PutObject.builder().bidid("bidId2").bidder("updatable_bidder").value(new TextNode("value2")).build()); + given(routingContext.getBody()) + .willReturn(givenVtrackRequest(putObjects)); + + given(bidderCatalog.isValidName(any())).willReturn(true); + given(bidderCatalog.isModifyingVastXmlAllowed(any())).willReturn(true); + + given(applicationSettings.getAccountById(any(), any())) + .willReturn(Future.succeededFuture(Account.builder().eventsEnabled(true).build())); + given(cacheService.cachePutObjects(any(), any(), any(), any())) + .willReturn(Future.succeededFuture(BidCacheResponse.of( + asList(CacheObject.of("uuid1"), CacheObject.of("uuid2"))))); + + // when + handler.handle(routingContext); + + // then + final HashSet expectedBidders = new HashSet<>(asList("bidder", "updatable_bidder")); + verify(cacheService).cachePutObjects(eq(putObjects), eq(expectedBidders), eq("accountId"), any()); + + verify(httpResponse).end(eq("{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}")); + } + + @Test + public void shouldSendToCacheExpectedPutsAndUpdatableUnknownBiddersWhenUnknownBidderIsAllowed() + throws JsonProcessingException { + // given + final List putObjects = asList( + PutObject.builder() + .bidid("bidId1") + .bidder("bidder") + .value(new TextNode("value1")) + .build(), + PutObject.builder() + .bidid("bidId2") + .bidder("updatable_bidder") + .value(new TextNode("value2")) + .build()); + given(routingContext.getBody()) + .willReturn(givenVtrackRequest(putObjects)); + + given(bidderCatalog.isValidName(any())).willReturn(false); + given(applicationSettings.getAccountById(any(), any())) .willReturn(Future.succeededFuture(Account.builder().eventsEnabled(true).build())); given(cacheService.cachePutObjects(any(), any(), any(), any())) @@ -254,15 +330,16 @@ public void shouldSendToCacheExpectedPutsAndUpdatableBidders() throws JsonProces handler.handle(routingContext); // then - verify(cacheService).cachePutObjects(eq(putObjects), eq(singleton("updatable_bidder")), - eq("accountId"), any()); + final HashSet expectedBidders = new HashSet<>(asList("bidder", "updatable_bidder")); + verify(cacheService).cachePutObjects(eq(putObjects), eq(expectedBidders), eq("accountId"), any()); verify(httpResponse).end(eq("{\"responses\":[{\"uuid\":\"uuid1\"},{\"uuid\":\"uuid2\"}]}")); } @SafeVarargs private static Buffer givenVtrackRequest( - Function... customizers) throws JsonProcessingException { + Function... customizers) + throws JsonProcessingException { final List putObjects; if (customizers != null) { diff --git a/src/test/java/org/prebid/server/handler/openrtb2/AmpHandlerTest.java b/src/test/java/org/prebid/server/handler/openrtb2/AmpHandlerTest.java index ede852b9e66..54de27ddbbe 100644 --- a/src/test/java/org/prebid/server/handler/openrtb2/AmpHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/openrtb2/AmpHandlerTest.java @@ -14,7 +14,6 @@ import io.vertx.core.http.CaseInsensitiveHeaders; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.logging.Logger; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -38,9 +37,9 @@ import org.prebid.server.exception.BlacklistedAppException; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.UnauthorizedAccountException; -import org.prebid.server.execution.LogModifier; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; +import org.prebid.server.manager.AdminManager; import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.proto.openrtb.ext.ExtPrebid; @@ -48,6 +47,7 @@ import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.proto.openrtb.ext.response.ExtBidResponse; +import org.prebid.server.proto.openrtb.ext.response.ExtBidResponsePrebid; import org.prebid.server.proto.openrtb.ext.response.ExtResponseDebug; import org.prebid.server.util.HttpUtil; @@ -99,7 +99,7 @@ public class AmpHandlerTest extends VertxTest { @Mock private Clock clock; @Mock - private LogModifier logModifier; + private AdminManager adminManager; private AmpHandler ampHandler; @Mock @@ -129,8 +129,6 @@ public void setUp() { given(uidsCookie.hasLiveUids()).willReturn(true); - given(logModifier.get()).willReturn(Logger::info); - given(clock.millis()).willReturn(Instant.now().toEpochMilli()); timeout = new TimeoutFactory(clock).create(2000L); @@ -143,7 +141,7 @@ public void setUp() { bidderCatalog, singleton("bidder1"), new AmpResponsePostProcessor.NoOpAmpResponsePostProcessor(), - logModifier, jacksonMapper + adminManager, jacksonMapper ); } @@ -208,7 +206,7 @@ public void shouldRespondWithBadRequestIfRequestIsInvalid() { // then verifyZeroInteractions(exchangeService); verify(httpResponse).setStatusCode(eq(400)); - verify(logModifier).get(); + verify(adminManager).accept(eq(AdminManager.COUNTER_KEY), any(), any()); assertThat(httpResponse.headers()).hasSize(2) .extracting(Map.Entry::getKey, Map.Entry::getValue) .containsOnly( @@ -348,8 +346,8 @@ public void shouldRespondWithExpectedResponse() { targeting.put("key1", "value1"); targeting.put("hb_cache_id_bidder1", "value2"); given(exchangeService.holdAuction(any())) - .willReturn(givenBidResponse( - mapper.valueToTree(ExtPrebid.of(ExtBidPrebid.of(null, null, targeting, null, null, null, null), null)))); + .willReturn(givenBidResponse(mapper.valueToTree(ExtPrebid.of(ExtBidPrebid.of( + null, null, targeting, null, null, null, null), null)))); // when ampHandler.handle(routingContext); @@ -379,7 +377,8 @@ public void shouldRespondWithCustomTargetingIncluded() { .seat("bidder1") .bid(singletonList(Bid.builder() .ext(mapper.valueToTree( - ExtPrebid.of(ExtBidPrebid.of(null, null, targeting, null, null, null, null), + ExtPrebid.of( + ExtBidPrebid.of(null, null, targeting, null, null, null, null), mapper.createObjectNode()))) .build())) .build())) @@ -403,8 +402,8 @@ public void shouldRespondWithCustomTargetingIncluded() { tuple("AMP-Access-Control-Allow-Source-Origin", "http://example.com"), tuple("Access-Control-Expose-Headers", "AMP-Access-Control-Allow-Source-Origin"), tuple("Content-Type", "application/json")); - verify(httpResponse).end(eq("{\"targeting\":{\"key1\":\"value1\",\"rpfl_11078\":\"15_tier0030\"," + - "\"hb_cache_id_bidder1\":\"value2\"}}")); + verify(httpResponse).end(eq("{\"targeting\":{\"key1\":\"value1\",\"rpfl_11078\":\"15_tier0030\"," + + "\"hb_cache_id_bidder1\":\"value2\"}}")); } @Test @@ -417,15 +416,15 @@ public void shouldRespondWithDebugInfoIncludedIfTestFlagIsTrue() { given(exchangeService.holdAuction(any())) .willReturn(givenBidResponseWithExt(mapper.valueToTree( ExtBidResponse.of(ExtResponseDebug.of(null, auctionContext.getBidRequest()), null, null, null, - null)))); + null, ExtBidResponsePrebid.of(1000L))))); // when ampHandler.handle(routingContext); // then verify(httpResponse).end(eq( - "{\"targeting\":{},\"debug\":{\"resolvedrequest\":{\"id\":\"reqId1\",\"imp\":[],\"test\":1," + - "\"tmax\":1000}}}")); + "{\"targeting\":{},\"debug\":{\"resolvedrequest\":{\"id\":\"reqId1\",\"imp\":[],\"test\":1," + + "\"tmax\":5000}}}")); } @Test @@ -440,14 +439,14 @@ public void shouldRespondWithDebugInfoIncludedIfExtPrebidDebugIsOn() { given(exchangeService.holdAuction(any())) .willReturn(givenBidResponseWithExt(mapper.valueToTree( ExtBidResponse.of(ExtResponseDebug.of(null, auctionContext.getBidRequest()), null, null, null, - null)))); + null, ExtBidResponsePrebid.of(1000L))))); // when ampHandler.handle(routingContext); // then verify(httpResponse).end( - eq("{\"targeting\":{},\"debug\":{\"resolvedrequest\":{\"id\":\"reqId1\",\"imp\":[],\"tmax\":1000," + eq("{\"targeting\":{},\"debug\":{\"resolvedrequest\":{\"id\":\"reqId1\",\"imp\":[],\"tmax\":5000," + "\"ext\":{\"prebid\":{\"debug\":1}}}}}")); } @@ -497,8 +496,8 @@ public void shouldIncrementNoCookieMetrics() { given(uidsCookie.hasLiveUids()).willReturn(false); - httpRequest.headers().add(HttpUtil.USER_AGENT_HEADER, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " + - "AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"); + httpRequest.headers().add(HttpUtil.USER_AGENT_HEADER, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " + + "AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"); // when ampHandler.handle(routingContext); @@ -761,7 +760,7 @@ public void shouldPassSuccessfulEventToAnalyticsReporter() { private AuctionContext givenAuctionContext( Function bidRequestBuilderCustomizer) { final BidRequest bidRequest = bidRequestBuilderCustomizer.apply(BidRequest.builder() - .imp(emptyList()).tmax(1000L)).build(); + .imp(emptyList()).tmax(5000L)).build(); return AuctionContext.builder() .uidsCookie(uidsCookie) diff --git a/src/test/java/org/prebid/server/handler/openrtb2/AuctionHandlerTest.java b/src/test/java/org/prebid/server/handler/openrtb2/AuctionHandlerTest.java index 7936bcaf398..a5a65fd7b22 100644 --- a/src/test/java/org/prebid/server/handler/openrtb2/AuctionHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/openrtb2/AuctionHandlerTest.java @@ -10,7 +10,6 @@ import io.vertx.core.http.CaseInsensitiveHeaders; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.http.HttpServerResponse; -import io.vertx.core.logging.Logger; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -31,9 +30,9 @@ import org.prebid.server.exception.BlacklistedAppException; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.UnauthorizedAccountException; -import org.prebid.server.execution.LogModifier; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; +import org.prebid.server.manager.AdminManager; import org.prebid.server.metric.MetricName; import org.prebid.server.metric.Metrics; import org.prebid.server.proto.openrtb.ext.request.ExtBidRequest; @@ -88,7 +87,7 @@ public class AuctionHandlerTest extends VertxTest { @Mock private Clock clock; @Mock - private LogModifier logModifier; + private AdminManager adminManager; private AuctionHandler auctionHandler; @Mock @@ -114,13 +113,11 @@ public void setUp() { given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); given(httpResponse.headers()).willReturn(new CaseInsensitiveHeaders()); - given(logModifier.get()).willReturn(Logger::info); - given(clock.millis()).willReturn(Instant.now().toEpochMilli()); timeout = new TimeoutFactory(clock).create(2000L); auctionHandler = new AuctionHandler( - auctionRequestFactory, exchangeService, analyticsReporter, metrics, clock, logModifier, jacksonMapper); + auctionRequestFactory, exchangeService, analyticsReporter, metrics, clock, adminManager, jacksonMapper); } @Test @@ -302,12 +299,13 @@ public void shouldRespondWithCorrectResolvedRequestMediaTypePriceGranularity() { final BidRequest resolvedRequest = BidRequest.builder() .ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(ExtRequestTargeting.builder().mediatypepricegranularity(priceGranuality).build()) + .auctiontimestamp(0L) .build()))) .build(); given(exchangeService.holdAuction(any())) .willReturn(Future.succeededFuture(BidResponse.builder() .ext(mapper.valueToTree(ExtBidResponse.of(ExtResponseDebug.of(null, resolvedRequest), - null, null, null, null))) + null, null, null, null, null))) .build())); // when @@ -315,10 +313,9 @@ public void shouldRespondWithCorrectResolvedRequestMediaTypePriceGranularity() { // then verify(exchangeService).holdAuction(any()); - - verify(httpResponse).end(eq("{\"ext\":{\"debug\":{\"resolvedrequest\":{\"ext\":{\"prebid\":" + - "{\"targeting\":{\"mediatypepricegranularity\":{\"banner\":{\"precision\":1,\"ranges\":" + - "[{\"max\":10,\"increment\":1}]},\"native\":{}}}}}}}}}")); + verify(httpResponse).end(eq("{\"ext\":{\"debug\":{\"resolvedrequest\":{\"ext\":{\"prebid\":" + + "{\"targeting\":{\"mediatypepricegranularity\":{\"banner\":{\"precision\":1,\"ranges\":" + + "[{\"max\":10,\"increment\":1}]},\"native\":{}}},\"auctiontimestamp\":0}}}}}}")); } @Test @@ -380,8 +377,8 @@ public void shouldIncrementNoCookieMetrics() { given(uidsCookie.hasLiveUids()).willReturn(false); - httpRequest.headers().add(HttpUtil.USER_AGENT_HEADER, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " + - "AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"); + httpRequest.headers().add(HttpUtil.USER_AGENT_HEADER, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) " + + "AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7"); // when auctionHandler.handle(routingContext); @@ -571,7 +568,7 @@ public void shouldPassBadRequestEventToAnalyticsReporterIfBidRequestIsInvalid() auctionHandler.handle(routingContext); // then - verify(logModifier).get(); + verify(adminManager).accept(eq(AdminManager.COUNTER_KEY), any(), any()); final AuctionEvent auctionEvent = captureAuctionEvent(); assertThat(auctionEvent).isEqualTo(AuctionEvent.builder() diff --git a/src/test/java/org/prebid/server/health/DatabaseHealthCheckerTest.java b/src/test/java/org/prebid/server/health/DatabaseHealthCheckerTest.java index af387db1e71..c4b3836aee2 100644 --- a/src/test/java/org/prebid/server/health/DatabaseHealthCheckerTest.java +++ b/src/test/java/org/prebid/server/health/DatabaseHealthCheckerTest.java @@ -126,4 +126,4 @@ private Answer withSelfAndPassObjectToHandler(int arg, Object result return result; }; } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/health/GeoLocationHealthCheckerTest.java b/src/test/java/org/prebid/server/health/GeoLocationHealthCheckerTest.java index f8a74fff83c..76f388e6399 100644 --- a/src/test/java/org/prebid/server/health/GeoLocationHealthCheckerTest.java +++ b/src/test/java/org/prebid/server/health/GeoLocationHealthCheckerTest.java @@ -1,6 +1,5 @@ package org.prebid.server.health; - import io.vertx.core.Future; import io.vertx.core.Handler; import io.vertx.core.Vertx; @@ -119,4 +118,4 @@ public void initializeShouldMakeOneInitialRequestAndTwoScheduledRequests() { verify(geoLocationService, times(3)).lookup(any(), any()); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/it/AdformTest.java b/src/test/java/org/prebid/server/it/AdformTest.java index e185c302f90..6891e0d78ab 100644 --- a/src/test/java/org/prebid/server/it/AdformTest.java +++ b/src/test/java/org/prebid/server/it/AdformTest.java @@ -28,7 +28,7 @@ public class AdformTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromAdform() throws IOException, JSONException { // given // adform bid response for imp 12 - wireMockRule.stubFor(get(urlPathEqualTo("/adform-exchange")) + WIRE_MOCK_RULE.stubFor(get(urlPathEqualTo("/adform-exchange")) .withQueryParam("CC", equalTo("1")) .withQueryParam("rp", equalTo("4")) .withQueryParam("fd", equalTo("1")) @@ -53,12 +53,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromAdform() throws IOException, .willReturn(aResponse().withBody(jsonFrom("openrtb2/adform/test-adform-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adform/test-cache-adform-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/adform/test-cache-adform-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -80,7 +80,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromAdform() throws IOException, public void auctionShouldRespondWithBidsFromAdform() throws IOException { // given // adform bid response for ad unit 12 - wireMockRule.stubFor(get(urlPathEqualTo("/adform-exchange")) + WIRE_MOCK_RULE.stubFor(get(urlPathEqualTo("/adform-exchange")) .withQueryParam("CC", equalTo("1")) .withQueryParam("rp", equalTo("4")) .withQueryParam("fd", equalTo("1")) @@ -104,12 +104,12 @@ public void auctionShouldRespondWithBidsFromAdform() throws IOException { .willReturn(aResponse().withBody(jsonFrom("auction/adform/test-adform-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/adform/test-cache-adform-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/adform/test-cache-adform-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/AdkernelAdnTest.java b/src/test/java/org/prebid/server/it/AdkernelAdnTest.java index 4c42bdc90bd..8f143fafb68 100644 --- a/src/test/java/org/prebid/server/it/AdkernelAdnTest.java +++ b/src/test/java/org/prebid/server/it/AdkernelAdnTest.java @@ -26,7 +26,7 @@ public class AdkernelAdnTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromAdkerneladn() throws IOException, JSONException { // given // adkernelAdn bid response for imp 021 - wireMockRule.stubFor(post(urlPathEqualTo("/adkernelAdn-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adkernelAdn-exchange")) .withQueryParam("account", equalTo("101")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) @@ -36,7 +36,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromAdkerneladn() throws IOExcep jsonFrom("openrtb2/adkerneladn/test-adkerneladn-bid-response-1.json")))); // adkernelAdn bid response for imp 022 - wireMockRule.stubFor(post(urlPathEqualTo("/adkernelAdn-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adkernelAdn-exchange")) .withQueryParam("account", equalTo("102")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) @@ -46,13 +46,13 @@ public void openrtb2AuctionShouldRespondWithBidsFromAdkerneladn() throws IOExcep jsonFrom("openrtb2/adkerneladn/test-adkerneladn-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adkerneladn/test-cache-adkerneladn-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/adkerneladn/test-cache-adkerneladn-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/AdkernelTest.java b/src/test/java/org/prebid/server/it/AdkernelTest.java index 0f32a69a6f9..989b4799647 100644 --- a/src/test/java/org/prebid/server/it/AdkernelTest.java +++ b/src/test/java/org/prebid/server/it/AdkernelTest.java @@ -26,7 +26,7 @@ public class AdkernelTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromAdkernel() throws IOException, JSONException { // given // adkernel bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/adkernel-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adkernel-exchange")) .withQueryParam("zone", equalTo("101")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) @@ -36,13 +36,13 @@ public void openrtb2AuctionShouldRespondWithBidsFromAdkernel() throws IOExceptio jsonFrom("openrtb2/adkernel/test-adkernel-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adkernel/test-cache-adkernel-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/adkernel/test-cache-adkernel-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/AdponeTest.java b/src/test/java/org/prebid/server/it/AdponeTest.java index 19b395fd24e..32d351269ce 100644 --- a/src/test/java/org/prebid/server/it/AdponeTest.java +++ b/src/test/java/org/prebid/server/it/AdponeTest.java @@ -25,18 +25,18 @@ public class AdponeTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromAdpone() throws IOException, JSONException { // given // Adpone bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/adpone-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adpone-exchange")) .withHeader("x-openrtb-version", equalTo("2.5")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adpone/test-adpone-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/adpone/test-adpone-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adpone/test-cache-adpone-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/adpone/test-cache-adpone-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/AdtelligentTest.java b/src/test/java/org/prebid/server/it/AdtelligentTest.java index b520c8f1a07..c293727c904 100644 --- a/src/test/java/org/prebid/server/it/AdtelligentTest.java +++ b/src/test/java/org/prebid/server/it/AdtelligentTest.java @@ -25,20 +25,20 @@ public class AdtelligentTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromAdtelligent() throws IOException, JSONException { // given // adtelligent bid response for imp 14 - wireMockRule.stubFor(post(urlPathEqualTo("/adtelligent-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/adtelligent-exchange")) .withQueryParam("aid", equalTo("1000")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adtelligent/test-adtelligent-bid-request-1.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/adtelligent/test-adtelligent-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/adtelligent/test-cache-adtelligent-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/adtelligent/test-cache-adtelligent-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/AdvangelistsTest.java b/src/test/java/org/prebid/server/it/AdvangelistsTest.java index a214af65710..55452a6b7d5 100644 --- a/src/test/java/org/prebid/server/it/AdvangelistsTest.java +++ b/src/test/java/org/prebid/server/it/AdvangelistsTest.java @@ -26,7 +26,7 @@ public class AdvangelistsTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromAdvangelists() throws IOException, JSONException { // given // advangelists bid response for imp - wireMockRule.stubFor(post(urlPathEqualTo("/advangelists-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/advangelists-exchange")) .withQueryParam("pubid", equalTo("19f1b372c7548ec1fe734d2c9f8dc688")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) @@ -36,13 +36,13 @@ public void openrtb2AuctionShouldRespondWithBidsFromAdvangelists() throws IOExce jsonFrom("openrtb2/advangelists/test-advangelists-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/advangelists/test-cache-advangelists-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/advangelists/test-cache-advangelists-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/ApplicationTest.java b/src/test/java/org/prebid/server/it/ApplicationTest.java index e742b35ee17..b6e63f421f6 100644 --- a/src/test/java/org/prebid/server/it/ApplicationTest.java +++ b/src/test/java/org/prebid/server/it/ApplicationTest.java @@ -69,7 +69,7 @@ public class ApplicationTest extends IntegrationTest { private static final int ADMIN_PORT = 8060; - private static final RequestSpecification adminSpec = new RequestSpecBuilder() + private static final RequestSpecification ADMIN_SPEC = new RequestSpecBuilder() .setBaseUri("http://localhost") .setPort(ADMIN_PORT) .setConfig(RestAssuredConfig.config() @@ -80,7 +80,7 @@ public class ApplicationTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromRubiconAndAppnexus() throws IOException, JSONException { // given // rubicon bid response for imp 1 - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withQueryParam("tk_xint", equalTo("dmbjs")) .withBasicAuth("rubicon_user", "rubicon_password") .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=utf-8")) @@ -91,25 +91,25 @@ public void openrtb2AuctionShouldRespondWithBidsFromRubiconAndAppnexus() throws "openrtb2/rubicon_appnexus/test-rubicon-bid-response-1.json")))); // rubicon bid response for imp 2 - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rubicon_appnexus/test-rubicon-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom( "openrtb2/rubicon_appnexus/test-rubicon-bid-response-2.json")))); // appnexus bid response for imp 3 - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rubicon_appnexus/test-appnexus-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom( "openrtb2/rubicon_appnexus/test-appnexus-bid-response-1.json")))); // appnexus bid response for imp 3 with alias parameters - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rubicon_appnexus/test-appnexus-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom( "openrtb2/rubicon_appnexus/test-appnexus-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom( "openrtb2/rubicon_appnexus/test-cache-rubicon-appnexus-request.json"), true, false)) .willReturn(aResponse() @@ -119,7 +119,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromRubiconAndAppnexus() throws )); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("User-Agent", "userAgent") .header("Origin", "http://www.example.com") @@ -140,17 +140,17 @@ public void openrtb2AuctionShouldRespondWithBidsFromRubiconAndAppnexus() throws public void auctionShouldRespondWithBidsFromAppnexusAlias() throws IOException { // given // appnexus bid response for ad unit 4 - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/districtm/test-districtm-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/districtm/test-districtm-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/districtm/test-cache-districtm-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/districtm/test-cache-districtm-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -178,7 +178,7 @@ public void auctionShouldRespondWithBidsFromAppnexusAlias() throws IOException { public void auctionShouldRespondWithBidsFromRubiconAndAppnexus() throws IOException { // given // rubicon bid response for ad unit 1 - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withQueryParam("tk_xint", equalTo("rp-pbs")) .withBasicAuth("rubicon_user", "rubicon_password") .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=utf-8")) @@ -189,32 +189,32 @@ public void auctionShouldRespondWithBidsFromRubiconAndAppnexus() throws IOExcept jsonFrom("auction/rubicon_appnexus/test-rubicon-bid-response-1.json")))); // rubicon bid response for ad unit 2 - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/rubicon_appnexus/test-rubicon-bid-request-2.json"))) .willReturn(aResponse().withBody( jsonFrom("auction/rubicon_appnexus/test-rubicon-bid-response-2.json")))); // rubicon bid response for ad unit 3 - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/rubicon_appnexus/test-rubicon-bid-request-3.json"))) .willReturn(aResponse().withBody( jsonFrom("auction/rubicon_appnexus/test-rubicon-bid-response-3.json")))); // appnexus bid response for ad unit 4 - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/rubicon_appnexus/test-appnexus-bid-request-1.json"))) .willReturn(aResponse().withBody( jsonFrom("auction/rubicon_appnexus/test-appnexus-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom( "auction/rubicon_appnexus/test-cache-rubicon-appnexus-request.json"))) .willReturn(aResponse().withBody(jsonFrom( "auction/rubicon_appnexus/test-cache-rubicon-appnexus-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -242,17 +242,17 @@ public void auctionShouldRespondWithBidsFromRubiconAndAppnexus() throws IOExcept public void ampShouldReturnTargeting() throws IOException, JSONException { // given // rubicon exchange - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withRequestBody(equalToJson(jsonFrom("amp/test-rubicon-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("amp/test-rubicon-bid-response.json")))); // appnexus exchange - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withRequestBody(equalToJson(jsonFrom("amp/test-appnexus-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("amp/test-appnexus-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("amp/test-cache-request.json"), true, false)) .willReturn(aResponse() .withTransformers("cache-response-transformer") @@ -260,7 +260,7 @@ public void ampShouldReturnTargeting() throws IOException, JSONException { )); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -268,15 +268,15 @@ public void ampShouldReturnTargeting() throws IOException, JSONException { // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT"}} .cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIn19") .when() - .get("/openrtb2/amp" + - "?tag_id=test-amp-stored-request" + - "&ow=980" + - "&oh=120" + - "&timeout=10000000" + - "&slot=overwrite-tagId" + - "&curl=https%3A%2F%2Fgoogle.com" + - "&account=accountId" + - "&us_privacy=1YNN"); + .get("/openrtb2/amp" + + "?tag_id=test-amp-stored-request" + + "&ow=980" + + "&oh=120" + + "&timeout=10000000" + + "&slot=overwrite-tagId" + + "&curl=https%3A%2F%2Fgoogle.com" + + "&account=accountId" + + "&us_privacy=1YNN"); // then JSONAssert.assertEquals(jsonFrom("amp/test-amp-response.json"), response.asString(), @@ -285,7 +285,7 @@ public void ampShouldReturnTargeting() throws IOException, JSONException { @Test public void statusShouldReturnReadyWithinResponseBodyAndHttp200Ok() { - assertThat(given(spec).when().get("/status")) + assertThat(given(SPEC).when().get("/status")) .extracting(Response::getStatusCode, response -> response.getBody().asString()) .containsOnly(200, "{\"application\":{\"status\":\"ok\"}}"); } @@ -293,12 +293,12 @@ public void statusShouldReturnReadyWithinResponseBodyAndHttp200Ok() { @Test public void optoutShouldSetOptOutFlagAndRedirectToOptOutUrl() throws IOException { // given - wireMockRule.stubFor(post("/optout") + WIRE_MOCK_RULE.stubFor(post("/optout") .withRequestBody(equalTo("secret=abc&response=recaptcha1")) .willReturn(aResponse().withBody("{\"success\": true}"))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Content-Type", "application/x-www-form-urlencoded") // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}} .cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0NSJ9fQ==") @@ -321,9 +321,9 @@ public void optoutShouldSetOptOutFlagAndRedirectToOptOutUrl() throws IOException @Test public void staticShouldReturnHttp200Ok() { - given(spec) + given(SPEC) .when() - .get("/static") + .get("/static/index.html") .then() .assertThat() .statusCode(200); @@ -344,9 +344,10 @@ public void cookieSyncShouldReturnBidderStatusWithExpectedUsersyncInfo() { .build()); // when - final CookieSyncResponse cookieSyncResponse = given(spec) + final CookieSyncResponse cookieSyncResponse = given(SPEC) .cookies("host-cookie-name", "host-cookie-uid") - .body(CookieSyncRequest.of(asList(RUBICON, APPNEXUS, ADFORM), 1, gdprConsent, "1YNN", false, null)) + .body(CookieSyncRequest.of(asList(RUBICON, APPNEXUS, ADFORM), 1, gdprConsent, "1YNN", false, null, + null)) .when() .post("/cookie_sync") .then() @@ -355,8 +356,10 @@ public void cookieSyncShouldReturnBidderStatusWithExpectedUsersyncInfo() { .as(CookieSyncResponse.class); // then - assertThat(cookieSyncResponse).isEqualTo(CookieSyncResponse.of("ok", - asList(BidderUsersyncStatus.builder() + assertThat(cookieSyncResponse.getStatus()).isEqualTo("ok"); + assertThat(cookieSyncResponse.getBidderStatus()) + .hasSize(3) + .containsOnly(BidderUsersyncStatus.builder() .bidder(RUBICON) .noCookie(true) .usersync(UsersyncInfo.of( @@ -378,14 +381,14 @@ public void cookieSyncShouldReturnBidderStatusWithExpectedUsersyncInfo() { .build(), BidderUsersyncStatus.builder() .bidder(ADFORM) - .error("Rejected by GDPR") - .build()))); + .error("Rejected by TCF") + .build()); } @Test public void setuidShouldUpdateRubiconUidInUidCookie() throws IOException { // when - final Cookie uidsCookie = given(spec) + final Cookie uidsCookie = given(SPEC) // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}, // "bday":"2017-08-15T19:47:59.523908376Z"} .cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0" @@ -421,7 +424,7 @@ public void setuidShouldUpdateRubiconUidInUidCookie() throws IOException { @Test public void getuidsShouldReturnJsonWithUids() throws JSONException { // given and when - final Response response = given(spec) + final Response response = given(SPEC) // this uids cookie value stands for {"uids":{"rubicon":"J5VLCWQP-26-CWFT","adnxs":"12345"}, // "bday":"2017-08-15T19:47:59.523908376Z"} .cookie("uids", "eyJ1aWRzIjp7InJ1Ymljb24iOiJKNVZMQ1dRUC0yNi1DV0ZUIiwiYWRueHMiOiIxMjM0" @@ -437,11 +440,11 @@ public void getuidsShouldReturnJsonWithUids() throws JSONException { @Test public void vtrackShouldReturnJsonWithUids() throws JSONException, IOException { // given and when - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("vtrack/test-cache-request.json"), true, false)) .willReturn(aResponse().withBody(jsonFrom("vtrack/test-vtrack-response.json")))); - final Response response = given(spec) + final Response response = given(SPEC) .when() .body(jsonFrom("vtrack/test-vtrack-request.json")) .queryParam("a", "14062") @@ -455,7 +458,7 @@ public void vtrackShouldReturnJsonWithUids() throws JSONException, IOException { @Test public void optionsRequestShouldRespondWithOriginalPolicyHeaders() { // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Origin", "origin.com") .header("Access-Control-Request-Method", "GET") .when() @@ -476,7 +479,7 @@ public void biddersParamsShouldReturnBidderSchemas() throws JSONException { .collect(Collectors.toMap(Function.identity(), ApplicationTest::jsonSchemaToJsonNode)); // when - final Response response = given(spec) + final Response response = given(SPEC) .when() .get("/bidders/params"); @@ -491,7 +494,7 @@ public void infoBiddersShouldReturnRegisteredActiveBidderNames() throws JSONExce final List bidderAliases = getBidderAliasesFromConfigFiles(); // when - final Response response = given(spec) + final Response response = given(SPEC) .when() .get("/info/bidders"); @@ -502,7 +505,7 @@ public void infoBiddersShouldReturnRegisteredActiveBidderNames() throws JSONExce @Test public void infoBidderDetailsShouldReturnMetadataForBidder() throws IOException { - given(spec) + given(SPEC) .when() .get("/info/bidders/rubicon") .then() @@ -512,11 +515,13 @@ public void infoBidderDetailsShouldReturnMetadataForBidder() throws IOException @Test public void eventHandlerShouldRespondWithTrackingPixel() throws IOException { - final Response response = given(spec) + final Response response = given(SPEC) .queryParam("t", "win") .queryParam("b", "bidId") .queryParam("a", "14062") .queryParam("f", "i") + .queryParam("bidder", "bidder") + .queryParam("ts", "1000") .get("/event"); assertThat(response.getStatusCode()).isEqualTo(200); @@ -529,7 +534,7 @@ public void eventHandlerShouldRespondWithTrackingPixel() throws IOException { public void shouldAskExchangeWithUpdatedSettingsFromCache() throws IOException, JSONException { // given // update stored settings cache - given(adminSpec) + given(ADMIN_SPEC) .body(jsonFrom("cache/update/test-update-settings-request.json")) .when() .post("/storedrequests/openrtb2") @@ -539,16 +544,16 @@ public void shouldAskExchangeWithUpdatedSettingsFromCache() throws IOException, .statusCode(200); // rubicon bid response - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withRequestBody(equalToJson(jsonFrom("cache/update/test-rubicon-bid-request1.json"))) .willReturn(aResponse().withBody(jsonFrom("cache/update/test-rubicon-bid-response1.json")))); - wireMockRule.stubFor(post(urlPathEqualTo("/rubicon-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rubicon-exchange")) .withRequestBody(equalToJson(jsonFrom("cache/update/test-rubicon-bid-request2.json"))) .willReturn(aResponse().withBody(jsonFrom("cache/update/test-rubicon-bid-response2.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -568,7 +573,7 @@ public void shouldAskExchangeWithUpdatedSettingsFromCache() throws IOException, @Test public void versionHandlerShouldRespondWithCommitRevision() { - given(adminSpec) + given(ADMIN_SPEC) .get("/version") .then() .assertThat() @@ -577,7 +582,7 @@ public void versionHandlerShouldRespondWithCommitRevision() { @Test public void adminHandlerShouldRespondWithOk() { - given(adminSpec) + given(ADMIN_SPEC) .get("/admin?logging=error&records=1200") .then() .assertThat() @@ -592,7 +597,7 @@ public void currencyRatesHandlerShouldRespondWithLastUpdateDate() { // ask endpoint after some time to ensure currency rates have already been fetched Vertx.vertx().setTimer(1000L, ignored -> { // when - final Response response = given(adminSpec).get("/currency-rates"); + final Response response = given(ADMIN_SPEC).get("/currency-rates"); // then final String lastUpdateValue = response.jsonPath().getString("last_update"); @@ -603,7 +608,7 @@ public void currencyRatesHandlerShouldRespondWithLastUpdateDate() { @Test public void invalidateSettingsCacheShouldReturnExpectedResponse() { - given(adminSpec) + given(ADMIN_SPEC) .body("{\"requests\":[],\"imps\":[]}") .when() .delete("/storedrequests/openrtb2") @@ -615,7 +620,7 @@ public void invalidateSettingsCacheShouldReturnExpectedResponse() { @Test public void updateAmpSettingsCacheShouldReturnExpectedResponse() { - given(adminSpec) + given(ADMIN_SPEC) .body("{\"requests\":{},\"imps\":{}}") .when() .post("/storedrequests/amp") @@ -627,7 +632,7 @@ public void updateAmpSettingsCacheShouldReturnExpectedResponse() { @Test public void invalidateAmpSettingsCacheShouldReturnExpectedResponse() { - given(adminSpec) + given(ADMIN_SPEC) .body("{\"requests\":[],\"imps\":[]}") .when() .delete("/storedrequests/amp") diff --git a/src/test/java/org/prebid/server/it/ApplogyTest.java b/src/test/java/org/prebid/server/it/ApplogyTest.java index b316d53089a..4a6351b4389 100644 --- a/src/test/java/org/prebid/server/it/ApplogyTest.java +++ b/src/test/java/org/prebid/server/it/ApplogyTest.java @@ -25,26 +25,26 @@ public class ApplogyTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromApplogy() throws IOException, JSONException { // given // Applogy bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/applogy-exchange/1234")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/applogy-exchange/1234")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) .withRequestBody(equalToJson(jsonFrom("openrtb2/applogy/test-applogy-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/applogy/test-applogy-bid-response-1.json")))); // Applogy bid response for imp 002 - wireMockRule.stubFor(post(urlPathEqualTo("/applogy-exchange/12345")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/applogy-exchange/12345")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) .withRequestBody(equalToJson(jsonFrom("openrtb2/applogy/test-applogy-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/applogy/test-applogy-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/applogy/test-cache-applogy-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/applogy/test-cache-applogy-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -58,8 +58,6 @@ public void openrtb2AuctionShouldRespondWithBidsFromApplogy() throws IOException "openrtb2/applogy/test-auction-applogy-response.json", response, singletonList("applogy")); - JSONAssert.assertEquals(expectedAuctionResponse, response.asString(), JSONCompareMode.NON_EXTENSIBLE); } } - diff --git a/src/test/java/org/prebid/server/it/AppnexusVideoTest.java b/src/test/java/org/prebid/server/it/AppnexusVideoTest.java index 85ff0289d0e..9a23e70aee1 100644 --- a/src/test/java/org/prebid/server/it/AppnexusVideoTest.java +++ b/src/test/java/org/prebid/server/it/AppnexusVideoTest.java @@ -24,25 +24,29 @@ public class AppnexusVideoTest extends IntegrationTest { @Test public void openrtb2VideoShouldRespondWithBidsFromAppnexus() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) .withRequestBody(equalToJson(jsonFrom("openrtb2/video/test-video-appnexus-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/video/test-video-appnexus-bid-response-1.json")))); - wireMockRule.stubFor(post(urlPathEqualTo("/appnexus-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/appnexus-exchange")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) .withRequestBody(equalToJson(jsonFrom("openrtb2/video/test-video-appnexus-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/video/test-video-appnexus-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/video/test-cache-video-appnexus-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/video/test-cache-video-appnexus-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/video/test-video-cache-request.json"), true, false)) + .willReturn(aResponse() + .withTransformers("cache-response-transformer") + .withTransformerParameter("matcherName", + "openrtb2/video/test-video-cache-response-matcher.json"))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -51,9 +55,9 @@ public void openrtb2VideoShouldRespondWithBidsFromAppnexus() throws IOException, .post("/openrtb2/video"); // then - final String expectedAuctionResponse = jsonFrom("openrtb2/video/test-video-appnexus-response.json"); + // TODO remove "empty" when VideoRequest will proceed consentValue. + final String expectedAuctionResponse = jsonFrom("openrtb2/video/test-video-appnexus-response-empty.json"); JSONAssert.assertEquals(expectedAuctionResponse, response.asString(), JSONCompareMode.NON_EXTENSIBLE); } } - diff --git a/src/test/java/org/prebid/server/it/BeachfrontTest.java b/src/test/java/org/prebid/server/it/BeachfrontTest.java index d5f2178fe5c..05e5b74c375 100644 --- a/src/test/java/org/prebid/server/it/BeachfrontTest.java +++ b/src/test/java/org/prebid/server/it/BeachfrontTest.java @@ -26,7 +26,7 @@ public class BeachfrontTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromBeachfront() throws IOException, JSONException { // given // beachfront bid response for imp 02 - wireMockRule.stubFor(post(urlPathEqualTo("/beachfront-exchange/video")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/beachfront-exchange/video")) .withQueryParam("exchange_id", equalTo("beachfrontAppId")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) @@ -39,7 +39,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromBeachfront() throws IOExcept .willReturn(aResponse().withBody(jsonFrom("openrtb2/beachfront/test-beachfront-bid-response-2.json")))); // beachfront bid response for imp 01 - wireMockRule.stubFor(post(urlPathEqualTo("/beachfront-exchange/video")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/beachfront-exchange/video")) .withQueryParam("exchange_id", equalTo("beachfrontAppId1")) .withQueryParam("prebidserver", equalTo("")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) @@ -53,7 +53,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromBeachfront() throws IOExcept .willReturn(aResponse().withBody(jsonFrom("openrtb2/beachfront/test-beachfront-bid-response-1.json")))); // beachfront bid response for imp 03 - wireMockRule.stubFor(post(urlPathEqualTo("/beachfront-exchange/banner")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/beachfront-exchange/banner")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withHeader("Accept", equalTo("application/json")) .withHeader("User-Agent", equalTo("userAgent")) @@ -64,12 +64,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromBeachfront() throws IOExcept .willReturn(aResponse().withBody(jsonFrom("openrtb2/beachfront/test-beachfront-bid-response-3.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/beachfront/test-cache-beachfront-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/beachfront/test-cache-beachfront-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/BrightrollTest.java b/src/test/java/org/prebid/server/it/BrightrollTest.java index 87b4b5903d0..45dbdc19ee2 100644 --- a/src/test/java/org/prebid/server/it/BrightrollTest.java +++ b/src/test/java/org/prebid/server/it/BrightrollTest.java @@ -26,8 +26,8 @@ public class BrightrollTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromBrightroll() throws IOException, JSONException { // given // brightroll bid response for imp 15 - wireMockRule.stubFor(post(urlPathEqualTo("/brightroll-exchange")) - .withQueryParam("publisher", equalTo("publisher")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/brightroll-exchange")) + .withQueryParam("publisher", equalTo("businessinsider")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=utf-8")) .withHeader("Accept", equalTo("application/json")) .withHeader("User-Agent", equalTo("userAgent")) @@ -39,12 +39,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromBrightroll() throws IOExcept .willReturn(aResponse().withBody(jsonFrom("openrtb2/brightroll/test-brightroll-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/brightroll/test-cache-brightroll-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/brightroll/test-cache-brightroll-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/ConsumableTest.java b/src/test/java/org/prebid/server/it/ConsumableTest.java index 02d1c6e8856..0c02200832d 100644 --- a/src/test/java/org/prebid/server/it/ConsumableTest.java +++ b/src/test/java/org/prebid/server/it/ConsumableTest.java @@ -25,7 +25,7 @@ public class ConsumableTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromConsumable() throws IOException, JSONException { // given // consumable bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/consumable-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/consumable-exchange")) .withHeader("Cookie", equalTo("azk=CS-UID")) .withHeader("Origin", equalTo("http://www.example.com")) .withHeader("Accept", equalTo("application/json")) @@ -43,12 +43,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromConsumable() throws IOExcept .willReturn(aResponse().withBody(jsonFrom("openrtb2/consumable/test-consumable-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/consumable/test-cache-consumable-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/consumable/test-cache-consumable-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/ConversantTest.java b/src/test/java/org/prebid/server/it/ConversantTest.java index 1d811bc466d..39259b1a8a0 100644 --- a/src/test/java/org/prebid/server/it/ConversantTest.java +++ b/src/test/java/org/prebid/server/it/ConversantTest.java @@ -29,17 +29,17 @@ public class ConversantTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromConversant() throws IOException, JSONException { // given // conversant bid response for imp 4 - wireMockRule.stubFor(post(urlPathEqualTo("/conversant-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/conversant-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/conversant/test-conversant-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/conversant/test-conversant-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/conversant/test-cache-conversant-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/conversant/test-cache-conversant-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -61,19 +61,19 @@ public void openrtb2AuctionShouldRespondWithBidsFromConversant() throws IOExcept public void openrtb2AuctionShouldRespondWithBidsFromConversantAlias() throws IOException, JSONException { // given // conversant bid response for imp 4 with alias parameters - wireMockRule.stubFor(post(urlPathEqualTo("/conversant-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/conversant-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/conversant/alias/test-conversant-bid-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/conversant/alias/test-conversant-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/conversant/alias/test-cache-conversant-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/conversant/alias/test-cache-conversant-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -95,17 +95,17 @@ public void openrtb2AuctionShouldRespondWithBidsFromConversantAlias() throws IOE public void auctionShouldRespondWithBidsFromConversant() throws IOException { // given // conversant bid response for ad unit 10 - wireMockRule.stubFor(post(urlPathEqualTo("/conversant-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/conversant-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/conversant/test-conversant-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/conversant/test-conversant-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/conversant/test-cache-conversant-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/conversant/test-cache-conversant-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/CpmStarTest.java b/src/test/java/org/prebid/server/it/CpmStarTest.java index 0ba7ce85ab2..57135fb477a 100644 --- a/src/test/java/org/prebid/server/it/CpmStarTest.java +++ b/src/test/java/org/prebid/server/it/CpmStarTest.java @@ -25,19 +25,19 @@ public class CpmStarTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromCPMStar() throws IOException, JSONException { // given // Cpmstar bid response - wireMockRule.stubFor(post(urlPathEqualTo("/cpmstar-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cpmstar-exchange")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) .withRequestBody(equalToJson(jsonFrom("openrtb2/cpmstar/test-cpmstar-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/cpmstar/test-cpmstar-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/cpmstar/test-cache-cpmstar-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/cpmstar/test-cache-cpmstar-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -51,7 +51,6 @@ public void openrtb2AuctionShouldRespondWithBidsFromCPMStar() throws IOException "openrtb2/cpmstar/test-auction-cpmstar-response.json", response, singletonList("cpmstar")); - JSONAssert.assertEquals(expectedAuctionResponse, response.asString(), JSONCompareMode.NON_EXTENSIBLE); } } diff --git a/src/test/java/org/prebid/server/it/DatablocksTest.java b/src/test/java/org/prebid/server/it/DatablocksTest.java index 2efc919d04c..dc7e8a2835b 100644 --- a/src/test/java/org/prebid/server/it/DatablocksTest.java +++ b/src/test/java/org/prebid/server/it/DatablocksTest.java @@ -25,24 +25,24 @@ public class DatablocksTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromDatablocks() throws IOException, JSONException { // given // Datablocks bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/datablocks-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/datablocks-exchange")) .withQueryParam("sid", equalTo("1")) .withRequestBody(equalToJson(jsonFrom("openrtb2/datablocks/test-datablocks-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/datablocks/test-datablocks-bid-response-1.json")))); // Datablocks bid response for imp 002 - wireMockRule.stubFor(post(urlPathEqualTo("/datablocks-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/datablocks-exchange")) .withQueryParam("sid", equalTo("2")) .withRequestBody(equalToJson(jsonFrom("openrtb2/datablocks/test-datablocks-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/datablocks/test-datablocks-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/datablocks/test-cache-datablocks-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/datablocks/test-cache-datablocks-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/EmxdigitalTest.java b/src/test/java/org/prebid/server/it/EmxdigitalTest.java index 49bee8d327a..b76fb83643e 100644 --- a/src/test/java/org/prebid/server/it/EmxdigitalTest.java +++ b/src/test/java/org/prebid/server/it/EmxdigitalTest.java @@ -25,7 +25,7 @@ public class EmxdigitalTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromEmxdigital() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/emx_digital-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/emx_digital-exchange")) .withQueryParam("t", equalTo("1000")) .withQueryParam("ts", equalTo("2060541160")) .withHeader("Accept", equalTo("application/json")) @@ -40,12 +40,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromEmxdigital() throws IOExcept .willReturn(aResponse().withBody(jsonFrom("openrtb2/emxdigital/test-emxdigital-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/emxdigital/test-cache-emxdigital-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/emxdigital/test-cache-emxdigital-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/EngagebdrTest.java b/src/test/java/org/prebid/server/it/EngagebdrTest.java index 810ec9bcca1..6e0491cc608 100644 --- a/src/test/java/org/prebid/server/it/EngagebdrTest.java +++ b/src/test/java/org/prebid/server/it/EngagebdrTest.java @@ -26,7 +26,7 @@ public class EngagebdrTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromEngagebdr() throws IOException, JSONException { // given // engagebdr bid response for imp 021 - wireMockRule.stubFor(post(urlPathEqualTo("/engagebdr-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/engagebdr-exchange")) .withQueryParam("zoneid", equalTo("99999")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withRequestBody(equalToJson(jsonFrom("openrtb2/engagebdr/test-engagebdr-bid-request-1.json"))) @@ -34,7 +34,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromEngagebdr() throws IOExcepti jsonFrom("openrtb2/engagebdr/test-engagebdr-bid-response-1.json")))); // engagebdr bid response for imp 022 - wireMockRule.stubFor(post(urlPathEqualTo("/engagebdr-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/engagebdr-exchange")) .withQueryParam("zoneid", equalTo("88888")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=UTF-8")) .withRequestBody(equalToJson(jsonFrom("openrtb2/engagebdr/test-engagebdr-bid-request-2.json"))) @@ -42,14 +42,13 @@ public void openrtb2AuctionShouldRespondWithBidsFromEngagebdr() throws IOExcepti jsonFrom("openrtb2/engagebdr/test-engagebdr-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/engagebdr/test-cache-engagebdr-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/engagebdr/test-cache-engagebdr-response.json")))); - // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/EplanningTest.java b/src/test/java/org/prebid/server/it/EplanningTest.java index 7ed841a05ca..df239b9d3d2 100644 --- a/src/test/java/org/prebid/server/it/EplanningTest.java +++ b/src/test/java/org/prebid/server/it/EplanningTest.java @@ -27,7 +27,7 @@ public class EplanningTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromEplanning() throws IOException, JSONException { // given // eplanning bid response for imp15 - wireMockRule.stubFor(get(urlPathEqualTo("/eplanning-exchange/12345/1/example.com/ROS")) + WIRE_MOCK_RULE.stubFor(get(urlPathEqualTo("/eplanning-exchange/12345/1/example.com/ROS")) .withQueryParam("r", equalTo("pbs")) .withQueryParam("ncb", equalTo("1")) .withQueryParam("ur", equalTo("https://www.example.com")) @@ -42,12 +42,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromEplanning() throws IOExcepti .willReturn(aResponse().withBody(jsonFrom("openrtb2/eplanning/test-eplanning-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/eplanning/test-cache-eplanning-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/eplanning/test-cache-eplanning-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "https://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/FacebookTest.java b/src/test/java/org/prebid/server/it/FacebookTest.java index 5ea1b366708..f36fcd3bc05 100644 --- a/src/test/java/org/prebid/server/it/FacebookTest.java +++ b/src/test/java/org/prebid/server/it/FacebookTest.java @@ -25,30 +25,30 @@ public class FacebookTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromFacebook() throws IOException, JSONException { // given // facebook bid response for impId001 - wireMockRule.stubFor(post(urlPathEqualTo("/audienceNetwork-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/audienceNetwork-exchange")) .withHeader("X-Fb-Pool-Routing-Token", equalTo("FB-UID")) .withRequestBody(equalToJson(jsonFrom("openrtb2/facebook/test-facebook-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/facebook/test-facebook-bid-response-1.json")))); // facebook bid response for impId002 - wireMockRule.stubFor(post(urlPathEqualTo("/audienceNetwork-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/audienceNetwork-exchange")) .withHeader("X-Fb-Pool-Routing-Token", equalTo("FB-UID")) .withRequestBody(equalToJson(jsonFrom("openrtb2/facebook/test-facebook-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/facebook/test-facebook-bid-response-2.json")))); // facebook bid response for impId003 - wireMockRule.stubFor(post(urlPathEqualTo("/audienceNetwork-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/audienceNetwork-exchange")) .withHeader("X-Fb-Pool-Routing-Token", equalTo("FB-UID")) .withRequestBody(equalToJson(jsonFrom("openrtb2/facebook/test-facebook-bid-request-3.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/facebook/test-facebook-bid-response-3.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/facebook/test-cache-facebook-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/facebook/test-cache-facebook-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/GammaTest.java b/src/test/java/org/prebid/server/it/GammaTest.java index f56e35344bd..ef34c4ff010 100644 --- a/src/test/java/org/prebid/server/it/GammaTest.java +++ b/src/test/java/org/prebid/server/it/GammaTest.java @@ -26,7 +26,7 @@ public class GammaTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromGamma() throws IOException, JSONException { // given - wireMockRule.stubFor(get(urlPathEqualTo("/gamma-exchange/")) + WIRE_MOCK_RULE.stubFor(get(urlPathEqualTo("/gamma-exchange/")) .withQueryParam("id", equalTo("id")) .withQueryParam("zid", equalTo("zid")) .withQueryParam("wid", equalTo("wid")) @@ -48,12 +48,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromGamma() throws IOException, .willReturn(aResponse().withBody(jsonFrom("openrtb2/gamma/test-gamma-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/gamma/test-cache-gamma-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/gamma/test-cache-gamma-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/GamoshiTest.java b/src/test/java/org/prebid/server/it/GamoshiTest.java index 17475558715..7d14af354c9 100644 --- a/src/test/java/org/prebid/server/it/GamoshiTest.java +++ b/src/test/java/org/prebid/server/it/GamoshiTest.java @@ -25,7 +25,7 @@ public class GamoshiTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromGamoshi() throws IOException, JSONException { // given // Gamoshi bid response for imp 001 and 002 - wireMockRule.stubFor(post(urlPathEqualTo("/gamoshi-exchange/r/1701/bidr")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/gamoshi-exchange/r/1701/bidr")) .withQueryParam("bidder", equalTo("prebid-server")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) @@ -38,12 +38,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromGamoshi() throws IOException .willReturn(aResponse().withBody(jsonFrom("openrtb2/gamoshi/test-gamoshi-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/gamoshi/test-cache-gamoshi-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/gamoshi/test-cache-gamoshi-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/GridTest.java b/src/test/java/org/prebid/server/it/GridTest.java index c23cf5c9031..c79783187b6 100644 --- a/src/test/java/org/prebid/server/it/GridTest.java +++ b/src/test/java/org/prebid/server/it/GridTest.java @@ -24,17 +24,17 @@ public class GridTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromTheMediaGrid() throws IOException, JSONException { // given // TheMediaGrid bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/grid-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/grid-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/grid/test-grid-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/grid/test-grid-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/grid/test-cache-grid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/grid/test-cache-grid-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/GungumTest.java b/src/test/java/org/prebid/server/it/GungumTest.java index b52adc155ec..01956f2aff5 100644 --- a/src/test/java/org/prebid/server/it/GungumTest.java +++ b/src/test/java/org/prebid/server/it/GungumTest.java @@ -24,17 +24,17 @@ public class GungumTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromGumGum() throws IOException, JSONException { // given // GumGum bid response for imp 001 and 002 - wireMockRule.stubFor(post(urlPathEqualTo("/gumgum-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/gumgum-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/gumgum/test-gumgum-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/gumgum/test-gumgum-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/gumgum/test-cache-gumgum-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/gumgum/test-cache-gumgum-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/ImprovedigitalTest.java b/src/test/java/org/prebid/server/it/ImprovedigitalTest.java index 0f70706ac41..5febb215a5b 100644 --- a/src/test/java/org/prebid/server/it/ImprovedigitalTest.java +++ b/src/test/java/org/prebid/server/it/ImprovedigitalTest.java @@ -24,21 +24,21 @@ public class ImprovedigitalTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromImproveDigital() throws IOException, JSONException { // given // Improvedigital bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/improvedigital-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/improvedigital-exchange")) .withRequestBody(equalToJson( jsonFrom("openrtb2/improvedigital/test-improvedigital-bid-request-1.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/improvedigital/test-improvedigital-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson( jsonFrom("openrtb2/improvedigital/test-cache-improvedigital-request.json"))) .willReturn(aResponse().withBody( jsonFrom("openrtb2/improvedigital/test-cache-improvedigital-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/IntegrationTest.java b/src/test/java/org/prebid/server/it/IntegrationTest.java index 49d64fa74b4..c1dfb1d317d 100644 --- a/src/test/java/org/prebid/server/it/IntegrationTest.java +++ b/src/test/java/org/prebid/server/it/IntegrationTest.java @@ -49,19 +49,19 @@ public abstract class IntegrationTest extends VertxTest { @SuppressWarnings("unchecked") @ClassRule - public static final WireMockClassRule wireMockRule = new WireMockClassRule( + public static final WireMockClassRule WIRE_MOCK_RULE = new WireMockClassRule( options().port(WIREMOCK_PORT).extensions(IntegrationTest.CacheResponseTransformer.class)); @Rule - public WireMockClassRule instanceRule = wireMockRule; + public WireMockClassRule instanceRule = WIRE_MOCK_RULE; - static final RequestSpecification spec = spec(APP_PORT); + static final RequestSpecification SPEC = spec(APP_PORT); @BeforeClass public static void setUp() throws IOException { - wireMockRule.stubFor(get(urlPathEqualTo("/periodic-update")) + WIRE_MOCK_RULE.stubFor(get(urlPathEqualTo("/periodic-update")) .willReturn(aResponse().withBody(jsonFrom("storedrequests/test-periodic-refresh.json")))); - wireMockRule.stubFor(get(urlPathEqualTo("/currency-rates")) + WIRE_MOCK_RULE.stubFor(get(urlPathEqualTo("/currency-rates")) .willReturn(aResponse().withBody(jsonFrom("currency/latest.json")))); } diff --git a/src/test/java/org/prebid/server/it/IxTest.java b/src/test/java/org/prebid/server/it/IxTest.java index 6cd1f4ea7dc..be75ae96fa2 100644 --- a/src/test/java/org/prebid/server/it/IxTest.java +++ b/src/test/java/org/prebid/server/it/IxTest.java @@ -27,22 +27,22 @@ public class IxTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromIx() throws IOException, JSONException { // given // ix bid response for imp 6 - wireMockRule.stubFor(post(urlPathEqualTo("/ix-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/ix-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/ix/test-ix-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/ix/test-ix-bid-response-1.json")))); // ix bid response for imp 61 - wireMockRule.stubFor(post(urlPathEqualTo("/ix-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/ix-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/ix/test-ix-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/ix/test-ix-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/ix/test-cache-ix-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/ix/test-cache-ix-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -64,17 +64,17 @@ public void openrtb2AuctionShouldRespondWithBidsFromIx() throws IOException, JSO public void auctionShouldRespondWithBidsFromIx() throws IOException { // given // ix bid response for ad unit 7 - wireMockRule.stubFor(post(urlPathEqualTo("/ix-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/ix-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/ix/test-ix-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/ix/test-ix-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/ix/test-cache-ix-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/ix/test-cache-ix-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/KubientTest.java b/src/test/java/org/prebid/server/it/KubientTest.java index 233b6e8576d..600bd6b79be 100644 --- a/src/test/java/org/prebid/server/it/KubientTest.java +++ b/src/test/java/org/prebid/server/it/KubientTest.java @@ -24,17 +24,17 @@ public class KubientTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromKubient() throws IOException, JSONException { // given // Kubient bid response for imp 001 and 002 - wireMockRule.stubFor(post(urlPathEqualTo("/kubient-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/kubient-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/kubient/test-kubient-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/kubient/test-kubient-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/kubient/test-cache-kubient-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/kubient/test-cache-kubient-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/LifestreetTest.java b/src/test/java/org/prebid/server/it/LifestreetTest.java index bcb9466db2e..33e85f51cce 100644 --- a/src/test/java/org/prebid/server/it/LifestreetTest.java +++ b/src/test/java/org/prebid/server/it/LifestreetTest.java @@ -27,22 +27,22 @@ public class LifestreetTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromLifestreet() throws IOException, JSONException { // given // lifestreet bid response for imp 7 - wireMockRule.stubFor(post(urlPathEqualTo("/lifestreet-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/lifestreet-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/lifestreet/test-lifestreet-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/lifestreet/test-lifestreet-bid-response-1.json")))); // lifestreet bid response for imp 71 - wireMockRule.stubFor(post(urlPathEqualTo("/lifestreet-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/lifestreet-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/lifestreet/test-lifestreet-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/lifestreet/test-lifestreet-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/lifestreet/test-cache-lifestreet-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/lifestreet/test-cache-lifestreet-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -64,17 +64,17 @@ public void openrtb2AuctionShouldRespondWithBidsFromLifestreet() throws IOExcept public void auctionShouldRespondWithBidsFromLifestreet() throws IOException { // given // lifestreet bid response for ad unit 8 - wireMockRule.stubFor(post(urlPathEqualTo("/lifestreet-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/lifestreet-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/lifestreet/test-lifestreet-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/lifestreet/test-lifestreet-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/lifestreet/test-cache-lifestreet-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/lifestreet/test-cache-lifestreet-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/LockerdomeTest.java b/src/test/java/org/prebid/server/it/LockerdomeTest.java index 74a646b50a7..16575a0458e 100644 --- a/src/test/java/org/prebid/server/it/LockerdomeTest.java +++ b/src/test/java/org/prebid/server/it/LockerdomeTest.java @@ -25,18 +25,18 @@ public class LockerdomeTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromLockerDome() throws IOException, JSONException { // given // LockerDome bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/lockerdome-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/lockerdome-exchange")) .withHeader("x-openrtb-version", equalTo("2.5")) .withRequestBody(equalToJson(jsonFrom("openrtb2/lockerdome/test-lockerdome-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/lockerdome/test-lockerdome-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/lockerdome/test-cache-lockerdome-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/lockerdome/test-cache-lockerdome-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/MarsmediaTest.java b/src/test/java/org/prebid/server/it/MarsmediaTest.java index ad7aa6ed0ff..2cfaa0245ff 100644 --- a/src/test/java/org/prebid/server/it/MarsmediaTest.java +++ b/src/test/java/org/prebid/server/it/MarsmediaTest.java @@ -25,7 +25,7 @@ public class MarsmediaTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromMarsmedia() throws IOException, JSONException { // given // Marsmedia bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/marsmedia-exchange&zone=zone_1")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/marsmedia-exchange&zone=zone_1")) //.withQueryParam("zone", equalTo("zone_1")) .withHeader("x-openrtb-version", equalTo("2.5")) .withHeader("DNT", equalTo("2")) @@ -34,12 +34,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromMarsmedia() throws IOExcepti .willReturn(aResponse().withBody(jsonFrom("openrtb2/marsmedia/test-marsmedia-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/marsmedia/test-cache-marsmedia-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/marsmedia/test-cache-marsmedia-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/MgidTest.java b/src/test/java/org/prebid/server/it/MgidTest.java index a690e8b3458..45258c55dbe 100644 --- a/src/test/java/org/prebid/server/it/MgidTest.java +++ b/src/test/java/org/prebid/server/it/MgidTest.java @@ -23,17 +23,17 @@ public class MgidTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromTheMgid() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/mgid-exchange/123")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/mgid-exchange/123")) .withRequestBody(equalToJson(jsonFrom("openrtb2/mgid/test-mgid-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/mgid/test-mgid-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/mgid/test-cache-mgid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/mgid/test-cache-mgid-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/OpenxTest.java b/src/test/java/org/prebid/server/it/OpenxTest.java index 396f3248d3f..3da4d82290c 100644 --- a/src/test/java/org/prebid/server/it/OpenxTest.java +++ b/src/test/java/org/prebid/server/it/OpenxTest.java @@ -24,29 +24,29 @@ public class OpenxTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromOpenx() throws IOException, JSONException { // given // openx bid response for imp 011 and 02 - wireMockRule.stubFor(post(urlPathEqualTo("/openx-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/openx-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/openx/test-openx-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/openx/test-openx-bid-response-1.json")))); // openx bid response for imp 03 - wireMockRule.stubFor(post(urlPathEqualTo("/openx-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/openx-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/openx/test-openx-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/openx/test-openx-bid-response-2.json")))); // openx bid response for imp 04 - wireMockRule.stubFor(post(urlPathEqualTo("/openx-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/openx-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/openx/test-openx-bid-request-3.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/openx/test-openx-bid-response-3.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/openx/test-cache-openx-request.json"), true, false)) .willReturn(aResponse() .withTransformers("cache-response-transformer") .withTransformerParameter("matcherName", "openrtb2/openx/test-cache-matcher-openx.json") )); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -58,8 +58,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromOpenx() throws IOException, // then final String expectedAuctionResponse = openrtbAuctionResponseFrom( - "openrtb2/openx/test-auction-openx-response.json", - response, singletonList("openx")); + "openrtb2/openx/test-auction-openx-response.json", response, singletonList("openx")); JSONAssert.assertEquals(expectedAuctionResponse, response.asString(), JSONCompareMode.NON_EXTENSIBLE); } diff --git a/src/test/java/org/prebid/server/it/PubmaticTest.java b/src/test/java/org/prebid/server/it/PubmaticTest.java index d55d5b3fcf6..390cffc1da8 100644 --- a/src/test/java/org/prebid/server/it/PubmaticTest.java +++ b/src/test/java/org/prebid/server/it/PubmaticTest.java @@ -27,12 +27,12 @@ public class PubmaticTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromPubmatic() throws IOException, JSONException { // given // pubmatic bid response for imp 9 - wireMockRule.stubFor(post(urlPathEqualTo("/pubmatic-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pubmatic-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pubmatic/test-pubmatic-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pubmatic/test-pubmatic-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pubmatic/test-cache-pubmatic-request.json"), true, false)) .willReturn(aResponse() @@ -41,7 +41,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromPubmatic() throws IOExceptio "openrtb2/pubmatic/test-cache-matcher-pubmatic.json"))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -63,17 +63,17 @@ public void openrtb2AuctionShouldRespondWithBidsFromPubmatic() throws IOExceptio public void auctionShouldRespondWithBidsFromPubmatic() throws IOException { // given // pubmatic bid response for ad unit 9 - wireMockRule.stubFor(post(urlPathEqualTo("/pubmatic-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pubmatic-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/pubmatic/test-pubmatic-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/pubmatic/test-pubmatic-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/pubmatic/test-cache-pubmatic-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/pubmatic/test-cache-pubmatic-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/PubnativeTest.java b/src/test/java/org/prebid/server/it/PubnativeTest.java index b721c6a2fdb..2f1b8a3b1aa 100644 --- a/src/test/java/org/prebid/server/it/PubnativeTest.java +++ b/src/test/java/org/prebid/server/it/PubnativeTest.java @@ -25,33 +25,33 @@ public class PubnativeTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromThePubnative() throws IOException, JSONException { // given // Pubnative bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/pubnative-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pubnative-exchange")) .withQueryParam("zoneid", equalTo("1")) .withQueryParam("apptoken", equalTo("4fd53a12b78af4b39835de9e449c3082")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pubnative/test-pubnative-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pubnative/test-pubnative-bid-response-1.json")))); // Pubnative bid response for imp 002 - wireMockRule.stubFor(post(urlPathEqualTo("/pubnative-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pubnative-exchange")) .withQueryParam("zoneid", equalTo("2")) .withQueryParam("apptoken", equalTo("4fd53a12b78af4b39835de9e449c")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pubnative/test-pubnative-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pubnative/test-pubnative-bid-response-2.json")))); // Pubnative bid response for imp 003 - wireMockRule.stubFor(post(urlPathEqualTo("/pubnative-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pubnative-exchange")) .withQueryParam("zoneid", equalTo("3")) .withQueryParam("apptoken", equalTo("4fd53a12b78af4b39835de9e")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pubnative/test-pubnative-bid-request-3.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pubnative/test-pubnative-bid-response-3.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pubnative/test-cache-pubnative-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pubnative/test-cache-pubnative-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/PulsepointTest.java b/src/test/java/org/prebid/server/it/PulsepointTest.java index 78307554ee0..99baee3c5c6 100644 --- a/src/test/java/org/prebid/server/it/PulsepointTest.java +++ b/src/test/java/org/prebid/server/it/PulsepointTest.java @@ -27,17 +27,17 @@ public class PulsepointTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromPulsepoint() throws IOException, JSONException { // given // pulsepoint bid response for imp 8 - wireMockRule.stubFor(post(urlPathEqualTo("/pulsepoint-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pulsepoint-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pulsepoint/test-pulsepoint-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pulsepoint/test-pulsepoint-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/pulsepoint/test-cache-pulsepoint-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/pulsepoint/test-cache-pulsepoint-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -59,17 +59,17 @@ public void openrtb2AuctionShouldRespondWithBidsFromPulsepoint() throws IOExcept public void auctionShouldRespondWithBidsFromPulsepoint() throws IOException { // given // pulsepoint bid response for ad unit 6 - wireMockRule.stubFor(post(urlPathEqualTo("/pulsepoint-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/pulsepoint-exchange")) .withRequestBody(equalToJson(jsonFrom("auction/pulsepoint/test-pulsepoint-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/pulsepoint/test-pulsepoint-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/pulsepoint/test-cache-pulsepoint-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/pulsepoint/test-cache-pulsepoint-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/RhythmoneTest.java b/src/test/java/org/prebid/server/it/RhythmoneTest.java index d6109cd2de6..e983632ae1e 100644 --- a/src/test/java/org/prebid/server/it/RhythmoneTest.java +++ b/src/test/java/org/prebid/server/it/RhythmoneTest.java @@ -25,19 +25,19 @@ public class RhythmoneTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromRhythmone() throws IOException, JSONException { // given // rhythmone bid response for imp002 - wireMockRule.stubFor(post(urlPathEqualTo("/rhythmone-exchange/72721/0/mvo")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rhythmone-exchange/72721/0/mvo")) .withQueryParam("z", equalTo("1r")) .withQueryParam("s2s", equalTo("true")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rhythmone/test-rhythmone-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/rhythmone/test-rhythmone-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rhythmone/test-cache-rhythmone-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/rhythmone/test-cache-rhythmone-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/RtbhouseTest.java b/src/test/java/org/prebid/server/it/RtbhouseTest.java index 86f75143608..2b90218d1b4 100644 --- a/src/test/java/org/prebid/server/it/RtbhouseTest.java +++ b/src/test/java/org/prebid/server/it/RtbhouseTest.java @@ -23,17 +23,17 @@ public class RtbhouseTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromTheRtbHouse() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/rtbhouse-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/rtbhouse-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rtbhouse/test-rtbhouse-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/rtbhouse/test-rtbhouse-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/rtbhouse/test-cache-rtbhouse-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/rtbhouse/test-cache-rtbhouse-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/SharethroughTest.java b/src/test/java/org/prebid/server/it/SharethroughTest.java index cc23b659400..2c28c82184e 100644 --- a/src/test/java/org/prebid/server/it/SharethroughTest.java +++ b/src/test/java/org/prebid/server/it/SharethroughTest.java @@ -33,7 +33,7 @@ public class SharethroughTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromSharethrough() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/sharethrough-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/sharethrough-exchange")) .withQueryParam("placement_key", equalTo("abc123")) .withQueryParam("bidId", equalTo("bid")) .withQueryParam("consent_required", equalTo("false")) @@ -59,13 +59,13 @@ public void openrtb2AuctionShouldRespondWithBidsFromSharethrough() throws IOExce aResponse().withBody(jsonFrom("openrtb2/sharethrough/test-sharethrough-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/sharethrough/test-cache-sharethrough-request.json"))) .willReturn( aResponse().withBody(jsonFrom("openrtb2/sharethrough/test-cache-sharethrough-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/SmartrtbTest.java b/src/test/java/org/prebid/server/it/SmartrtbTest.java index d2ef9d22301..1c3a29d0b04 100644 --- a/src/test/java/org/prebid/server/it/SmartrtbTest.java +++ b/src/test/java/org/prebid/server/it/SmartrtbTest.java @@ -1,7 +1,6 @@ package org.prebid.server.it; import io.restassured.response.Response; -import java.io.IOException; import org.json.JSONException; import org.junit.Test; import org.junit.runner.RunWith; @@ -9,6 +8,8 @@ import org.skyscreamer.jsonassert.JSONCompareMode; import org.springframework.test.context.junit4.SpringRunner; +import java.io.IOException; + import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; @@ -24,7 +25,7 @@ public class SmartrtbTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromSmartrtb() throws IOException, JSONException { // given // Smartrtb bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/smartrtb-exchange/1234")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/smartrtb-exchange/1234")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) .withHeader("x-openrtb-version", equalTo("2.5")) @@ -32,12 +33,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromSmartrtb() throws IOExceptio .willReturn(aResponse().withBody(jsonFrom("openrtb2/smartrtb/test-smartrtb-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/smartrtb/test-cache-smartrtb-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/smartrtb/test-cache-smartrtb-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -51,9 +52,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromSmartrtb() throws IOExceptio "openrtb2/smartrtb/test-auction-smartrtb-response.json", response, singletonList("smartrtb")); - String actualStr = response.asString(); JSONAssert.assertEquals(expectedAuctionResponse, actualStr, JSONCompareMode.NON_EXTENSIBLE); } } - diff --git a/src/test/java/org/prebid/server/it/SomoaudienceTest.java b/src/test/java/org/prebid/server/it/SomoaudienceTest.java index 0d7b3849d9f..dff938a72df 100644 --- a/src/test/java/org/prebid/server/it/SomoaudienceTest.java +++ b/src/test/java/org/prebid/server/it/SomoaudienceTest.java @@ -25,7 +25,7 @@ public class SomoaudienceTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromSomoaudience() throws IOException, JSONException { // given // somoaudience bid response for imp 16 & 17 - wireMockRule.stubFor(post(urlPathEqualTo("/somoaudience-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/somoaudience-exchange")) .withQueryParam("s", equalTo("placementId02")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) @@ -39,7 +39,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromSomoaudience() throws IOExce "openrtb2/somoaudience/test-somoaudience-bid-response-1.json")))); // somoaudience bid response for imp 18 - wireMockRule.stubFor(post(urlPathEqualTo("/somoaudience-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/somoaudience-exchange")) .withQueryParam("s", equalTo("placementId03")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) @@ -53,7 +53,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromSomoaudience() throws IOExce "openrtb2/somoaudience/test-somoaudience-bid-response-2.json")))); // somoaudience bid response for imp 19 - wireMockRule.stubFor(post(urlPathEqualTo("/somoaudience-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/somoaudience-exchange")) .withQueryParam("s", equalTo("placementId04")) .withHeader("Accept", equalTo("application/json")) .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) @@ -67,7 +67,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromSomoaudience() throws IOExce "openrtb2/somoaudience/test-somoaudience-bid-response-3.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/somoaudience/test-cache-somoaudience-request.json"), true, false)) .willReturn(aResponse() @@ -76,7 +76,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromSomoaudience() throws IOExce "openrtb2/somoaudience/test-cache-matcher-somoaudience.json"))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/SonobiTest.java b/src/test/java/org/prebid/server/it/SonobiTest.java index cef379b6f57..1201c492fde 100644 --- a/src/test/java/org/prebid/server/it/SonobiTest.java +++ b/src/test/java/org/prebid/server/it/SonobiTest.java @@ -24,22 +24,22 @@ public class SonobiTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromSonobi() throws IOException, JSONException { // given // Sonobi bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/sonobi-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/sonobi-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/sonobi/test-sonobi-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/sonobi/test-sonobi-bid-response-1.json")))); // Sonobi bid response for imp 002 - wireMockRule.stubFor(post(urlPathEqualTo("/sonobi-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/sonobi-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/sonobi/test-sonobi-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/sonobi/test-sonobi-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/sonobi/test-cache-sonobi-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/sonobi/test-cache-sonobi-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/SovrnTest.java b/src/test/java/org/prebid/server/it/SovrnTest.java index 925298f7c45..b9b0d11cccc 100644 --- a/src/test/java/org/prebid/server/it/SovrnTest.java +++ b/src/test/java/org/prebid/server/it/SovrnTest.java @@ -29,7 +29,7 @@ public class SovrnTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromSovrn() throws IOException, JSONException { // given // sovrn bid response for imp 13 - wireMockRule.stubFor(post(urlPathEqualTo("/sovrn-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/sovrn-exchange")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=utf-8")) .withHeader("Accept", equalTo("application/json")) .withHeader("User-Agent", equalTo("userAgent")) @@ -41,12 +41,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromSovrn() throws IOException, .willReturn(aResponse().withBody(jsonFrom("openrtb2/sovrn/test-sovrn-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/sovrn/test-cache-sovrn-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/sovrn/test-cache-sovrn-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") @@ -68,7 +68,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromSovrn() throws IOException, public void auctionShouldRespondWithBidsFromSovrn() throws IOException { // given // sovrn bid response for ad unit 11 - wireMockRule.stubFor(post(urlPathEqualTo("/sovrn-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/sovrn-exchange")) .withHeader("Content-Type", equalToIgnoreCase("application/json;charset=utf-8")) .withHeader("Accept", equalTo("application/json")) .withHeader("User-Agent", equalTo("userAgent")) @@ -80,12 +80,12 @@ public void auctionShouldRespondWithBidsFromSovrn() throws IOException { .willReturn(aResponse().withBody(jsonFrom("auction/sovrn/test-sovrn-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("auction/sovrn/test-cache-sovrn-request.json"))) .willReturn(aResponse().withBody(jsonFrom("auction/sovrn/test-cache-sovrn-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/SynacormediaTest.java b/src/test/java/org/prebid/server/it/SynacormediaTest.java index 21f74bdabcb..28d38262843 100644 --- a/src/test/java/org/prebid/server/it/SynacormediaTest.java +++ b/src/test/java/org/prebid/server/it/SynacormediaTest.java @@ -24,17 +24,21 @@ public class SynacormediaTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromSynacorMedia() throws IOException, JSONException { // given // SynacorMedia bid response for imp 001 and imp 002 - wireMockRule.stubFor(post(urlPathEqualTo("/synacormedia-exchange/228")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/synacormedia/test-synacormedia-bid-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/synacormedia/test-synacormedia-bid-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/synacormedia-exchange/228")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/synacormedia/test-synacormedia-bid-request.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/synacormedia/test-synacormedia-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/synacormedia/test-cache-synacormedia-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/synacormedia/test-cache-synacormedia-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/synacormedia/test-cache-synacormedia-request.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/synacormedia/test-cache-synacormedia-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/TappxTest.java b/src/test/java/org/prebid/server/it/TappxTest.java index 66ed07a8cdb..fe12b651953 100644 --- a/src/test/java/org/prebid/server/it/TappxTest.java +++ b/src/test/java/org/prebid/server/it/TappxTest.java @@ -26,7 +26,7 @@ public class TappxTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromTappx() throws IOException, JSONException { // given // tappx bid response for imp 12 - wireMockRule.stubFor(post(urlPathEqualTo("/tappx-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/tappx-exchange")) .withQueryParam("tappxkey", equalTo("pub-12345-android-9876")) .withQueryParam("v", equalTo("1.1")) .withQueryParam("type_cnn", equalTo("prebid")) @@ -36,12 +36,12 @@ public void openrtb2AuctionShouldRespondWithBidsFromTappx() throws IOException, .willReturn(aResponse().withBody(jsonFrom("openrtb2/tappx/test-tappx-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/tappx/test-cache-tappx-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/tappx/test-cache-tappx-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/TripleliftNativeTest.java b/src/test/java/org/prebid/server/it/TripleliftNativeTest.java index ef268c30807..40de0046252 100644 --- a/src/test/java/org/prebid/server/it/TripleliftNativeTest.java +++ b/src/test/java/org/prebid/server/it/TripleliftNativeTest.java @@ -23,17 +23,21 @@ public class TripleliftNativeTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromTriplelift() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/triplelift_native-exchange")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/tripleliftnative/test-triplelift-native-bid-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/tripleliftnative/test-triplelift-native-bid-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/triplelift_native-exchange")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/tripleliftnative/test-triplelift-native-bid-request.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/tripleliftnative/test-triplelift-native-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/tripleliftnative/test-cache-triplelift-native-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/tripleliftnative/test-cache-triplelift-native-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/tripleliftnative/test-cache-triplelift-native-request.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/tripleliftnative/test-cache-triplelift-native-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/TripleliftTest.java b/src/test/java/org/prebid/server/it/TripleliftTest.java index f8a780ad11c..f10a63e3787 100644 --- a/src/test/java/org/prebid/server/it/TripleliftTest.java +++ b/src/test/java/org/prebid/server/it/TripleliftTest.java @@ -23,17 +23,17 @@ public class TripleliftTest extends IntegrationTest { @Test public void openrtb2AuctionShouldRespondWithBidsFromTriplelift() throws IOException, JSONException { // given - wireMockRule.stubFor(post(urlPathEqualTo("/triplelift-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/triplelift-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/triplelift/test-triplelift-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/triplelift/test-triplelift-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/triplelift/test-cache-triplelift-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/triplelift/test-cache-triplelift-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/TtxTest.java b/src/test/java/org/prebid/server/it/TtxTest.java index 2241386f224..a4dbf3754f5 100644 --- a/src/test/java/org/prebid/server/it/TtxTest.java +++ b/src/test/java/org/prebid/server/it/TtxTest.java @@ -24,17 +24,17 @@ public class TtxTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFrom33Across() throws IOException, JSONException { // given // 33Across bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/ttx-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/ttx-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/ttx/test-ttx-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/ttx/test-ttx-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/ttx/test-cache-ttx-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/ttx/test-cache-ttx-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/UnrulyTest.java b/src/test/java/org/prebid/server/it/UnrulyTest.java index 25da30b8d9f..3598d888414 100644 --- a/src/test/java/org/prebid/server/it/UnrulyTest.java +++ b/src/test/java/org/prebid/server/it/UnrulyTest.java @@ -24,22 +24,22 @@ public class UnrulyTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromUnruly() throws IOException, JSONException { // given // Unruly bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/unruly-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/unruly-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/unruly/test-unruly-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/unruly/test-unruly-bid-response-1.json")))); // Unruly bid response for imp 002 - wireMockRule.stubFor(post(urlPathEqualTo("/unruly-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/unruly-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/unruly/test-unruly-bid-request-2.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/unruly/test-unruly-bid-response-2.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/unruly/test-cache-unruly-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/unruly/test-cache-unruly-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/VerizonmediaTest.java b/src/test/java/org/prebid/server/it/VerizonmediaTest.java index 70c1114e75e..70f3ff099ec 100644 --- a/src/test/java/org/prebid/server/it/VerizonmediaTest.java +++ b/src/test/java/org/prebid/server/it/VerizonmediaTest.java @@ -24,17 +24,21 @@ public class VerizonmediaTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromVerizonmedia() throws IOException, JSONException { // given // Verizonmedia bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/verizonmedia-exchange")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/verizonmedia/test-verizonmedia-bid-request-1.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/verizonmedia/test-verizonmedia-bid-response-1.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/verizonmedia-exchange")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/verizonmedia/test-verizonmedia-bid-request-1.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/verizonmedia/test-verizonmedia-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) - .withRequestBody(equalToJson(jsonFrom("openrtb2/verizonmedia/test-cache-verizonmedia-request.json"))) - .willReturn(aResponse().withBody(jsonFrom("openrtb2/verizonmedia/test-cache-verizonmedia-response.json")))); + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) + .withRequestBody(equalToJson( + jsonFrom("openrtb2/verizonmedia/test-cache-verizonmedia-request.json"))) + .willReturn(aResponse().withBody( + jsonFrom("openrtb2/verizonmedia/test-cache-verizonmedia-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/VisxTest.java b/src/test/java/org/prebid/server/it/VisxTest.java index 11ce11b97e6..47e3ab58bdd 100644 --- a/src/test/java/org/prebid/server/it/VisxTest.java +++ b/src/test/java/org/prebid/server/it/VisxTest.java @@ -24,17 +24,17 @@ public class VisxTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromVisx() throws IOException, JSONException { // given // VisxTest bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/visx-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/visx-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/visx/test-visx-bid-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/visx/test-visx-bid-response.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/visx/test-cache-visx-request.json"), true, false)) .willReturn(aResponse().withBody(jsonFrom("openrtb2/visx/test-cache-visx-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/VrtcalTest.java b/src/test/java/org/prebid/server/it/VrtcalTest.java index 3085ce2fabf..c4a2ab8975e 100644 --- a/src/test/java/org/prebid/server/it/VrtcalTest.java +++ b/src/test/java/org/prebid/server/it/VrtcalTest.java @@ -24,17 +24,17 @@ public class VrtcalTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromVrtcal() throws IOException, JSONException { // given // Vrtcal bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/vrtcal-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/vrtcal-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/vrtcal/test-vrtcal-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/vrtcal/test-vrtcal-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/vrtcal/test-cache-vrtcal-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/vrtcal/test-cache-vrtcal-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/YieldmoTest.java b/src/test/java/org/prebid/server/it/YieldmoTest.java index cbb7a6f3bfc..9718ec40452 100644 --- a/src/test/java/org/prebid/server/it/YieldmoTest.java +++ b/src/test/java/org/prebid/server/it/YieldmoTest.java @@ -24,17 +24,17 @@ public class YieldmoTest extends IntegrationTest { public void openrtb2AuctionShouldRespondWithBidsFromYieldmo() throws IOException, JSONException { // given // Yieldmo bid response for imp 001 - wireMockRule.stubFor(post(urlPathEqualTo("/yieldmo-exchange")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/yieldmo-exchange")) .withRequestBody(equalToJson(jsonFrom("openrtb2/yieldmo/test-yieldmo-bid-request-1.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/yieldmo/test-yieldmo-bid-response-1.json")))); // pre-bid cache - wireMockRule.stubFor(post(urlPathEqualTo("/cache")) + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) .withRequestBody(equalToJson(jsonFrom("openrtb2/yieldmo/test-cache-yieldmo-request.json"))) .willReturn(aResponse().withBody(jsonFrom("openrtb2/yieldmo/test-cache-yieldmo-response.json")))); // when - final Response response = given(spec) + final Response response = given(SPEC) .header("Referer", "http://www.example.com") .header("X-Forwarded-For", "193.168.244.1") .header("User-Agent", "userAgent") diff --git a/src/test/java/org/prebid/server/it/YieldoneTest.java b/src/test/java/org/prebid/server/it/YieldoneTest.java new file mode 100644 index 00000000000..bdfcb173938 --- /dev/null +++ b/src/test/java/org/prebid/server/it/YieldoneTest.java @@ -0,0 +1,56 @@ +package org.prebid.server.it; + +import io.restassured.response.Response; +import org.json.JSONException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; +import org.springframework.test.context.junit4.SpringRunner; + +import java.io.IOException; + +import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; +import static com.github.tomakehurst.wiremock.client.WireMock.post; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static io.restassured.RestAssured.given; +import static java.util.Collections.singletonList; + +@RunWith(SpringRunner.class) +public class YieldoneTest extends IntegrationTest { + + @Test + public void openrtb2AuctionShouldRespondWithBidsFromYieldone() throws IOException, JSONException { + // given + // Yieldone bid response for imp 001 + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/yieldone-exchange")) + .withHeader("Accept", equalTo("application/json")) + .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/yieldone/test-yieldone-bid-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/yieldone/test-yieldone-bid-response.json")))); + + // pre-bid cache + WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/cache")) + .withRequestBody(equalToJson(jsonFrom("openrtb2/yieldone/test-cache-yieldone-request.json"))) + .willReturn(aResponse().withBody(jsonFrom("openrtb2/yieldone/test-cache-yieldone-response.json")))); + + // when + final Response response = given(SPEC) + .header("Referer", "http://www.example.com") + .header("X-Forwarded-For", "193.168.244.1") + .header("User-Agent", "userAgent") + .header("Origin", "http://www.example.com") + .cookie("uids", "eyJ1aWRzIjp7InlpZWxkb25lIjoiWUQtVUlEIn19") + .body(jsonFrom("openrtb2/yieldone/test-auction-yieldone-request.json")) + .post("/openrtb2/auction"); + + // then + final String expectedAuctionResponse = openrtbAuctionResponseFrom( + "openrtb2/yieldone/test-auction-yieldone-response.json", + response, singletonList("yieldone")); + + JSONAssert.assertEquals(expectedAuctionResponse, response.asString(), JSONCompareMode.NON_EXTENSIBLE); + } +} diff --git a/src/test/java/org/prebid/server/json/ZonedDateTimeModuleTest.java b/src/test/java/org/prebid/server/json/ZonedDateTimeModuleTest.java index ebde5babcbd..7cf0cbaa1fd 100644 --- a/src/test/java/org/prebid/server/json/ZonedDateTimeModuleTest.java +++ b/src/test/java/org/prebid/server/json/ZonedDateTimeModuleTest.java @@ -19,8 +19,8 @@ public class ZonedDateTimeModuleTest { @Test public void shouldEncodeSuccessfully() throws IOException { // given - final ZonedDateTime VALUE = ZonedDateTime.of(2017, 12, 10, 15, 45, 55, 237018349, ZoneOffset.UTC); - final Model model = new Model(VALUE); + final ZonedDateTime value = ZonedDateTime.of(2017, 12, 10, 15, 45, 55, 237018349, ZoneOffset.UTC); + final Model model = new Model(value); // when final String modelAsString = MAPPER.writeValueAsString(model); @@ -32,8 +32,8 @@ public void shouldEncodeSuccessfully() throws IOException { @Test public void shouldEncodeVariableNumberOfNanos() throws IOException { // given - final ZonedDateTime VALUE = ZonedDateTime.of(2017, 12, 10, 15, 45, 55, 237018000, ZoneOffset.UTC); - final Model model = new Model(VALUE); + final ZonedDateTime value = ZonedDateTime.of(2017, 12, 10, 15, 45, 55, 237018000, ZoneOffset.UTC); + final Model model = new Model(value); // when final String modelAsString = MAPPER.writeValueAsString(model); diff --git a/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java b/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java index e7f6c100505..943cf54f87f 100644 --- a/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java +++ b/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java @@ -1,17 +1,26 @@ package org.prebid.server.log; +import io.vertx.core.Vertx; import io.vertx.core.logging.Logger; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import static org.mockito.ArgumentMatchers.any; +import java.util.concurrent.TimeUnit; + +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +@RunWith(VertxUnitRunner.class) public class ConditionalLoggerTest { @Rule @@ -20,20 +29,76 @@ public class ConditionalLoggerTest { @Mock private Logger logger; + private Vertx vertx; + private ConditionalLogger conditionalLogger; @Before - public void setUp() throws Exception { + public void setUp() { + vertx = Vertx.vertx(); conditionalLogger = new ConditionalLogger(logger); } + @After + public void tearDown(TestContext context) { + vertx.close(context.asyncAssertSuccess()); + } + + @Test + public void infoShouldCallLoggerWithExpectedCount() { + // when + for (int i = 0; i < 10; i++) { + conditionalLogger.info("Log Message", 2); + } + + // then + verify(logger, times(5)).info("Log Message"); + } + + @Test + public void infoShouldCallLoggerBySpecifiedKeyWithExpectedCount() { + // given + conditionalLogger = new ConditionalLogger("key1", logger); + + // when + for (int i = 0; i < 10; i++) { + conditionalLogger.info("Log Message" + i, 2); + } + + // then + verify(logger, times(5)).info(argThat(o -> o.toString().startsWith("Log Message"))); + } + @Test - public void log() { + public void infoShouldCallLoggerWithExpectedTimeout(TestContext context) { // when - for (int i = 0; i < 100; i++) { - conditionalLogger.info("Hello", 20); + for (int i = 0; i < 5; i++) { + conditionalLogger.info("Log Message", 200, TimeUnit.MILLISECONDS); + doWait(context, 100); } + // then - verify(logger, times(5)).info(any()); + verify(logger, times(2)).info("Log Message"); + } + + @Test + public void infoShouldCallLoggerBySpecifiedKeyWithExpectedTimeout(TestContext context) { + // given + conditionalLogger = new ConditionalLogger("key1", logger); + + // when + for (int i = 0; i < 5; i++) { + conditionalLogger.info("Log Message" + i, 200, TimeUnit.MILLISECONDS); + doWait(context, 100); + } + + // then + verify(logger, times(2)).info(argThat(o -> o.toString().startsWith("Log Message"))); + } + + private void doWait(TestContext context, long timeout) { + final Async async = context.async(); + vertx.setTimer(timeout, id -> async.complete()); + async.await(); } } diff --git a/src/test/java/org/prebid/server/manager/AdminManagerTest.java b/src/test/java/org/prebid/server/manager/AdminManagerTest.java new file mode 100644 index 00000000000..354e57d84e3 --- /dev/null +++ b/src/test/java/org/prebid/server/manager/AdminManagerTest.java @@ -0,0 +1,92 @@ +package org.prebid.server.manager; + +import io.vertx.core.logging.Logger; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.function.BiConsumer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +public class AdminManagerTest { + + private static final String KEY = "key"; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private AdminManager adminManager; + + @Mock + Logger logger; + + @Before + public void setUp() { + adminManager = new AdminManager(); + } + + @Test + public void shouldExecuteFixedAmountOfTimes() { + // given + adminManager.setupByCounter(KEY, 20, (BiConsumer) Logger::info, + (BiConsumer) (logger, text) -> logger.info(String.format("Done %s", text))); + + // when + for (int i = 0; i < 30; i++) { + adminManager.accept(KEY, logger, "Text"); + } + + // then + verify(logger, times(20)).info("Text"); + verify(logger, times(10)).info("Done Text"); + } + + @Test + public void shouldReturnTrueIfAdminManagerContainsKey() { + // given + adminManager.setupByCounter(KEY, 20, (BiConsumer) Logger::info, + (BiConsumer) (logger, text) -> logger.info(String.format("Done %s", text))); + + // when + boolean contains = adminManager.contains(KEY); + + // then + assertThat(contains).isTrue(); + } + + @Test + public void shouldReturnFalseIfKeyIsMissing() { + // given + adminManager.setupByCounter(KEY, 20, (BiConsumer) Logger::info, + (BiConsumer) (logger, text) -> logger.info(String.format("Done %s", text))); + + // when + boolean contains = adminManager.contains("WrongKey"); + + // then + assertThat(contains).isFalse(); + } + + @Test + public void shouldExecuteByTime() throws InterruptedException { + // given + adminManager.setupByTime(KEY, 1000, (BiConsumer) Logger::info, + (BiConsumer) (logger, text) -> logger.info(String.format("Done %s", text))); + + // when + for (int i = 0; i < 15; i++) { + adminManager.accept(KEY, logger, "Text"); + Thread.sleep(100); + } + + // then + verify(logger, times(10)).info("Text"); + verify(logger, times(5)).info("Done Text"); + } +} diff --git a/src/test/java/org/prebid/server/metric/AccountMetricsVerbosityTest.java b/src/test/java/org/prebid/server/metric/AccountMetricsVerbosityTest.java index ba65f4aed65..1f9327ce633 100644 --- a/src/test/java/org/prebid/server/metric/AccountMetricsVerbosityTest.java +++ b/src/test/java/org/prebid/server/metric/AccountMetricsVerbosityTest.java @@ -31,4 +31,4 @@ public void forAccountShouldReturnDetailedLevel() { public void forAccountShouldReturnDefaultLevel() { assertThat(verbosity.forAccount("3")).isEqualTo(AccountMetricsVerbosityLevel.none); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/metric/MetricsTest.java b/src/test/java/org/prebid/server/metric/MetricsTest.java index 302310ac0d7..78609ab811a 100644 --- a/src/test/java/org/prebid/server/metric/MetricsTest.java +++ b/src/test/java/org/prebid/server/metric/MetricsTest.java @@ -107,22 +107,22 @@ public void forAdapterShouldReturnAdapterMetricsConfiguredWithAdapterType() { @Test public void shouldReturnSameAdapterRequestTypeMetricsOnSuccessiveCalls() { - assertThat(metrics.forAdapter(RUBICON).requestType()) - .isSameAs(metrics.forAdapter(RUBICON).requestType()); + assertThat(metrics.forAdapter(RUBICON).requestType(MetricName.amp)) + .isSameAs(metrics.forAdapter(RUBICON).requestType(MetricName.amp)); } @Test public void shouldReturnAdapterRequestTypeMetricsConfiguredWithCounterType() { verifyCreatesConfiguredCounterType(metrics -> metrics .forAdapter(RUBICON) - .requestType() - .incCounter(MetricName.openrtb2app)); + .requestType(MetricName.openrtb2app) + .incCounter(MetricName.requests)); } @Test public void shouldReturnAdapterRequestTypeMetricsConfiguredWithAdapterType() { // when - metrics.forAdapter(RUBICON).requestType().incCounter(MetricName.openrtb2web); + metrics.forAdapter(RUBICON).requestType(MetricName.openrtb2web).incCounter(MetricName.requests); // then assertThat(metricRegistry.counter("adapter.rubicon.requests.type.openrtb2-web").getCount()).isEqualTo(1); @@ -200,22 +200,22 @@ public void shouldReturnAccountAdapterRequestMetricsConfiguredWithAccountAndAdap @Test public void shouldReturnSameAccountRequestTypeMetricsOnSuccessiveCalls() { - assertThat(metrics.forAccount(ACCOUNT_ID).requestType()) - .isSameAs(metrics.forAccount(ACCOUNT_ID).requestType()); + assertThat(metrics.forAccount(ACCOUNT_ID).requestType(MetricName.amp)) + .isSameAs(metrics.forAccount(ACCOUNT_ID).requestType(MetricName.amp)); } @Test public void shouldReturnAccountRequestTypeMetricsConfiguredWithCounterType() { verifyCreatesConfiguredCounterType(metrics -> metrics .forAccount(ACCOUNT_ID) - .requestType() - .incCounter(MetricName.openrtb2app)); + .requestType(MetricName.openrtb2app) + .incCounter(MetricName.requests)); } @Test public void shouldReturnAccountRequestTypeMetricsConfiguredWithAccount() { // when - metrics.forAccount(ACCOUNT_ID).requestType().incCounter(MetricName.openrtb2web); + metrics.forAccount(ACCOUNT_ID).requestType(MetricName.openrtb2web).incCounter(MetricName.requests); // then assertThat(metricRegistry.counter("account.accountId.requests.type.openrtb2-web").getCount()).isEqualTo(1); @@ -591,28 +591,28 @@ public void updateUserSyncSetsMetricShouldIncrementMetric() { } @Test - public void updateUserSyncGdprPreventMetricShouldIncrementMetric() { + public void updateUserSyncTcfBlockedMetricShouldIncrementMetric() { // when - metrics.updateUserSyncGdprPreventMetric(RUBICON); + metrics.updateUserSyncTcfBlockedMetric(RUBICON); // then - assertThat(metricRegistry.counter("usersync.rubicon.gdpr_prevent").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("usersync.rubicon.tcf.blocked").getCount()).isEqualTo(1); } @Test - public void updateCookieSyncGdprPreventMetricShouldIncrementMetric() { + public void updateCookieSyncTcfBlockedMetricShouldIncrementMetric() { // given given(bidderCatalog.isValidName(INVALID_BIDDER)).willReturn(false); given(bidderCatalog.nameByAlias(INVALID_BIDDER)).willReturn(RUBICON, null); // when - metrics.updateCookieSyncGdprPreventMetric(RUBICON); - metrics.updateCookieSyncGdprPreventMetric(INVALID_BIDDER); - metrics.updateCookieSyncGdprPreventMetric(INVALID_BIDDER); + metrics.updateCookieSyncTcfBlockedMetric(RUBICON); + metrics.updateCookieSyncTcfBlockedMetric(INVALID_BIDDER); + metrics.updateCookieSyncTcfBlockedMetric(INVALID_BIDDER); // then - assertThat(metricRegistry.counter("cookie_sync.rubicon.gdpr_prevent").getCount()).isEqualTo(2); - assertThat(metricRegistry.counter("cookie_sync.UNKNOWN.gdpr_prevent").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("cookie_sync.rubicon.tcf.blocked").getCount()).isEqualTo(2); + assertThat(metricRegistry.counter("cookie_sync.UNKNOWN.tcf.blocked").getCount()).isEqualTo(1); } @Test @@ -634,12 +634,66 @@ public void updateCookieSyncMatchesMetricShouldIncrementMetric() { } @Test - public void updateGdprMaskedMetricShouldIncrementMetric() { + public void updateAuctionTcfMetricShouldIncrementMetrics() { // when - metrics.updateGdprMaskedMetric(RUBICON); + metrics.updateAuctionTcfMetrics(RUBICON, MetricName.openrtb2web, true, true, true, true); // then - assertThat(metricRegistry.counter("adapter.rubicon.gdpr_masked").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("adapter.rubicon.openrtb2-web.tcf.userid_removed").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("adapter.rubicon.openrtb2-web.tcf.geo_masked").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("adapter.rubicon.openrtb2-web.tcf.request_blocked").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("adapter.rubicon.openrtb2-web.tcf.analytics_blocked").getCount()) + .isEqualTo(1); + } + + @Test + public void updatePrivacyCoppaMetricShouldIncrementMetric() { + // when + metrics.updatePrivacyCoppaMetric(); + + // then + assertThat(metricRegistry.counter("privacy.coppa").getCount()).isEqualTo(1); + } + + @Test + public void updatePrivacyLmtMetricShouldIncrementMetric() { + // when + metrics.updatePrivacyLmtMetric(); + + // then + assertThat(metricRegistry.counter("privacy.lmt").getCount()).isEqualTo(1); + } + + @Test + public void updatePrivacyCcpaMetricsShouldIncrementMetrics() { + // when + metrics.updatePrivacyCcpaMetrics(true, true); + + // then + assertThat(metricRegistry.counter("privacy.usp.specified").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("privacy.usp.opt-out").getCount()).isEqualTo(1); + } + + @Test + public void updatePrivacyTcfInvalidMetricShouldIncrementMetric() { + // when + metrics.updatePrivacyTcfInvalidMetric(); + + // then + assertThat(metricRegistry.counter("privacy.tcf.invalid").getCount()).isEqualTo(1); + } + + @Test + public void updatePrivacyTcfGeoMetricShouldIncrementMetrics() { + // when + metrics.updatePrivacyTcfGeoMetric(1, null); + metrics.updatePrivacyTcfGeoMetric(2, true); + metrics.updatePrivacyTcfGeoMetric(2, false); + + // then + assertThat(metricRegistry.counter("privacy.tcf.v1.unknown-geo").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("privacy.tcf.v2.in-geo").getCount()).isEqualTo(1); + assertThat(metricRegistry.counter("privacy.tcf.v2.out-geo").getCount()).isEqualTo(1); } @Test @@ -855,7 +909,6 @@ private void verifyCreatesConfiguredCounterType(Consumer metricsConsume for (CounterType counterType : CounterType.values()) { // given - metricRegistry = new MetricRegistry(); // when diff --git a/src/test/java/org/prebid/server/metric/model/AccountMetricsVerbosityLevelTest.java b/src/test/java/org/prebid/server/metric/model/AccountMetricsVerbosityLevelTest.java index 736f5a2d4e9..bfad7f41972 100644 --- a/src/test/java/org/prebid/server/metric/model/AccountMetricsVerbosityLevelTest.java +++ b/src/test/java/org/prebid/server/metric/model/AccountMetricsVerbosityLevelTest.java @@ -19,4 +19,4 @@ public void isAtLeastShouldReturnTrue() { assertThat(AccountMetricsVerbosityLevel.detailed.isAtLeast(AccountMetricsVerbosityLevel.basic)).isTrue(); assertThat(AccountMetricsVerbosityLevel.detailed.isAtLeast(AccountMetricsVerbosityLevel.detailed)).isTrue(); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/model/UidWithExpiryTest.java b/src/test/java/org/prebid/server/model/UidWithExpiryTest.java index 2d479d25c5e..b9ecb47b1d8 100644 --- a/src/test/java/org/prebid/server/model/UidWithExpiryTest.java +++ b/src/test/java/org/prebid/server/model/UidWithExpiryTest.java @@ -9,7 +9,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.within; - public class UidWithExpiryTest { @Test diff --git a/src/test/java/org/prebid/server/privacy/ccpa/CcpaTest.java b/src/test/java/org/prebid/server/privacy/ccpa/CcpaTest.java index 12cd8e086d4..edfc70e39d9 100644 --- a/src/test/java/org/prebid/server/privacy/ccpa/CcpaTest.java +++ b/src/test/java/org/prebid/server/privacy/ccpa/CcpaTest.java @@ -92,4 +92,4 @@ public void validateUsPrivacyShouldThrowPrebidExceptionWhenServiceProviderAgreem .isInstanceOf(PreBidException.class) .hasMessage("us_privacy must specify 'N', 'Y', or '-' for the limited service provider agreement"); } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/GdprServiceTest.java b/src/test/java/org/prebid/server/privacy/gdpr/GdprServiceTest.java index 081d57ca098..ce3461b1471 100644 --- a/src/test/java/org/prebid/server/privacy/gdpr/GdprServiceTest.java +++ b/src/test/java/org/prebid/server/privacy/gdpr/GdprServiceTest.java @@ -8,29 +8,19 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.VertxTest; -import org.prebid.server.geolocation.GeoLocationService; -import org.prebid.server.geolocation.model.GeoInfo; -import org.prebid.server.metric.Metrics; -import org.prebid.server.privacy.gdpr.model.GdprPurpose; -import org.prebid.server.privacy.gdpr.model.GdprResponse; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; import org.prebid.server.privacy.gdpr.vendorlist.VendorListService; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV1; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV1; -import java.util.Arrays; -import java.util.HashSet; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptySet; +import static java.util.Collections.emptyMap; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.BDDMockito.given; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; +import static org.prebid.server.assertion.FutureAssertion.assertThat; public class GdprServiceTest extends VertxTest { @@ -38,326 +28,137 @@ public class GdprServiceTest extends VertxTest { public final MockitoRule mockitoRule = MockitoJUnit.rule(); @Mock - private GeoLocationService geoLocationService; - @Mock - private Metrics metrics; - @Mock - private VendorListService vendorListService; + private VendorListService vendorListService; private GdprService gdprService; @Before public void setUp() { - given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( - singletonMap(1, singleton(GdprPurpose.informationStorageAndAccess.getId())))); - given(geoLocationService.lookup(anyString(), any())) - .willReturn(Future.succeededFuture(GeoInfo.builder().vendor("vendor").country("country1").build())); - - gdprService = new GdprService(emptyList(), "1", null, metrics, vendorListService); + gdprService = new GdprService(vendorListService); } @Test - public void isGdprEnforcedShouldConsiderRequestValue() { - // when - final boolean result = gdprService.isGdprEnforced("1", null, emptySet()); - - // then - assertTrue(result); - } - - @Test - public void isGdprEnforcedShouldConsiderAccountConfigValue() { - // when - final boolean result = gdprService.isGdprEnforced(null, true, emptySet()); - - // then - assertTrue(result); + public void shouldReturnAllDeniedWhenNoConsentParam() { + assertThat(gdprService.resultFor(singleton(1), null)) + .succeededWith(singletonList(VendorPermission.of(1, null, denyAll()))); } @Test - public void isGdprEnforcedShouldConsiderGdprEnforcedVendorsIfIsGdprEnforcedIsNull() { - // when - final boolean result = gdprService.isGdprEnforced(null, null, singleton(1)); - - // then - assertTrue(result); + public void shouldReturnAllDeniedWhenConsentParamIsInvalid() { + assertThat(gdprService.resultFor(singleton(1), "invalid-consent")) + .succeededWith(singletonList(VendorPermission.of(1, null, denyAll()))); } @Test - public void shouldReturnGdprFromGeoLocationServiceIfGdprFromRequestIsNotValidAndUpdateMetrics() { + public void shouldReturnAllDeniedWhenVendorIsNotAllowed() { // given - gdprService = new GdprService( - singletonList("country1"), "1", geoLocationService, metrics, vendorListService); - - // when - final Future future = gdprService.resultByVendor(singleton(GdprPurpose.informationStorageAndAccess), - singleton(1), "15", null, "ip", null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, false), "country1")); - - verify(metrics).updateGeoLocationMetric(true); - } - - @Test - public void shouldReturnSuccessResultIfGdprParamIsZero() { - // when - final Future future = gdprService.resultByVendor(emptySet(), singleton(1), "0", null, null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(false, singletonMap(1, true), null)); - } - - @Test - public void shouldReturnFalseForAllVendorIdsIfGdprParamIsOneAndNoConsentParam() { - // when - final Future future = gdprService.resultByVendor(emptySet(), singleton(1), "1", null, null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, false), null)); - } - - @Test - public void shouldReturnTrueForAllVendorIdsIfGdprParamIsZeroAndNoConsentParam() { - // when - final Future future = gdprService.resultByVendor(emptySet(), singleton(1), "0", null, null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(false, singletonMap(1, true), null)); - } - - @Test - public void shouldReturnFalseForAllVendorIdsIfGdprIsOneButConsentParamIsInvalid() { - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(1), "1", "invalid-consent", null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, false), null)); - } - - @Test - public void shouldReturnTrueForAllVendorIdsIfGdprIsZeroButConsentParamIsInvalid() { - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(1), "0", "invalid-consent", null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(false, singletonMap(1, true), null)); - } - - @Test - public void shouldReturnRestrictedResultIfPurposeIsNotAllowed() { - // when - final Future future = - gdprService.resultByVendor(singleton(GdprPurpose.adSelectionAndDeliveryAndReporting), singleton(1), "1", - "BN5lERiOMYEdiAKAWXEND1HoSBE6CAFAApAMgBkIDIgM0AgOJxAnQA", null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, false), null)); - } + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture(emptyMap())); - @Test - public void shouldReturnRestrictedResultIfVendorIdIsNull() { - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(null), "1", "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", - null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(null, false), null)); - } - - @Test - public void shouldReturnRestrictedResultIfVendorIdIsNotAllowed() { - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(9), "1", "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", null, - null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(9, false), null)); - } - - @Test - public void shouldReturnRestrictedResultIfVendorIdIsAbsentInVendorConsent() { - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(20), "1", "BOb3F3yOb3F3yABABBENABoAAAABQAAAgA", null, - null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(20, false), null)); + // when and then + assertThat(gdprService.resultFor(singleton(9), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(9, null, denyAll()))); } @Test - public void shouldReturnAllowedResultIfGdprParamIsOneAndConsentParamIsValid() { - // when - final Future future = - gdprService.resultByVendor(singleton(GdprPurpose.informationStorageAndAccess), singleton(1), "1", - "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, true), null)); - } - - @Test - public void shouldReturnAllowedResultIfNoGdprParamAndCountryIsNotFoundButDefaultGdprIsZeroAndUpdateMetrics() { + public void shouldReturnAllDeniedWhenVendorIsNotInVendorList() { // given - given(geoLocationService.lookup(anyString(), any())).willReturn(Future.failedFuture("country not found")); - gdprService = new GdprService(emptyList(), "0", geoLocationService, metrics, vendorListService); - - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(1), null, null, "ip", null); + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture(emptyMap())); - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(false, singletonMap(1, true), null)); - - verify(metrics).updateGeoLocationMetric(false); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(1, null, denyAll()))); } @Test - public void shouldReturnAllowedResultIfNoGdprParamAndCountryIsNotInEEA() { + public void shouldReturnAllDeniedWhenAllClaimedPurposesAreNotAllowed() { // given - gdprService = new GdprService(emptyList(), "1", geoLocationService, metrics, vendorListService); - - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(1), null, null, "ip", null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(false, singletonMap(1, true), "country1")); + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( + singletonMap(1, VendorV1.of(1, singleton(4), singleton(5))))); - verify(metrics).updateGeoLocationMetric(true); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(1, null, denyAll()))); } @Test - public void shouldReturnAllowedResultIfNoPurposesProvided() { + public void shouldReturnPrivateInfoAllowedUserSyncDeniedWhenAllClaimedPurposesAreAllowed() { // given given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( - singletonMap(1, new HashSet<>(Arrays.asList(1, 2, 3))))); - - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(1), "1", - "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", null, null); + singletonMap(1, VendorV1.of(1, singleton(2), singleton(3))))); - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, true), null)); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(1, null, action(true, false)))); } @Test - public void shouldReturnAllowedResultIfNoGdprParamAndConsentParamIsValidAndCountryIsInEEA() { + public void shouldReturnAllAllowedWhenAllClaimedPurposesAreAllowedIncludingPurposeOne() { // given - gdprService = new GdprService( - singletonList("country1"), "1", geoLocationService, metrics, vendorListService); - - // when - final Future future = - gdprService.resultByVendor(singleton(GdprPurpose.informationStorageAndAccess), singleton(1), null, - "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", "ip", null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, true), "country1")); + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( + singletonMap(1, VendorV1.of(1, singleton(1), singleton(2))))); - verify(metrics).updateGeoLocationMetric(true); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(1, null, action(true, true)))); } @Test - public void shouldReturnAllowedResultIfNoGdprParamAndNoIpButGdprDefaultValueIsZero() { + public void shouldReturnPrivateInfoDeniedUserSyncAllowedWhenNotAllClaimedPurposesAreAllowedButPurposeOneIs() { // given - gdprService = new GdprService(emptyList(), "0", null, metrics, vendorListService); - - // when - final Future future = - gdprService.resultByVendor(emptySet(), singleton(1), null, null, null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(false, singletonMap(1, true), null)); - } - - @Test - public void shouldNotCallGeoLocationServiceIfValidGdprAndIpAddressAreInRequest() { - // when - final Future future = - gdprService.resultByVendor(singleton(GdprPurpose.informationStorageAndAccess), singleton(1), "1", - null, "ip", null); + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( + singletonMap(1, VendorV1.of(1, singleton(1), singleton(4))))); - // then - assertThat(future.succeeded()).isTrue(); - verifyZeroInteractions(geoLocationService); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(1, null, action(false, true)))); } @Test - public void shouldReturnFailedFutureIfGdprSdkCantGetAllowedPurposesInAReasonOfInvalidConsentString() { - // when - final Future future = - gdprService.resultByVendor(singleton(GdprPurpose.informationStorageAndAccess), singleton(1), "1", - "BONciguONcjGKADACHENAOLS1r", null, null); + public void shouldReturnUserSyncDeniedWhenPurposeOneIsAllowedButNotClaimed() { + // given + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( + singletonMap(1, VendorV1.of(1, singleton(2), singleton(3))))); - // then - assertThat(future.failed()).isTrue(); - assertThat(future.cause().getMessage()) - .isEqualTo("Error when retrieving allowed purpose ids in a reason of invalid consent string"); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA")) + .succeededWith(singletonList(VendorPermission.of(1, null, action(true, false)))); } @Test - public void shouldReturnFailedFutureIfGdprSdkCantCheckIfVendorAllowedInAReasonOfInvalidConsentString() { - // when - final Future future = - gdprService.resultByVendor(singleton(GdprPurpose.informationStorageAndAccess), singleton(1), "1", - "BOSbaBZOSbaBoABABBENBcoAAAAgSABgBAA", null, null); + public void shouldReturnFailedFutureWhenGettingAllowedPurposesFails() { + // given + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture(emptyMap())); - // then - assertThat(future.failed()).isTrue(); - assertThat(future.cause().getMessage()) - .isEqualTo("Error when checking if vendor is allowed in a reason of invalid consent string"); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BONciguONcjGKADACHENAOLS1r")) + .isFailed() + .hasMessage("Error when retrieving allowed purpose ids in a reason of invalid consent string"); } @Test - public void shouldReturnRestrictedResultIfGdprParamIsOneAndConsentHasNotAllVendorPurposes() { + public void shouldReturnFailedFutureWhenGettingIfVendorAllowedFails() { // given - given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( - singletonMap(1, new HashSet<>(Arrays.asList(1, 2, 3, 4))))); + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture(emptyMap())); - // when - final Future future = - gdprService.resultByVendor(singleton(1), "1", "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", null, null); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, false), null)); + // when and then + assertThat(gdprService.resultFor(singleton(1), "BOSbaBZOSbaBoABABBENBcoAAAAgSABgBAA")) + .isFailed() + .hasMessage("Error when checking if vendor is allowed in a reason of invalid consent string"); } - @Test - public void shouldReturnAllowedResultIfGdprParamIsOneAndConsentHasAllVendorPurposes() { - // given - given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture( - singletonMap(1, new HashSet<>(Arrays.asList(1, 2, 3))))); - - // when - final Future future = - gdprService.resultByVendor(singleton(1), "1", "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", null, null); + private static PrivacyEnforcementAction denyAll() { + return action(false, false); + } - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo(GdprResponse.of(true, singletonMap(1, true), null)); + private static PrivacyEnforcementAction action(boolean allowPrivateInfo, boolean allowUserSync) { + return PrivacyEnforcementAction.builder() + .removeUserIds(!allowPrivateInfo) + .maskGeo(!allowPrivateInfo) + .maskDeviceIp(!allowPrivateInfo) + .maskDeviceInfo(!allowPrivateInfo) + .blockAnalyticsReport(false) + .blockBidderRequest(false) + .blockPixelSync(!allowUserSync) + .build(); } } diff --git a/src/test/java/org/prebid/server/privacy/gdpr/Tcf2ServiceTest.java b/src/test/java/org/prebid/server/privacy/gdpr/Tcf2ServiceTest.java new file mode 100644 index 00000000000..478a1d29d60 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/Tcf2ServiceTest.java @@ -0,0 +1,427 @@ +package org.prebid.server.privacy.gdpr; + +import com.iabtcf.decoder.TCString; +import io.vertx.core.Future; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.internal.util.reflection.FieldSetter; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.PurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature.SpecialFeaturesStrategy; +import org.prebid.server.privacy.gdpr.vendorlist.VendorListServiceV2; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.settings.model.AccountGdprConfig; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.GdprConfig; +import org.prebid.server.settings.model.Purpose; +import org.prebid.server.settings.model.PurposeOneTreatmentInterpretation; +import org.prebid.server.settings.model.Purposes; +import org.prebid.server.settings.model.SpecialFeature; +import org.prebid.server.settings.model.SpecialFeatures; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyCollection; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.prebid.server.assertion.FutureAssertion.assertThat; + +public class Tcf2ServiceTest extends VertxTest { + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private BidderCatalog bidderCatalog; + @Mock + private VendorListServiceV2 vendorListService; + @Mock + private PurposeStrategy purposeStrategyOne; + @Mock + private PurposeStrategy purposeStrategyTwo; + @Mock + private PurposeStrategy purposeStrategyFour; + @Mock + private PurposeStrategy purposeStrategySeven; + @Mock + private SpecialFeaturesStrategy specialFeaturesStrategyOne; + @Mock + private TCString tcString; + + private Tcf2Service target; + + private Purposes purposes; + + private Purpose purpose1; + private Purpose purpose2; + private Purpose purpose4; + private Purpose purpose7; + + private SpecialFeature specialFeature1; + private SpecialFeatures specialFeatures; + + private GdprConfig gdprConfig; + + private List purposeStrategies; + private List specialFeaturesStrategies; + + @Before + public void setUp() throws NoSuchFieldException { + given(tcString.getVendorListVersion()).willReturn(10); + given(purposeStrategyOne.getPurposeId()).willReturn(1); + given(purposeStrategyTwo.getPurposeId()).willReturn(2); + given(purposeStrategyFour.getPurposeId()).willReturn(4); + given(purposeStrategySeven.getPurposeId()).willReturn(7); + purposeStrategies = asList(purposeStrategyOne, purposeStrategyTwo, purposeStrategyFour, purposeStrategySeven); + + given(specialFeaturesStrategyOne.getSpecialFeatureId()).willReturn(1); + specialFeaturesStrategies = singletonList(specialFeaturesStrategyOne); + + given(vendorListService.forVersion(anyInt())).willReturn(Future.succeededFuture(emptyMap())); + + initPurposes(); + initSpecialFeatures(); + initGdpr(); + target = new Tcf2Service(gdprConfig, vendorListService, bidderCatalog); + + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedPurposeStrategies"), purposeStrategies); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedSpecialFeatureStrategies"), specialFeaturesStrategies); + } + + private void initPurposes() { + purpose1 = Purpose.of(EnforcePurpose.basic, true, emptyList()); + purpose2 = Purpose.of(EnforcePurpose.no, true, emptyList()); + purpose4 = Purpose.of(EnforcePurpose.no, false, emptyList()); + purpose7 = Purpose.of(EnforcePurpose.full, false, emptyList()); + purposes = Purposes.builder() + .p1(purpose1) + .p2(purpose2) + .p4(purpose4) + .p7(purpose7) + .build(); + } + + private void initSpecialFeatures() { + specialFeature1 = SpecialFeature.of(true, emptyList()); + specialFeatures = SpecialFeatures.builder() + .sf1(specialFeature1) + .build(); + } + + private void initGdpr() { + gdprConfig = GdprConfig.builder() + .defaultValue("1") + .enabled(true) + .purposes(purposes) + .specialFeatures(specialFeatures) + .purposeOneTreatmentInterpretation(PurposeOneTreatmentInterpretation.ignore) + .build(); + } + + @Test + public void permissionsForShouldReturnByGdprPurpose() { + // given + given(bidderCatalog.nameByVendorId(any())).willReturn("rubicon"); + + // when + final Future> result = target.permissionsFor(singleton(1), tcString); + + // then + final VendorPermission expectedVendorPermission = + VendorPermission.of(1, "rubicon", PrivacyEnforcementAction.restrictAll()); + + assertThat(result).succeededWith(singletonList(expectedVendorPermission)); + + final VendorPermissionWithGvl expectedVendorPermissionWitGvl = VendorPermissionWithGvl.of( + expectedVendorPermission, VendorV2.empty(1)); + verifyEachPurposeStrategyReceive(singletonList(expectedVendorPermissionWitGvl)); + verifyEachSpecialFeatureStrategyReceive(singletonList(expectedVendorPermission)); + + verify(bidderCatalog).nameByVendorId(1); + verify(tcString).getVendorListVersion(); + verify(vendorListService).forVersion(10); + } + + @Test + public void permissionsForShouldReturnByGdprPurposeAndDowngradeToBasicTypeWhenVendorListServiceIsFailed() { + // given + given(vendorListService.forVersion(anyInt())).willReturn(Future.failedFuture("Bad version")); + given(bidderCatalog.nameByVendorId(any())).willReturn("rubicon"); + + // when + final Future> result = target.permissionsFor(singleton(1), tcString); + + // then + final VendorPermission expectedVendorPermission = VendorPermission.of(1, "rubicon", + PrivacyEnforcementAction.restrictAll()); + assertThat(result).succeededWith(singletonList(expectedVendorPermission)); + + final VendorPermissionWithGvl expectedVendorPermissionWitGvl = VendorPermissionWithGvl.of( + expectedVendorPermission, VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(expectedVendorPermissionWitGvl); + verify(purposeStrategyOne).processTypePurposeStrategy(tcString, purpose1, vendorPermissionWithGvls); + verify(purposeStrategyTwo).processTypePurposeStrategy(tcString, purpose2, vendorPermissionWithGvls); + verify(purposeStrategyFour).processTypePurposeStrategy(tcString, purpose4, vendorPermissionWithGvls); + + final Purpose expectedDowngradedPurpose = Purpose.of(EnforcePurpose.basic, purpose7.getEnforceVendors(), + purpose1.getVendorExceptions()); + verify(purposeStrategySeven).processTypePurposeStrategy(tcString, expectedDowngradedPurpose, + vendorPermissionWithGvls); + verifyEachSpecialFeatureStrategyReceive(singletonList(expectedVendorPermission)); + + verify(bidderCatalog).nameByVendorId(1); + verify(tcString).getVendorListVersion(); + verify(vendorListService).forVersion(10); + } + + @Test + public void permissionsForShouldMergeAccountPurposes() { + // given + final Purpose accountPurposeOne = Purpose.of(EnforcePurpose.full, false, singletonList("test")); + final Purposes accountPurposes = Purposes.builder() + .p1(accountPurposeOne) + .build(); + + final AccountGdprConfig accountGdprConfig = AccountGdprConfig.builder().purposes(accountPurposes).build(); + + final VendorIdResolver vendorIdResolver = mock(VendorIdResolver.class); + given(vendorIdResolver.resolve(anyString())).willReturn(null); + + // when + final Future> result = + target.permissionsFor(singleton("b1"), vendorIdResolver, tcString, accountGdprConfig); + + // then + final VendorPermission expectedVendorPermission = + VendorPermission.of(null, "b1", PrivacyEnforcementAction.restrictAll()); + assertThat(result).succeededWith(singletonList(expectedVendorPermission)); + + verify(purposeStrategyOne).processTypePurposeStrategy( + tcString, + accountPurposeOne, + singletonList(VendorPermissionWithGvl.of(expectedVendorPermission, VendorV2.empty(null)))); + verify(tcString).getVendorListVersion(); + verify(vendorListService).forVersion(10); + } + + @Test + public void permissionsForShouldMergeAccountSpecialFeatures() { + // given + final SpecialFeature accountSpecialFeatureOne = SpecialFeature.of(false, emptyList()); + final SpecialFeatures specialFeatures = SpecialFeatures.builder() + .sf1(accountSpecialFeatureOne) + .build(); + + final AccountGdprConfig accountGdprConfig = AccountGdprConfig.builder() + .specialFeatures(specialFeatures) + .build(); + + final VendorIdResolver vendorIdResolver = mock(VendorIdResolver.class); + given(vendorIdResolver.resolve(anyString())).willReturn(null); + + // when + final Future> result = + target.permissionsFor(singleton("b1"), vendorIdResolver, tcString, accountGdprConfig); + + // then + final VendorPermission expectedVendorPermission = + VendorPermission.of(null, "b1", PrivacyEnforcementAction.restrictAll()); + assertThat(result).succeededWith(singletonList(expectedVendorPermission)); + + verify(specialFeaturesStrategyOne).processSpecialFeaturesStrategy( + tcString, + accountSpecialFeatureOne, + singletonList(expectedVendorPermission)); + } + + @Test + public void permissionsForShouldReturnBidderNamesResult() { + // given + final VendorIdResolver vendorIdResolver = mock(VendorIdResolver.class); + given(vendorIdResolver.resolve(eq("b1"))).willReturn(1); + given(vendorIdResolver.resolve(eq("b2"))).willReturn(null); + + // when + final Future> result = + target.permissionsFor(new HashSet<>(asList("b1", "b2")), vendorIdResolver, tcString, null); + + // then + final VendorPermission expectedVendorPermission1 = + VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission expectedVendorPermission2 = + VendorPermission.of(null, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl expectedVendorPermissionWitGvl1 = + VendorPermissionWithGvl.of(expectedVendorPermission1, VendorV2.empty(1)); + final VendorPermissionWithGvl expectedVendorPermissionWitGvl2 = + VendorPermissionWithGvl.of(expectedVendorPermission2, VendorV2.empty(null)); + assertThat(result).succeededWith(asList(expectedVendorPermission2, expectedVendorPermission1)); + + verifyEachPurposeStrategyReceive(asList(expectedVendorPermissionWitGvl2, expectedVendorPermissionWitGvl1)); + verifyEachSpecialFeatureStrategyReceive(asList(expectedVendorPermission2, expectedVendorPermission1)); + + verify(vendorIdResolver, times(2)).resolve(anyString()); + verify(tcString).getVendorListVersion(); + } + + @Test + public void permissionsForShouldReturnVendorIdsResult() { + // given + given(bidderCatalog.nameByVendorId(eq(1))).willReturn("b1"); + + // when + final Future> result = + target.permissionsFor(new HashSet<>(asList(1, 2)), tcString); + + // then + final VendorPermission expectedVendorPermission1 = VendorPermission.of(1, "b1", + PrivacyEnforcementAction.restrictAll()); + final VendorPermission expectedVendorPermission2 = VendorPermission.of(2, null, + PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl expectedVendorPermissionWitGvl1 = VendorPermissionWithGvl.of( + expectedVendorPermission1, VendorV2.empty(1)); + final VendorPermissionWithGvl expectedVendorPermissionWitGvl2 = VendorPermissionWithGvl.of( + expectedVendorPermission2, VendorV2.empty(2)); + assertThat(result).succeededWith(asList(expectedVendorPermission1, expectedVendorPermission2)); + verifyEachPurposeStrategyReceive(asList(expectedVendorPermissionWitGvl1, expectedVendorPermissionWitGvl2)); + verifyEachSpecialFeatureStrategyReceive(asList(expectedVendorPermission1, expectedVendorPermission2)); + + verify(bidderCatalog, times(2)).nameByVendorId(anyInt()); + verify(tcString).getVendorListVersion(); + + verifyNoMoreInteractions(bidderCatalog); + } + + @Test + public void permissionsForShouldReturnAllDeniedWhenP1TIIsNoAccessAllowed() throws NoSuchFieldException { + // given + given(bidderCatalog.nameByVendorId(any())).willReturn("rubicon"); + + given(tcString.getPurposeOneTreatment()).willReturn(true); + + target = new Tcf2Service( + GdprConfig.builder() + .purposes(purposes) + .purposeOneTreatmentInterpretation(PurposeOneTreatmentInterpretation.noAccessAllowed) + .build(), + vendorListService, + bidderCatalog); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedPurposeStrategies"), purposeStrategies); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedSpecialFeatureStrategies"), specialFeaturesStrategies); + + // when + final Future> result = target.permissionsFor(singleton(1), tcString); + + // then + assertThat(result).succeededWith( + singletonList(VendorPermission.of(1, "rubicon", PrivacyEnforcementAction.restrictAll()))); + + verify(purposeStrategyOne, never()).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategyTwo).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategySeven).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategyFour).processTypePurposeStrategy(any(), any(), anyCollection()); + + verify(specialFeaturesStrategyOne).processSpecialFeaturesStrategy(any(), any(), anyCollection()); + } + + @Test + public void permissionsForShouldAllowAllWhenP1TIIsAccessAllowed() throws NoSuchFieldException { + // given + given(bidderCatalog.nameByVendorId(any())).willReturn("rubicon"); + + given(tcString.getPurposeOneTreatment()).willReturn(true); + + target = new Tcf2Service( + GdprConfig.builder() + .purposes(purposes) + .purposeOneTreatmentInterpretation(PurposeOneTreatmentInterpretation.accessAllowed) + .build(), + vendorListService, + bidderCatalog); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedPurposeStrategies"), purposeStrategies); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedSpecialFeatureStrategies"), specialFeaturesStrategies); + + // when + target.permissionsFor(singleton(1), tcString); + + // then + verify(purposeStrategyOne, never()).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategyOne).allow(any()); + verify(purposeStrategyTwo).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategySeven).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategyFour).processTypePurposeStrategy(any(), any(), anyCollection()); + + verify(specialFeaturesStrategyOne).processSpecialFeaturesStrategy(any(), any(), anyCollection()); + } + + @Test + public void permissionsForShouldNotAllowAllWhenP1TIsFalseAndP1TIIsAccessAllowed() throws NoSuchFieldException { + // given + given(bidderCatalog.nameByVendorId(any())).willReturn("rubicon"); + + given(tcString.getPurposeOneTreatment()).willReturn(false); + + target = new Tcf2Service( + GdprConfig.builder() + .purposes(purposes) + .purposeOneTreatmentInterpretation(PurposeOneTreatmentInterpretation.accessAllowed) + .build(), + vendorListService, + bidderCatalog); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedPurposeStrategies"), purposeStrategies); + FieldSetter.setField(target, + target.getClass().getDeclaredField("supportedSpecialFeatureStrategies"), specialFeaturesStrategies); + + // when + target.permissionsFor(singleton(1), tcString); + + // then + verify(purposeStrategyOne, never()).allow(any()); + verify(purposeStrategyOne).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategyTwo).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategySeven).processTypePurposeStrategy(any(), any(), anyCollection()); + verify(purposeStrategyFour).processTypePurposeStrategy(any(), any(), anyCollection()); + + verify(specialFeaturesStrategyOne).processSpecialFeaturesStrategy(any(), any(), anyCollection()); + } + + public void verifyEachPurposeStrategyReceive(List vendorPermissionWithGvls) { + verify(purposeStrategyOne).processTypePurposeStrategy(tcString, purpose1, vendorPermissionWithGvls); + verify(purposeStrategyTwo).processTypePurposeStrategy(tcString, purpose2, vendorPermissionWithGvls); + verify(purposeStrategyFour).processTypePurposeStrategy(tcString, purpose4, vendorPermissionWithGvls); + verify(purposeStrategySeven).processTypePurposeStrategy(tcString, purpose7, vendorPermissionWithGvls); + } + + public void verifyEachSpecialFeatureStrategyReceive(List vendorPermission) { + verify(specialFeaturesStrategyOne).processSpecialFeaturesStrategy(tcString, specialFeature1, vendorPermission); + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/TcfDefinerServiceTest.java b/src/test/java/org/prebid/server/privacy/gdpr/TcfDefinerServiceTest.java new file mode 100644 index 00000000000..ffa7a49b17f --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/TcfDefinerServiceTest.java @@ -0,0 +1,370 @@ +package org.prebid.server.privacy.gdpr; + +import io.vertx.core.Future; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.geolocation.GeoLocationService; +import org.prebid.server.geolocation.model.GeoInfo; +import org.prebid.server.metric.Metrics; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.TCStringEmpty; +import org.prebid.server.privacy.gdpr.model.TcfResponse; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.settings.model.AccountGdprConfig; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.GdprConfig; +import org.prebid.server.settings.model.Purpose; +import org.prebid.server.settings.model.Purposes; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonMap; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anySet; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.prebid.server.assertion.FutureAssertion.assertThat; + +public class TcfDefinerServiceTest { + + private static final String EEA_COUNTRY = "ua"; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private GdprService gdprService; + @Mock + private Tcf2Service tcf2Service; + @Mock + private GeoLocationService geoLocationService; + @Mock + private BidderCatalog bidderCatalog; + @Mock + private Metrics metrics; + + private TcfDefinerService target; + + private Purposes purposes; + + private GdprConfig gdprConfig; + + @Before + public void setUp() { + given(geoLocationService.lookup(anyString(), any())) + .willReturn(Future.succeededFuture(GeoInfo.builder().vendor("vendor").country(EEA_COUNTRY).build())); + + initPurposes(); + initGdpr(); + + target = new TcfDefinerService(gdprConfig, singleton(EEA_COUNTRY), gdprService, tcf2Service, + geoLocationService, bidderCatalog, metrics); + } + + private void initPurposes() { + final Purpose purpose1 = Purpose.of(EnforcePurpose.basic, true, emptyList()); + purposes = Purposes.builder() + .p1(purpose1) + .build(); + } + + private void initGdpr() { + gdprConfig = GdprConfig.builder() + .defaultValue("1") + .enabled(true) + .purposes(purposes) + .build(); + } + + @Test + public void resultForVendorIdsShouldAllowAllWhenGdprIsDisabled() { + // given + final GdprConfig gdprConfig = GdprConfig.builder().enabled(false).build(); + target = new TcfDefinerService(gdprConfig, singleton(EEA_COUNTRY), gdprService, tcf2Service, + geoLocationService, bidderCatalog, metrics); + + // when + final Future> result = target.resultForVendorIds(singleton(1), null, null, null, null, + null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap(1, PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(gdprService); + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(geoLocationService); + verifyZeroInteractions(metrics); + } + + @Test + public void resultForBidderNamesShouldAllowAllWhenGdprIsDisabledByAccount() { + // given + final AccountGdprConfig accountGdprConfig = AccountGdprConfig.builder().enabled(false).build(); + + // when + final Future> result = target.resultForBidderNames( + singleton("b"), null, null, null, null, accountGdprConfig, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap("b", PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(gdprService); + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(geoLocationService); + verifyZeroInteractions(metrics); + } + + @Test + public void resultForVendorIdsShouldAllowAllWhenGdprIsDisabledByAccount() { + // given + final AccountGdprConfig accountGdprConfig = AccountGdprConfig.builder().enabled(false).build(); + + // when + final Future> result = target.resultForVendorIds(singleton(1), "1", "consent", "ip", + accountGdprConfig, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap(1, PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(gdprService); + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(geoLocationService); + verifyZeroInteractions(metrics); + } + + @Test + public void resultForVendorIdsShouldReturnGdprFromGeoLocationServiceWhenGdprFromRequestIsNotValid() { + // when + target.resultForVendorIds(singleton(1), null, "consent", "ip", null, null); + + // then + verify(geoLocationService).lookup(eq("ip"), any()); + verify(metrics).updateGeoLocationMetric(true); + } + + @Test + public void resultForVendorIdsShouldReturnRestrictAllWhenConsentIsNotValid() { + // when + target.resultForVendorIds(singleton(1), "1", "consent", "ip", null, null); + + // then + verify(tcf2Service).permissionsFor( + any(), argThat(arg -> arg.getClass() == TCStringEmpty.class)); + verifyZeroInteractions(gdprService); + verify(metrics).updatePrivacyTcfInvalidMetric(); + } + + @Test + public void resultForVendorIdsShouldReturnAllowAllWhenGdprIsZero() { + // when + final Future> result = + target.resultForVendorIds(singleton(1), "0", "consent", "ip", null, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap(1, PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(gdprService); + } + + @Test + public void resultForBidderNamesShouldReturnAllowAllWhenGdprIsZero() { + // when + final Future> result = + target.resultForBidderNames(singleton("b1"), "0", "consent", "ip", null, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap("b1", PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(gdprService); + } + + @Test + public void resultForVendorIdsShouldReturnAllowAllWhenGdprByGeoLookupIsZero() { + // given + given(geoLocationService.lookup(anyString(), any())) + .willReturn(Future.succeededFuture(GeoInfo.builder().vendor("aa").country("aa").build())); + + // when + final Future> result = + target.resultForVendorIds(singleton(1), null, "consent", "ip", null, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap(1, PrivacyEnforcementAction.allowAll()), "aa")); + + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(gdprService); + } + + @Test + public void resultForVendorIdsShouldReturnAllowAllWhenGdprByGeoLookupIsFailedAndByDefaultIsZero() { + // given + final GdprConfig gdprConfig = GdprConfig.builder().enabled(true).defaultValue("0").build(); + target = new TcfDefinerService(gdprConfig, singleton(EEA_COUNTRY), gdprService, tcf2Service, + geoLocationService, bidderCatalog, metrics); + + given(geoLocationService.lookup(anyString(), any())).willReturn(Future.failedFuture("Bad ip")); + + // when + final Future> result = + target.resultForVendorIds(singleton(1), null, "consent", "ip", null, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap(1, PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(gdprService); + } + + @Test + public void resultForVendorIdsShouldReturnAllowAllWhenIpIsNullAndByDefaultIsZero() { + // given + final GdprConfig gdprConfig = GdprConfig.builder().enabled(true).defaultValue("0").build(); + target = new TcfDefinerService(gdprConfig, singleton(EEA_COUNTRY), gdprService, tcf2Service, + geoLocationService, bidderCatalog, metrics); + + // when + final Future> result = + target.resultForVendorIds(singleton(1), null, "consent", null, null, null); + + // then + assertThat(result).succeededWith( + TcfResponse.of(false, singletonMap(1, PrivacyEnforcementAction.allowAll()), null)); + + verifyZeroInteractions(tcf2Service); + verifyZeroInteractions(gdprService); + } + + @Test + public void resultForVendorIdsShouldReturnTcfResponseFromGdprServiceWhenConsentStringIsFirstVersion() { + // given + given(gdprService.resultFor(anySet(), anyString())) + .willReturn(Future.succeededFuture(asList( + VendorPermission.of(1, null, PrivacyEnforcementAction.allowAll()), + VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll())))); + + // when + final Future> result = target.resultForVendorIds( + new HashSet<>(asList(1, 2)), + "1", + "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", + null, + AccountGdprConfig.builder().build(), + null); + + // then + final HashMap expectedVendorIdToPrivacyMap = new HashMap<>(); + expectedVendorIdToPrivacyMap.put(1, PrivacyEnforcementAction.allowAll()); + expectedVendorIdToPrivacyMap.put(2, PrivacyEnforcementAction.restrictAll()); + assertThat(result).succeededWith(TcfResponse.of(true, expectedVendorIdToPrivacyMap, null)); + + verifyZeroInteractions(tcf2Service); + verify(metrics).updatePrivacyTcfGeoMetric(1, null); + } + + @Test + public void resultForBidderNamesShouldReturnTcfResponseFromGdprServiceWhenConsentStringIsFirstVersion() { + // given + given(gdprService.resultFor(anySet(), anyString())) + .willReturn(Future.succeededFuture(asList( + VendorPermission.of(1, null, PrivacyEnforcementAction.allowAll()), + VendorPermission.of(2, null, PrivacyEnforcementAction.allowAll())))); + + given(bidderCatalog.isActive(eq("b1"))).willReturn(true); + given(bidderCatalog.isActive(eq("b2"))).willReturn(true); + given(bidderCatalog.isActive(eq("b3"))).willReturn(false); + given(bidderCatalog.vendorIdByName(eq("b1"))).willReturn(1); + given(bidderCatalog.vendorIdByName(eq("b2"))).willReturn(2); + + // when + final Future> result = target.resultForBidderNames( + new HashSet<>(asList("b1", "b2", "b3")), + "1", + "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA", + null, + null, + null); + + // then + final HashMap expectedBidderNameToPrivacyMap = new HashMap<>(); + expectedBidderNameToPrivacyMap.put("b1", PrivacyEnforcementAction.allowAll()); + expectedBidderNameToPrivacyMap.put("b2", PrivacyEnforcementAction.allowAll()); + expectedBidderNameToPrivacyMap.put("b3", PrivacyEnforcementAction.builder() + .removeUserIds(true) + .maskGeo(true) + .maskDeviceIp(true) + .maskDeviceInfo(true) + .blockAnalyticsReport(false) + .blockBidderRequest(false) + .blockPixelSync(true) + .build()); + assertThat(result).succeededWith(TcfResponse.of(true, expectedBidderNameToPrivacyMap, null)); + + verifyZeroInteractions(tcf2Service); + verify(metrics).updatePrivacyTcfGeoMetric(1, null); + } + + @Test + public void resultForVendorIdsShouldReturnTcfResponseFromTcf2ServiceWhenConsentStringIsNull() { + // given + given(tcf2Service.permissionsFor(anySet(), any())).willReturn(Future.succeededFuture(asList( + VendorPermission.of(1, null, PrivacyEnforcementAction.allowAll()), + VendorPermission.of(2, null, PrivacyEnforcementAction.allowAll())))); + + // when + final Future> result = + target.resultForVendorIds(new HashSet<>(asList(1, 2)), "1", null, null, null, null); + + // then + final HashMap expectedVendorIdToPrivacyMap = new HashMap<>(); + expectedVendorIdToPrivacyMap.put(1, PrivacyEnforcementAction.allowAll()); + expectedVendorIdToPrivacyMap.put(2, PrivacyEnforcementAction.allowAll()); + assertThat(result).succeededWith(TcfResponse.of(true, expectedVendorIdToPrivacyMap, null)); + + verifyZeroInteractions(gdprService); + } + + @Test + public void resultForBidderNamesShouldReturnTcfResponseFromTcf2ServiceWhenConsentStringIsSecondVersion() { + // given + given(tcf2Service.permissionsFor(anySet(), any(), any(), any())).willReturn(Future.succeededFuture(asList( + VendorPermission.of(1, "b1", PrivacyEnforcementAction.allowAll()), + VendorPermission.of(null, "b2", PrivacyEnforcementAction.allowAll())))); + + // when + final Set bidderNames = new HashSet<>(asList("b1", "b2")); + final Future> result = target.resultForBidderNames( + bidderNames, "1", "COwayg7OwaybYN6AAAENAPCgAIAAAAAAAAAAASkAAAAAAAAAAA", null, null, null); + + // then + final HashMap expectedBidderNameToPrivacyMap = new HashMap<>(); + expectedBidderNameToPrivacyMap.put("b1", PrivacyEnforcementAction.allowAll()); + expectedBidderNameToPrivacyMap.put("b2", PrivacyEnforcementAction.allowAll()); + assertThat(result).succeededWith(TcfResponse.of(true, expectedBidderNameToPrivacyMap, null)); + + verifyZeroInteractions(gdprService); + verify(metrics).updatePrivacyTcfGeoMetric(2, null); + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeFourStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeFourStrategyTest.java new file mode 100644 index 00000000000..31e0b681659 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeFourStrategyTest.java @@ -0,0 +1,231 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import com.iabtcf.decoder.TCString; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.Purpose; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +public class PurposeFourStrategyTest { + + private static final int PURPOSE_ID = 4; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private FullEnforcePurposeStrategy fullEnforcePurposeStrategy; + + @Mock + private BasicEnforcePurposeStrategy basicEnforcePurposeStrategy; + + @Mock + private NoEnforcePurposeStrategy noEnforcePurposeStrategy; + + private PurposeFourStrategy target; + + @Mock + private TCString tcString; + + @Before + public void setUp() { + target = new PurposeFourStrategy(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, + noEnforcePurposeStrategy); + } + + @Test + public void allowShouldReturnExpectedValue() { + // given + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + + // when + target.allow(privacyEnforcementAction); + + // then + assertThat(privacyEnforcementAction).isEqualTo(allowPurpose()); + } + + @Test + public void getPurposeIdShouldReturnExpectedValue() { + // when and then + assertThat(target.getPurposeId()).isEqualTo(PURPOSE_ID); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToNoType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.no, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(noEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(noEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToBaseType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), + singletonList(vendorPermissionWitGvl2), false); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithEnforcementsWhenAllBiddersAreExcluded() { + // given + final List vendorExceptions = Arrays.asList("b1", "b2", "b3", "b5", "b7"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, null, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithFullEnforcementsWhenAllBiddersAreExcluded() { + // given + final Purpose purpose = Purpose.of(EnforcePurpose.full, null, Arrays.asList("b1", "b2", "b3", "b5", "b7")); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(fullEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(fullEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + private static PrivacyEnforcementAction allowPurpose() { + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + privacyEnforcementAction.setRemoveUserIds(false); + privacyEnforcementAction.setMaskDeviceInfo(false); + return privacyEnforcementAction; + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeOneStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeOneStrategyTest.java new file mode 100644 index 00000000000..e2f5688b027 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeOneStrategyTest.java @@ -0,0 +1,230 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import com.iabtcf.decoder.TCString; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.Purpose; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +public class PurposeOneStrategyTest { + + private static final int PURPOSE_ID = 1; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private FullEnforcePurposeStrategy fullEnforcePurposeStrategy; + + @Mock + private BasicEnforcePurposeStrategy basicEnforcePurposeStrategy; + + @Mock + private NoEnforcePurposeStrategy noEnforcePurposeStrategy; + + private PurposeOneStrategy target; + + @Mock + private TCString tcString; + + @Before + public void setUp() { + target = new PurposeOneStrategy(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, + noEnforcePurposeStrategy); + } + + @Test + public void allowShouldReturnExpectedValue() { + // given + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + + // when + target.allow(privacyEnforcementAction); + + // then + assertThat(privacyEnforcementAction).isEqualTo(allowPurpose()); + } + + @Test + public void getPurposeIdShouldReturnExpectedValue() { + // when and then + assertThat(target.getPurposeId()).isEqualTo(PURPOSE_ID); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToNoType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.no, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(noEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(noEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToBaseType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithEnforcementsWhenAllBiddersAreExcluded() { + // given + final List vendorExceptions = Arrays.asList("b1", "b2", "b3", "b5", "b7"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, null, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithFullEnforcementsWhenAllBiddersAreExcluded() { + // given + final Purpose purpose = Purpose.of(EnforcePurpose.full, null, Arrays.asList("b1", "b2", "b3", "b5", "b7")); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(fullEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(fullEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + private static PrivacyEnforcementAction allowPurpose() { + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + privacyEnforcementAction.setBlockPixelSync(false); + return privacyEnforcementAction; + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeSevenStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeSevenStrategyTest.java new file mode 100644 index 00000000000..91d837e9273 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeSevenStrategyTest.java @@ -0,0 +1,229 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import com.iabtcf.decoder.TCString; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.Purpose; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +public class PurposeSevenStrategyTest { + + private static final int PURPOSE_ID = 7; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private FullEnforcePurposeStrategy fullEnforcePurposeStrategy; + + @Mock + private BasicEnforcePurposeStrategy basicTypeStrategy; + + @Mock + private NoEnforcePurposeStrategy noEnforcePurposeStrategy; + + private PurposeSevenStrategy target; + + @Mock + private TCString tcString; + + @Before + public void setUp() { + target = new PurposeSevenStrategy(fullEnforcePurposeStrategy, basicTypeStrategy, noEnforcePurposeStrategy); + } + + @Test + public void allowShouldReturnExpectedValue() { + // given + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + + // when + target.allow(privacyEnforcementAction); + + // then + assertThat(privacyEnforcementAction).isEqualTo(allowPurpose()); + } + + @Test + public void getPurposeIdShouldReturnExpectedValue() { + // when and then + assertThat(target.getPurposeId()).isEqualTo(PURPOSE_ID); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToNoType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.no, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(noEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(noEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToBaseType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicTypeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicTypeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithEnforcementsWhenAllBiddersAreExcluded() { + // given + final List vendorExceptions = Arrays.asList("b1", "b2", "b3", "b5", "b7"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, null, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicTypeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicTypeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), vendorPermissionsWithGvl, + true); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithFullEnforcementsWhenAllBiddersAreExcluded() { + // given + final Purpose purpose = Purpose.of(EnforcePurpose.full, null, Arrays.asList("b1", "b2", "b3", "b5", "b7")); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(fullEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(fullEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + private static PrivacyEnforcementAction allowPurpose() { + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + privacyEnforcementAction.setBlockAnalyticsReport(false); + return privacyEnforcementAction; + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeTwoStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeTwoStrategyTest.java new file mode 100644 index 00000000000..72283d918ff --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/PurposeTwoStrategyTest.java @@ -0,0 +1,227 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose; + +import com.iabtcf.decoder.TCString; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.NoEnforcePurposeStrategy; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.Purpose; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; + +public class PurposeTwoStrategyTest { + + private static final int PURPOSE_ID = 2; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private FullEnforcePurposeStrategy fullEnforcePurposeStrategy; + + @Mock + private BasicEnforcePurposeStrategy basicEnforceTypeStrategy; + + @Mock + private NoEnforcePurposeStrategy noEnforcePurposeStrategy; + + private PurposeTwoStrategy target; + + @Mock + private TCString tcString; + + @Before + public void setUp() { + target = new PurposeTwoStrategy(fullEnforcePurposeStrategy, basicEnforceTypeStrategy, noEnforcePurposeStrategy); + } + + @Test + public void allowShouldReturnExpectedValue() { + // given + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + + // when + target.allow(privacyEnforcementAction); + + // then + assertThat(privacyEnforcementAction).isEqualTo(allowPurpose()); + } + + @Test + public void getPurposeIdShouldReturnExpectedValue() { + // when and then + assertThat(target.getPurposeId()).isEqualTo(PURPOSE_ID); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToNoType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.no, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(noEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(noEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToBaseType() { + // given + final List vendorExceptions = Arrays.asList("b1", "b3"); + final Purpose purpose = Purpose.of(EnforcePurpose.basic, false, vendorExceptions); + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + given(basicEnforceTypeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(Arrays.asList(vendorPermission1, vendorPermission2)); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, null, + PrivacyEnforcementAction.restrictAll()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicEnforceTypeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(vendorPermissionWitGvl1, vendorPermissionWitGvl3), singletonList(vendorPermissionWitGvl2), + false); + } + + @Test + public void processTypePurposeStrategyShouldPassListWithEnforcementsAndExcludeBiddersToFullType() { + // given + final Purpose purpose = Purpose.of(EnforcePurpose.basic, null, Arrays.asList("b1", "b2", "b3", "b5", "b7")); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(basicEnforceTypeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(basicEnforceTypeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + @Test + public void processTypePurposeStrategyShouldPassEmptyListWithFullEnforcementsWhenAllBiddersAreExcluded() { + // given + final Purpose purpose = Purpose.of(EnforcePurpose.full, null, Arrays.asList("b1", "b2", "b3", "b5", "b7")); + final VendorPermission vendorPermission1 = VendorPermission.of(1, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b2", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl vendorPermissionWitGvl3 = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + final List vendorPermissionsWithGvl = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2, vendorPermissionWitGvl3); + + given(fullEnforcePurposeStrategy.allowedByTypeStrategy(anyInt(), any(), any(), any(), anyBoolean())) + .willReturn(vendorPermissions); + + // when + final Collection result = target.processTypePurposeStrategy(tcString, purpose, + vendorPermissionsWithGvl); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, "b1", allowPurpose()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b2", allowPurpose()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowPurpose()); + assertThat(result).usingFieldByFieldElementComparator().isEqualTo( + Arrays.asList(vendorPermission1Changed, vendorPermission2Changed, vendorPermission3Changed)); + + verify(fullEnforcePurposeStrategy).allowedByTypeStrategy(PURPOSE_ID, tcString, emptyList(), + vendorPermissionsWithGvl, true); + } + + private static PrivacyEnforcementAction allowPurpose() { + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + privacyEnforcementAction.setBlockBidderRequest(false); + return privacyEnforcementAction; + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/BasicEnforcePurposeStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/BasicEnforcePurposeStrategyTest.java new file mode 100644 index 00000000000..272e62f5683 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/BasicEnforcePurposeStrategyTest.java @@ -0,0 +1,267 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; + +public class BasicEnforcePurposeStrategyTest { + private static final int PURPOSE_ID = 1; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private BasicEnforcePurposeStrategy target; + + @Mock + private TCString tcString; + @Mock + private IntIterable allowedVendors; + @Mock + private IntIterable allowedVendorsLI; + @Mock + private IntIterable purposesConsent; + @Mock + private IntIterable purposesLI; + + @Before + public void setUp() { + given(tcString.getVendorConsent()).willReturn(allowedVendors); + given(tcString.getVendorLegitimateInterest()).willReturn(allowedVendorsLI); + given(tcString.getPurposesConsent()).willReturn(purposesConsent); + given(tcString.getPurposesLITransparency()).willReturn(purposesLI); + + given(allowedVendors.contains(anyInt())).willReturn(false); + given(allowedVendorsLI.contains(anyInt())).willReturn(false); + given(purposesConsent.contains(anyInt())).willReturn(false); + given(purposesLI.contains(anyInt())).willReturn(false); + + target = new BasicEnforcePurposeStrategy(); + } + + @Test + public void allowedByTypeStrategyShouldReturnEmptyListWhenVendorIsNotAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnEmptyListWhenVendorIsNotAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorIsAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorLIIsAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorLIIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenPurposeLIAndPurposeIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenPurposeLIAndPurposeIsAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenPurposeLIAndVendorIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final List vendorPermissionWithGvls = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2); + + given(allowedVendors.contains(anyInt())).willReturn(true); + given(purposesLI.contains(PURPOSE_ID)).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, vendorPermission2); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenPurposeAndVendorLIIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final List vendorPermissionWithGvls = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2); + + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(PURPOSE_ID)).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, vendorPermission2); + } + + @Test + public void allowedByTypeStrategyShouldReturnExcludedVendors() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + singleton(vendorPermissionWitGvl1), singleton(vendorPermissionWitGvl2), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission2); + } +} + diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/FullEnforcePurposeStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/FullEnforcePurposeStrategyTest.java new file mode 100644 index 00000000000..a90989fe1cf --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/FullEnforcePurposeStrategyTest.java @@ -0,0 +1,1041 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import com.iabtcf.v2.PublisherRestriction; +import com.iabtcf.v2.RestrictionType; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +public class FullEnforcePurposeStrategyTest { + private static final int PURPOSE_ID = 1; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private FullEnforcePurposeStrategy target; + + @Mock + private TCString tcString; + @Mock + private IntIterable allowedVendors; + @Mock + private IntIterable allowedVendorsLI; + @Mock + private IntIterable purposesConsent; + @Mock + private IntIterable purposesLI; + @Mock + private IntIterable vendorIds; + + @Mock + private PublisherRestriction publisherRestriction; + + @Before + public void setUp() { + given(tcString.getVendorConsent()).willReturn(allowedVendors); + given(tcString.getVendorLegitimateInterest()).willReturn(allowedVendorsLI); + given(tcString.getPurposesConsent()).willReturn(purposesConsent); + given(tcString.getPurposesLITransparency()).willReturn(purposesLI); + + given(tcString.getPublisherRestrictions()).willReturn(singletonList(publisherRestriction)); + + given(publisherRestriction.getPurposeId()).willReturn(PURPOSE_ID); + given(publisherRestriction.getVendorIds()).willReturn(vendorIds); + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.UNDEFINED); + + given(allowedVendors.contains(anyInt())).willReturn(false); + given(allowedVendorsLI.contains(anyInt())).willReturn(false); + given(purposesConsent.contains(anyInt())).willReturn(false); + given(purposesLI.contains(anyInt())).willReturn(false); + given(vendorIds.contains(anyInt())).willReturn(false); + + target = new FullEnforcePurposeStrategy(); + } + + @Test + public void shouldReturnOnlyExcludedAllowedWhenMultiplePublisherRestrictionsProvided() { + // given + final IntIterable requireConsentIterable = mock(IntIterable.class); + final PublisherRestriction publisherRestriction1 = new PublisherRestriction(PURPOSE_ID, + RestrictionType.REQUIRE_CONSENT, requireConsentIterable); + given(requireConsentIterable.spliterator()).willReturn(singletonList(1).spliterator()); + + final IntIterable notAllowedIterable = mock(IntIterable.class); + final PublisherRestriction publisherRestriction2 = new PublisherRestriction(PURPOSE_ID, + RestrictionType.NOT_ALLOWED, notAllowedIterable); + given(notAllowedIterable.spliterator()).willReturn(Arrays.asList(4, 2).spliterator()); + + given(tcString.getPublisherRestrictions()).willReturn( + Arrays.asList(publisherRestriction1, publisherRestriction2)); + + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission4 = VendorPermission.of(4, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission5 = VendorPermission.of(5, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl requireConsentPermission = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl notAllowedPermission = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + final VendorPermissionWithGvl excludedNotMentionedPermission = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.empty(3)); + final VendorPermissionWithGvl excludedNotAllowedPermission = VendorPermissionWithGvl.of(vendorPermission4, + VendorV2.empty(4)); + final VendorPermissionWithGvl notMentionedPermission = VendorPermissionWithGvl.of(vendorPermission5, + VendorV2.empty(5)); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(requireConsentPermission, notAllowedPermission, notMentionedPermission), + Arrays.asList(excludedNotMentionedPermission, excludedNotAllowedPermission), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission3); + } + + @Test + public void shouldReturnExpectedWhenMultiplePublisherRestrictionsProvided() { + // given + final IntIterable requireConsentIterable = mock(IntIterable.class); + final PublisherRestriction publisherRestriction1 = new PublisherRestriction(PURPOSE_ID, + RestrictionType.REQUIRE_CONSENT, requireConsentIterable); + given(requireConsentIterable.spliterator()).willReturn(singletonList(1).spliterator()); + given(requireConsentIterable.contains(eq(1))).willReturn(true); + + final IntIterable notAllowedIterable = mock(IntIterable.class); + final PublisherRestriction publisherRestriction2 = new PublisherRestriction(PURPOSE_ID, + RestrictionType.NOT_ALLOWED, notAllowedIterable); + given(notAllowedIterable.spliterator()).willReturn(Arrays.asList(4, 2).spliterator()); + given(notAllowedIterable.contains(eq(4))).willReturn(true); + given(notAllowedIterable.contains(eq(2))).willReturn(true); + + given(tcString.getPublisherRestrictions()).willReturn( + Arrays.asList(publisherRestriction1, publisherRestriction2)); + + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission4 = VendorPermission.of(4, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission5 = VendorPermission.of(5, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl requireConsentPermission = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.builder().id(1).purposes(singleton(PURPOSE_ID)).build()); + final VendorPermissionWithGvl notAllowedPermission = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.builder().id(2).purposes(singleton(PURPOSE_ID)).build()); + final VendorPermissionWithGvl excludedNotMentionedPermission = VendorPermissionWithGvl.of(vendorPermission3, + VendorV2.builder().id(3).purposes(singleton(PURPOSE_ID)).build()); + final VendorPermissionWithGvl excludedNotAllowedPermission = VendorPermissionWithGvl.of(vendorPermission4, + VendorV2.builder().id(4).purposes(singleton(PURPOSE_ID)).build()); + final VendorPermissionWithGvl notMentionedPermission = VendorPermissionWithGvl.of(vendorPermission5, + VendorV2.builder().id(5).purposes(singleton(PURPOSE_ID)).build()); + + given(purposesConsent.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + Arrays.asList(requireConsentPermission, notAllowedPermission, notMentionedPermission), + Arrays.asList(excludedNotMentionedPermission, excludedNotAllowedPermission), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, vendorPermission3, + vendorPermission5); + } + + @Test + public void shouldAllowWhenInGvlPurposeAndPurposeConsentAllowed() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesConsent.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesConsent).contains(PURPOSE_ID); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeLIAllowed() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesLI); + } + + @Test + public void shouldAllowWhenInGvlPurposeAndPurposeConsentAllowedAndVendorConsentAllowedAndEnforced() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesConsent).contains(PURPOSE_ID); + verify(allowedVendors).contains(1); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeConsentAllowedAndVendorLIAllowedAndEnforced() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(purposesConsent).contains(PURPOSE_ID); + verifyZeroInteractions(purposesLI); + } + + @Test + public void shouldAllowWhenInGvlPurposeLIAndPurposeLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesLI).contains(PURPOSE_ID); + } + + @Test + public void shouldAllowWhenInGvlPurposeLIAndPurposeLIAndVendorLIAllowedAndEnforced() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesLI).contains(PURPOSE_ID); + verify(allowedVendorsLI).contains(1); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeConsentAllowedAndVendorConsentAllowedAndEnforced() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(emptySet()) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(purposesLI.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(purposesLI).contains(PURPOSE_ID); + verifyZeroInteractions(allowedVendors); + } + + // Flexible GVL Purpose part + + // Restriction type is REQUIRE_CONSENT + + @Test + public void shouldAllowWhenInGvlPurposeAndPurposeConsentAllowedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(purposesConsent.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesConsent).contains(PURPOSE_ID); + } + + @Test + public void shouldAllowWhenInGvlPurposeAndPurposeConsentAndVendorConsentAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesConsent).contains(PURPOSE_ID); + verify(allowedVendors).contains(1); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeLIAllowedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesLI); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeLIAndVendorLIAllowedAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesLI); + verifyZeroInteractions(allowedVendorsLI); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeConsentAndVendorLIAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(purposesConsent).contains(PURPOSE_ID); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeLIAndVendorConsentAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + } + + // Restriction tipe is REQUIRE_LEGITIMATE_INTEREST + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeConsentAllowedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesConsent); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeConsentAndVendorConsentAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesConsent); + verifyZeroInteractions(allowedVendors); + } + + @Test + public void shouldAllowWhenInGvlPurposeAndPurposeLIAllowedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesLI).contains(PURPOSE_ID); + } + + @Test + public void shouldAllowWhenInGvlPurposeAndPurposeLIAndVendorLIAllowedAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesLI).contains(PURPOSE_ID); + verify(allowedVendorsLI).contains(1); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeConsentAndVendorLIAllowedAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(allowedVendorsLI).contains(1); + verifyZeroInteractions(purposesConsent); + } + + @Test + public void shouldEmptyWhenInGvlPurposeAndPurposeLIAndVendorConsentAllowedAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .purposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(purposesLI).contains(PURPOSE_ID); + verifyZeroInteractions(allowedVendors); + } + + // Flexible GVL Purpose Legitimate interest part + + // Restriction type is REQUIRE_CONSENT + + @Test + public void shouldAllowWhenInGvlPurposeLIAndPurposeConsentAllowedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(purposesConsent.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesConsent).contains(PURPOSE_ID); + } + + @Test + public void shouldAllowWhenInGvlPurposeLIAndPurposeAndVendorConsentAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesConsent).contains(PURPOSE_ID); + verify(allowedVendors).contains(1); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeLIAllowedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesLI); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeLIAndVendorLIAllowedAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesLI); + verifyZeroInteractions(allowedVendorsLI); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeConsentAndVendorLIAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(purposesConsent).contains(PURPOSE_ID); + verifyZeroInteractions(allowedVendorsLI); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeLIAndVendorConsentAndEnforcedAndFlexibleAndRequireConsent() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_CONSENT); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(allowedVendors).contains(PURPOSE_ID); + verifyZeroInteractions(purposesLI); + } + + // Restriction type is REQUIRE_LEGITIMATE_INTEREST + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeConsentAllowedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesConsent); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeConsentAndVendorConsentAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verifyZeroInteractions(purposesConsent); + verifyZeroInteractions(allowedVendors); + } + + @Test + public void shouldAllowWhenInGvlPurposeLIAndPurposeLIAllowedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(purposesLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesLI).contains(PURPOSE_ID); + } + + @Test + public void shouldAllowWhenInGvlPurposeLIAndPurposeLIAndVendorLIAllowedAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + + verify(purposesLI).contains(PURPOSE_ID); + verify(allowedVendorsLI).contains(1); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeConsentAndVendorLIAllowedAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesConsent.contains(anyInt())).willReturn(true); + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(allowedVendorsLI).contains(1); + verifyZeroInteractions(purposesConsent); + } + + @Test + public void shouldEmptyWhenInGvlPurposeLIAndPurposeLIAndVendorConsentAllowedAndEnforcedAndFlexibleAndRequireLI() { + // given + final VendorV2 vendorGvl = VendorV2.builder() + .legIntPurposes(singleton(PURPOSE_ID)) + .flexiblePurposes(singleton(PURPOSE_ID)) + .build(); + + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, vendorGvl); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(publisherRestriction.getRestrictionType()).willReturn(RestrictionType.REQUIRE_LEGITIMATE_INTEREST); + + given(vendorIds.contains(anyInt())).willReturn(true); + given(purposesLI.contains(anyInt())).willReturn(true); + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + + verify(purposesLI).contains(1); + verifyZeroInteractions(allowedVendors); + } + + @Test + public void shouldReturnExcludedVendors() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(2)); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + singleton(vendorPermissionWitGvl1), singleton(vendorPermissionWitGvl2), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission2); + } +} + diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/NoEnforcePurposeStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/NoEnforcePurposeStrategyTest.java new file mode 100644 index 00000000000..f52c0b5d68d --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/purpose/typestrategies/NoEnforcePurposeStrategyTest.java @@ -0,0 +1,266 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.privacy.gdpr.model.VendorPermissionWithGvl; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; + +public class NoEnforcePurposeStrategyTest { + private static final int PURPOSE_ID = 1; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private NoEnforcePurposeStrategy target; + + @Mock + private TCString tcString; + @Mock + private IntIterable allowedVendors; + @Mock + private IntIterable allowedVendorsLI; + + @Before + public void setUp() { + given(tcString.getVendorConsent()).willReturn(allowedVendors); + given(tcString.getVendorLegitimateInterest()).willReturn(allowedVendorsLI); + + given(allowedVendors.contains(anyInt())).willReturn(false); + given(allowedVendorsLI.contains(anyInt())).willReturn(false); + + target = new NoEnforcePurposeStrategy(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedListWhenVendorIsNotAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + } + + @Test + public void allowedByTypeStrategyShouldReturnEmptyListWhenVendorIsNotAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).isEmpty(); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorIsAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPermissionWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendors.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPermissionWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorLIIsAllowedAndVendorEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPurposeWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPurposeWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorLIIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl = VendorPermissionWithGvl.of(vendorPermission, + VendorV2.empty(1)); + final List vendorPurposeWithGvls = singletonList(vendorPermissionWitGvl); + + given(allowedVendorsLI.contains(anyInt())).willReturn(true); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPurposeWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorIsAllowedForFirstAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(1)); + final List vendorPurposeWithGvls = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2); + + given(allowedVendors.contains(eq(1))).willReturn(true); + given(allowedVendors.contains(eq(2))).willReturn(false); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPurposeWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, vendorPermission2); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenVendorIsAllowedForFirstAndVendorIsEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(1)); + final List vendorPurposeWithGvls = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2); + given(allowedVendors.contains(eq(1))).willReturn(true); + given(allowedVendors.contains(eq(2))).willReturn(false); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPurposeWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenPurposeAndVendorLIIsAllowedAndVendorIsNotEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(1)); + final List vendorPurposeWithGvls = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2); + + given(allowedVendorsLI.contains(eq(1))).willReturn(true); + given(allowedVendorsLI.contains(eq(2))).willReturn(false); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPurposeWithGvls, emptyList(), false); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, vendorPermission2); + } + + @Test + public void allowedByTypeStrategyShouldReturnExpectedValueWhenPurposeAndVendorLIIsAllowedAndVendorIsEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(1)); + final List vendorPurposeWithGvls = Arrays.asList(vendorPermissionWitGvl1, + vendorPermissionWitGvl2); + + given(allowedVendorsLI.contains(eq(1))).willReturn(true); + given(allowedVendorsLI.contains(eq(2))).willReturn(false); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + vendorPurposeWithGvls, emptyList(), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1); + } + + @Test + public void allowedByTypeStrategyShouldReturnExcludedVendors() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermissionWithGvl vendorPermissionWitGvl1 = VendorPermissionWithGvl.of(vendorPermission1, + VendorV2.empty(1)); + final VendorPermissionWithGvl vendorPermissionWitGvl2 = VendorPermissionWithGvl.of(vendorPermission2, + VendorV2.empty(1)); + + // when + final Collection result = target.allowedByTypeStrategy(PURPOSE_ID, tcString, + singletonList(vendorPermissionWitGvl1), singletonList(vendorPermissionWitGvl2), true); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission2); + } +} + diff --git a/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesOneStrategyTest.java b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesOneStrategyTest.java new file mode 100644 index 00000000000..9b230593859 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/tcfstrategies/specialfeature/SpecialFeaturesOneStrategyTest.java @@ -0,0 +1,162 @@ +package org.prebid.server.privacy.gdpr.tcfstrategies.specialfeature; + +import com.iabtcf.decoder.TCString; +import com.iabtcf.utils.IntIterable; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction; +import org.prebid.server.privacy.gdpr.model.VendorPermission; +import org.prebid.server.settings.model.SpecialFeature; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; + +public class SpecialFeaturesOneStrategyTest { + + private static final int SPECIAL_FEATURE_ID = 1; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private SpecialFeaturesOneStrategy target; + + @Mock + private TCString tcString; + @Mock + private IntIterable specialFeatureOptIns; + + @Before + public void setUp() { + given(tcString.getSpecialFeatureOptIns()).willReturn(specialFeatureOptIns); + given(specialFeatureOptIns.contains(anyInt())).willReturn(false); + + target = new SpecialFeaturesOneStrategy(); + } + + @Test + public void allowShouldReturnExpectedValue() { + // given + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + + // when + target.allow(privacyEnforcementAction); + + // then + assertThat(privacyEnforcementAction).isEqualTo(allowSpecialFeature()); + } + + @Test + public void getSpecialFeatureIdShouldReturnExpectedValue() { + // when and then + assertThat(target.getSpecialFeatureId()).isEqualTo(SPECIAL_FEATURE_ID); + } + + @Test + public void processSpecialFeaturesStrategyShouldAllowForAllWhenIsNotEnforced() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2); + + final SpecialFeature specialFeature = SpecialFeature.of(false, emptyList()); + + // when + final Collection result = target.processSpecialFeaturesStrategy(tcString, specialFeature, + vendorPermissions); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowSpecialFeature()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowSpecialFeature()); + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1Changed, + vendorPermission2Changed); + + verifyZeroInteractions(specialFeatureOptIns); + } + + @Test + public void processSpecialFeaturesStrategyShouldAllowEmptyListWhenAllOptOutAndNoExcluded() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2); + + final SpecialFeature specialFeature = SpecialFeature.of(true, emptyList()); + + // when + final Collection result = target.processSpecialFeaturesStrategy(tcString, specialFeature, + vendorPermissions); + + // then + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, vendorPermission2); + + verify(specialFeatureOptIns).contains(SPECIAL_FEATURE_ID); + } + + @Test + public void processSpecialFeaturesStrategyShouldAllowOnlyExcludedWhenAllOptOutAndExcluded() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2); + + final SpecialFeature specialFeature = SpecialFeature.of(true, singletonList("b1")); + + // when + final Collection result = target.processSpecialFeaturesStrategy(tcString, specialFeature, + vendorPermissions); + + // then + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowSpecialFeature()); + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1, + vendorPermission2Changed); + + verify(specialFeatureOptIns).contains(SPECIAL_FEATURE_ID); + } + + @Test + public void processSpecialFeaturesStrategyShouldAllowExcludedAndOptIn() { + // given + final VendorPermission vendorPermission1 = VendorPermission.of(1, null, PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission2 = VendorPermission.of(2, "b1", PrivacyEnforcementAction.restrictAll()); + final VendorPermission vendorPermission3 = VendorPermission.of(3, "b3", PrivacyEnforcementAction.restrictAll()); + final List vendorPermissions = Arrays.asList(vendorPermission1, vendorPermission2, + vendorPermission3); + + final SpecialFeature specialFeature = SpecialFeature.of(true, singletonList("b1")); + + given(specialFeatureOptIns.contains(SPECIAL_FEATURE_ID)).willReturn(true); + + // when + final Collection result = target.processSpecialFeaturesStrategy(tcString, specialFeature, + vendorPermissions); + + // then + final VendorPermission vendorPermission1Changed = VendorPermission.of(1, null, allowSpecialFeature()); + final VendorPermission vendorPermission2Changed = VendorPermission.of(2, "b1", allowSpecialFeature()); + final VendorPermission vendorPermission3Changed = VendorPermission.of(3, "b3", allowSpecialFeature()); + assertThat(result).usingFieldByFieldElementComparator().containsOnly(vendorPermission1Changed, + vendorPermission2Changed, vendorPermission3Changed); + + verify(specialFeatureOptIns).contains(SPECIAL_FEATURE_ID); + } + + private static PrivacyEnforcementAction allowSpecialFeature() { + final PrivacyEnforcementAction privacyEnforcementAction = PrivacyEnforcementAction.restrictAll(); + privacyEnforcementAction.setMaskDeviceIp(false); + privacyEnforcementAction.setMaskGeo(false); + return privacyEnforcementAction; + } +} diff --git a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV1Test.java similarity index 72% rename from src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java rename to src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV1Test.java index 36bf0d8b1bb..2dcbef77668 100644 --- a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java +++ b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV1Test.java @@ -15,24 +15,20 @@ import org.prebid.server.VertxTest; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.exception.PreBidException; -import org.prebid.server.privacy.gdpr.vendorlist.proto.Vendor; -import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorList; -import org.prebid.server.proto.response.BidderInfo; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV1; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV1; import org.prebid.server.vertx.http.HttpClient; import org.prebid.server.vertx.http.model.HttpClientResponse; import java.io.File; -import java.util.Arrays; import java.util.Date; -import java.util.HashSet; import java.util.Map; -import java.util.Set; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; @@ -41,8 +37,9 @@ import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.prebid.server.assertion.FutureAssertion.assertThat; -public class VendorListServiceTest extends VertxTest { +public class VendorListServiceV1Test extends VertxTest { private static final String CACHE_DIR = "/cache/dir"; @@ -56,26 +53,16 @@ public class VendorListServiceTest extends VertxTest { @Mock private BidderCatalog bidderCatalog; - private VendorListService vendorListService; + private VendorListService vendorListService; @Before public void setUp() { given(fileSystem.existsBlocking(anyString())).willReturn(false); // always create cache dir - given(bidderCatalog.names()).willReturn(singleton(null)); - given(bidderCatalog.bidderInfoByName(any())) - .willReturn(new BidderInfo(true, null, null, null, - new BidderInfo.GdprInfo(52, true), false)); - - vendorListService = VendorListService.create( - CACHE_DIR, - "http://vendorlist/{VERSION}", - 0, - null, - bidderCatalog, - fileSystem, - httpClient, - jacksonMapper); + given(bidderCatalog.knownVendorIds()).willReturn(singleton(52)); + + vendorListService = new VendorListServiceV1(CACHE_DIR, "http://vendorlist/{VERSION}", 0, null, bidderCatalog, + fileSystem, httpClient, jacksonMapper); } // Creation related tests @@ -86,15 +73,9 @@ public void creationShouldFailsIfCannotCreateCacheDir() { given(fileSystem.mkdirsBlocking(anyString())).willThrow(new RuntimeException("dir creation error")); // then - assertThatThrownBy(() -> VendorListService.create( - CACHE_DIR, - "http://vendorlist/%s", - 0, - null, - bidderCatalog, - fileSystem, - httpClient, - jacksonMapper)) + assertThatThrownBy( + () -> new VendorListServiceV1(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, + httpClient, jacksonMapper)) .hasMessage("dir creation error"); } @@ -104,15 +85,9 @@ public void creationShouldFailsIfCannotReadFiles() { given(fileSystem.readDirBlocking(anyString())).willThrow(new RuntimeException("read error")); // then - assertThatThrownBy(() -> VendorListService.create( - CACHE_DIR, - "http://vendorlist/%s", - 0, - null, - bidderCatalog, - fileSystem, - httpClient, - jacksonMapper)) + assertThatThrownBy( + () -> new VendorListServiceV1(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, + httpClient, jacksonMapper)) .isInstanceOf(RuntimeException.class) .hasMessage("read error"); } @@ -124,15 +99,9 @@ public void creationShouldFailsIfCannotReadAtLeastOneVendorListFile() { given(fileSystem.readFileBlocking(anyString())).willThrow(new RuntimeException("read error")); // then - assertThatThrownBy(() -> VendorListService.create( - CACHE_DIR, - "http://vendorlist/%s", - 0, - null, - bidderCatalog, - fileSystem, - httpClient, - jacksonMapper)) + assertThatThrownBy( + () -> new VendorListServiceV1(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, + httpClient, jacksonMapper)) .isInstanceOf(RuntimeException.class) .hasMessage("read error"); } @@ -144,15 +113,9 @@ public void creationShouldFailsIfAtLeastOneVendorListFileCannotBeParsed() { given(fileSystem.readFileBlocking(anyString())).willReturn(Buffer.buffer("invalid")); // then - assertThatThrownBy(() -> VendorListService.create( - CACHE_DIR, - "http://vendorlist/%s", - 0, - null, - bidderCatalog, - fileSystem, - httpClient, - jacksonMapper)) + assertThatThrownBy( + () -> new VendorListServiceV1(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, + httpClient, jacksonMapper)) .isInstanceOf(PreBidException.class) .hasMessage("Cannot parse vendor list from: invalid"); } @@ -213,7 +176,7 @@ public void shouldNotAskToSaveFileIfResponseBodyCouldNotBeParsed() { @Test public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidVendorListVersion() throws JsonProcessingException { // given - final VendorList vendorList = VendorList.of(null, null, null); + final VendorListV1 vendorList = VendorListV1.of(null, null, null); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); // when @@ -227,7 +190,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidVendorListVersion @Test public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidLastUpdated() throws JsonProcessingException { // given - final VendorList vendorList = VendorList.of(1, null, null); + final VendorListV1 vendorList = VendorListV1.of(1, null, null); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); // when @@ -241,7 +204,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidLastUpdated() thr @Test public void shouldNotAskToSaveFileIfFetchedVendorListHasNoVendors() throws JsonProcessingException { // given - final VendorList vendorList = VendorList.of(1, new Date(), null); + final VendorListV1 vendorList = VendorListV1.of(1, new Date(), null); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); // when @@ -255,7 +218,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasNoVendors() throws JsonP @Test public void shouldNotAskToSaveFileIfFetchedVendorListHasEmptyVendors() throws JsonProcessingException { // given - final VendorList vendorList = VendorList.of(1, new Date(), emptyList()); + final VendorListV1 vendorList = VendorListV1.of(1, new Date(), emptyList()); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); // when @@ -269,7 +232,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasEmptyVendors() throws Js @Test public void shouldNotAskToSaveFileIfFetchedVendorListHasAtLeastOneInvalidVendor() throws JsonProcessingException { // given - final VendorList vendorList = VendorList.of(1, new Date(), singletonList(Vendor.of(null, null, null))); + final VendorListV1 vendorList = VendorListV1.of(1, new Date(), singletonList(VendorV1.of(null, null, null))); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); // when @@ -305,12 +268,10 @@ public void shouldFailIfVendorListNotFound() { givenHttpClientProducesException(new RuntimeException()); // when - final Future future = vendorListService.forVersion(1); + final Future> future = vendorListService.forVersion(1); // then - assertThat(future.failed()).isTrue(); - assertThat(future.cause()) - .hasMessage("Vendor list for version 1 not fetched yet, try again later."); + assertThat(future).isFailed().hasMessage("Vendor list for version 1 not fetched yet, try again later."); } @Test @@ -323,19 +284,17 @@ public void shouldReturnVendorListFromCache() throws JsonProcessingException { // when vendorListService.forVersion(1); // populate cache - final Future>> future = vendorListService.forVersion(1); + final Future> result = vendorListService.forVersion(1); // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).hasSize(1) - .containsEntry(52, new HashSet<>(Arrays.asList(1, 2))); + assertThat(result).succeededWith(singletonMap(52, VendorV1.of(52, singleton(1), singleton(2)))); } @Test public void shouldKeepPurposesOnlyForKnownVendors() throws JsonProcessingException { // given - final VendorList vendorList = VendorList.of(1, new Date(), - asList(Vendor.of(52, singleton(1), singleton(2)), Vendor.of(42, singleton(1), singleton(2)))); + final VendorListV1 vendorList = VendorListV1.of(1, new Date(), + asList(VendorV1.of(52, singleton(1), singleton(2)), VendorV1.of(42, singleton(1), singleton(2)))); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); given(fileSystem.writeFile(anyString(), any(), any())) @@ -343,17 +302,15 @@ public void shouldKeepPurposesOnlyForKnownVendors() throws JsonProcessingExcepti // when vendorListService.forVersion(1); // populate cache - final Future>> future = vendorListService.forVersion(1); + final Future> future = vendorListService.forVersion(1); // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).hasSize(1) - .containsEntry(52, new HashSet<>(asList(1, 2))); + assertThat(future).succeededWith(singletonMap(52, VendorV1.of(52, singleton(1), singleton(2)))); } - private static VendorList givenVendorList() { - final Vendor vendor = Vendor.of(52, singleton(1), singleton(2)); - return VendorList.of(1, new Date(), singletonList(vendor)); + private static VendorListV1 givenVendorList() { + final VendorV1 vendor = VendorV1.of(52, singleton(1), singleton(2)); + return VendorListV1.of(1, new Date(), singletonList(vendor)); } private void givenHttpClientReturnsResponse(int statusCode, String response) { diff --git a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV2Test.java b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV2Test.java new file mode 100644 index 00000000000..af743d0f542 --- /dev/null +++ b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceV2Test.java @@ -0,0 +1,363 @@ +package org.prebid.server.privacy.gdpr.vendorlist; + +import com.fasterxml.jackson.core.JsonProcessingException; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.buffer.Buffer; +import io.vertx.core.file.FileSystem; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; +import org.prebid.server.VertxTest; +import org.prebid.server.bidder.BidderCatalog; +import org.prebid.server.exception.PreBidException; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorListV2; +import org.prebid.server.privacy.gdpr.vendorlist.proto.VendorV2; +import org.prebid.server.vertx.http.HttpClient; +import org.prebid.server.vertx.http.model.HttpClientResponse; + +import java.io.File; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; +import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.prebid.server.assertion.FutureAssertion.assertThat; + +public class VendorListServiceV2Test extends VertxTest { + private static final String CACHE_DIR = "/cache/dir"; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private FileSystem fileSystem; + @Mock + private HttpClient httpClient; + @Mock + private BidderCatalog bidderCatalog; + + private VendorListService vendorListService; + + @Before + public void setUp() { + given(fileSystem.existsBlocking(anyString())).willReturn(false); // always create cache dir + + given(bidderCatalog.knownVendorIds()).willReturn(singleton(52)); + + vendorListService = new VendorListServiceV2(CACHE_DIR, "http://vendorlist/{VERSION}", 0, null, bidderCatalog, fileSystem, httpClient, jacksonMapper); + } + + // Creation related tests + + @Test + public void creationShouldFailsIfCannotCreateCacheDir() { + // given + given(fileSystem.mkdirsBlocking(anyString())).willThrow(new RuntimeException("dir creation error")); + + // then + assertThatThrownBy(() -> new VendorListServiceV2(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, httpClient, jacksonMapper)) + .hasMessage("dir creation error"); + } + + @Test + public void creationShouldFailsIfCannotReadFiles() { + // given + given(fileSystem.readDirBlocking(anyString())).willThrow(new RuntimeException("read error")); + + // then + assertThatThrownBy(() -> new VendorListServiceV2(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, httpClient, jacksonMapper)) + .isInstanceOf(RuntimeException.class) + .hasMessage("read error"); + } + + @Test + public void creationShouldFailsIfCannotReadAtLeastOneVendorListFile() { + // given + given(fileSystem.readDirBlocking(anyString())).willReturn(singletonList("1.json")); + given(fileSystem.readFileBlocking(anyString())).willThrow(new RuntimeException("read error")); + + // then + assertThatThrownBy(() -> new VendorListServiceV2(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, httpClient, jacksonMapper)) + .isInstanceOf(RuntimeException.class) + .hasMessage("read error"); + } + + @Test + public void creationShouldFailsIfAtLeastOneVendorListFileCannotBeParsed() { + // given + given(fileSystem.readDirBlocking(anyString())).willReturn(singletonList("1.json")); + given(fileSystem.readFileBlocking(anyString())).willReturn(Buffer.buffer("invalid")); + + // then + assertThatThrownBy(() -> new VendorListServiceV2(CACHE_DIR, "http://vendorlist/%s", 0, null, bidderCatalog, fileSystem, httpClient, jacksonMapper)) + .isInstanceOf(PreBidException.class) + .hasMessage("Cannot parse vendor list from: invalid"); + } + + // Http related tests + + @Test + public void shouldPerformHttpRequestWithExpectedQueryIfVendorListNotFound() { + // given + givenHttpClientReturnsResponse(200, null); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(eq("http://vendorlist/1"), anyLong()); + } + + @Test + public void shouldNotAskToSaveFileIfReadingHttpResponseFails() { + // given + givenHttpClientProducesException(new RuntimeException("Response exception")); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfResponseCodeIsNot200() { + // given + givenHttpClientReturnsResponse(503, "response"); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfResponseBodyCouldNotBeParsed() { + // given + givenHttpClientReturnsResponse(200, "response"); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidVendorListVersion() throws JsonProcessingException { + // given + final VendorListV2 vendorList = VendorListV2.of(null, null, null); + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidLastUpdated() throws JsonProcessingException { + // given + final VendorListV2 vendorList = VendorListV2.of(1, null, null); + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfFetchedVendorListHasNoVendors() throws JsonProcessingException { + // given + final VendorListV2 vendorList = VendorListV2.of(1, new Date(), null); + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfFetchedVendorListHasEmptyVendors() throws JsonProcessingException { + // given + final VendorListV2 vendorList = VendorListV2.of(1, new Date(), emptyMap()); + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + @Test + public void shouldNotAskToSaveFileIfFetchedVendorListHasAtLeastOneInvalidVendor() throws JsonProcessingException { + // given + final VendorListV2 vendorList = VendorListV2.of(1, new Date(), singletonMap(1, VendorV2.builder().build())); + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); + + // when + vendorListService.forVersion(1); + + // then + verify(httpClient).get(anyString(), anyLong()); + verify(fileSystem, never()).writeFile(any(), any(), any()); + } + + // File system related tests + + @Test + public void shouldSaveFileWithExpectedPathAndContentIfVendorListNotFound() throws JsonProcessingException { + // given + final String vendorListAsString = mapper.writeValueAsString(givenVendorList()); + givenHttpClientReturnsResponse(200, vendorListAsString); + // generate file path to avoid conflicts with path separators in different OS + final String filePath = new File("/cache/dir/1.json").getPath(); + + // when + vendorListService.forVersion(1); + + // then + verify(fileSystem).writeFile(eq(filePath), eq(Buffer.buffer(vendorListAsString)), any()); + } + + // In-memory cache related tests + + @Test + public void shouldFailIfVendorListNotFound() { + // given + givenHttpClientProducesException(new RuntimeException()); + + // when + final Future> future = vendorListService.forVersion(1); + + // then + assertThat(future).isFailed().hasMessage("Vendor list for version 1 not fetched yet, try again later."); + } + + @Test + public void shouldReturnVendorListFromCache() throws JsonProcessingException { + // given + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(givenVendorList())); + + given(fileSystem.writeFile(anyString(), any(), any())) + .willAnswer(withSelfAndPassObjectToHandler(Future.succeededFuture())); + + // when + vendorListService.forVersion(1); // populate cache + final Future> result = vendorListService.forVersion(1); + + // then + assertThat(result).succeededWith(singletonMap( + 52, VendorV2.builder() + .id(52) + .purposes(singleton(1)) + .legIntPurposes(singleton(2)) + .flexiblePurposes(emptySet()) + .specialPurposes(emptySet()) + .features(emptySet()) + .specialFeatures(emptySet()) + .build())); + } + + @Test + public void shouldKeepPurposesForAllVendors() throws JsonProcessingException { + // given + final VendorV2 firstExternalV2 = VendorV2.builder() + .id(52) + .purposes(singleton(1)) + .legIntPurposes(singleton(2)) + .flexiblePurposes(emptySet()) + .specialPurposes(emptySet()) + .features(emptySet()) + .specialFeatures(emptySet()) + .build(); + final VendorV2 secondExternalV2 = VendorV2.builder() + .id(42) + .purposes(singleton(1)) + .legIntPurposes(singleton(2)) + .flexiblePurposes(emptySet()) + .specialPurposes(emptySet()) + .features(emptySet()) + .specialFeatures(emptySet()) + .build(); + final Map idToVendor = new HashMap<>(); + idToVendor.put(52, firstExternalV2); + idToVendor.put(42, secondExternalV2); + + final VendorListV2 vendorList = VendorListV2.of(1, new Date(), idToVendor); + givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); + + given(fileSystem.writeFile(anyString(), any(), any())) + .willAnswer(withSelfAndPassObjectToHandler(Future.succeededFuture())); + + // when + vendorListService.forVersion(1); // populate cache + final Future> future = vendorListService.forVersion(1); + + // then + assertThat(future).succeededWith(idToVendor); + } + + private static VendorListV2 givenVendorList() { + final VendorV2 vendor = VendorV2.builder() + .id(52) + .purposes(singleton(1)) + .legIntPurposes(singleton(2)) + .flexiblePurposes(emptySet()) + .specialPurposes(emptySet()) + .features(emptySet()) + .specialFeatures(emptySet()) + .build(); + return VendorListV2.of(1, new Date(), singletonMap(52, vendor)); + } + + private void givenHttpClientReturnsResponse(int statusCode, String response) { + given(httpClient.get(anyString(), anyLong())) + .willReturn(Future.succeededFuture(HttpClientResponse.of(statusCode, null, response))); + } + + private void givenHttpClientProducesException(Throwable throwable) { + given(httpClient.get(anyString(), anyLong())) + .willReturn(Future.failedFuture(throwable)); + } + + @SuppressWarnings("unchecked") + private static Answer withSelfAndPassObjectToHandler(T obj) { + return inv -> { + // invoking handler right away passing mock to it + ((Handler) inv.getArgument(2)).handle(obj); + return inv.getMock(); + }; + } +} diff --git a/src/test/java/org/prebid/server/settings/FileApplicationSettingsTest.java b/src/test/java/org/prebid/server/settings/FileApplicationSettingsTest.java index 2ebe91108b8..50ffa89a7f8 100644 --- a/src/test/java/org/prebid/server/settings/FileApplicationSettingsTest.java +++ b/src/test/java/org/prebid/server/settings/FileApplicationSettingsTest.java @@ -9,6 +9,13 @@ import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountGdprConfig; +import org.prebid.server.settings.model.EnforcePurpose; +import org.prebid.server.settings.model.Purpose; +import org.prebid.server.settings.model.PurposeOneTreatmentInterpretation; +import org.prebid.server.settings.model.Purposes; +import org.prebid.server.settings.model.SpecialFeature; +import org.prebid.server.settings.model.SpecialFeatures; import org.prebid.server.settings.model.StoredDataResult; import org.prebid.server.settings.model.StoredResponseDataResult; @@ -63,10 +70,29 @@ public void getAccountByIdShouldReturnEmptyWhenAccountsAreMissing() { @Test public void getAccountByIdShouldReturnPresentAccount() { // given - given(fileSystem.readFileBlocking(anyString())) - .willReturn(Buffer.buffer("accounts: [ { id: '123', priceGranularity: 'low', bannerCacheTtl: '100'," - + " videoCacheTtl : '100', eventsEnabled: 'true', enforceGdpr: 'true'," - + " analyticsSamplingFactor : '1'} ]")); + given(fileSystem.readFileBlocking(anyString())).willReturn(Buffer.buffer( + "accounts: [" + + "{" + + "id: '123'," + + "priceGranularity: 'low'," + + "bannerCacheTtl: '100'," + + "videoCacheTtl : '100'," + + "eventsEnabled: 'true'," + + "gdpr: {" + + "enabled: true," + + "purposes: {" + + "p1: {enforce-purpose: basic,enforce-vendors: false,vendor-exceptions: [rubicon, appnexus]}," + + "p2: {enforce-purpose: full,enforce-vendors: true,vendor-exceptions: [openx]}" + + "}," + + "special-features: {" + + "sf1: {enforce: true,vendor-exceptions: [rubicon, appnexus]}," + + "sf2: {enforce: false,vendor-exceptions: [openx]}" + + "}," + + "purpose-one-treatment-interpretation: access-allowed" + + "}," + + "analyticsSamplingFactor : '1'" + + "}" + + "]")); final FileApplicationSettings applicationSettings = new FileApplicationSettings(fileSystem, "ignore", "ignore", "ignore", "ignore"); @@ -82,9 +108,21 @@ public void getAccountByIdShouldReturnPresentAccount() { .bannerCacheTtl(100) .videoCacheTtl(100) .eventsEnabled(true) - .enforceGdpr(true) + .gdpr(AccountGdprConfig.builder() + .enabled(true) + .purposes(Purposes.builder() + .p1(Purpose.of(EnforcePurpose.basic, false, asList("rubicon", "appnexus"))) + .p2(Purpose.of(EnforcePurpose.full, true, singletonList("openx"))) + .build()) + .specialFeatures(SpecialFeatures.builder() + .sf1(SpecialFeature.of(true, asList("rubicon", "appnexus"))) + .sf2(SpecialFeature.of(false, singletonList("openx"))) + .build()) + .purposeOneTreatmentInterpretation(PurposeOneTreatmentInterpretation.accessAllowed) + .build()) .analyticsSamplingFactor(1) .build()); + } @Test diff --git a/src/test/java/org/prebid/server/settings/JdbcApplicationSettingsTest.java b/src/test/java/org/prebid/server/settings/JdbcApplicationSettingsTest.java index 725d351982d..dbf51f5005a 100644 --- a/src/test/java/org/prebid/server/settings/JdbcApplicationSettingsTest.java +++ b/src/test/java/org/prebid/server/settings/JdbcApplicationSettingsTest.java @@ -17,11 +17,13 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.prebid.server.VertxTest; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.metric.Metrics; import org.prebid.server.settings.model.Account; +import org.prebid.server.settings.model.AccountGdprConfig; import org.prebid.server.settings.model.StoredDataResult; import org.prebid.server.settings.model.StoredResponseDataResult; import org.prebid.server.vertx.jdbc.BasicJdbcClient; @@ -47,35 +49,37 @@ import static org.assertj.core.api.Assertions.assertThat; @RunWith(VertxUnitRunner.class) -public class JdbcApplicationSettingsTest { +public class JdbcApplicationSettingsTest extends VertxTest { @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); private static final String JDBC_URL = "jdbc:h2:mem:test"; - private static final String selectQuery = + private static final String SELECT_QUERY = "SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) " + "UNION ALL " + "SELECT impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%)"; - private static final String selectUnionQuery = + private static final String SELECT_UNION_QUERY = "SELECT reqid, requestData, 'request' as dataType FROM stored_requests WHERE reqid IN (%REQUEST_ID_LIST%) " + "UNION ALL " - + "SELECT reqid, requestData, 'request' as dataType FROM stored_requests2 WHERE reqid IN (%REQUEST_ID_LIST%) " + + "SELECT reqid, requestData, 'request' as dataType FROM stored_requests2 " + + "WHERE reqid IN (%REQUEST_ID_LIST%) " + "UNION ALL " + "SELECT impid, impData, 'imp' as dataType FROM stored_imps WHERE impid IN (%IMP_ID_LIST%) " + "UNION ALL " + "SELECT impid, impData, 'imp' as dataType FROM stored_imps2 WHERE impid IN (%IMP_ID_LIST%)"; - private static final String selectFromOneColumnTableQuery = "SELECT reqid FROM one_column_table WHERE reqid IN " + - "(%REQUEST_ID_LIST%)"; + private static final String SELECT_FROM_ONE_COLUMN_TABLE_QUERY = + "SELECT reqid FROM one_column_table WHERE reqid IN " + + "(%REQUEST_ID_LIST%)"; - private static final String selectResponseQuery = "SELECT responseId, responseData FROM stored_responses" + - " WHERE responseId IN (%RESPONSE_ID_LIST%)"; + private static final String SELECT_RESPONSE_QUERY = "SELECT responseId, responseData FROM stored_responses" + + " WHERE responseId IN (%RESPONSE_ID_LIST%)"; - private static final String selectOneColumnResponseQuery = "SELECT responseId FROM stored_responses" + - " WHERE responseId IN (%RESPONSE_ID_LIST%)"; + private static final String SELECT_ONE_COLUMN_RESPONSE_QUERY = "SELECT responseId FROM stored_responses" + + " WHERE responseId IN (%RESPONSE_ID_LIST%)"; private static Connection connection; @@ -92,11 +96,12 @@ public class JdbcApplicationSettingsTest { @BeforeClass public static void beforeClass() throws SQLException { connection = DriverManager.getConnection(JDBC_URL); - connection.createStatement().execute("CREATE TABLE accounts_account (id SERIAL PRIMARY KEY, uuid varchar(40) " + - "NOT NULL, price_granularity varchar(6), granularityMultiplier numeric(9,3), banner_cache_ttl INT, " + - "video_cache_ttl INT, events_enabled BIT, enforce_gdpr BIT, analytics_sampling_factor INT);"); - connection.createStatement().execute("CREATE TABLE s2sconfig_config (id SERIAL PRIMARY KEY, uuid varchar(40) " + - "NOT NULL, config varchar(512));"); + connection.createStatement().execute("CREATE TABLE accounts_account (id SERIAL PRIMARY KEY, " + + "uuid varchar(40) NOT NULL, price_granularity varchar(6), granularityMultiplier numeric(9,3), " + + "banner_cache_ttl INT, video_cache_ttl INT, events_enabled BIT, tcf_config varchar(512), " + + "analytics_sampling_factor INT);"); + connection.createStatement().execute("CREATE TABLE s2sconfig_config (id SERIAL PRIMARY KEY, uuid varchar(40) " + + "NOT NULL, config varchar(512));"); connection.createStatement().execute("CREATE TABLE stored_requests (id SERIAL PRIMARY KEY, reqid varchar(40) " + "NOT NULL, requestData varchar(512));"); connection.createStatement().execute("CREATE TABLE stored_requests2 (id SERIAL PRIMARY KEY, reqid varchar(40) " @@ -105,15 +110,17 @@ public static void beforeClass() throws SQLException { + "NOT NULL, impData varchar(512));"); connection.createStatement().execute("CREATE TABLE stored_imps2 (id SERIAL PRIMARY KEY, impid varchar(40) " + "NOT NULL, impData varchar(512));"); - connection.createStatement().execute("CREATE TABLE stored_responses (id SERIAL PRIMARY KEY, responseId varchar(40) " - + "NOT NULL, responseData varchar(512));"); + connection.createStatement().execute( + "CREATE TABLE stored_responses (id SERIAL PRIMARY KEY, responseId varchar(40) NOT NULL," + + " responseData varchar(512));"); connection.createStatement().execute("CREATE TABLE one_column_table (id SERIAL PRIMARY KEY, reqid varchar(40)" + " NOT NULL);"); - connection.createStatement().execute("insert into accounts_account " + - "(uuid, price_granularity, banner_cache_ttl, video_cache_ttl, events_enabled, enforce_gdpr, analytics_sampling_factor)" + - " values ('accountId','med', 100, 100, TRUE, TRUE, 1);"); - connection.createStatement().execute("insert into s2sconfig_config (uuid, config)" + - " values ('adUnitConfigId', 'config');"); + connection.createStatement().execute("insert into accounts_account " + + "(uuid, price_granularity, banner_cache_ttl, video_cache_ttl, events_enabled, tcf_config, " + + "analytics_sampling_factor)" + + " values ('accountId','med', 100, 100, TRUE, '{\"enabled\": true}', 1);"); + connection.createStatement().execute("insert into s2sconfig_config (uuid, config)" + + " values ('adUnitConfigId', 'config');"); connection.createStatement().execute("insert into stored_requests (reqid, requestData) values ('1','value1');"); connection.createStatement().execute("insert into stored_requests (reqid, requestData) values ('2','value2');"); connection.createStatement().execute( @@ -121,8 +128,10 @@ public static void beforeClass() throws SQLException { connection.createStatement().execute("insert into stored_imps (impid, impData) values ('4','value4');"); connection.createStatement().execute("insert into stored_imps (impid, impData) values ('5','value5');"); connection.createStatement().execute("insert into stored_imps2 (impid, impData) values ('6','value6');"); - connection.createStatement().execute("insert into stored_responses (responseId, responseData) values ('1','response1');"); - connection.createStatement().execute("insert into stored_responses (responseId, responseData) values ('2','response2');"); + connection.createStatement().execute("insert into stored_responses (responseId, responseData) " + + "values ('1','response1');"); + connection.createStatement().execute("insert into stored_responses (responseId, responseData) " + + "values ('2','response2');"); connection.createStatement().execute("insert into one_column_table (reqid) values ('3');"); } @@ -136,7 +145,8 @@ public void setUp() { vertx = Vertx.vertx(); clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); timeout = new TimeoutFactory(clock).create(5000L); - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectQuery, selectQuery, selectResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, SELECT_QUERY, SELECT_QUERY, + SELECT_RESPONSE_QUERY); } @After @@ -159,7 +169,9 @@ public void getAccountByIdShouldReturnAccountWithAllFieldsPopulated(TestContext .videoCacheTtl(100) .analyticsSamplingFactor(1) .eventsEnabled(true) - .enforceGdpr(true) + .gdpr(AccountGdprConfig.builder() + .enabled(true) + .build()) .build()); async.complete(); })); @@ -173,7 +185,8 @@ public void getAccountByIdShouldFailIfAccountNotFound(TestContext context) { // then final Async async = context.async(); future.setHandler(context.asyncAssertFailure(exception -> { - assertThat(exception).isInstanceOf(PreBidException.class).hasMessage("Not found"); + assertThat(exception).isInstanceOf(PreBidException.class) + .hasMessage("Account not found: non-existing"); async.complete(); })); } @@ -199,7 +212,8 @@ public void getAdUnitConfigByIdShouldFailIfConfigNotFound(TestContext context) { // then final Async async = context.async(); future.setHandler(context.asyncAssertFailure(exception -> { - assertThat(exception).isInstanceOf(PreBidException.class).hasMessage("Not found"); + assertThat(exception).isInstanceOf(PreBidException.class) + .hasMessage("AdUnitConfig not found: non-existing"); async.complete(); })); } @@ -267,8 +281,8 @@ public void getVideoStoredDataShouldReturnExpectedResult(TestContext context) { @Test public void getVideoStoredDataShouldReturnStoredRequests(TestContext context) { // given - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectUnionQuery, selectUnionQuery, - selectResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, SELECT_UNION_QUERY, + SELECT_UNION_QUERY, SELECT_RESPONSE_QUERY); // when final Future storedRequestResultFuture = @@ -295,8 +309,8 @@ public void getVideoStoredDataShouldReturnStoredRequests(TestContext context) { @Test public void getStoredDataUnionSelectByIdShouldReturnStoredRequests(TestContext context) { // given - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectUnionQuery, selectUnionQuery, - selectResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, SELECT_UNION_QUERY, + SELECT_UNION_QUERY, SELECT_RESPONSE_QUERY); // when final Future storedRequestResultFuture = @@ -323,8 +337,8 @@ public void getStoredDataUnionSelectByIdShouldReturnStoredRequests(TestContext c @Test public void getAmpStoredDataUnionSelectByIdShouldReturnStoredRequests(TestContext context) { // given - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectUnionQuery, selectUnionQuery, - selectResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, SELECT_UNION_QUERY, + SELECT_UNION_QUERY, SELECT_RESPONSE_QUERY); // when final Future storedRequestResultFuture = @@ -392,8 +406,8 @@ public void getAmpStoredDataShouldReturnResultWithErrorIfNoStoredRequestFound(Te @Test public void getStoredDataShouldReturnErrorIfResultContainsLessColumnsThanExpected(TestContext context) { // given - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectFromOneColumnTableQuery, - selectFromOneColumnTableQuery, selectResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, + SELECT_FROM_ONE_COLUMN_TABLE_QUERY, SELECT_FROM_ONE_COLUMN_TABLE_QUERY, SELECT_RESPONSE_QUERY); // when final Future storedRequestResultFuture = @@ -411,8 +425,9 @@ public void getStoredDataShouldReturnErrorIfResultContainsLessColumnsThanExpecte @Test public void getAmpStoredDataShouldReturnErrorIfResultContainsLessColumnsThanExpected(TestContext context) { // given - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectFromOneColumnTableQuery, - selectFromOneColumnTableQuery, selectResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, + SELECT_FROM_ONE_COLUMN_TABLE_QUERY, + SELECT_FROM_ONE_COLUMN_TABLE_QUERY, SELECT_RESPONSE_QUERY); // when final Future storedRequestResultFuture = @@ -510,8 +525,8 @@ public void getStoredResponseShouldReturnResultWithErrorIfNotAllStoredResponsesW @Test public void getStoredResponseShouldReturnErrorIfResultContainsLessColumnsThanExpected(TestContext context) { // given - jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), selectQuery, selectQuery, - selectOneColumnResponseQuery); + jdbcApplicationSettings = new JdbcApplicationSettings(jdbcClient(), jacksonMapper, SELECT_QUERY, SELECT_QUERY, + SELECT_ONE_COLUMN_RESPONSE_QUERY); // when final Future storedResponseDataResultFuture = diff --git a/src/test/java/org/prebid/server/settings/service/HttpPeriodicRefreshServiceTest.java b/src/test/java/org/prebid/server/settings/service/HttpPeriodicRefreshServiceTest.java index d82aa513e6d..3f62fb2d073 100644 --- a/src/test/java/org/prebid/server/settings/service/HttpPeriodicRefreshServiceTest.java +++ b/src/test/java/org/prebid/server/settings/service/HttpPeriodicRefreshServiceTest.java @@ -185,4 +185,4 @@ private static Answer withSelfAndPassObjectToHandler(T... objects) { return 0L; }; } -} \ No newline at end of file +} diff --git a/src/test/java/org/prebid/server/util/HttpUtilTest.java b/src/test/java/org/prebid/server/util/HttpUtilTest.java index c3696bd30e8..77242c33ca2 100644 --- a/src/test/java/org/prebid/server/util/HttpUtilTest.java +++ b/src/test/java/org/prebid/server/util/HttpUtilTest.java @@ -1,7 +1,7 @@ package org.prebid.server.util; import io.vertx.core.MultiMap; -import io.vertx.ext.web.Cookie; +import io.vertx.core.http.Cookie; import io.vertx.ext.web.RoutingContext; import org.junit.Rule; import org.junit.Test; @@ -11,7 +11,7 @@ import java.util.Map; -import static java.util.Collections.singleton; +import static java.util.Collections.singletonMap; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.entry; @@ -124,7 +124,7 @@ public void getDomainFromUrlShouldReturnNullIfUrlIsMalformed() { @Test public void cookiesAsMapShouldReturnExpectedResult() { // given - given(routingContext.cookies()).willReturn(singleton(Cookie.cookie("name", "value"))); + given(routingContext.cookieMap()).willReturn(singletonMap("name", Cookie.cookie("name", "value"))); // when final Map cookies = HttpUtil.cookiesAsMap(routingContext); diff --git a/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java b/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java index d42cd97e9d5..96e718ad11d 100644 --- a/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java +++ b/src/test/java/org/prebid/server/validation/BidderParamValidatorTest.java @@ -304,7 +304,6 @@ public void validateShouldReturnValidationMessagesWhenOpenxExtNotValid() { assertThat(messages.size()).isEqualTo(1); } - @Test public void validateShouldNotReturnValidationMessagesWhenEplanningImpExtIsOk() { // given diff --git a/src/test/java/org/prebid/server/validation/RequestValidatorTest.java b/src/test/java/org/prebid/server/validation/RequestValidatorTest.java index 8a5799d1645..67b93e77230 100644 --- a/src/test/java/org/prebid/server/validation/RequestValidatorTest.java +++ b/src/test/java/org/prebid/server/validation/RequestValidatorTest.java @@ -1315,9 +1315,12 @@ public void validateShouldReturnValidationMessageWhenCantParseTargetingPriceGran // given final BidRequest bidRequest = validBidRequestBuilder() .ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() - .targeting(ExtRequestTargeting.builder().pricegranularity(new TextNode("pricegranularity")).build()) + .targeting(ExtRequestTargeting.builder() + .pricegranularity(new TextNode("pricegranularity")) + .build()) .build()))) .build(); + // when final ValidationResult result = requestValidator.validate(bidRequest); @@ -1336,6 +1339,7 @@ public void validateShouldReturnValidationMessageWhenRangesAreEmptyList() { .build()) .build()))) .build(); + // when final ValidationResult result = requestValidator.validate(bidRequest); @@ -1356,6 +1360,7 @@ public void validateShouldReturnValidationMessageWhenIncrementIsZero() { .build()) .build()))) .build(); + // when final ValidationResult result = requestValidator.validate(bidRequest); @@ -1370,8 +1375,10 @@ public void validateShouldReturnValidationMessageWhenIncrementIsNegative() { final BidRequest bidRequest = validBidRequestBuilder() .ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(ExtRequestTargeting.builder() - .pricegranularity(mapper.valueToTree(ExtPriceGranularity.of(2, - singletonList(ExtGranularityRange.of(BigDecimal.valueOf(5), BigDecimal.valueOf(-1)))))) + .pricegranularity(mapper.valueToTree(ExtPriceGranularity.of( + 2, + singletonList(ExtGranularityRange.of( + BigDecimal.valueOf(5), BigDecimal.valueOf(-1)))))) .build()) .build()))) .build(); @@ -1416,6 +1423,7 @@ public void validateShouldReturnValidationMessageWhenMediaTypePriceGranularityTy .build()) .build()))) .build(); + // when final ValidationResult result = requestValidator.validate(bidRequest); @@ -1430,8 +1438,11 @@ public void validateShouldReturnValidationMessageWithCorrectMediaType() { final ExtPriceGranularity priceGranularity = ExtPriceGranularity.of(1, singletonList( ExtGranularityRange.of(BigDecimal.valueOf(5), BigDecimal.valueOf(0.01)))); final ExtMediaTypePriceGranularity mediaTypePriceGranuality = ExtMediaTypePriceGranularity.of( - mapper.valueToTree(ExtPriceGranularity.of(-1, singletonList(ExtGranularityRange.of(BigDecimal.valueOf(5), - BigDecimal.valueOf(1))))), null, null); + mapper.valueToTree(ExtPriceGranularity.of( + -1, + singletonList(ExtGranularityRange.of(BigDecimal.valueOf(5), BigDecimal.valueOf(1))))), + null, + null); final BidRequest bidRequest = validBidRequestBuilder() .ext(mapper.valueToTree(ExtBidRequest.of(ExtRequestPrebid.builder() .targeting(ExtRequestTargeting.builder() @@ -1440,6 +1451,7 @@ public void validateShouldReturnValidationMessageWithCorrectMediaType() { .build()) .build()))) .build(); + // when final ValidationResult result = requestValidator.validate(bidRequest); @@ -1462,6 +1474,7 @@ public void validateShouldReturnValidationMessageForInvalidTargeting() { .build()) .build()))) .build(); + // when final ValidationResult result = requestValidator.validate(bidRequest); @@ -1663,7 +1676,7 @@ public void validateShouldReturnValidationMessageWhenEidHasEmptySource() { // then assertThat(result.getErrors()).hasSize(1) - .containsOnly("request.user.ext.eids[0].source missing required field: \"source\""); + .containsOnly("request.user.ext.eids[0] missing required field: \"source\""); } @Test @@ -1818,7 +1831,7 @@ public void validateShouldReturnValidationResultWithErrorsWhenRegsExtIsNotValidJ } @Test - public void validateShouldReturnValidationResultWithErrorsWhenCcpaIsNotValid(){ + public void validateShouldReturnValidationResultWithErrorsWhenCcpaIsNotValid() { // given final ObjectNode ext = mapper.createObjectNode().put("us_privacy", "invalid"); final BidRequest bidRequest = validBidRequestBuilder().regs(Regs.of(null, ext)).build(); @@ -1892,7 +1905,7 @@ public void validateShouldReturnValidationResultWithErrorWhenContextSubTypeOutOf } @Test - public void validateShouldReturnValidationResultWithErrorWhenContextSubTypeAndContextTypeOutOfPossibleContentValuesRange() + public void validateShouldReturnErrorWhenContextSubTypeAndContextTypeOutOfPossibleContentValuesRange() throws JsonProcessingException { // given final BidRequest bidRequest = givenBidRequestWithNativeRequest(nativeReqCustomizer -> @@ -1909,7 +1922,7 @@ public void validateShouldReturnValidationResultWithErrorWhenContextSubTypeAndCo } @Test - public void validateShouldReturnValidationResultWithErrorWhenContextSubTypeAndContextTypeOutOfPossibleSocialValuesRange() + public void validateShouldReturnErrorWhenContextSubTypeAndContextTypeOutOfPossibleSocialValuesRange() throws JsonProcessingException { // given final BidRequest bidRequest = givenBidRequestWithNativeRequest(nativeReqCustomizer -> @@ -1926,7 +1939,7 @@ public void validateShouldReturnValidationResultWithErrorWhenContextSubTypeAndCo } @Test - public void validateShouldReturnValidationResultWithErrorWhenContextSubTypeAndContextTypeOutOfPossibleProductValuesRange() + public void validateShouldReturnErrorWhenContextSubTypeAndContextTypeOutOfPossibleProductValuesRange() throws JsonProcessingException { // given final BidRequest bidRequest = givenBidRequestWithNativeRequest(nativeReqCustomizer -> @@ -2142,7 +2155,6 @@ public void validateShouldReturnValidationResultWithErrorWhenIndividualAssetHasT + " {title, img, video, data}"); } - @Test public void validateShouldReturnValidationResultWithErrorWhenIndividualAssetHasTitleAndData() throws JsonProcessingException { @@ -2201,7 +2213,6 @@ public void validateShouldReturnValidationResultWithErrorWhenIndividualAssetHasI "request.imp[0].native.request.assets[0] must define at most one of {title, img, video, data}"); } - @Test public void validateShouldReturnValidationResultWithErrorWhenHasZeroTitleLen() throws JsonProcessingException { // given @@ -2413,8 +2424,8 @@ public void validateShouldReturnEmptyValidationMessagesWhenNativeVideoIsValid() // then assertThat(result.getErrors()).hasSize(1) .containsOnly( - "request.imp[0].native.request.assets[0].video.protocols[0] must be in the range [1, 10]. Got" + - " 0"); + "request.imp[0].native.request.assets[0].video.protocols[0] must be in the range [1, 10]." + + " Got 0"); } @Test @@ -2485,7 +2496,6 @@ public void validateShouldReturnValidationMessageWhenAdjustmentFactorNegative() "request.ext.prebid.bidadjustmentfactors.rubicon must be a positive number. Got -1.100000"); } - @Test public void validateShouldReturnValidationMessageWhenBidderUnknown() { // given @@ -2558,14 +2568,14 @@ public void validateShouldReturnValidationMessageWhenRequestHaveDuplicatedImpIds .containsOnly("request.imp[0].id and request.imp[1].id are both \"11\". Imp IDs must be unique."); } - private BidRequest givenBidRequest( + private static BidRequest givenBidRequest( Function nativeCustomizer) { return validBidRequestBuilder() .imp(singletonList(validImpBuilder() .xNative(nativeCustomizer.apply(Native.builder()).build()).build())).build(); } - private BidRequest givenBidRequestWithNativeRequest( + private static BidRequest givenBidRequestWithNativeRequest( Function nativeRequestCustomizer) throws JsonProcessingException { return validBidRequestBuilder() diff --git a/src/test/java/org/prebid/server/validation/VideoRequestValidatorTest.java b/src/test/java/org/prebid/server/validation/VideoRequestValidatorTest.java index 1f32b7f237d..4d62b564611 100644 --- a/src/test/java/org/prebid/server/validation/VideoRequestValidatorTest.java +++ b/src/test/java/org/prebid/server/validation/VideoRequestValidatorTest.java @@ -12,12 +12,12 @@ import org.prebid.server.auction.model.WithPodErrors; import org.prebid.server.exception.InvalidRequestException; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.UnaryOperator; +import static java.util.Arrays.asList; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; import static java.util.function.UnaryOperator.identity; @@ -131,7 +131,8 @@ public void validateStoredBidRequestShouldThrowExceptionWhenAppHaveBlacklistedAc // when and then assertThatExceptionOfType(InvalidRequestException.class) - .isThrownBy(() -> videoRequestValidator.validateStoredBidRequest(requestVideo, false, singletonList("BAD"))) + .isThrownBy(() -> videoRequestValidator.validateStoredBidRequest( + requestVideo, false, singletonList("BAD"))) .withMessage("Prebid-server does not process requests from App ID: BAD"); } @@ -144,7 +145,8 @@ public void validateStoredBidRequestShouldThrowExceptionWhenAppIdAndBundleIsEmpt // when and then assertThatExceptionOfType(InvalidRequestException.class) - .isThrownBy(() -> videoRequestValidator.validateStoredBidRequest(requestVideo, false, singletonList("BAD"))) + .isThrownBy(() -> videoRequestValidator.validateStoredBidRequest( + requestVideo, false, singletonList("BAD"))) .withMessage("request.app missing required field: id or bundle"); } @@ -199,10 +201,19 @@ public void validPodsShouldReturnExpectedResult() { final Pod notStoredPod = Pod.of(7, 1, "conf19"); final Pod normalPod = Pod.of(10, 1, "conf10"); - final Podconfig podConfig = Podconfig.builder().pods(Arrays.asList(pod, duplicatedPod, negativeDurationPod, missingConfigIdPod, - negativeIdPod, notStoredPod, normalPod, missingDurationPod)).build(); + final Podconfig podConfig = Podconfig.builder() + .pods(asList( + pod, + duplicatedPod, + negativeDurationPod, + missingConfigIdPod, + negativeIdPod, + notStoredPod, + normalPod, + missingDurationPod)) + .build(); - final Set storedIds = new HashSet<>(Arrays.asList("cnf1", "cnf2", "cnf3", "cnf4", "cnf5", "conf10")); + final Set storedIds = new HashSet<>(asList("cnf1", "cnf2", "cnf3", "cnf4", "cnf5", "conf10")); // when final WithPodErrors> result = videoRequestValidator.validPods(podConfig, storedIds); @@ -211,15 +222,30 @@ public void validPodsShouldReturnExpectedResult() { assertThat(result.getData()).containsOnly(normalPod); assertThat(result.getPodErrors()).containsOnly( PodError.of(1, 1, singletonList("request duplicated required field: PodConfig.Pods.PodId, Pod id: 1")), - PodError.of(5, 2, singletonList("request incorrect required field: PodConfig.Pods.AdPodDurationSec is negative, Pod index: 2")), - PodError.of(6, 3, Arrays.asList( - "request incorrect required field: PodConfig.Pods.AdPodDurationSec is negative, Pod index: 3", - "request missing or incorrect required field: PodConfig.Pods.ConfigId, Pod index: 3")), - PodError.of(-100, 4, singletonList("request missing required field: PodConfig.Pods.PodId, Pod index: 4")), - PodError.of(-100, 7, Arrays.asList( - "request duplicated required field: PodConfig.Pods.PodId, Pod id: -100", - "request missing required field: PodConfig.Pods.PodId, Pod index: 7", - "request missing or incorrect required field: PodConfig.Pods.AdPodDurationSec, Pod index: 7")), + PodError.of( + 5, + 2, + singletonList("request incorrect required field: PodConfig.Pods.AdPodDurationSec is negative," + + " Pod index: 2")), + PodError.of( + 6, + 3, + asList( + "request incorrect required field: PodConfig.Pods.AdPodDurationSec is negative, Pod " + + "index: 3", + "request missing or incorrect required field: PodConfig.Pods.ConfigId, Pod index: 3")), + PodError.of( + -100, + 4, + singletonList("request missing required field: PodConfig.Pods.PodId, Pod index: 4")), + PodError.of( + -100, + 7, + asList( + "request duplicated required field: PodConfig.Pods.PodId, Pod id: -100", + "request missing required field: PodConfig.Pods.PodId, Pod index: 7", + "request missing or incorrect required field: PodConfig.Pods.AdPodDurationSec, Pod " + + "index: 7")), PodError.of(7, 5, singletonList("unable to load Pod id: 7"))); } @@ -231,11 +257,10 @@ private BidRequestVideo givenBidRequestVideo( .storedrequestid("storedrequestid") .podconfig(podconfigCustomizer.apply(Podconfig.builder() .pods(singletonList(Pod.of(123, 100, "1"))) - .durationRangeSec(Arrays.asList(200, 100))) + .durationRangeSec(asList(200, 100))) .build()) .site(Site.builder().id("siteId").build()) .video(VideoVideo.builder().mimes(singletonList("mime")).protocols(singletonList(123)).build())) .build(); } - } diff --git a/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java b/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java index 9b1164442e1..5402bf37c40 100644 --- a/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java +++ b/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java @@ -2,6 +2,7 @@ import io.vertx.core.Future; import io.vertx.core.Handler; +import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.ext.unit.Async; import io.vertx.ext.unit.TestContext; @@ -136,14 +137,14 @@ public void executeShouldFailsWithOriginalExceptionIfOpeningIntervalExceeds(Test } private Future executeWithSuccess(TestContext context, String result) { - return execute(context, operationFuture -> operationFuture.complete(result)); + return execute(context, operationPromise -> operationPromise.complete(result)); } private Future executeWithFail(TestContext context, String errorMessage) { - return execute(context, operationFuture -> operationFuture.fail(new RuntimeException(errorMessage))); + return execute(context, operationPromise -> operationPromise.fail(new RuntimeException(errorMessage))); } - private Future execute(TestContext context, Handler> handler) { + private Future execute(TestContext context, Handler> handler) { final Future future = circuitBreaker.execute(handler); final Async async = context.async(); diff --git a/src/test/resources/org/prebid/server/it/amp/test-appnexus-bid-request.json b/src/test/resources/org/prebid/server/it/amp/test-appnexus-bid-request.json index 19b183d8997..f3f18bdf9ee 100644 --- a/src/test/resources/org/prebid/server/it/amp/test-appnexus-bid-request.json +++ b/src/test/resources/org/prebid/server/it/amp/test-appnexus-bid-request.json @@ -52,6 +52,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -70,22 +80,13 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, "cache": { "bids": {} - } + }, + "auctiontimestamp": 1000 } } } diff --git a/src/test/resources/org/prebid/server/it/auction/adform/test-auction-adform-request.json b/src/test/resources/org/prebid/server/it/auction/adform/test-auction-adform-request.json index f4512277dbf..0413c04ffe4 100644 --- a/src/test/resources/org/prebid/server/it/auction/adform/test-auction-adform-request.json +++ b/src/test/resources/org/prebid/server/it/auction/adform/test-auction-adform-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode12", diff --git a/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-request.json b/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-request.json index 140814dcf52..2e66d02422d 100644 --- a/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-request.json +++ b/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode10", diff --git a/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-response.json b/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-response.json index 54ec99241ba..fec15683456 100644 --- a/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-response.json +++ b/src/test/resources/org/prebid/server/it/auction/conversant/test-auction-conversant-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ conversant.exchange_uri }}", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode10\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250,\"pos\":28},\"displaymanager\":\"prebid-s2s\",\"displaymanagerver\":\"1.0.1\",\"tagid\":\"tagId1\",\"bidfloor\":7.32,\"secure\":42}],\"site\":{\"id\":\"siteId1\",\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"mobile\":64},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"CV-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode10\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250,\"pos\":28},\"displaymanager\":\"prebid-s2s\",\"displaymanagerver\":\"1.0.1\",\"tagid\":\"tagId1\",\"bidfloor\":7.32,\"secure\":42}],\"site\":{\"id\":\"siteId1\",\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"mobile\":64},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"CV-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId10\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode10\",\"price\":5.78,\"adm\":\"adm10\",\"crid\":\"crid10\",\"dealid\":\"dealId10\",\"w\":300,\"h\":250}],\"seat\":\"seatId10\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/conversant/test-conversant-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/conversant/test-conversant-bid-request-1.json index b6cd9a171ed..a7bedd264ce 100644 --- a/src/test/resources/org/prebid/server/it/auction/conversant/test-conversant-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/conversant/test-conversant-bid-request-1.json @@ -52,7 +52,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-request.json b/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-request.json index d41b6ec78e8..23849c265da 100644 --- a/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-request.json +++ b/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode4", diff --git a/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-response.json b/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-response.json index 61739d0a783..33df9613410 100644 --- a/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-response.json +++ b/src/test/resources/org/prebid/server/it/auction/districtm/test-auction-districtm-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ appnexus.exchange_uri }}?member_id=member1", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode4\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"skipmin\":0,\"skipafter\":0,\"playbackmethod\":[1]},\"tagid\":\"invCode1\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"placement_id\":9848285,\"keywords\":\"k1=v1,k1=v2\",\"traffic_source_code\":\"trafficSourceCode1\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"id\":\"12345\",\"buyeruid\":\"12345\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode4\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"playbackmethod\":[1]},\"tagid\":\"invCode1\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"placement_id\":9848285,\"keywords\":\"k1=v1,k1=v2\",\"traffic_source_code\":\"trafficSourceCode1\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"id\":\"12345\",\"buyeruid\":\"12345\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId4\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode4\",\"price\":5.78,\"adm\":\"adm4\",\"crid\":\"crid4\",\"dealid\":\"dealId4\",\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"bid_ad_type\":1}}}],\"seat\":\"seatId4\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/districtm/test-districtm-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/districtm/test-districtm-bid-request-1.json index 11b7bb65ee8..5acca6e19ea 100644 --- a/src/test/resources/org/prebid/server/it/auction/districtm/test-districtm-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/districtm/test-districtm-bid-request-1.json @@ -15,8 +15,6 @@ "w": 300, "h": 250, "startdelay": 5, - "skipmin": 0, - "skipafter": 0, "playbackmethod": [ 1 ] @@ -38,11 +36,11 @@ }, "device": { "ua": "userAgent", + "dnt": 10, "ip": "193.168.244.1", "pxratio": 4.2, "language": "en", - "ifa": "ifaId", - "dnt": 10 + "ifa": "ifaId" }, "user": { "id": "12345", @@ -56,15 +54,15 @@ } } }, - "regs": { - "ext": { - "gdpr": 1 - } - }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" + }, + "regs": { + "ext": { + "gdpr": 1 + } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-request.json b/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-request.json index eea052c9e4d..1df884d2720 100644 --- a/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-request.json +++ b/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode7", diff --git a/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-response.json b/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-response.json index cc89cecd2b2..398840b9c3e 100644 --- a/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-response.json +++ b/src/test/resources/org/prebid/server/it/auction/ix/test-auction-ix-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ ix.exchange_uri }}", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode7\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250},\"tagid\":\"adUnitCode7\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"486\"}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"IE-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode7\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250},\"tagid\":\"adUnitCode7\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"486\"}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"IE-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId7\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode7\",\"price\":5.78,\"adm\":\"adm7\",\"crid\":\"crid7\",\"dealid\":\"dealId7\",\"w\":300,\"h\":250}],\"seat\":\"seatId7\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/ix/test-ix-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/ix/test-ix-bid-request-1.json index 695d695223d..311b3bd37fd 100644 --- a/src/test/resources/org/prebid/server/it/auction/ix/test-ix-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/ix/test-ix-bid-request-1.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-request.json b/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-request.json index 19c2a36c428..c05eadda14c 100644 --- a/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-request.json +++ b/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode8", diff --git a/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-response.json b/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-response.json index 91e4545afe7..2ba37a52718 100644 --- a/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-response.json +++ b/src/test/resources/org/prebid/server/it/auction/lifestreet/test-auction-lifestreet-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ lifestreet.exchange_uri }}", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode8\",\"banner\":{\"w\":300,\"h\":250},\"tagid\":\"slot.tag1\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"LS-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode8\",\"banner\":{\"w\":300,\"h\":250},\"tagid\":\"slot.tag1\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"LS-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId8\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode8\",\"price\":5.78,\"adm\":\"adm8\",\"crid\":\"crid8\",\"dealid\":\"dealId8\",\"w\":300,\"h\":250}],\"seat\":\"seatId8\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/lifestreet/test-lifestreet-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/lifestreet/test-lifestreet-bid-request-1.json index acdff453ed5..b6351131bbe 100644 --- a/src/test/resources/org/prebid/server/it/auction/lifestreet/test-lifestreet-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/lifestreet/test-lifestreet-bid-request-1.json @@ -39,7 +39,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-request.json b/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-request.json index 4090c8c2d85..2befcd7a7e4 100644 --- a/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-request.json +++ b/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode9", diff --git a/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-response.json b/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-response.json index 7e69c6dc3bf..e8c3ab7e747 100644 --- a/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-response.json +++ b/src/test/resources/org/prebid/server/it/auction/pubmatic/test-auction-pubmatic-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ pubmatic.exchange_uri }}", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode9\",\"banner\":{\"format\":[{\"w\":200,\"h\":150}],\"w\":300,\"h\":250},\"tagid\":\"slot9\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId9\",\"domain\":\"example.com\"}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"PM-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode9\",\"banner\":{\"format\":[{\"w\":200,\"h\":150}],\"w\":300,\"h\":250},\"tagid\":\"slot9\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId9\",\"domain\":\"example.com\"}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"PM-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId9\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode9\",\"price\":5.78,\"adm\":\"adm9\",\"crid\":\"crid9\",\"dealid\":\"dealId9\",\"w\":300,\"h\":250}],\"seat\":\"seatId9\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/pubmatic/test-pubmatic-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/pubmatic/test-pubmatic-bid-request-1.json index 685242d2c46..f42d82b05d8 100644 --- a/src/test/resources/org/prebid/server/it/auction/pubmatic/test-pubmatic-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/pubmatic/test-pubmatic-bid-request-1.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-request.json b/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-request.json index a7474d46a57..ef099a0f325 100644 --- a/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-request.json +++ b/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode6", diff --git a/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-response.json b/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-response.json index 4213565d8d7..1cc5f52f719 100644 --- a/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-response.json +++ b/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-auction-pulsepoint-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ pulsepoint.exchange_uri }}", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode6\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250},\"tagid\":\"456\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"123\"}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"PP-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode6\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250},\"tagid\":\"456\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"123\"}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"PP-UID\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId6\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode6\",\"price\":5.78,\"adm\":\"adm6\",\"crid\":\"crid6\",\"dealid\":\"dealId6\",\"w\":300,\"h\":250}],\"seat\":\"seatId6\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-pulsepoint-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-pulsepoint-bid-request-1.json index 83c0e0632cd..04973cac104 100644 --- a/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-pulsepoint-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/pulsepoint/test-pulsepoint-bid-request-1.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-appnexus-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-appnexus-bid-request-1.json index 11b7bb65ee8..5acca6e19ea 100644 --- a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-appnexus-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-appnexus-bid-request-1.json @@ -15,8 +15,6 @@ "w": 300, "h": 250, "startdelay": 5, - "skipmin": 0, - "skipafter": 0, "playbackmethod": [ 1 ] @@ -38,11 +36,11 @@ }, "device": { "ua": "userAgent", + "dnt": 10, "ip": "193.168.244.1", "pxratio": 4.2, "language": "en", - "ifa": "ifaId", - "dnt": 10 + "ifa": "ifaId" }, "user": { "id": "12345", @@ -56,15 +54,15 @@ } } }, - "regs": { - "ext": { - "gdpr": 1 - } - }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" + }, + "regs": { + "ext": { + "gdpr": 1 + } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-request.json b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-request.json index 836e24a7c1d..0ec5c77e558 100644 --- a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-request.json +++ b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode1", diff --git a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-response.json b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-response.json index 02db48ae70e..0d599bcb5e4 100644 --- a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-response.json +++ b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-auction-rubicon-appnexus-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ appnexus.exchange_uri }}?member_id=member1", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode4\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"skipmin\":0,\"skipafter\":0,\"playbackmethod\":[1]},\"tagid\":\"invCode1\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"placement_id\":9848285,\"keywords\":\"k1=v1,k1=v2\",\"traffic_source_code\":\"trafficSourceCode1\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"id\":\"12345\",\"buyeruid\":\"12345\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode4\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"playbackmethod\":[1]},\"tagid\":\"invCode1\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"placement_id\":9848285,\"keywords\":\"k1=v1,k1=v2\",\"traffic_source_code\":\"trafficSourceCode1\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"id\":\"12345\",\"buyeruid\":\"12345\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId4\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode4\",\"price\":5.78,\"adm\":\"adm4\",\"crid\":\"crid4\",\"dealid\":\"dealId4\",\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"bid_ad_type\":1}}}],\"seat\":\"seatId4\",\"group\":0}]}", "status_code": 200 } @@ -22,19 +22,19 @@ "debug": [ { "request_uri": "{{ rubicon.exchange_uri }}?tk_xint=rp-pbs", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode1\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"skipmin\":0,\"skipafter\":0,\"playbackmethod\":[1],\"ext\":{\"skip\":5,\"skipdelay\":1,\"rp\":{\"size_id\":15}}},\"ext\":{\"rp\":{\"zone_id\":4001,\"target\":{\"rating\":[\"5-star\"],\"prodtype\":[\"tech\"]},\"track\":{\"mint\":\"prebid\",\"mint_version\":\"source1_platform1_version1\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":2001}}},\"ext\":{\"rp\":{\"site_id\":3001}}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"id\":\"12345\",\"buyeruid\":\"J5VLCWQP-26-CWFT\",\"ext\":{\"consent\":\"consent1\",\"rp\":{\"target\":{\"ucat\":[\"new\"],\"search\":[\"iphone\"]}}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode1\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"playbackmethod\":[1],\"ext\":{\"skip\":5,\"skipdelay\":1,\"rp\":{\"size_id\":15}}},\"ext\":{\"rp\":{\"zone_id\":4001,\"target\":{\"rating\":[\"5-star\"],\"prodtype\":[\"tech\"]},\"track\":{\"mint\":\"prebid\",\"mint_version\":\"source1_platform1_version1\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":2001}}},\"ext\":{\"rp\":{\"site_id\":3001}}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"id\":\"12345\",\"buyeruid\":\"J5VLCWQP-26-CWFT\",\"ext\":{\"consent\":\"consent1\",\"rp\":{\"target\":{\"ucat\":[\"new\"],\"search\":[\"iphone\"]}}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId1\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode1\",\"price\":8.43,\"adm\":\"adm1\",\"crid\":\"crid1\",\"dealid\":\"dealId1\",\"w\":300,\"h\":250,\"ext\":{\"rp\":{\"targeting\":[{\"key\":\"rpfl_1001\",\"values\":[\"2_tier0100\"]}]}}}],\"seat\":\"seatId1\",\"group\":0}]}", "status_code": 200 }, { "request_uri": "{{ rubicon.exchange_uri }}?tk_xint=rp-pbs", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode2\",\"banner\":{\"format\":[{\"w\":300,\"h\":600}],\"w\":300,\"h\":600,\"ext\":{\"rp\":{\"size_id\":10,\"mime\":\"text/html\"}}},\"ext\":{\"rp\":{\"zone_id\":7001,\"track\":{\"mint\":\"prebid\",\"mint_version\":\"source1_platform1_version1\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":5001}}},\"ext\":{\"rp\":{\"site_id\":6001}}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"id\":\"12345\",\"buyeruid\":\"J5VLCWQP-26-CWFT\",\"ext\":{\"consent\":\"consent1\"}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode2\",\"banner\":{\"format\":[{\"w\":300,\"h\":600}],\"w\":300,\"h\":600,\"ext\":{\"rp\":{\"size_id\":10,\"mime\":\"text/html\"}}},\"ext\":{\"rp\":{\"zone_id\":7001,\"track\":{\"mint\":\"prebid\",\"mint_version\":\"source1_platform1_version1\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":5001}}},\"ext\":{\"rp\":{\"site_id\":6001}}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"id\":\"12345\",\"buyeruid\":\"J5VLCWQP-26-CWFT\",\"ext\":{\"consent\":\"consent1\"}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId2\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode2\",\"price\":4.26,\"adm\":\"adm2\",\"crid\":\"crid2\",\"dealid\":\"dealId2\",\"w\":300,\"h\":600}],\"seat\":\"seatId2\",\"group\":0}]}", "status_code": 200 }, { "request_uri": "{{ rubicon.exchange_uri }}?tk_xint=rp-pbs", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode3\",\"banner\":{\"format\":[{\"w\":768,\"h\":1024},{\"w\":980,\"h\":400}],\"w\":768,\"h\":1024,\"ext\":{\"rp\":{\"size_id\":80,\"alt_size_ids\":[102],\"mime\":\"text/html\"}}},\"ext\":{\"rp\":{\"zone_id\":4001,\"track\":{\"mint\":\"prebid\",\"mint_version\":\"source1_platform1_version1\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":2001}}},\"ext\":{\"rp\":{\"site_id\":3001}}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"id\":\"12345\",\"buyeruid\":\"J5VLCWQP-26-CWFT\",\"ext\":{\"consent\":\"consent1\"}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode3\",\"banner\":{\"format\":[{\"w\":768,\"h\":1024},{\"w\":980,\"h\":400}],\"w\":768,\"h\":1024,\"ext\":{\"rp\":{\"size_id\":80,\"alt_size_ids\":[102],\"mime\":\"text/html\"}}},\"ext\":{\"rp\":{\"zone_id\":4001,\"track\":{\"mint\":\"prebid\",\"mint_version\":\"source1_platform1_version1\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":2001}}},\"ext\":{\"rp\":{\"site_id\":3001}}},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"id\":\"12345\",\"buyeruid\":\"J5VLCWQP-26-CWFT\",\"ext\":{\"consent\":\"consent1\"}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId3\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode3\",\"price\":5.12,\"adm\":\"adm3\",\"crid\":\"crid3\",\"dealid\":\"dealId3\",\"w\":0,\"h\":0}],\"seat\":\"seatId3\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-1.json index 631de22e2b1..fb6db46cdb6 100644 --- a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-1.json @@ -15,8 +15,6 @@ "w": 300, "h": 250, "startdelay": 5, - "skipmin": 0, - "skipafter": 0, "playbackmethod": [ 1 ], @@ -65,11 +63,11 @@ }, "device": { "ua": "userAgent", + "dnt": 10, "ip": "193.168.244.1", "pxratio": 4.2, "language": "en", "ifa": "ifaId", - "dnt": 10, "ext": { "rp": { "pixelratio": 4.2 @@ -80,6 +78,7 @@ "id": "12345", "buyeruid": "J5VLCWQP-26-CWFT", "ext": { + "consent": "consent1", "rp": { "target": { "ucat": [ @@ -89,19 +88,18 @@ "iphone" ] } - }, - "consent": "consent1" - } - }, - "regs": { - "ext": { - "gdpr": 1 + } } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" + }, + "regs": { + "ext": { + "gdpr": 1 + } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-2.json b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-2.json index e0f1f1c11a6..9325d46f3f8 100644 --- a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-2.json @@ -72,7 +72,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-3.json b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-3.json index cb7c21fccbd..6d72214c356 100644 --- a/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-3.json +++ b/src/test/resources/org/prebid/server/it/auction/rubicon_appnexus/test-rubicon-bid-request-3.json @@ -79,7 +79,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-request.json b/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-request.json index ec85e72cfe0..930ae4cceb0 100644 --- a/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-request.json +++ b/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-request.json @@ -3,7 +3,7 @@ "tid": "tid", "cache_markup": 1, "sort_bids": 1, - "timeout_millis": 1000, + "timeout_millis": 5000, "ad_units": [ { "code": "adUnitCode11", diff --git a/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-response.json b/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-response.json index 6d27c5da2ae..b08299832c8 100644 --- a/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-response.json +++ b/src/test/resources/org/prebid/server/it/auction/sovrn/test-auction-sovrn-response.json @@ -9,7 +9,7 @@ "debug": [ { "request_uri": "{{ sovrn.exchange_uri }}", - "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode11\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250},\"tagid\":\"tagId1\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"990011\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":1000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", + "request_body": "{\"id\":\"tid\",\"imp\":[{\"id\":\"adUnitCode11\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":300,\"h\":250},\"tagid\":\"tagId1\"}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\"},\"device\":{\"ua\":\"userAgent\",\"dnt\":10,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"990011\",\"ext\":{\"consent\":\"consent1\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":1}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":1}}}", "response_body": "{\"id\":\"bidResponseId11\",\"seatbid\":[{\"bid\":[{\"impid\":\"adUnitCode11\",\"price\":5.78,\"adm\":\"adm11\",\"crid\":\"crid11\",\"dealid\":\"dealId11\",\"w\":300,\"h\":250}],\"seat\":\"seatId11\",\"group\":0}]}", "status_code": 200 } diff --git a/src/test/resources/org/prebid/server/it/auction/sovrn/test-sovrn-bid-request-1.json b/src/test/resources/org/prebid/server/it/auction/sovrn/test-sovrn-bid-request-1.json index 5bfdbefc8fe..67edaac40d7 100644 --- a/src/test/resources/org/prebid/server/it/auction/sovrn/test-sovrn-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/auction/sovrn/test-sovrn-bid-request-1.json @@ -45,7 +45,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid" diff --git a/src/test/resources/org/prebid/server/it/cache/update/test-auction-request.json b/src/test/resources/org/prebid/server/it/cache/update/test-auction-request.json index 4e3769013d3..a22728bd972 100644 --- a/src/test/resources/org/prebid/server/it/cache/update/test-auction-request.json +++ b/src/test/resources/org/prebid/server/it/cache/update/test-auction-request.json @@ -27,7 +27,7 @@ } ], "at": 1, - "tmax": 1900, + "tmax": 5000, "cur": [ "USD" ], @@ -53,7 +53,8 @@ } } } - } + }, + "auctiontimestamp": 1000 } }, "regs": { diff --git a/src/test/resources/org/prebid/server/it/cache/update/test-auction-response.json b/src/test/resources/org/prebid/server/it/cache/update/test-auction-response.json index 5b8cf3afa44..aed8243dab0 100644 --- a/src/test/resources/org/prebid/server/it/cache/update/test-auction-response.json +++ b/src/test/resources/org/prebid/server/it/cache/update/test-auction-response.json @@ -77,6 +77,9 @@ "responsetimemillis": { "rubicon": "{{ rubicon.response_time_ms }}" }, - "tmaxrequest": 1900 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request1.json b/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request1.json index 1ae7f272868..dede9e3cdff 100644 --- a/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request1.json +++ b/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request1.json @@ -58,7 +58,7 @@ "buyeruid": "J5VLCWQP-26-CWFT" }, "at": 1, - "tmax": 1900, + "tmax": 5000, "regs": { "ext": { "gdpr": 0 diff --git a/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request2.json b/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request2.json index ef90e5a84b0..e2c8bff3bd2 100644 --- a/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request2.json +++ b/src/test/resources/org/prebid/server/it/cache/update/test-rubicon-bid-request2.json @@ -59,7 +59,7 @@ "buyeruid": "J5VLCWQP-26-CWFT" }, "at": 1, - "tmax": 1900, + "tmax": 5000, "regs": { "ext": { "gdpr": 0 diff --git a/src/test/resources/org/prebid/server/it/gdpr-vendorlist/79.json b/src/test/resources/org/prebid/server/it/gdpr-vendorlist1/79.json similarity index 99% rename from src/test/resources/org/prebid/server/it/gdpr-vendorlist/79.json rename to src/test/resources/org/prebid/server/it/gdpr-vendorlist1/79.json index 63de8df975a..c0951f9ae52 100644 --- a/src/test/resources/org/prebid/server/it/gdpr-vendorlist/79.json +++ b/src/test/resources/org/prebid/server/it/gdpr-vendorlist1/79.json @@ -5633,4 +5633,4 @@ "featureIds": [] } ] -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/gdpr-vendorlist/8.json b/src/test/resources/org/prebid/server/it/gdpr-vendorlist1/8.json similarity index 99% rename from src/test/resources/org/prebid/server/it/gdpr-vendorlist/8.json rename to src/test/resources/org/prebid/server/it/gdpr-vendorlist1/8.json index 84d03c52ab8..99f9356c4a5 100644 --- a/src/test/resources/org/prebid/server/it/gdpr-vendorlist/8.json +++ b/src/test/resources/org/prebid/server/it/gdpr-vendorlist1/8.json @@ -482,4 +482,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-request.json index f0d57f27382..d9f826c1958 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-request.json @@ -31,7 +31,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -41,6 +41,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -50,16 +60,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -67,7 +67,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-response.json index 1b79c20e5ad..d7c6f51aa9f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adform/test-auction-adform-response.json @@ -48,6 +48,9 @@ "adform": "{{ adform.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adform/test-cache-adform-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adform/test-cache-adform-request.json index ae92156a703..f0dead6a19f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adform/test-cache-adform-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adform/test-cache-adform-request.json @@ -13,4 +13,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-adkernel-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-adkernel-bid-request.json index 0f3670cc67c..79b089c32b9 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-adkernel-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-adkernel-bid-request.json @@ -31,16 +31,16 @@ "user": { "buyeruid": "AK-UID", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -55,6 +55,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -65,16 +75,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -83,7 +83,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-request.json index 58b510f4d3d..5075fa709f0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-request.json @@ -38,7 +38,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -48,6 +48,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -57,16 +67,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -74,7 +74,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-response.json index 0817a6ada3e..47f5ecfa16c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-auction-adkernel-response.json @@ -55,6 +55,9 @@ "adkernel": "{{ adkernel.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-cache-adkernel-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-cache-adkernel-request.json index 0407022ed3a..8bbdb8380ee 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-cache-adkernel-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkernel/test-cache-adkernel-request.json @@ -21,4 +21,4 @@ "expiry": 120 } ] -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-1.json index c134c5318fc..841a9aefcf0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-1.json @@ -33,16 +33,16 @@ "user": { "buyeruid": "AK-UID", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -57,6 +57,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -67,16 +77,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -85,7 +85,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-2.json index 6646ab12b9b..ca5d2f77996 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-adkerneladn-bid-request-2.json @@ -8,9 +8,7 @@ "video/mp4" ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 } } ], @@ -32,16 +30,16 @@ "user": { "buyeruid": "AK-UID", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -56,6 +54,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -66,16 +74,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -84,7 +82,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-request.json index 752dba817e9..26db2d90d3e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-request.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -59,6 +59,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -68,16 +78,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -85,7 +85,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-response.json index 0ec2f59fbc0..86bf5172040 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adkerneladn/test-auction-adkerneladn-response.json @@ -100,6 +100,9 @@ "adkernelAdn": "{{ adkernelAdn.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-adpone-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-adpone-bid-request.json index 4eff98cb8ee..77b09c0bc79 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-adpone-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-adpone-bid-request.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -63,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -73,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -91,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-request.json index 410473bfa38..10783c7357f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-request.json @@ -30,7 +30,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -40,6 +40,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -49,16 +59,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -66,7 +66,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-response.json index 2046ab0d481..d364f881b12 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adpone/test-auction-adpone-response.json @@ -50,6 +50,9 @@ "adpone": "{{ adpone.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-adtelligent-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-adtelligent-bid-request-1.json index 00139008575..32274bab41c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-adtelligent-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-adtelligent-bid-request-1.json @@ -43,16 +43,16 @@ "user": { "buyeruid": "AT-UID", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +67,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +87,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +95,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-request.json b/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-request.json index 15e200f20b2..81b442df31e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-request.json @@ -33,7 +33,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -43,6 +43,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -52,16 +62,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -69,7 +69,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-response.json b/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-response.json index 701d9ea903a..4eeef9fce47 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/adtelligent/test-auction-adtelligent-response.json @@ -48,6 +48,9 @@ "adtelligent": "{{ adtelligent.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-advangelists-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-advangelists-bid-request.json index 3cdabbbfe24..9e7fd5be23e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-advangelists-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-advangelists-bid-request.json @@ -38,16 +38,16 @@ "user": { "buyeruid": "AV-UID", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -62,6 +62,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -72,16 +82,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -90,7 +90,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-request.json b/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-request.json index 7eb9e2e2949..7918156c41d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-request.json @@ -38,7 +38,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -48,6 +48,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -57,16 +67,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -74,7 +74,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-response.json b/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-response.json index 44842400579..6bdcf3da2fa 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/advangelists/test-auction-advangelists-response.json @@ -45,6 +45,9 @@ "advangelists": "{{ advangelists.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-1.json index 1175bea4bd9..68f61eda0d4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-1.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -64,6 +64,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -74,16 +84,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -92,7 +92,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-2.json index e41adbe8a8f..5567a6451a9 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-applogy-bid-request-2.json @@ -12,9 +12,7 @@ 5 ], "w":1024, - "h":576, - "skipmin":0, - "skipafter":0 + "h":576 }, "ext":{ "bidder":{ @@ -52,7 +50,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +65,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +85,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +93,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-request.json b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-request.json index a39be687fac..7e76df91e62 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-request.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -59,6 +59,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -68,16 +78,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -85,7 +85,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-response.json b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-response.json index 9e7f0bd80f5..e196306801e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/applogy/test-auction-applogy-response.json @@ -92,6 +92,9 @@ "applogy": "{{ applogy.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-request.json b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-request.json index 3ad86978a54..8e29d32beb3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-request.json @@ -61,7 +61,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -71,6 +71,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -80,16 +90,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -97,7 +97,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-response.json b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-response.json index 5c7e41c89b3..94faf170025 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-auction-beachfront-response.json @@ -48,6 +48,9 @@ "beachfront": "{{ beachfront.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-1.json index 74750a38bc7..8347a1bcd33 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-1.json @@ -12,9 +12,7 @@ "mimes" ], "w": 300, - "h": 250, - "skipmin": 0, - "skipafter": 0 + "h": 250 }, "bidfloor": 1, "secure": 0 @@ -51,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -66,6 +64,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -76,16 +84,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -94,7 +92,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-2.json index 678a6817b5c..7525d16b361 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/beachfront/test-beachfront-bid-request-2.json @@ -11,9 +11,7 @@ "mimes" ], "w": 300, - "h": 250, - "skipmin": 0, - "skipafter": 0 + "h": 250 }, "bidfloor": 2, "secure": 0 @@ -50,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-request.json b/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-request.json index c8ca857939d..6bf1295e6c0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-request.json @@ -15,7 +15,7 @@ }, "ext": { "brightroll": { - "publisher": "publisher" + "publisher": "businessinsider" } } } @@ -32,7 +32,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -42,6 +42,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -51,16 +61,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -68,7 +68,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { @@ -86,4 +87,4 @@ "gdpr": 0 } } -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-response.json b/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-response.json index 217dad3751a..0ad98b1147b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-auction-brightroll-response.json @@ -48,6 +48,9 @@ "brightroll": "{{ brightroll.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-brightroll-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-brightroll-bid-request-1.json index 1ebb7677ff1..37320d487ee 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-brightroll-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/brightroll/test-brightroll-bid-request-1.json @@ -11,11 +11,14 @@ "w": 300, "h": 250 } + ], + "battr": [ + 1, 3, 8, 9, 10, 13, 14, 17 ] }, "ext": { "bidder": { - "publisher": "publisher" + "publisher": "businessinsider" } } } @@ -50,10 +53,111 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], + "bcat": [ + "IAB7", "IAB7-39", "IAB7-44", "IAB9-30", + "IAB11", "IAB13-2", "IAB14-1", "IAB15-1", + "IAB15-5", "IAB17-18", "IAB18-1", + "IAB18-2", "IAB7-19", "IAB19-30", + "IAB23", "IAB25-7", "IAB26-1", + "IAB26-2", "IAB26-3", "IAB26-4" + ], + "badv": [ + "1smartpenny.com", + "advantagegold.com", + "beverlyhillsmd.com", + "beyonddiet.com", + "fisheradviser.com", + "fisherinvestments.com", + "fisherretirementtips.com", + "fool.com", + "freescore360.com", + "gruener-fisher.de", + "instantcheckmate.com", + "intercreditreport.com", + "king.com", + "ladyfitnessandhealth.com", + "ladyfitnessutah.com", + "livecellresearch.com", + "lowermybills.com", + "promeritumgroup.com", + "righttobear.com", + "slendertone.com", + "Squattypotty.com", + "thebeverlyhillsmdsolution.com", + "thecrux.com", + "thehornnews.com", + "ezmob.com", + "mediasmart.io", + "a4g.com", + "servedbyadbutler.com", + "adglobal.tech", + "adfyre.co", + "valo.ai", + "metanetwork.mobi", + "ato.mx", + "avazutracking.net", + "aztracking.net", + "avidadserver.com", + "avid-ad-server.com", + "avid-adserver.com", + "bidsopt.com", + "bo-rtb.com", + "bizzclick.com", + "aibidsrv.com", + "aibidauction.com", + "brightmountainads.com", + "bkserving.com", + "bucksense.io", + "ajillionmax.com", + "decenterads.com", + "digitaladsystems.com", + "dspbox.io", + "envisionx.co", + "fmlabsonline.com", + "gadmobe.com", + "g2trk.com", + "kds.media", + "media-servers.net", + "mediasmart.es", + "motionspots.com", + "nativeads.com", + "niutux.com", + "nuviad.com", + "oxonux.com", + "adx1.com", + "plt7.com", + "pltfrm.click", + "plf1.net", + "pfm.ninja", + "readywind.com", + "rklmstr.com", + "reklamdsp.com", + "revive-adserver.net", + "adp3.net", + "smrt-view.com", + "vabilitytech.com", + "bidderrtb.com", + "doyour.bid", + "dsptr.com", + "howto5.io", + "rtbadtrading.com", + "trading-rtbg.com", + "rtbsbengine.com", + "uuidksinc.net", + "rtbtradein.com", + "mobuppsrtb.com", + "vashoot.com", + "psdwc.com", + "cwkuki.com", + "waardex.com", + "webtradingspot.com", + "wapstart.ru", + "xapads.com" + ], "source": { "fd": 1, "tid": "tid" @@ -65,6 +169,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +189,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +197,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-request.json b/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-request.json index 0bf1c8366d0..6821b66d0b8 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-request.json @@ -33,7 +33,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -43,6 +43,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -52,16 +62,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -69,7 +69,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-response.json b/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-response.json index 403308fe5ff..e78b04b6df8 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/consumable/test-auction-consumable-response.json @@ -49,6 +49,9 @@ "cache": "{{ cache.response_time_ms }}", "consumable": "{{ consumable.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-request.json b/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-request.json index bda7cf43db6..d01f1bf96e3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-request.json @@ -32,7 +32,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -71,7 +71,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-response.json b/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-response.json index a2d0c57f4b6..2a6bc6f5e3c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-auction-conversant-response.json @@ -48,6 +48,9 @@ "conversantAlias": "{{ conversantAlias.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-conversant-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-conversant-bid-request.json index a82f3acec98..da8e6b9bcf6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-conversant-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/conversant/alias/test-conversant-bid-request.json @@ -44,16 +44,16 @@ "user": { "buyeruid": "CV-UID", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -81,16 +81,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -99,7 +89,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-request.json b/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-request.json index 270eea59cc9..5ae4e8a4df7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-request.json @@ -47,7 +47,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -57,6 +57,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -66,16 +76,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -83,7 +83,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-response.json b/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-response.json index 81cc095ce04..99466035722 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-auction-conversant-response.json @@ -88,6 +88,9 @@ "conversant": "{{ conversant.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-conversant-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-conversant-bid-request.json index 6f7ba09ee4e..ab47257786f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-conversant-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/conversant/test-conversant-bid-request.json @@ -28,9 +28,7 @@ "mimes" ], "w": 300, - "h": 600, - "skipmin": 0, - "skipafter": 0 + "h": 600 }, "displaymanager": "prebid-s2s", "displaymanagerver": "1.0.1", @@ -72,7 +70,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -87,6 +85,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -97,16 +105,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -115,7 +113,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-request.json b/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-request.json index 0d043848433..22c6acd038a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-request.json @@ -51,7 +51,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -61,6 +61,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -70,16 +80,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -87,7 +87,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-response.json b/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-response.json index dea068e4a57..77b2b9d1acb 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-auction-cpmstar-response.json @@ -92,6 +92,9 @@ "cpmstar": "{{ cpmstar.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-cpmstar-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-cpmstar-bid-request-1.json index cddaef1aa2e..25e72986ed5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-cpmstar-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/cpmstar/test-cpmstar-bid-request-1.json @@ -1,109 +1,107 @@ { - "id":"tid", - "imp":[ + "id": "tid", + "imp": [ { - "id":"impId001", - "banner":{ - "format":[ + "id": "impId001", + "banner": { + "format": [ { - "w":300, - "h":250 + "w": 300, + "h": 250 } ] }, - "ext":{ - "placementId":1234, - "subpoolId":1234 + "ext": { + "placementId": 1234, + "subpoolId": 1234 } }, { - "id":"impId002", - "video":{ - "mimes":[ + "id": "impId002", + "video": { + "mimes": [ "video/mp4" ], - "protocols":[ + "protocols": [ 2, 5 ], - "w":1024, - "h":576, - "skipmin":0, - "skipafter":0 + "w": 1024, + "h": 576 }, - "ext":{ - "placementId":1234, - "subpoolId":1234 + "ext": { + "placementId": 1234, + "subpoolId": 1234 } } ], - "site":{ - "domain":"example.com", - "page":"http://www.example.com", - "publisher":{ - "id":"publisherId" + "site": { + "domain": "example.com", + "page": "http://www.example.com", + "publisher": { + "id": "publisherId" }, - "ext":{ - "amp":0 + "ext": { + "amp": 0 } }, - "device":{ - "ua":"userAgent", - "dnt":2, - "ip":"193.168.244.1", - "pxratio":4.2, - "language":"en", - "ifa":"ifaId" + "device": { + "ua": "userAgent", + "dnt": 2, + "ip": "193.168.244.1", + "pxratio": 4.2, + "language": "en", + "ifa": "ifaId" }, - "user":{ - "buyeruid":"CS-UID", - "ext":{ - "consent":"consentValue", - "digitrust":{ - "id":"id", - "keyv":123, - "pref":0 + "user": { + "buyeruid": "CS-UID", + "ext": { + "consent": "consentValue", + "digitrust": { + "id": "id", + "keyv": 123, + "pref": 0 } } }, - "at":1, - "tmax":3000, - "cur":[ + "at": 1, + "tmax": 5000, + "cur": [ "USD" ], - "source":{ - "fd":1, - "tid":"tid" + "source": { + "fd": 1, + "tid": "tid" }, - "regs":{ - "ext":{ - "gdpr":0 + "regs": { + "ext": { + "gdpr": 0 } }, - "ext":{ - "prebid":{ - "targeting":{ - "pricegranularity":{ - "precision":2, - "ranges":[ + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, + "targeting": { + "pricegranularity": { + "precision": 2, + "ranges": [ { - "max":20, - "increment":0.1 + "max": 20, + "increment": 0.1 } ] }, - "currency":{ - "rates":{ - "EUR":{ - "USD":1.2406 - }, - "USD":{ - "EUR":0.811 - } - } - }, - "includewinners":true, - "includebidderkeys":true + "includewinners": true, + "includebidderkeys": true }, "cache":{ "bids":{ @@ -112,7 +110,8 @@ "vastxml":{ "ttlseconds":120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-request.json b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-request.json index 1c7a4238fd4..8e020f89897 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-request.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -59,6 +59,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -68,16 +78,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -85,7 +85,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-response.json b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-response.json index 74d559e403c..745dfbc1659 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-auction-datablocks-response.json @@ -102,13 +102,13 @@ "datablocks": [ { "uri": "{{ datablocks.exchange_uri }}?sid=2", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId002\",\"video\":{\"mimes\":[\"video/mp4\"],\"w\":300,\"h\":250,\"skipmin\":0,\"skipafter\":0,\"pos\":1},\"ext\":{\"bidder\":{\"host\":\"localhost:8090\",\"sourceId\":2}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"DB-UID\",\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0}}},\"at\":1,\"tmax\":1000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId002\",\"video\":{\"mimes\":[\"video/mp4\"],\"w\":300,\"h\":250,\"pos\":1},\"ext\":{\"bidder\":{\"host\":\"localhost:8090\",\"sourceId\":2}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"DB-UID\",\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0}}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"tid\",\"seatbid\":[{\"bid\":[{\"id\":\"bid002\",\"impid\":\"impId002\",\"price\":9.99,\"crid\":\"crid002\",\"cid\":\"cid002\",\"adomain\":[\"psacentral.org\"],\"h\":250,\"w\":300}],\"seat\":\"datablocks\"}]}", "status": 200 }, { "uri": "{{ datablocks.exchange_uri }}?sid=1", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId001\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}]},\"ext\":{\"bidder\":{\"host\":\"localhost:8090\",\"sourceId\":1}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"DB-UID\",\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0}}},\"at\":1,\"tmax\":1000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId001\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}]},\"ext\":{\"bidder\":{\"host\":\"localhost:8090\",\"sourceId\":1}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"DB-UID\",\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0}}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"tid\",\"seatbid\":[{\"bid\":[{\"id\":\"bid001\",\"impid\":\"impId001\",\"price\":7.77,\"adid\":\"adid001\",\"crid\":\"crid001\",\"cid\":\"cid001\",\"adm\":\"adm001\",\"h\":250,\"w\":300}],\"seat\":\"datablocks\"}]}", "status": 200 } @@ -142,8 +142,6 @@ ], "w": 300, "h": 250, - "skipmin": 0, - "skipafter": 0, "pos": 1 }, "ext": { @@ -183,7 +181,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -199,6 +197,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -209,16 +217,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -227,7 +225,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } @@ -236,6 +235,9 @@ "datablocks": "{{ datablocks.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 1000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-1.json index 4de2ff34a7b..922f359d9d1 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-1.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +65,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +85,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +93,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-2.json index 334db09901a..8e93b43f2db 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/datablocks/test-datablocks-bid-request-2.json @@ -9,8 +9,6 @@ ], "w": 300, "h": 250, - "skipmin": 0, - "skipafter": 0, "pos": 1 }, "ext": { @@ -51,7 +49,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +65,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +85,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +93,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-request.json b/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-request.json index 4da15aaee92..dd274c70b88 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-request.json @@ -36,7 +36,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -47,6 +47,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -60,16 +70,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -77,7 +77,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-response.json b/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-response.json index 2aac85d7e40..d74c404273e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-auction-emxdigital-response.json @@ -18,8 +18,8 @@ "targeting": { "hb_pb": "2.90", "hb_cache_id_emx_digital": "9a5d11a7-de5a-4ce4-8e89-d37f18a10045", - "hb_cache_path": "{{ cache.path }}", - "hb_cache_path_emx_digital": "{{ cache.path }}", + "hb_cache_path": "{{ cache.path }}", + "hb_cache_path_emx_digital": "{{ cache.path }}", "hb_cache_host": "{{ cache.host }}", "hb_cache_host_emx_digital": "{{ cache.host }}", "hb_size": "300x250", @@ -50,7 +50,7 @@ "emx_digital": [ { "uri": "{{ emx_digital.exchange_uri }}?t=1000&ts=2060541160", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"uuid\",\"banner\":{\"format\":[],\"w\":300,\"h\":250},\"tagid\":\"25251\",\"secure\":0}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"Android Chrome/60\",\"dnt\":2,\"ip\":\"127.0.0.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"ext\":{\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"consent\":\"consentValue\"}},\"at\":1,\"tmax\":3000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\",\"conversantAlias\":\"conversant\"},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"uuid\",\"banner\":{\"format\":[],\"w\":300,\"h\":250},\"tagid\":\"25251\",\"secure\":0}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"Android Chrome/60\",\"dnt\":2,\"ip\":\"127.0.0.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"ext\":{\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"consent\":\"consentValue\"}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\",\"conversantAlias\":\"conversant\"},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"some_test_auction\",\"seatbid\":[{\"seat\":\"12356\",\"bid\":[{\"id\":\"uuid\",\"adm\":\"
    \",\"impid\":\"uuid\",\"ttl\":300,\"crid\":\"94395500\",\"w\":300,\"price\":2.942808,\"adid\":\"94395500\",\"h\":250}]}],\"cur\":\"USD\"}", "status": 200 } @@ -113,7 +113,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -129,6 +129,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -143,16 +153,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -161,7 +161,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } @@ -170,6 +171,9 @@ "cache": "{{ cache.response_time_ms }}", "emx_digital": "{{ emx_digital.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-emxdigital-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-emxdigital-bid-request.json index b11be13c005..69641db9991 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-emxdigital-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/emxdigital/test-emxdigital-bid-request.json @@ -41,7 +41,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -57,6 +57,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -71,16 +81,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -89,7 +89,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-request.json b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-request.json index 47976a099e0..929645b6247 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-request.json @@ -42,7 +42,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -52,6 +52,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -61,16 +71,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -78,7 +78,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-response.json b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-response.json index d71ee7b7ed2..3bfdf6603a2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-auction-engagebdr-response.json @@ -100,6 +100,9 @@ "cache": "{{ cache.response_time_ms }}", "engagebdr": "{{ engagebdr.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-cache-engagebdr-request.json b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-cache-engagebdr-request.json index 2f72c9061e7..15a07e1bde4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-cache-engagebdr-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-cache-engagebdr-request.json @@ -42,4 +42,4 @@ "expiry": 120 } ] -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-1.json index 8dd50f577de..da048457d87 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-1.json @@ -44,7 +44,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -59,6 +59,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -69,16 +79,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -87,7 +87,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-2.json index 3280c1eadb4..6e315e14a54 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/engagebdr/test-engagebdr-bid-request-2.json @@ -9,9 +9,7 @@ "video/mp4" ], "w": 300, - "h": 250, - "skipmin": 0, - "skipafter": 0 + "h": 250 }, "ext": { "bidder": { @@ -50,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-request.json b/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-request.json index b644fce3e05..858a330efa3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-request.json @@ -31,7 +31,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -41,6 +41,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -50,16 +60,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -67,7 +67,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-response.json b/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-response.json index 3e767e01bcf..f5f19965a02 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/eplanning/test-auction-eplanning-response.json @@ -49,6 +49,9 @@ "eplanning": "{{ eplanning.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-request.json b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-request.json index f4b4c5983c6..3d83e650412 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-request.json @@ -62,7 +62,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -72,6 +72,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -81,16 +91,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -98,7 +98,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-response.json b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-response.json index 01113750a7d..d7893eaf806 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-auction-facebook-response.json @@ -119,6 +119,9 @@ "audienceNetwork": "{{ audienceNetwork.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-1.json index ddcf732c6d9..7faa8e8a93a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-1.json @@ -40,7 +40,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-2.json index a15a221bb92..548a28a59c0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-2.json @@ -9,8 +9,6 @@ ], "w": 0, "h": 0, - "skipmin": 0, - "skipafter": 0, "pos": 1 }, "tagid": "pub2_placement2" @@ -46,7 +44,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-3.json b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-3.json index f6406185a56..b616f2cebdc 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-3.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/facebook/test-facebook-bid-request-3.json @@ -40,7 +40,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-request.json b/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-request.json index 4582f48c18c..364cb51bcbc 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-request.json @@ -37,7 +37,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -47,6 +47,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -56,16 +66,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -73,7 +73,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-response.json b/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-response.json index c3819587cc3..ba9bb7be433 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gamma/test-auction-gamma-response.json @@ -53,6 +53,9 @@ "gamma": "{{ gamma.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-request.json b/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-request.json index dcb9db7bd81..0bcce25c2d2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-request.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -59,6 +59,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -68,16 +78,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -85,7 +85,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-response.json b/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-response.json index 3f8d18ab429..908108e5952 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-auction-gamoshi-response.json @@ -92,6 +92,9 @@ "gamoshi": "{{ gamoshi.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-gamoshi-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-gamoshi-bid-request-1.json index a0b8ac339b3..1ea94e142bf 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-gamoshi-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gamoshi/test-gamoshi-bid-request-1.json @@ -30,9 +30,7 @@ 5 ], "w": 1024, - "h": 576, - "skipmin": 0, - "skipafter": 0 + "h": 576 }, "ext": { "bidder": { @@ -71,7 +69,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -86,6 +84,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -96,16 +104,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -114,7 +112,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-request.json index c6eae4d59d3..0a0f7c6f484 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-request.json @@ -28,7 +28,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -38,6 +38,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -47,16 +57,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -64,7 +64,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-response.json index 3e5e193aa6f..8b377341d58 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-auction-grid-response.json @@ -50,6 +50,9 @@ "grid": "{{ grid.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request-1.json index d99f002a3bd..fe64061d8cc 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/grid/test-grid-bid-request-1.json @@ -46,7 +46,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -61,6 +61,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -71,16 +81,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -89,7 +89,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-request.json b/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-request.json index 5eae8bd7f1f..235758c00e4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-request.json @@ -63,7 +63,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -73,6 +73,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -82,16 +92,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -99,7 +99,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-response.json b/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-response.json index dbbcb523a83..800002e5d10 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-auction-gumgum-response.json @@ -78,6 +78,9 @@ "cache": "{{ cache.response_time_ms }}", "gumgum": "{{ gumgum.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-gumgum-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-gumgum-bid-request-1.json index a4e63b31905..a70edfbc00d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-gumgum-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/gumgum/test-gumgum-bid-request-1.json @@ -68,7 +68,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -83,6 +83,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -93,16 +103,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -111,7 +111,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-request.json b/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-request.json index 9ef81aec78d..77be89e620f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-request.json @@ -34,7 +34,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -44,6 +44,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -53,16 +63,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -70,7 +70,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-response.json b/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-response.json index 081d25c4e14..90aec3ab37d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-auction-improvedigital-response.json @@ -50,6 +50,9 @@ "improvedigital": "{{ improvedigital.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-improvedigital-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-improvedigital-bid-request-1.json index c32abe9187c..e48c93ae008 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-improvedigital-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/improvedigital/test-improvedigital-bid-request-1.json @@ -52,7 +52,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +67,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +87,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +95,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-request.json b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-request.json index 8646a707913..a932865ec3d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-request.json @@ -36,7 +36,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -46,6 +46,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -55,16 +65,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -72,7 +72,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-response.json b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-response.json index c1b76b59426..8486bad90b7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-auction-ix-response.json @@ -62,6 +62,9 @@ "ix": "{{ ix.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-1.json index d86112806ea..b65c3564437 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-1.json @@ -51,7 +51,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -66,6 +66,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -76,16 +86,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -94,7 +94,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-2.json index 409634c9c7b..574d1cc8336 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ix/test-ix-bid-request-2.json @@ -51,7 +51,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -66,6 +66,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -76,16 +86,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -94,7 +94,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-request.json b/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-request.json index b8fd151547d..46764e53b5a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-request.json @@ -31,7 +31,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -42,6 +42,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -55,16 +65,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -72,7 +72,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-response.json b/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-response.json index 2a603f3c5e9..a4ab9f9273a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-auction-kubient-response.json @@ -62,7 +62,7 @@ "kubient": [ { "uri": "{{ kubient.exchange_uri }}", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"test-imp-banner-id\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":500,\"h\":400},\"ext\":{\"bidder\":{}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0}}},\"at\":1,\"tmax\":1000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\",\"conversantAlias\":\"conversant\"},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"test-imp-banner-id\",\"banner\":{\"format\":[{\"w\":300,\"h\":250}],\"w\":500,\"h\":400},\"ext\":{\"bidder\":{}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"publisherId\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0}}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\",\"conversantAlias\":\"conversant\"},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"tid\",\"seatbid\":[{\"bid\":[{\"id\":\"7706636740145184841\",\"impid\":\"test-imp-banner-id\",\"price\":0.5,\"adid\":\"29681110\",\"adm\":\"some-test-ad\",\"adomain\":[\"advertsite.com\"],\"cid\":\"772\",\"crid\":\"29681110\",\"h\":576,\"w\":1024}]}]}", "status": 200 } @@ -118,7 +118,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -134,6 +134,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -148,16 +158,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -166,7 +166,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } @@ -175,6 +176,9 @@ "cache": "{{ cache.response_time_ms }}", "kubient": "{{ kubient.response_time_ms }}" }, - "tmaxrequest": 1000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-kubient-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-kubient-bid-request-1.json index 8b9b0742d70..ea0bb52f5c2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-kubient-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/kubient/test-kubient-bid-request-1.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 1000, + "tmax": 5000, "cur": [ "USD" ], @@ -64,6 +64,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -78,16 +88,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -96,7 +96,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-request.json b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-request.json index 0659d200841..a711af63c52 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-request.json @@ -47,7 +47,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -57,6 +57,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -66,16 +76,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -83,7 +83,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-response.json b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-response.json index 60dbabeb953..25d8b3576fb 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-auction-lifestreet-response.json @@ -88,6 +88,9 @@ "lifestreet": "{{ lifestreet.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-1.json index cc89384d69d..02e239098fd 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-1.json @@ -45,7 +45,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -60,6 +60,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -70,16 +80,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -88,7 +88,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-2.json index 4b7b474a6b4..bb4a7dd0200 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lifestreet/test-lifestreet-bid-request-2.json @@ -8,9 +8,7 @@ "mimes" ], "w": 300, - "h": 600, - "skipmin": 0, - "skipafter": 0 + "h": 600 }, "tagid": "slot.tag", "ext": { @@ -50,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-request.json b/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-request.json index c3d5b382110..2f66bf18f69 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-request.json @@ -30,7 +30,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -40,6 +40,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -49,16 +59,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -66,7 +66,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-response.json b/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-response.json index b284db07031..e23846981a2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-auction-lockerdome-response.json @@ -50,6 +50,9 @@ "lockerdome": "{{ lockerdome.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-lockerdome-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-lockerdome-bid-request.json index b4c1d2f3957..9f68924077d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-lockerdome-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/lockerdome/test-lockerdome-bid-request.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -63,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -73,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -91,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-request.json b/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-request.json index 46b9442438f..970f79136c2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-request.json @@ -45,7 +45,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -55,6 +55,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -64,16 +74,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -81,7 +81,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-response.json b/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-response.json index f8d6446dcb1..707de20c353 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-auction-marsmedia-response.json @@ -50,6 +50,9 @@ "marsmedia": "{{ marsmedia.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-marsmedia-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-marsmedia-bid-request-1.json index 762f963b921..e3a07212937 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-marsmedia-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/marsmedia/test-marsmedia-bid-request-1.json @@ -26,9 +26,7 @@ "video/mp4" ], "w": 1024, - "h": 576, - "skipmin": 0, - "skipafter": 0 + "h": 576 }, "ext": { "bidder": { @@ -67,7 +65,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -82,6 +80,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -92,16 +100,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -110,7 +108,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-request.json index 51948dc2286..88595741d0e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-request.json @@ -37,7 +37,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -47,6 +47,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -56,16 +66,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -73,7 +73,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-response.json index d2dca86bd99..eade228010f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-auction-mgid-response.json @@ -52,6 +52,9 @@ "cache": "{{ cache.response_time_ms }}", "mgid": "{{ mgid.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-mgid-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-mgid-bid-request.json index 76a0873a284..610b9cd60d7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-mgid-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/mgid/test-mgid-bid-request.json @@ -58,7 +58,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -73,6 +73,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -83,16 +93,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -101,7 +101,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-request.json index 4532b7b43a5..442100f1940 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-request.json @@ -103,7 +103,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -113,6 +113,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -122,16 +132,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -139,7 +139,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-response.json index 08a5b316606..c370665046c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-auction-openx-response.json @@ -162,6 +162,9 @@ "openx": "{{ openx.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-1.json index f4a7f638723..75fcba22d7d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-1.json @@ -72,7 +72,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-2.json index d0893563bfb..fdc7ca0e9db 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-2.json @@ -9,9 +9,7 @@ "video/mp4" ], "w": 900, - "h": 250, - "skipmin": 0, - "skipafter": 0 + "h": 250 }, "tagid": "539439964", "bidfloor": 0.1, @@ -52,7 +50,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-3.json b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-3.json index 81cb32a0d52..4b19cfe27a3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-3.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/openx/test-openx-bid-request-3.json @@ -9,9 +9,7 @@ "video/mp4" ], "w": 900, - "h": 250, - "skipmin": 0, - "skipafter": 0 + "h": 250 }, "tagid": "539439964", "bidfloor": 0.1, @@ -52,7 +50,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-request.json b/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-request.json index 6cd6395a2dd..5df0aaf9d96 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-request.json @@ -71,7 +71,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -81,6 +81,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -90,16 +100,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -107,7 +107,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-response.json b/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-response.json index fccf4c15e66..8762503e76a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-auction-pubmatic-response.json @@ -91,6 +91,9 @@ "pubmatic": "{{ pubmatic.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-pubmatic-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-pubmatic-bid-request-1.json index 14680d6b34b..4c77a806ed2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-pubmatic-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubmatic/test-pubmatic-bid-request-1.json @@ -26,9 +26,7 @@ "mimes" ], "w": 300, - "h": 600, - "skipmin": 0, - "skipafter": 0 + "h": 600 }, "ext": { "pmZoneID": "Zone1,Zone2" @@ -65,7 +63,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-request.json b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-request.json index 89c0a51f174..89790a7ef1f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-request.json @@ -61,7 +61,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -71,6 +71,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -80,16 +90,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -97,7 +97,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-response.json b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-response.json index b2cd2a0b2dc..d2e7188bf9f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-auction-pubnative-response.json @@ -124,6 +124,9 @@ "pubnative": "{{ pubnative.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-1.json index 12f37cd1110..7424672e75d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-1.json @@ -53,7 +53,7 @@ }, "test": 0, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -68,6 +68,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -78,16 +88,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -96,7 +96,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-2.json index d8e8221486f..5cd892ec25f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-2.json @@ -8,9 +8,7 @@ "video/mp4" ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "bidder": { @@ -52,7 +50,7 @@ }, "test": 0, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +65,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +85,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +93,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-3.json b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-3.json index 48dc9f545f3..0c19ff43e9a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-3.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pubnative/test-pubnative-bid-request-3.json @@ -47,7 +47,7 @@ }, "test": 0, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -62,6 +62,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -72,16 +82,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -90,7 +90,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-request.json b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-request.json index 18114e74b1d..fecb6896f00 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-request.json @@ -54,7 +54,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -64,6 +64,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -73,16 +83,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -90,7 +90,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-response.json b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-response.json index 8b22ac97330..1854292af69 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-auction-pulsepoint-response.json @@ -82,6 +82,9 @@ "pulsepoint": "{{ pulsepoint.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-1.json index af03aab7e72..cae66297df6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/pulsepoint/test-pulsepoint-bid-request-1.json @@ -74,7 +74,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -89,6 +89,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -99,16 +109,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -117,7 +117,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-request.json index 3fb63e14e87..f1a81849714 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-request.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -59,6 +59,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -68,16 +78,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -85,7 +85,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-response.json b/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-response.json index 9c129c8112e..d089f29db65 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-auction-rhythmone-response.json @@ -62,6 +62,9 @@ "rhythmone": "{{ rhythmone.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-rhythmone-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-rhythmone-bid-request-1.json index a854c0f037a..d60db302de5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-rhythmone-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rhythmone/test-rhythmone-bid-request-1.json @@ -27,9 +27,7 @@ "video/mp4" ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "bidder": { @@ -71,7 +69,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -86,6 +84,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -96,16 +104,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -114,7 +112,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-request.json index 4b3b2138ca2..c2fcb7d7c09 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-request.json @@ -31,7 +31,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -41,6 +41,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -50,16 +60,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -67,7 +67,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { @@ -85,4 +86,4 @@ "gdpr": 0 } } -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-response.json b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-response.json index 660e693e1c3..a7c869c424b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-auction-rtbhouse-response.json @@ -50,6 +50,9 @@ "rtbhouse": "{{ rtbhouse.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-cache-rtbhouse-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-cache-rtbhouse-request.json index 28165adcaaa..f40295ff504 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-cache-rtbhouse-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-cache-rtbhouse-request.json @@ -15,4 +15,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request-1.json index 61e7a347383..4026b162898 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rtbhouse/test-rtbhouse-bid-request-1.json @@ -46,7 +46,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -61,6 +61,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -71,16 +81,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -89,7 +89,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-1.json index a79249c789c..f5e00942ea3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-1.json @@ -67,47 +67,11 @@ }, "user": { "ext": { - "consent": "consentValue", - "digitrust": { - "id": "id", - "keyv": 123, - "pref": 0 - }, - "eids": [ - { - "source": "adserver.org", - "uids": [ - { - "id": "cd96870f-f53d-4986-a08e-cd1612fb13b0", - "ext": { - "rtiPartner": "TDID" - } - } - ] - }, - { - "source": "liveintent.com", - "uids": [ - { - "id": "efcf3a33-2eaf-4d6b-bf11-a411f134278c" - } - ], - "ext": { - "segments": [ - "999", - "888" - ] - } - }, - { - "source": "pubcid", - "id": "29cfaea8-a429-48fc-9537-8a19a8eb4f0d" - } - ] + "consent": "BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA" } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -123,14 +87,25 @@ "regs": { "ext": { "us_privacy": "1YNN" - } + } }, "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus" }, + "events": {}, "targeting": { "pricegranularity": { "precision": 2, @@ -141,16 +116,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -159,7 +124,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-2.json index 4b1e128393b..bf574771916 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-appnexus-bid-request-2.json @@ -55,47 +55,11 @@ }, "user": { "ext": { - "consent": "consentValue", - "digitrust": { - "id": "id", - "keyv": 123, - "pref": 0 - }, - "eids": [ - { - "source": "adserver.org", - "uids": [ - { - "id": "cd96870f-f53d-4986-a08e-cd1612fb13b0", - "ext": { - "rtiPartner": "TDID" - } - } - ] - }, - { - "source": "liveintent.com", - "uids": [ - { - "id": "efcf3a33-2eaf-4d6b-bf11-a411f134278c" - } - ], - "ext": { - "segments": [ - "999", - "888" - ] - } - }, - { - "source": "pubcid", - "id": "29cfaea8-a429-48fc-9537-8a19a8eb4f0d" - } - ] + "consent": "BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA" } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -116,9 +80,20 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus" }, + "events": {}, "targeting": { "pricegranularity": { "precision": 2, @@ -129,16 +104,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -147,7 +112,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-request.json index da04e59f1f4..27e441b6059 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-request.json @@ -197,7 +197,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -208,6 +208,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "schains": [ { "bidders": [ @@ -242,6 +252,7 @@ "aliases": { "appnexusAlias": "appnexus" }, + "events": {}, "targeting": { "pricegranularity": { "precision": 2, @@ -251,16 +262,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -268,12 +269,13 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { "ext": { - "consent": "consentValue", + "consent": "BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA", "digitrust": { "id": "id", "keyv": 123 diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-response.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-response.json index deae74893c2..b69bc2507d5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-auction-rubicon-appnexus-response.json @@ -14,7 +14,7 @@ "hb_pb": "0.90", "hb_pb_appnexus": "0.90", "hb_cache_path": "/cache", - "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26f%3Di", + "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26ts%3D1000%26bidder%3Dappnexus%26f%3Di", "hb_cache_path_appnexus": "/cache", "hb_bidder_appnexus": "appnexus", "hb_bidder": "appnexus", @@ -32,8 +32,8 @@ } }, "events": { - "win": "http://localhost:8000/event?t=win&b=a121a07f-1579-4465-bc5e-5c5b02a0c421&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=a121a07f-1579-4465-bc5e-5c5b02a0c421&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=a121a07f-1579-4465-bc5e-5c5b02a0c421&a=5001&ts=1000&bidder=appnexus&f=i", + "imp": "http://localhost:8000/event?t=imp&b=a121a07f-1579-4465-bc5e-5c5b02a0c421&a=5001&ts=1000&bidder=appnexus&f=i" } } } @@ -58,7 +58,7 @@ "targeting": { "hb_pb": "5.50", "hb_pb_appnexus": "5.50", - "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26f%3Di", + "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26ts%3D1000%26bidder%3Dappnexus%26f%3Di", "hb_size": "300x250", "hb_bidder_appnexus": "appnexus", "hb_bidder": "appnexus", @@ -73,8 +73,8 @@ "hb_cache_path_appnexus": "{{ cache.path }}" }, "events": { - "win": "http://localhost:8000/event?t=win&b=7706636740145184841&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=7706636740145184841&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=7706636740145184841&a=5001&ts=1000&bidder=appnexus&f=i", + "imp": "http://localhost:8000/event?t=imp&b=7706636740145184841&a=5001&ts=1000&bidder=appnexus&f=i" }, "cache": { "bids": { @@ -119,7 +119,7 @@ "hb_bidder": "appnexus", "hb_bidid": "928185755156387460", "hb_bidid_appnexus": "928185755156387460", - "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26f%3Di", + "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26ts%3D1000%26bidder%3Dappnexus%26f%3Di", "hb_cache_id": "6cf69b42-96f5-4ba1-a984-a9b4d8ff21cf", "hb_cache_id_appnexus": "6cf69b42-96f5-4ba1-a984-a9b4d8ff21cf", "hb_cache_host": "{{ cache.host }}", @@ -128,8 +128,8 @@ "hb_cache_path_appnexus": "{{ cache.path }}" }, "events": { - "win": "http://localhost:8000/event?t=win&b=928185755156387460&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=928185755156387460&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=928185755156387460&a=5001&ts=1000&bidder=appnexus&f=i", + "imp": "http://localhost:8000/event?t=imp&b=928185755156387460&a=5001&ts=1000&bidder=appnexus&f=i" }, "cache": { "bids": { @@ -182,8 +182,8 @@ "hb_cache_path_appnexusAlias": "{{ cache.path }}" }, "events": { - "win": "http://localhost:8000/event?t=win&b=7706636740145184840&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=7706636740145184840&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=7706636740145184840&a=5001&ts=1000&bidder=appnexusAlias&f=i", + "imp": "http://localhost:8000/event?t=imp&b=7706636740145184840&a=5001&ts=1000&bidder=appnexusAlias&f=i" }, "cache": { "bids": { @@ -222,7 +222,7 @@ "hb_pb_rubicon": "0.80", "hb_cache_id_rubicon": "734b7948-e41d-4c14-b2c3-c31634b32376", "hb_cache_path": "/cache", - "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26f%3Di", + "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26ts%3D1000%26bidder%3Drubicon%26f%3Di", "hb_bidder": "rubicon", "hb_bidder_rubicon": "rubicon", "hb_bidid": "f227a07f-1579-4465-bc5e-5c5b02a0c181", @@ -239,8 +239,8 @@ } }, "events": { - "win": "http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c181&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=f227a07f-1579-4465-bc5e-5c5b02a0c181&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c181&a=5001&ts=1000&bidder=rubicon&f=i", + "imp": "http://localhost:8000/event?t=imp&b=f227a07f-1579-4465-bc5e-5c5b02a0c181&a=5001&ts=1000&bidder=rubicon&f=i" } } } @@ -266,8 +266,8 @@ } }, "events": { - "win": "http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c180&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=f227a07f-1579-4465-bc5e-5c5b02a0c180&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c180&a=5001&ts=1000&bidder=rubicon&f=i", + "imp": "http://localhost:8000/event?t=imp&b=f227a07f-1579-4465-bc5e-5c5b02a0c180&a=5001&ts=1000&bidder=rubicon&f=i" } } } @@ -300,8 +300,8 @@ "hb_cache_path_rubicon": "{{ cache.path }}" }, "events": { - "win": "http://localhost:8000/event?t=win&b=880290288&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=880290288&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=880290288&a=5001&ts=1000&bidder=rubicon&f=i", + "imp": "http://localhost:8000/event?t=imp&b=880290288&a=5001&ts=1000&bidder=rubicon&f=i" }, "cache": { "vastXml": { @@ -343,7 +343,7 @@ "hb_pb": "4.20", "hb_pb_rubicon": "4.20", "hb_cache_id_rubicon": "4fe59ef5-6fb4-48c5-88b6-9870257fc49e", - "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26f%3Di", + "hb_winurl": "http%3A%2F%2Flocalhost%3A8000%2Fevent%3Ft%3Dwin%26b%3DBIDID%26a%3D5001%26ts%3D1000%26bidder%3Drubicon%26f%3Di", "hb_size": "300x600", "hb_size_rubicon": "300x600", "hb_bidder": "rubicon", @@ -357,8 +357,8 @@ "hb_cache_path_rubicon": "{{ cache.path }}" }, "events": { - "win": "http://localhost:8000/event?t=win&b=466223845&a=5001&f=i", - "imp": "http://localhost:8000/event?t=imp&b=466223845&a=5001&f=i" + "win": "http://localhost:8000/event?t=win&b=466223845&a=5001&ts=1000&bidder=rubicon&f=i", + "imp": "http://localhost:8000/event?t=imp&b=466223845&a=5001&ts=1000&bidder=rubicon&f=i" }, "cache": { "bids": { @@ -381,7 +381,7 @@ "appnexus": [ { "uri": "{{ appnexus.exchange_uri }}?member_id=103", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId3\",\"banner\":{\"format\":[{\"w\":300,\"h\":250},{\"w\":300,\"h\":600}],\"w\":300,\"h\":250,\"pos\":3},\"tagid\":\"abc\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"keywords\":\"foo=bar,foo=baz\",\"traffic_source_code\":\"trafficSource\"}}},{\"id\":\"impId131\",\"native\":{\"request\":\"{\\\"ver\\\":\\\"1.1\\\",\\\"context\\\":1,\\\"contextsubtype\\\":11,\\\"plcmttype\\\":4,\\\"plcmtcnt\\\":1,\\\"assets\\\":[{\\\"id\\\":0,\\\"required\\\":1,\\\"title\\\":{\\\"len\\\":500}},{\\\"id\\\":1,\\\"required\\\":1,\\\"img\\\":{\\\"type\\\":3,\\\"wmin\\\":1,\\\"hmin\\\":1}},{\\\"id\\\":2,\\\"required\\\":0,\\\"data\\\":{\\\"len\\\":200}},{\\\"id\\\":3,\\\"required\\\":0,\\\"data\\\":{\\\"type\\\":2,\\\"len\\\":15000}},{\\\"id\\\":4,\\\"required\\\":0,\\\"data\\\":{\\\"len\\\":40}},{\\\"id\\\":5,\\\"required\\\":0,\\\"data\\\":{\\\"type\\\":11}}]}\",\"ver\":\"1.1\"},\"ext\":{\"appnexus\":{\"placement_id\":9880618}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"5001\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"prebid\":{\"interstitial\":{\"minwidthperc\":50,\"minheightperc\":60}}}},\"user\":{\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"eids\":[{\"source\":\"adserver.org\",\"uids\":[{\"id\":\"cd96870f-f53d-4986-a08e-cd1612fb13b0\",\"ext\":{\"rtiPartner\":\"TDID\"}}]},{\"source\":\"liveintent.com\",\"uids\":[{\"id\":\"efcf3a33-2eaf-4d6b-bf11-a411f134278c\"}],\"ext\":{\"segments\":[\"999\",\"888\"]}},{\"source\":\"pubcid\",\"id\":\"29cfaea8-a429-48fc-9537-8a19a8eb4f0d\"}]}},\"at\":1,\"tmax\":3000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\"}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\"},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId3\",\"banner\":{\"format\":[{\"w\":300,\"h\":250},{\"w\":300,\"h\":600}],\"w\":300,\"h\":250,\"pos\":3},\"tagid\":\"abc\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"keywords\":\"foo=bar,foo=baz\",\"traffic_source_code\":\"trafficSource\"}}},{\"id\":\"impId131\",\"native\":{\"request\":\"{\\\"ver\\\":\\\"1.1\\\",\\\"context\\\":1,\\\"contextsubtype\\\":11,\\\"plcmttype\\\":4,\\\"plcmtcnt\\\":1,\\\"assets\\\":[{\\\"id\\\":0,\\\"required\\\":1,\\\"title\\\":{\\\"len\\\":500}},{\\\"id\\\":1,\\\"required\\\":1,\\\"img\\\":{\\\"type\\\":3,\\\"wmin\\\":1,\\\"hmin\\\":1}},{\\\"id\\\":2,\\\"required\\\":0,\\\"data\\\":{\\\"len\\\":200}},{\\\"id\\\":3,\\\"required\\\":0,\\\"data\\\":{\\\"type\\\":2,\\\"len\\\":15000}},{\\\"id\\\":4,\\\"required\\\":0,\\\"data\\\":{\\\"len\\\":40}},{\\\"id\\\":5,\\\"required\\\":0,\\\"data\\\":{\\\"type\\\":11}}]}\",\"ver\":\"1.1\"},\"ext\":{\"appnexus\":{\"placement_id\":9880618}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"5001\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"prebid\":{\"interstitial\":{\"minwidthperc\":50,\"minheightperc\":60}}}},\"user\":{\"ext\":{\"consent\":\"BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA\"}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\"}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\"},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"events\":{},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"tid\",\"seatbid\":[{\"seat\":\"958\",\"bid\":[{\"id\":\"7706636740145184841\",\"impid\":\"impId3\",\"price\":5.5,\"adid\":\"29681110\",\"adm\":\"some-test-ad\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"h\":250,\"w\":300,\"ext\":{\"appnexus\":{\"brand_id\":1,\"auction_id\":8189378542222915032,\"bidder_id\":2,\"bid_ad_type\":0,\"ranking_price\":0.0}}},{\"id\":\"928185755156387460\",\"impid\":\"impId131\",\"price\":1.0,\"adid\":\"69595837\",\"adm\":\"{\\\"assets\\\":[{\\\"id\\\":0,\\\"img\\\":{\\\"url\\\":\\\"http://vcdn.adnxs.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\\\",\\\"w\\\":3000,\\\"h\\\":2250,\\\"ext\\\":{\\\"appnexus\\\":{\\\"prevent_crop\\\":0}}}},{\\\"id\\\":1,\\\"title\\\":{\\\"text\\\":\\\"This is an example Prebid Native creative\\\"}},{\\\"id\\\":2,\\\"data\\\":{\\\"value\\\":\\\"Prebid.org\\\"}},{\\\"id\\\":3,\\\"data\\\":{\\\"value\\\":\\\"ThisisaPrebidNativeCreative.Therearemanylikeit,butthisoneismine.\\\"}}],\\\"link\\\":{\\\"url\\\":\\\"http://nym1-ib.adnxs.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\\\"},\\\"imptrackers\\\":[\\\"http://nym1-ib.adnxs.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\\\"],\\\"jstracker\\\":\\\"\\\"}\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=69595837\",\"cid\":\"958\",\"crid\":\"69595837\",\"ext\":{\"appnexus\":{\"brand_id\":1,\"brand_category_id\":1,\"auction_id\":5607483846416358664,\"bidder_id\":2,\"bid_ad_type\":3}}}]}],\"bidid\":\"5778926625248726496\",\"cur\":\"USD\"}", "status": 200 } @@ -389,7 +389,7 @@ "appnexusAlias": [ { "uri": "{{ appnexus.exchange_uri }}?member_id=104", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId3\",\"banner\":{\"format\":[{\"w\":300,\"h\":250},{\"w\":300,\"h\":600}],\"w\":300,\"h\":250,\"pos\":1},\"tagid\":\"abc\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"keywords\":\"foo=barAlias,foo=bazAlias\",\"traffic_source_code\":\"trafficSourceAlias\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"5001\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"prebid\":{\"interstitial\":{\"minwidthperc\":50,\"minheightperc\":60}}}},\"user\":{\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"eids\":[{\"source\":\"adserver.org\",\"uids\":[{\"id\":\"cd96870f-f53d-4986-a08e-cd1612fb13b0\",\"ext\":{\"rtiPartner\":\"TDID\"}}]},{\"source\":\"liveintent.com\",\"uids\":[{\"id\":\"efcf3a33-2eaf-4d6b-bf11-a411f134278c\"}],\"ext\":{\"segments\":[\"999\",\"888\"]}},{\"source\":\"pubcid\",\"id\":\"29cfaea8-a429-48fc-9537-8a19a8eb4f0d\"}]}},\"at\":1,\"tmax\":3000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\"}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\"},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId3\",\"banner\":{\"format\":[{\"w\":300,\"h\":250},{\"w\":300,\"h\":600}],\"w\":300,\"h\":250,\"pos\":1},\"tagid\":\"abc\",\"bidfloor\":1.0,\"ext\":{\"appnexus\":{\"keywords\":\"foo=barAlias,foo=bazAlias\",\"traffic_source_code\":\"trafficSourceAlias\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"5001\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"prebid\":{\"interstitial\":{\"minwidthperc\":50,\"minheightperc\":60}}}},\"user\":{\"ext\":{\"consent\":\"BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA\"}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\"}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\"},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"events\":{},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"tid\",\"seatbid\":[{\"seat\":\"959\",\"bid\":[{\"id\":\"7706636740145184840\",\"impid\":\"impId3\",\"price\":5.0,\"adid\":\"29681110\",\"adm\":\"some-test-ad\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"h\":250,\"w\":300,\"cat\":[\"IAB20-3\"],\"ext\":{\"appnexus\":{\"brand_id\":350,\"brand_category_id\":350,\"auction_id\":8189378542222915031,\"bidder_id\":2,\"bid_ad_type\":0,\"ranking_price\":0.0}}}]}],\"bidid\":\"5778926625248726496\",\"cur\":\"USD\"}", "status": 200 } @@ -397,13 +397,13 @@ "rubicon": [ { "uri": "{{ rubicon.exchange_uri }}?tk_xint=dmbjs", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId1\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"skipmin\":0,\"skipafter\":0,\"playbackmethod\":[1],\"ext\":{\"skip\":5,\"skipdelay\":1,\"rp\":{\"size_id\":15},\"videotype\":\"rewarded\"}},\"ext\":{\"rp\":{\"zone_id\":4001,\"target\":{\"rating\":[\"5-star\"],\"prodtype\":[\"tech\"]},\"track\":{\"mint\":\"\",\"mint_version\":\"\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":2001}}},\"ext\":{\"rp\":{\"site_id\":3001},\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"eids\":[{\"source\":\"adserver.org\",\"uids\":[{\"id\":\"cd96870f-f53d-4986-a08e-cd1612fb13b0\",\"ext\":{\"rtiPartner\":\"TDID\"}}]},{\"source\":\"liveintent.com\",\"uids\":[{\"id\":\"efcf3a33-2eaf-4d6b-bf11-a411f134278c\"}],\"ext\":{\"segments\":[\"999\",\"888\"]}},{\"source\":\"pubcid\",\"id\":\"29cfaea8-a429-48fc-9537-8a19a8eb4f0d\"}],\"tpid\":[{\"source\":\"tdid\",\"uid\":\"cd96870f-f53d-4986-a08e-cd1612fb13b0\"},{\"source\":\"liveintent.com\",\"uid\":\"efcf3a33-2eaf-4d6b-bf11-a411f134278c\"}],\"rp\":{\"target\":{\"ucat\":[\"new\"],\"search\":[\"iphone\"],\"LIseg\":[\"999\",\"888\"]}}}},\"at\":1,\"tmax\":3000,\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\",\"complete\":1,\"nodes\":[{\"asi\":\"superads.com\",\"sid\":\"123\",\"hp\":1}]}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId1\",\"video\":{\"mimes\":[\"mimes\"],\"minduration\":20,\"maxduration\":60,\"protocols\":[1],\"w\":300,\"h\":250,\"startdelay\":5,\"skipmin\":0,\"skipafter\":0,\"playbackmethod\":[1],\"ext\":{\"skip\":5,\"skipdelay\":1,\"rp\":{\"size_id\":15},\"videotype\":\"rewarded\"}},\"ext\":{\"rp\":{\"zone_id\":4001,\"target\":{\"rating\":[\"5-star\"],\"prodtype\":[\"tech\"]},\"track\":{\"mint\":\"\",\"mint_version\":\"\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":2001}}},\"ext\":{\"rp\":{\"site_id\":3001},\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"ext\":{\"consent\":\"BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA\",\"rp\":{\"target\":{\"ucat\":[\"new\"],\"search\":[\"iphone\"]}}}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\",\"complete\":1,\"nodes\":[{\"asi\":\"superads.com\",\"sid\":\"123\",\"hp\":1}]}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}}}", "responsebody": "{\"id\":\"bidResponseId1\",\"seatbid\":[{\"bid\":[{\"id\":\"880290288\",\"impid\":\"impId1\",\"price\":8.43,\"adm\":\"\",\"crid\":\"crid1\",\"w\":300,\"h\":250,\"ext\":{\"rp\":{\"targeting\":[{\"key\":\"rpfl_1001\",\"values\":[\"2_tier0100\"]}]}}}],\"seat\":\"seatId1\",\"group\":0}]}", "status": 200 }, { "uri": "{{ rubicon.exchange_uri }}?tk_xint=dmbjs", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId2\",\"banner\":{\"format\":[{\"w\":300,\"h\":600}],\"w\":300,\"h\":600,\"ext\":{\"rp\":{\"size_id\":10,\"mime\":\"text/html\"}}},\"ext\":{\"rp\":{\"zone_id\":7001,\"track\":{\"mint\":\"\",\"mint_version\":\"\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":5001}}},\"ext\":{\"rp\":{\"site_id\":6001},\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"ext\":{\"consent\":\"consentValue\",\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"eids\":[{\"source\":\"adserver.org\",\"uids\":[{\"id\":\"cd96870f-f53d-4986-a08e-cd1612fb13b0\",\"ext\":{\"rtiPartner\":\"TDID\"}}]},{\"source\":\"liveintent.com\",\"uids\":[{\"id\":\"efcf3a33-2eaf-4d6b-bf11-a411f134278c\"}],\"ext\":{\"segments\":[\"999\",\"888\"]}},{\"source\":\"pubcid\",\"id\":\"29cfaea8-a429-48fc-9537-8a19a8eb4f0d\"}],\"tpid\":[{\"source\":\"tdid\",\"uid\":\"cd96870f-f53d-4986-a08e-cd1612fb13b0\"},{\"source\":\"liveintent.com\",\"uid\":\"efcf3a33-2eaf-4d6b-bf11-a411f134278c\"}],\"rp\":{\"target\":{\"LIseg\":[\"999\",\"888\"]}}}},\"at\":1,\"tmax\":3000,\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\",\"complete\":1,\"nodes\":[{\"asi\":\"superads.com\",\"sid\":\"123\",\"hp\":1}]}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId2\",\"banner\":{\"format\":[{\"w\":300,\"h\":600}],\"w\":300,\"h\":600,\"ext\":{\"rp\":{\"size_id\":10,\"mime\":\"text/html\"}}},\"ext\":{\"rp\":{\"zone_id\":7001,\"track\":{\"mint\":\"\",\"mint_version\":\"\"}}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"ext\":{\"rp\":{\"account_id\":5001}}},\"ext\":{\"rp\":{\"site_id\":6001},\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"80.215.195.0\",\"pxratio\":4.2,\"language\":\"en\",\"ext\":{\"rp\":{\"pixelratio\":4.2}}},\"user\":{\"ext\":{\"consent\":\"BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA\"}},\"at\":1,\"tmax\":5000,\"source\":{\"fd\":1,\"tid\":\"tid\",\"ext\":{\"schain\":{\"ver\":\"1.0\",\"complete\":1,\"nodes\":[{\"asi\":\"superads.com\",\"sid\":\"123\",\"hp\":1}]}}},\"regs\":{\"ext\":{\"us_privacy\":\"1YNN\"}}}", "responsebody": "{\"id\":\"bidResponseId2\",\"seatbid\":[{\"bid\":[{\"id\":\"466223845\",\"impid\":\"impId2\",\"price\":4.26,\"adm\":\"adm2\",\"crid\":\"crid2\",\"w\":300,\"h\":600}],\"seat\":\"seatId2\",\"group\":0}]}", "status": 200 } @@ -411,7 +411,7 @@ "cache": [ { "uri": "{{ cache.endpoint }}", - "requestbody": "{\"puts\":[{\"type\":\"json\",\"value\":{\"id\":\"f227a07f-1579-4465-bc5e-5c5b02a0c180\",\"impid\":\"impStoredAuctionResponse\",\"price\":0.8}},{\"type\":\"json\",\"value\":{\"id\":\"466223845\",\"impid\":\"impId2\",\"price\":4.26,\"adm\":\"adm2\",\"crid\":\"crid2\",\"w\":300,\"h\":600}},{\"type\":\"json\",\"value\":{\"id\":\"7706636740145184840\",\"impid\":\"impId3\",\"price\":5,\"adm\":\"some-test-ad\",\"adid\":\"29681110\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"cat\":[],\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"brand_id\":350,\"brand_category_id\":350,\"auction_id\":8189378542222915031,\"bidder_id\":2,\"bid_ad_type\":0,\"ranking_price\":0.0}}}},{\"type\":\"json\",\"value\":{\"id\":\"f227a07f-1579-4465-bc5e-5c5b02a0c181\",\"impid\":\"impStoredBidResponse\",\"price\":0.8}},{\"type\":\"json\",\"value\":{\"id\":\"928185755156387460\",\"impid\":\"impId131\",\"price\":1,\"adm\":\"{\\\"assets\\\":[{\\\"id\\\":0,\\\"img\\\":{\\\"url\\\":\\\"http://vcdn.adnxs.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\\\",\\\"w\\\":3000,\\\"h\\\":2250,\\\"ext\\\":{\\\"appnexus\\\":{\\\"prevent_crop\\\":0}}}},{\\\"id\\\":1,\\\"title\\\":{\\\"text\\\":\\\"This is an example Prebid Native creative\\\"}},{\\\"id\\\":2,\\\"data\\\":{\\\"value\\\":\\\"Prebid.org\\\"}},{\\\"id\\\":3,\\\"data\\\":{\\\"value\\\":\\\"ThisisaPrebidNativeCreative.Therearemanylikeit,butthisoneismine.\\\"}}],\\\"link\\\":{\\\"url\\\":\\\"http://nym1-ib.adnxs.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\\\"},\\\"imptrackers\\\":[\\\"http://nym1-ib.adnxs.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\\\"],\\\"jstracker\\\":\\\"\\\"}\",\"adid\":\"69595837\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=69595837\",\"cid\":\"958\",\"crid\":\"69595837\",\"cat\":[\"IAB20-3\"],\"ext\":{\"appnexus\":{\"brand_id\":1,\"brand_category_id\":1,\"auction_id\":5607483846416358664,\"bidder_id\":2,\"bid_ad_type\":3}}}},{\"type\":\"json\",\"value\":{\"id\":\"880290288\",\"impid\":\"impId1\",\"price\":8.43,\"adm\":\"\",\"crid\":\"crid1\",\"w\":300,\"h\":250,\"ext\":{\"rp\":{\"targeting\":[{\"key\":\"rpfl_1001\",\"values\":[\"2_tier0100\"]}]}}}},{\"type\":\"json\",\"value\":{\"id\":\"a121a07f-1579-4465-bc5e-5c5b02a0c421\",\"impid\":\"impStoredAuctionResponse\",\"price\":0.9}},{\"type\":\"json\",\"value\":{\"id\":\"7706636740145184841\",\"impid\":\"impId3\",\"price\":5.5,\"adm\":\"some-test-ad\",\"adid\":\"29681110\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"brand_id\":1,\"auction_id\":8189378542222915032,\"bidder_id\":2,\"bid_ad_type\":0,\"ranking_price\":0.0}}}},{\"type\":\"xml\",\"value\":\"\",\"expiry\":120}]}", + "requestbody": "{\"puts\":[{\"type\":\"json\",\"value\":{\"id\":\"7706636740145184840\",\"impid\":\"impId3\",\"price\":5,\"adm\":\"some-test-ad\",\"adid\":\"29681110\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"cat\":[],\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"brand_id\":350,\"brand_category_id\":350,\"auction_id\":8189378542222915031,\"bidder_id\":2,\"bid_ad_type\":0,\"ranking_price\":0.0}},\"wurl\":\"http://localhost:8000/event?t=win&b=7706636740145184840&a=5001&ts=1000&bidder=appnexusAlias&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"f227a07f-1579-4465-bc5e-5c5b02a0c180\",\"impid\":\"impStoredAuctionResponse\",\"price\":0.8,\"wurl\":\"http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c180&a=5001&ts=1000&bidder=rubicon&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"466223845\",\"impid\":\"impId2\",\"price\":4.26,\"adm\":\"adm2\",\"crid\":\"crid2\",\"w\":300,\"h\":600,\"wurl\":\"http://localhost:8000/event?t=win&b=466223845&a=5001&ts=1000&bidder=rubicon&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"f227a07f-1579-4465-bc5e-5c5b02a0c181\",\"impid\":\"impStoredBidResponse\",\"price\":0.8,\"wurl\":\"http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c181&a=5001&ts=1000&bidder=rubicon&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"880290288\",\"impid\":\"impId1\",\"price\":8.43,\"adm\":\"\",\"crid\":\"crid1\",\"w\":300,\"h\":250,\"ext\":{\"rp\":{\"targeting\":[{\"key\":\"rpfl_1001\",\"values\":[\"2_tier0100\"]}]}},\"wurl\":\"http://localhost:8000/event?t=win&b=880290288&a=5001&ts=1000&bidder=rubicon&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"a121a07f-1579-4465-bc5e-5c5b02a0c421\",\"impid\":\"impStoredAuctionResponse\",\"price\":0.9,\"wurl\":\"http://localhost:8000/event?t=win&b=a121a07f-1579-4465-bc5e-5c5b02a0c421&a=5001&ts=1000&bidder=appnexus&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"928185755156387460\",\"impid\":\"impId131\",\"price\":1,\"adm\":\"{\\\"assets\\\":[{\\\"id\\\":0,\\\"img\\\":{\\\"url\\\":\\\"http://vcdn.adnxs.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\\\",\\\"w\\\":3000,\\\"h\\\":2250,\\\"ext\\\":{\\\"appnexus\\\":{\\\"prevent_crop\\\":0}}}},{\\\"id\\\":1,\\\"title\\\":{\\\"text\\\":\\\"This is an example Prebid Native creative\\\"}},{\\\"id\\\":2,\\\"data\\\":{\\\"value\\\":\\\"Prebid.org\\\"}},{\\\"id\\\":3,\\\"data\\\":{\\\"value\\\":\\\"ThisisaPrebidNativeCreative.Therearemanylikeit,butthisoneismine.\\\"}}],\\\"link\\\":{\\\"url\\\":\\\"http://nym1-ib.adnxs.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\\\"},\\\"imptrackers\\\":[\\\"http://nym1-ib.adnxs.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\\\"],\\\"jstracker\\\":\\\"\\\"}\",\"adid\":\"69595837\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=69595837\",\"cid\":\"958\",\"crid\":\"69595837\",\"cat\":[\"IAB20-3\"],\"ext\":{\"appnexus\":{\"brand_id\":1,\"brand_category_id\":1,\"auction_id\":5607483846416358664,\"bidder_id\":2,\"bid_ad_type\":3}},\"wurl\":\"http://localhost:8000/event?t=win&b=928185755156387460&a=5001&ts=1000&bidder=appnexus&f=i\"}},{\"type\":\"json\",\"value\":{\"id\":\"7706636740145184841\",\"impid\":\"impId3\",\"price\":5.5,\"adm\":\"some-test-ad\",\"adid\":\"29681110\",\"adomain\":[\"appnexus.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"w\":300,\"h\":250,\"ext\":{\"appnexus\":{\"brand_id\":1,\"auction_id\":8189378542222915032,\"bidder_id\":2,\"bid_ad_type\":0,\"ranking_price\":0.0}},\"wurl\":\"http://localhost:8000/event?t=win&b=7706636740145184841&a=5001&ts=1000&bidder=appnexus&f=i\"}},{\"type\":\"xml\",\"value\":\"\",\"expiry\":120}]}", "responsebody": "{\"responses\":[{\"uuid\":\"91912e5b-dfa8-42bc-9c7e-df6ce0449c19\"},{\"uuid\":\"765e116a-5773-49d5-a648-0b97a9907a4e\"},{\"uuid\":\"117431c9-807a-41e1-82a7-dcd8f8875493\"},{\"uuid\":\"6cf69b42-96f5-4ba1-a984-a9b4d8ff21cf\"},{\"uuid\":\"734b7948-e41d-4c14-b2c3-c31634b32376\"},{\"uuid\":\"c75130ed-bcdd-4821-ad91-90cf835615c5\"},{\"uuid\":\"683fe79f-6df7-4971-ac70-820e0486992d\"},{\"uuid\":\"4fe59ef5-6fb4-48c5-88b6-9870257fc49e\"},{\"uuid\":\"b2528f73-96ab-42ab-8f15-fbe6ed779a26\"}]}", "status": 200 } @@ -644,7 +644,7 @@ "keyv": 123, "pref": 0 }, - "consent": "consentValue", + "consent": "BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA", "eids": [ { "source": "adserver.org", @@ -679,7 +679,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -695,9 +695,20 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, "aliases": { "appnexusAlias": "appnexus" }, + "events": {}, "targeting": { "pricegranularity": { "precision": 2, @@ -708,16 +719,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -757,7 +758,8 @@ "rubicon": { "integration": "dmbjs" } - } + }, + "auctiontimestamp": 1000 } } } @@ -776,6 +778,9 @@ "rubicon": "{{ rubicon.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-matcher-rubicon-appnexus.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-matcher-rubicon-appnexus.json index 89411f3c8a7..fe6680ed067 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-matcher-rubicon-appnexus.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-matcher-rubicon-appnexus.json @@ -3,7 +3,7 @@ "928185755156387460@1": "6cf69b42-96f5-4ba1-a984-a9b4d8ff21cf", "7706636740145184841@5.5": "117431c9-807a-41e1-82a7-dcd8f8875493", "880290288@8.43": "683fe79f-6df7-4971-ac70-820e0486992d", - "": "b2528f73-96ab-42ab-8f15-fbe6ed779a26", + "": "b2528f73-96ab-42ab-8f15-fbe6ed779a26", "7706636740145184840@5": "91912e5b-dfa8-42bc-9c7e-df6ce0449c19", "f227a07f-1579-4465-bc5e-5c5b02a0c180@0.8": "c75130ed-bcdd-4821-ad91-90cf835615c5", "a121a07f-1579-4465-bc5e-5c5b02a0c421@0.9": "765e116a-5773-49d5-a648-0b97a9907a4e", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-rubicon-appnexus-request.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-rubicon-appnexus-request.json index ad14ac64e06..af03838fc07 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-rubicon-appnexus-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-cache-rubicon-appnexus-request.json @@ -5,7 +5,8 @@ "value": { "id": "f227a07f-1579-4465-bc5e-5c5b02a0c180", "impid": "impStoredAuctionResponse", - "price": 0.8 + "price": 0.8, + "wurl": "http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c180&a=5001&ts=1000&bidder=rubicon&f=i" } }, { @@ -17,7 +18,8 @@ "adm": "adm2", "crid": "crid2", "w": 300, - "h": 600 + "h": 600, + "wurl": "http://localhost:8000/event?t=win&b=466223845&a=5001&ts=1000&bidder=rubicon&f=i" } }, { @@ -37,6 +39,7 @@ "cat": [], "w": 300, "h": 250, + "wurl": "http://localhost:8000/event?t=win&b=7706636740145184840&a=5001&ts=1000&bidder=appnexusAlias&f=i", "ext": { "appnexus": { "brand_id": 350, @@ -54,7 +57,8 @@ "value": { "id": "f227a07f-1579-4465-bc5e-5c5b02a0c181", "impid": "impStoredBidResponse", - "price": 0.8 + "price": 0.8, + "wurl": "http://localhost:8000/event?t=win&b=f227a07f-1579-4465-bc5e-5c5b02a0c181&a=5001&ts=1000&bidder=rubicon&f=i" } }, { @@ -82,7 +86,8 @@ "bidder_id": 2, "bid_ad_type": 3 } - } + }, + "wurl": "http://localhost:8000/event?t=win&b=928185755156387460&a=5001&ts=1000&bidder=appnexus&f=i" } }, { @@ -90,7 +95,8 @@ "value": { "id": "a121a07f-1579-4465-bc5e-5c5b02a0c421", "impid": "impStoredAuctionResponse", - "price": 0.9 + "price": 0.9, + "wurl": "http://localhost:8000/event?t=win&b=a121a07f-1579-4465-bc5e-5c5b02a0c421&a=5001&ts=1000&bidder=appnexus&f=i" } }, { @@ -103,6 +109,7 @@ "crid": "crid1", "w": 300, "h": 250, + "wurl": "http://localhost:8000/event?t=win&b=880290288&a=5001&ts=1000&bidder=rubicon&f=i", "ext": { "rp": { "targeting": [ @@ -133,6 +140,7 @@ "crid": "29681110", "w": 300, "h": 250, + "wurl": "http://localhost:8000/event?t=win&b=7706636740145184841&a=5001&ts=1000&bidder=appnexus&f=i", "ext": { "appnexus": { "brand_id": 1, @@ -146,7 +154,7 @@ }, { "type": "xml", - "value": "", + "value": "", "expiry": 120 } ] diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-1.json index cc3827f1c23..db799424704 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-1.json @@ -79,53 +79,7 @@ }, "user": { "ext": { - "consent": "consentValue", - "digitrust": { - "id": "id", - "keyv": 123, - "pref": 0 - }, - "eids": [ - { - "source": "adserver.org", - "uids": [ - { - "id": "cd96870f-f53d-4986-a08e-cd1612fb13b0", - "ext": { - "rtiPartner": "TDID" - } - } - ] - }, - { - "source": "liveintent.com", - "uids": [ - { - "id": "efcf3a33-2eaf-4d6b-bf11-a411f134278c" - } - ], - "ext": { - "segments": [ - "999", - "888" - ] - } - }, - { - "source": "pubcid", - "id": "29cfaea8-a429-48fc-9537-8a19a8eb4f0d" - } - ], - "tpid": [ - { - "source": "tdid", - "uid": "cd96870f-f53d-4986-a08e-cd1612fb13b0" - }, - { - "source": "liveintent.com", - "uid": "efcf3a33-2eaf-4d6b-bf11-a411f134278c" - } - ], + "consent": "BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA", "rp": { "target": { "ucat": [ @@ -133,17 +87,13 @@ ], "search": [ "iphone" - ], - "LIseg": [ - "999", - "888" ] } } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-2.json index 7619597f699..24644399c9c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/rubicon_appnexus/test-rubicon-bid-request-2.json @@ -61,65 +61,11 @@ }, "user": { "ext": { - "consent": "consentValue", - "digitrust": { - "id": "id", - "keyv": 123, - "pref": 0 - }, - "eids": [ - { - "source": "adserver.org", - "uids": [ - { - "id": "cd96870f-f53d-4986-a08e-cd1612fb13b0", - "ext": { - "rtiPartner": "TDID" - } - } - ] - }, - { - "source": "liveintent.com", - "uids": [ - { - "id": "efcf3a33-2eaf-4d6b-bf11-a411f134278c" - } - ], - "ext": { - "segments": [ - "999", - "888" - ] - } - }, - { - "source": "pubcid", - "id": "29cfaea8-a429-48fc-9537-8a19a8eb4f0d" - } - ], - "tpid": [ - { - "source": "tdid", - "uid": "cd96870f-f53d-4986-a08e-cd1612fb13b0" - }, - { - "source": "liveintent.com", - "uid": "efcf3a33-2eaf-4d6b-bf11-a411f134278c" - } - ], - "rp": { - "target": { - "LIseg": [ - "999", - "888" - ] - } - } + "consent": "BOEFEAyOEFEAyAHABDENAIgAAAB9vABAASA" } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "source": { "fd": 1, "tid": "tid", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-request.json index aa94be5cb7d..a55d2aa7a58 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-request.json @@ -57,6 +57,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -70,16 +80,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -87,7 +87,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-response.json index c5bd7737d49..c11fd7763dc 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sharethrough/test-auction-sharethrough-response.json @@ -150,6 +150,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -164,16 +174,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -182,7 +182,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } @@ -191,6 +192,9 @@ "sharethrough": "{{ sharethrough.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, + "prebid": { + "auctiontimestamp": 1000 + }, "tmaxrequest": 3000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-request.json b/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-request.json index ac44f9d6ce0..de57446bf33 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-request.json @@ -64,7 +64,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -74,6 +74,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "includebidderkeys": true, "includewinners": true, @@ -85,16 +95,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -102,7 +102,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-response.json b/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-response.json index ef5acd23eea..593440c16a4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-auction-smartrtb-response.json @@ -1,12 +1,5 @@ { "cur": "USD", - "ext": { - "responsetimemillis": { - "cache": "{{ cache.response_time_ms }}", - "smartrtb": "{{ smartrtb.response_time_ms }}" - }, - "tmaxrequest": 3000 - }, "id": "tid", "seatbid": [ { @@ -46,5 +39,15 @@ "group": 0, "seat": "smartrtb" } - ] -} \ No newline at end of file + ], + "ext": { + "responsetimemillis": { + "cache": "{{ cache.response_time_ms }}", + "smartrtb": "{{ smartrtb.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-smartrtb-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-smartrtb-bid-request.json index f01b251c89e..c62ebd6a4b0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-smartrtb-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/smartrtb/test-smartrtb-bid-request.json @@ -20,17 +20,17 @@ "ttlseconds": 120 } }, - "targeting": { - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 } - }, + } + }, + "targeting": { "includebidderkeys": true, "includewinners": true, "pricegranularity": { @@ -42,7 +42,8 @@ } ] } - } + }, + "auctiontimestamp": 1000 } }, "id": "tid", @@ -110,7 +111,7 @@ "fd": 1, "tid": "tid" }, - "tmax": 3000, + "tmax": 5000, "user": { "ext": { "consent": "consentValue", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-request.json b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-request.json index dddd36436c3..2cbd60b8f9b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-request.json @@ -84,7 +84,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -94,6 +94,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -103,16 +113,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -120,7 +120,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-response.json b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-response.json index 8f672676c54..577cf9ef6ab 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-auction-somoaudience-response.json @@ -161,6 +161,9 @@ "somoaudience": "{{ somoaudience.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-1.json index 9f3f6312db5..077c83ddce5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-1.json @@ -56,7 +56,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-2.json index e957d0a7da3..d23c70e4ebf 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-2.json @@ -12,9 +12,7 @@ 5 ], "w": 1024, - "h": 576, - "skipmin": 0, - "skipafter": 0 + "h": 576 }, "bidfloor": 2.1 } @@ -49,7 +47,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-3.json b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-3.json index e88358083e0..bca7fa68205 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-3.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/somoaudience/test-somoaudience-bid-request-3.json @@ -40,7 +40,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-request.json index 65c802167e3..e4ad7878ceb 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-request.json @@ -45,7 +45,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -55,6 +55,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -64,16 +74,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -81,7 +81,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-response.json index 97577cf31e9..4c5f14ab944 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-auction-sonobi-response.json @@ -96,6 +96,9 @@ "sonobi": "{{ sonobi.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-1.json index 16980d3ba93..9a825b89f1e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-1.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -64,6 +64,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -74,16 +84,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -92,7 +92,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-2.json index 6e9f3ca224a..ba088664bd8 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sonobi/test-sonobi-bid-request-2.json @@ -8,9 +8,7 @@ "video/mp4" ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "tagid": "second-tagid", "ext": { @@ -50,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-request.json b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-request.json index a69bea0696e..86049767240 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-request.json @@ -32,7 +32,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -42,6 +42,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -51,16 +61,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -68,7 +68,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-response.json index 1cae6c52a0c..f6fe198ca04 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-auction-sovrn-response.json @@ -48,6 +48,9 @@ "sovrn": "{{ sovrn.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-request-1.json index c1660e4fcfa..ae3607854af 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-request-1.json @@ -42,16 +42,16 @@ "user": { "buyeruid": "990011", "ext": { + "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - }, - "consent": "consentValue" + } } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -66,6 +66,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -76,16 +86,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -94,7 +94,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-request.json b/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-request.json index a5743e31c38..16cfc64f50e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-request.json @@ -48,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -58,6 +58,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -67,16 +77,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -84,7 +84,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-response.json b/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-response.json index f16537ddd83..9268e249a56 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-auction-synacormedia-response.json @@ -93,6 +93,9 @@ "synacormedia": "{{ synacormedia.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-synacormedia-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-synacormedia-bid-request.json index 0b2feb50329..f153dfa9688 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-synacormedia-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/synacormedia/test-synacormedia-bid-request.json @@ -50,8 +50,6 @@ "video/mp4" ], "pos": 1, - "skipafter": 0, - "skipmin": 0, "w": 300 } } @@ -75,7 +73,7 @@ "fd": 1, "tid": "tid" }, - "tmax": 3000, + "tmax": 5000, "user": { "buyeruid": "SCM-UID", "ext": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-request.json index 5c8da7e02dd..2423865570c 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-request.json @@ -33,7 +33,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -43,6 +43,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -52,16 +62,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -69,7 +69,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-response.json index 85688be7578..b8c423172e3 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-auction-tappx-response.json @@ -56,6 +56,9 @@ "tappx": "{{ tappx.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-tappx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-tappx-bid-request.json index 3cd370b49f1..c4ed1aa82da 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-tappx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tappx/test-tappx-bid-request.json @@ -43,16 +43,16 @@ "user": { "buyeruid": "TX-UID", "ext": { - "consent": "consentValue", "digitrust": { "id": "id", "keyv": 123, "pref": 0 - } + }, + "consent": "consentValue" } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +67,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +87,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +95,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-request.json b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-request.json index 66bc59485e9..24e2afabbff 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-request.json @@ -30,7 +30,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -40,6 +40,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -49,16 +59,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -66,7 +66,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-response.json b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-response.json index 67833085d3a..c06053eea40 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-auction-triplelift-response.json @@ -59,6 +59,9 @@ "triplelift": "{{ triplelift.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-cache-triplelift-request.json b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-cache-triplelift-request.json index 2a0b39a0ae1..23689d131c7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-cache-triplelift-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-cache-triplelift-request.json @@ -24,4 +24,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-triplelift-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-triplelift-bid-request.json index 1a56f49e9c3..cd8f3fa770d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-triplelift-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/triplelift/test-triplelift-bid-request.json @@ -49,7 +49,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -64,6 +64,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -74,16 +84,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -92,7 +92,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-request.json b/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-request.json index 1f7e5aa7a6b..eb65136b086 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-request.json @@ -25,7 +25,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -36,6 +36,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -49,16 +59,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -66,7 +66,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-response.json b/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-response.json index 0abdbd187a7..c872dbc9b6b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-auction-triplelift-native-response.json @@ -63,7 +63,7 @@ "triplelift_native": [ { "uri": "{{ triplelift_native.exchange_uri }}", - "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId1\",\"native\":{\"request\":\"{\\\"ver\\\":\\\"1.1\\\",\\\"context\\\":1,\\\"contextsubtype\\\":11,\\\"plcmttype\\\":4,\\\"plcmtcnt\\\":1,\\\"assets\\\":[{\\\"id\\\":0,\\\"required\\\":1,\\\"title\\\":{\\\"len\\\":500}}]}\"},\"tagid\":\"foo\",\"ext\":{\"bidder\":{\"inventoryCode\":\"foo\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"test\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"T\",\"ext\":{\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"consent\":\"consentValue\"}},\"at\":1,\"tmax\":3000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\",\"conversantAlias\":\"conversant\"},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}}}}}", + "requestbody": "{\"id\":\"tid\",\"imp\":[{\"id\":\"impId1\",\"native\":{\"request\":\"{\\\"ver\\\":\\\"1.1\\\",\\\"context\\\":1,\\\"contextsubtype\\\":11,\\\"plcmttype\\\":4,\\\"plcmtcnt\\\":1,\\\"assets\\\":[{\\\"id\\\":0,\\\"required\\\":1,\\\"title\\\":{\\\"len\\\":500}}]}\"},\"tagid\":\"foo\",\"ext\":{\"bidder\":{\"inventoryCode\":\"foo\"}}}],\"site\":{\"domain\":\"example.com\",\"page\":\"http://www.example.com\",\"publisher\":{\"id\":\"test\"},\"ext\":{\"amp\":0}},\"device\":{\"ua\":\"userAgent\",\"dnt\":2,\"ip\":\"193.168.244.1\",\"pxratio\":4.2,\"language\":\"en\",\"ifa\":\"ifaId\"},\"user\":{\"buyeruid\":\"T\",\"ext\":{\"digitrust\":{\"id\":\"id\",\"keyv\":123,\"pref\":0},\"consent\":\"consentValue\"}},\"at\":1,\"tmax\":5000,\"cur\":[\"USD\"],\"source\":{\"fd\":1,\"tid\":\"tid\"},\"regs\":{\"ext\":{\"gdpr\":0}},\"ext\":{\"prebid\":{\"debug\":1,\"aliases\":{\"appnexusAlias\":\"appnexus\",\"conversantAlias\":\"conversant\"},\"currency\":{\"rates\":{\"EUR\":{\"USD\":1.2406},\"USD\":{\"EUR\":0.811}}},\"targeting\":{\"pricegranularity\":{\"precision\":2,\"ranges\":[{\"max\":20,\"increment\":0.1}]},\"includewinners\":true,\"includebidderkeys\":true},\"cache\":{\"bids\":{},\"vastxml\":{\"ttlseconds\":120}},\"auctiontimestamp\":1000}}}", "responsebody": "{\"id\":\"test-request-id\",\"seatbid\":[{\"seat\":\"958\",\"bid\":[{\"id\":\"7706636740145184841\",\"impid\":\"test-imp-id\",\"price\":0.5,\"adid\":\"29681110\",\"adm\":\"some-test-ad\",\"adomain\":[\"triplelift.com\"],\"iurl\":\"http://nym1-ib.adnxs.com/cr?id=29681110\",\"cid\":\"958\",\"crid\":\"29681110\",\"h\":250,\"w\":300}]}],\"bidid\":\"5778926625248726496\",\"cur\":\"USD\"}", "status": 200 } @@ -113,7 +113,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -129,6 +129,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -143,16 +153,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -161,7 +161,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } @@ -170,6 +171,9 @@ "triplelift_native": "{{ triplelift_native.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-triplelift-native-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-triplelift-native-bid-request.json index 9c860fa43e6..a07fce3109e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-triplelift-native-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/tripleliftnative/test-triplelift-native-bid-request.json @@ -44,7 +44,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -60,6 +60,16 @@ "ext": { "prebid": { "debug": 1, + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "aliases": { "appnexusAlias": "appnexus", "conversantAlias": "conversant" @@ -74,16 +84,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -92,7 +92,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json index 7d0e8b148ea..5265277088f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-request.json @@ -32,7 +32,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -42,6 +42,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -51,16 +61,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -68,7 +68,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json index 40b55a287dc..25a26488bc6 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-auction-ttx-response.json @@ -48,6 +48,9 @@ "ttx": "{{ ttx.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request-1.json index 766ec323a79..ddfcb8ac62b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/ttx/test-ttx-bid-request-1.json @@ -50,7 +50,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +65,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +85,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +93,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-request.json b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-request.json index 1ffbb1883fa..0663f645242 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-request.json @@ -46,7 +46,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -56,6 +56,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -65,16 +75,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -82,7 +82,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-response.json b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-response.json index 39dddec3cb0..4ae45e5168a 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-auction-unruly-response.json @@ -94,6 +94,9 @@ "unruly": "{{ unruly.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-1.json index 2d888ddcc5e..79896c35704 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-1.json @@ -8,9 +8,7 @@ "video/mp4" ], "w": 800, - "h": 600, - "skipmin": 0, - "skipafter": 0 + "h": 600 }, "ext": { "unruly": { @@ -50,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-2.json index 1b91d57ae1d..14165293de5 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/unruly/test-unruly-bid-request-2.json @@ -8,9 +8,7 @@ "video/mp4" ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "unruly": { @@ -50,7 +48,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -65,6 +63,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -75,16 +83,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -93,7 +91,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-request.json b/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-request.json index 36b864bf796..bd44f1e08b2 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-request.json @@ -31,7 +31,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -41,6 +41,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -50,16 +60,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -67,7 +67,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-response.json b/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-response.json index 8b774d1ef35..920e42dc4e9 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-auction-verizonmedia-response.json @@ -48,6 +48,9 @@ "verizonmedia": "{{ verizonmedia.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-verizonmedia-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-verizonmedia-bid-request-1.json index 180a7cf34f7..a73e8d232ea 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-verizonmedia-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/verizonmedia/test-verizonmedia-bid-request-1.json @@ -52,7 +52,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -67,6 +67,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -77,16 +87,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -95,7 +95,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-cache-video-appnexus-response.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-cache-video-appnexus-response.json deleted file mode 100644 index 525c5d73a6d..00000000000 --- a/src/test/resources/org/prebid/server/it/openrtb2/video/test-cache-video-appnexus-response.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "responses": [ - { - "uuid": "2202329f-f30b-424a-a82d-d8cfbf15eed6" - }, - { - "uuid": "f2f0a7d4-fa87-478f-8797-e57bd5c4b067" - }, - { - "uuid": "65fdb393-7344-4873-b825-1515aee4df40" - } - ] -} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-1.json index 90391cc20e0..af712452338 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-1.json @@ -16,9 +16,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -41,9 +39,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -66,9 +62,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -91,9 +85,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -116,9 +108,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -141,9 +131,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -166,9 +154,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -191,9 +177,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -216,9 +200,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { @@ -241,9 +223,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-2.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-2.json index 420ccdf23bb..991c4ddf098 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-2.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-bid-request-2.json @@ -16,9 +16,7 @@ 6 ], "w": 640, - "h": 480, - "skipmin": 0, - "skipafter": 0 + "h": 480 }, "ext": { "appnexus": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-request.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-request.json index 8e34015c531..8c7abb10755 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-request.json @@ -29,7 +29,7 @@ }, "gdpr": { "consentrequired": false, - "consentstring": "something" + "consentstring": "BOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA" }, "yob": 1991, "gender": "F", diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-response-empty.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-response-empty.json new file mode 100644 index 00000000000..b773ce30155 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-appnexus-response-empty.json @@ -0,0 +1,3 @@ +{ + "adPods": [] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-cache-video-appnexus-request.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-cache-request.json similarity index 99% rename from src/test/resources/org/prebid/server/it/openrtb2/video/test-cache-video-appnexus-request.json rename to src/test/resources/org/prebid/server/it/openrtb2/video/test-video-cache-request.json index d86a37b05b4..43d4dd4080b 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/video/test-cache-video-appnexus-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-cache-request.json @@ -13,4 +13,4 @@ "value": "some-test-ad-2" } ] -} +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-cache-response-matcher.json b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-cache-response-matcher.json new file mode 100644 index 00000000000..e1ad042f7cb --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/video/test-video-cache-response-matcher.json @@ -0,0 +1,5 @@ +{ + "some-test-ad-3": "2202329f-f30b-424a-a82d-d8cfbf15eed6", + "some-test-ad": "f2f0a7d4-fa87-478f-8797-e57bd5c4b067", + "some-test-ad-2": "65fdb393-7344-4873-b825-1515aee4df40" +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-request.json b/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-request.json index f448acf0a3f..3587d420a8d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-request.json @@ -38,7 +38,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -48,6 +48,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -57,16 +67,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -74,7 +74,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-response.json b/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-response.json index b6bd0a2b0d3..b6b167420fe 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/visx/test-auction-visx-response.json @@ -51,6 +51,9 @@ "cache": "{{ cache.response_time_ms }}", "visx": "{{ visx.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/visx/test-visx-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/visx/test-visx-bid-request.json index 0b4102c2890..cc25ce178e7 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/visx/test-visx-bid-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/visx/test-visx-bid-request.json @@ -56,7 +56,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -71,6 +71,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -81,16 +91,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -99,7 +99,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-request.json b/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-request.json index ff520f6aa08..9a74cfc1ac9 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-request.json @@ -27,7 +27,7 @@ "app": { }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -37,6 +37,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -46,16 +56,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -63,7 +63,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-response.json b/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-response.json index 6cf7bcab9aa..36b4155213f 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-auction-vrtcal-response.json @@ -50,6 +50,9 @@ "vrtcal": "{{ vrtcal.response_time_ms }}", "cache": "{{ cache.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-vrtcal-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-vrtcal-bid-request-1.json index f2adf2e6eb9..5d7f79772b0 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-vrtcal-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/vrtcal/test-vrtcal-bid-request-1.json @@ -39,7 +39,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -54,6 +54,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -64,16 +74,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -82,7 +82,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-request.json index 8be15f3b150..02695f3005e 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-request.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-request.json @@ -30,7 +30,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -40,6 +40,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -49,16 +59,6 @@ "increment": 0.1 } ] - }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } - } } }, "cache": { @@ -66,7 +66,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } }, "user": { diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-response.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-response.json index 67b2c325003..36386f57789 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-auction-yieldmo-response.json @@ -50,6 +50,9 @@ "cache": "{{ cache.response_time_ms }}", "yieldmo": "{{ yieldmo.response_time_ms }}" }, - "tmaxrequest": 3000 + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 } } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-request-1.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-request-1.json index e29d96b53f2..2bf2e43d4d4 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-request-1.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldmo/test-yieldmo-bid-request-1.json @@ -46,7 +46,7 @@ } }, "at": 1, - "tmax": 3000, + "tmax": 5000, "cur": [ "USD" ], @@ -61,6 +61,16 @@ }, "ext": { "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, "targeting": { "pricegranularity": { "precision": 2, @@ -71,16 +81,6 @@ } ] }, - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.811 - } - } - }, "includewinners": true, "includebidderkeys": true }, @@ -89,7 +89,8 @@ "vastxml": { "ttlseconds": 120 } - } + }, + "auctiontimestamp": 1000 } } } \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-auction-yieldone-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-auction-yieldone-request.json new file mode 100644 index 00000000000..48977a69049 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-auction-yieldone-request.json @@ -0,0 +1,88 @@ +{ + "id": "tid", + "imp": [ + { + "id": "impId001", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "yieldone": { + "placementId": "36891" + } + } + } + ], + "device": { + "pxratio": 4.2, + "dnt": 2, + "language": "en", + "ifa": "ifaId" + }, + "site": { + "publisher": { + "id": "publisherId" + } + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "source": { + "fd": 1, + "tid": "tid" + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 + } + } + }, + "targeting": { + "pricegranularity": { + "precision": 2, + "ranges": [ + { + "max": 20, + "increment": 0.1 + } + ] + } + }, + "cache": { + "bids": {}, + "vastxml": { + "ttlseconds": 120 + } + }, + "auctiontimestamp": 1000 + } + }, + "user": { + "ext": { + "consent": "consentValue", + "digitrust": { + "id": "id", + "keyv": 123, + "pref": 0 + } + } + }, + "regs": { + "ext": { + "gdpr": 0 + } + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-auction-yieldone-response.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-auction-yieldone-response.json new file mode 100644 index 00000000000..0eebe0f049e --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-auction-yieldone-response.json @@ -0,0 +1,58 @@ +{ + "id": "tid", + "seatbid": [ + { + "bid": [ + { + "id": "bid001", + "impid": "impId001", + "price": 3.33, + "adm": "adm001", + "adid": "adid001", + "cid": "cid001", + "crid": "crid001", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner", + "targeting": { + "hb_pb": "3.30", + "hb_size_yieldone": "300x250", + "hb_bidder_yieldone": "yieldone", + "hb_cache_path": "{{ cache.path }}", + "hb_size": "300x250", + "hb_cache_host_yieldone": "{{ cache.host }}", + "hb_cache_path_yieldone": "{{ cache.path }}", + "hb_cache_id_yieldone": "f0ab9105-cb21-4e59-b433-70f5ad6671cb", + "hb_bidder": "yieldone", + "hb_cache_id": "f0ab9105-cb21-4e59-b433-70f5ad6671cb", + "hb_pb_yieldone": "3.30", + "hb_cache_host": "{{ cache.host }}" + }, + "cache": { + "bids": { + "url": "{{ cache.resource_url }}f0ab9105-cb21-4e59-b433-70f5ad6671cb", + "cacheId": "f0ab9105-cb21-4e59-b433-70f5ad6671cb" + } + } + } + } + } + ], + "seat": "yieldone", + "group": 0 + } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "yieldone": "{{ yieldone.response_time_ms }}", + "cache": "{{ cache.response_time_ms }}" + }, + "prebid": { + "auctiontimestamp": 1000 + }, + "tmaxrequest": 5000 + } +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-cache-yieldone-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-cache-yieldone-request.json new file mode 100644 index 00000000000..23ddbec96e5 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-cache-yieldone-request.json @@ -0,0 +1,18 @@ +{ + "puts": [ + { + "type": "json", + "value": { + "id": "bid001", + "impid": "impId001", + "price": 3.33, + "adm": "adm001", + "adid": "adid001", + "cid": "cid001", + "crid": "crid001", + "w": 300, + "h": 250 + } + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-cache-yieldone-response.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-cache-yieldone-response.json new file mode 100644 index 00000000000..1112a7b5a6a --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-cache-yieldone-response.json @@ -0,0 +1,7 @@ +{ + "responses": [ + { + "uuid": "f0ab9105-cb21-4e59-b433-70f5ad6671cb" + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-yieldone-bid-request.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-yieldone-bid-request.json new file mode 100644 index 00000000000..33da4187e03 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-yieldone-bid-request.json @@ -0,0 +1,100 @@ +{ + "id": "tid", + "imp": [ + { + "id": "impId001", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "placementId": "36891" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "http://www.example.com", + "publisher": { + "id": "publisherId" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "dnt": 2, + "ip": "193.168.244.1", + "pxratio": 4.2, + "language": "en", + "ifa": "ifaId" + }, + "user": { + "buyeruid": "YD-UID", + "ext": { + "consent": "consentValue", + "digitrust": { + "id": "id", + "keyv": 123, + "pref": 0 + } + } + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "source": { + "fd": 1, + "tid": "tid" + }, + "regs": { + "ext": { + "gdpr": 0 + } + }, + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.811 + } + } + }, + "targeting": { + "pricegranularity": { + "precision": 2, + "ranges": [ + { + "max": 20, + "increment": 0.1 + } + ] + }, + "includewinners": true, + "includebidderkeys": true + }, + "cache": { + "bids": {}, + "vastxml": { + "ttlseconds": 120 + } + }, + "auctiontimestamp": 1000 + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-yieldone-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-yieldone-bid-response.json new file mode 100644 index 00000000000..95a93284e04 --- /dev/null +++ b/src/test/resources/org/prebid/server/it/openrtb2/yieldone/test-yieldone-bid-response.json @@ -0,0 +1,20 @@ +{ + "id": "tid", + "seatbid": [ + { + "bid": [ + { + "id": "bid001", + "impid": "impId001", + "price": 3.33, + "adid": "adid001", + "crid": "crid001", + "cid": "cid001", + "adm": "adm001", + "h": 250, + "w": 300 + } + ] + } + ] +} \ No newline at end of file diff --git a/src/test/resources/org/prebid/server/it/storedrequests/test-amp-stored-request.json b/src/test/resources/org/prebid/server/it/storedrequests/test-amp-stored-request.json index 650ae3eec22..d3d93cfef4c 100644 --- a/src/test/resources/org/prebid/server/it/storedrequests/test-amp-stored-request.json +++ b/src/test/resources/org/prebid/server/it/storedrequests/test-amp-stored-request.json @@ -42,28 +42,29 @@ "domain": "example.com", "page": "http://www.example.com" }, - "tmax": 2000, + "tmax": 5000, "cur": [ "USD" ], "ext": { "prebid": { - "targeting": { - "pricegranularity": "dense", - "currency": { - "rates": { - "EUR": { - "USD": 1.2406 - }, - "USD": { - "EUR": 0.8110 - } + "currency": { + "rates": { + "EUR": { + "USD": 1.2406 + }, + "USD": { + "EUR": 0.8110 } } }, + "targeting": { + "pricegranularity": "dense" + }, "cache": { "bids": {} - } + }, + "auctiontimestamp": 1000 } }, "regs": { diff --git a/src/test/resources/org/prebid/server/it/test-app-settings.yaml b/src/test/resources/org/prebid/server/it/test-app-settings.yaml index 7061de504a0..80005f45c2f 100644 --- a/src/test/resources/org/prebid/server/it/test-app-settings.yaml +++ b/src/test/resources/org/prebid/server/it/test-app-settings.yaml @@ -9,7 +9,6 @@ accounts: - id: 2763 - id: 5001 eventsEnabled: true - enforceGdpr: true configs: - id: 14062 config: > 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 006da712357..bd107576b9d 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -210,6 +210,10 @@ adapters.yieldmo.enabled=true adapters.yieldmo.endpoint=http://localhost:8090/yieldmo-exchange adapters.yieldmo.pbs-enforces-gdpr=true adapters.yieldmo.usersync.url=//yieldmo-usersync +adapters.yieldone.enabled=true +adapters.yieldone.endpoint=http://localhost:8090/yieldone-exchange +adapters.yieldone.pbs-enforces-gdpr=true +adapters.yieldone.usersync.url=//yieldone-usersync http-client.circuit-breaker.enabled=true http-client.circuit-breaker.opening-threshold=1 http-client.circuit-breaker.opening-interval-ms=1000 @@ -249,5 +253,6 @@ admin.port=8060 status-response=ok analytics.log.enabled=true gdpr.host-vendor-id=1 -gdpr.vendorlist.filesystem-cache-dir=src/test/resources/org/prebid/server/it/gdpr-vendorlist +gdpr.vendorlist.v1.cache-dir=src/test/resources/org/prebid/server/it/gdpr-vendorlist1 +gdpr.vendorlist.v2.cache-dir=src/test/resources/org/prebid/server/it/gdpr-vendorlist2 ccpa.enforce=false diff --git a/src/test/resources/org/prebid/server/it/vtrack/test-cache-request.json b/src/test/resources/org/prebid/server/it/vtrack/test-cache-request.json index 7fec57b7949..2ab63152efe 100644 --- a/src/test/resources/org/prebid/server/it/vtrack/test-cache-request.json +++ b/src/test/resources/org/prebid/server/it/vtrack/test-cache-request.json @@ -1,11 +1,9 @@ - { - "puts": [ - { - "value": "prebid.org wrapper", - "bidid": "bidid", - "bidder": "rubicon", - "ttlseconds": 3600, - "type": "xml" - } - ] - } +{ + "puts": [ + { + "type": "xml", + "value": "prebid.org wrapper", + "ttlseconds": 3600 + } + ] +} diff --git a/src/test/resources/org/prebid/server/it/vtrack/test-vtrack-request.json b/src/test/resources/org/prebid/server/it/vtrack/test-vtrack-request.json index fc98f07a89d..1be8338394a 100644 --- a/src/test/resources/org/prebid/server/it/vtrack/test-vtrack-request.json +++ b/src/test/resources/org/prebid/server/it/vtrack/test-vtrack-request.json @@ -1,11 +1,12 @@ { "puts": [ { - "bidid": "bidid", - "bidder": "rubicon", "type": "xml", "value": "prebid.org wrapper", - "ttlseconds": 3600 + "ttlseconds": 3600, + "bidid": "bidid", + "bidder": "rubicon", + "timestamp": 1000 } ] }