diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f64a14137d4..23e63602f2f 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,3 +1,3 @@ # From https://github.com/microsoft/vscode-dev-containers/blob/master/containers/go/.devcontainer/Dockerfile -ARG VARIANT="21-jdk-bookworm" +ARG VARIANT="25-jdk-trixie" FROM mcr.microsoft.com/vscode/devcontainers/java:${VARIANT} diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d9a309d3661..6b872b2b8d0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "dockerfile": "Dockerfile", "args": { // Update the VARIANT arg to pick a version of Java - "VARIANT": "21-jdk-bookworm", + "VARIANT": "25-jdk-trixie", } }, "containerEnv": { diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index a6852ae7c92..ad440b85e32 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -34,7 +34,7 @@ jobs: uses: actions/setup-java@v5 with: distribution: 'temurin' - java-version: 21 + java-version: 25 - name: Cache Maven packages uses: actions/cache@v5 @@ -52,7 +52,7 @@ jobs: - name: Build with Maven if: matrix.build-mode == 'manual' - run: mvn -B package --file extra/pom.xml + run: mvn -B clean package -DskipUnitTests --file extra/pom.xml - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/docker-image-publish.yml b/.github/workflows/docker-image-publish.yml index 7f993ade73d..e3991f85a1e 100644 --- a/.github/workflows/docker-image-publish.yml +++ b/.github/workflows/docker-image-publish.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 21 ] + java: [ 25 ] dockerfile-path: [ Dockerfile, Dockerfile-modules ] include: - dockerfile-path: Dockerfile diff --git a/.github/workflows/pr-functional-tests.yml b/.github/workflows/pr-functional-tests.yml index d512022413a..f2f8fb0c571 100644 --- a/.github/workflows/pr-functional-tests.yml +++ b/.github/workflows/pr-functional-tests.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - java: [ 21 ] + java: [ 25 ] steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/pr-java-ci.yml b/.github/workflows/pr-java-ci.yml index d69d222592f..608191c6d5f 100644 --- a/.github/workflows/pr-java-ci.yml +++ b/.github/workflows/pr-java-ci.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - java: [ 21 ] + java: [ 25 ] steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/pr-module-functional-tests.yml b/.github/workflows/pr-module-functional-tests.yml index c3b04858677..6741e45b1d6 100644 --- a/.github/workflows/pr-module-functional-tests.yml +++ b/.github/workflows/pr-module-functional-tests.yml @@ -22,7 +22,7 @@ jobs: strategy: matrix: - java: [ 21 ] + java: [ 25 ] steps: - uses: actions/checkout@v5 diff --git a/.github/workflows/release-asset-publish.yml b/.github/workflows/release-asset-publish.yml index bfa938bebe9..9b6e38c7a7c 100644 --- a/.github/workflows/release-asset-publish.yml +++ b/.github/workflows/release-asset-publish.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - java: [ 21 ] + java: [ 25 ] steps: - uses: actions/checkout@v5 - name: Set up JDK diff --git a/Dockerfile b/Dockerfile index 7de0126d535..402df0e39d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM amazoncorretto:21.0.8-al2023 +FROM amazoncorretto:25.0.3-al2023-headless WORKDIR /app/prebid-server diff --git a/Dockerfile-modules b/Dockerfile-modules index 1626999164a..f794f7c1946 100644 --- a/Dockerfile-modules +++ b/Dockerfile-modules @@ -1,4 +1,4 @@ -FROM amazoncorretto:21.0.8-al2023 +FROM amazoncorretto:25.0.3-al2023-headless WORKDIR /app/prebid-server diff --git a/README.md b/README.md index b5aa6539aae..795bb29af77 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Follow next steps to create JAR file which can be deployed locally. - Install prerequsites - Java SDK: Oracle's or Corretto. Let us know if there's a distribution PBS-Java doesn't work with. - - Java SDK Version: 21 + - Java SDK Version: 25 - Maven - Clone the project: diff --git a/docs/config-app.md b/docs/config-app.md index a661f5a74a2..5d4c16a731b 100644 --- a/docs/config-app.md +++ b/docs/config-app.md @@ -49,7 +49,7 @@ This parameter exists to allow to change the location of the directory Vert.x wi - `http-client.connect-timeout-ms` - set the connect timeout. - `http-client.circuit-breaker.enabled` - if equals to `true` circuit breaker will be used to make http client more robust. - `http-client.circuit-breaker.opening-threshold` - the number of failures before opening the circuit. -- `http-client.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. +- `http-client.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. (Must be a multiple of 1000) - `http-client.circuit-breaker.closing-interval-ms` - time spent in open state before attempting to re-try. - `http-client.circuit-breaker.idle-expire-hours` - idle time to clean the circuit breaker up. - `http-client.use-compression` - if equals to `true` httpclient compression is enabled for requests (see [also](https://vertx.io/docs/apidocs/io/vertx/core/http/HttpClientOptions.html#setTryUseCompression-boolean-)) @@ -338,7 +338,7 @@ For database data source available next options: - `settings.database.stored-responses-query` - the SQL query to fetch stored responses. - `settings.database.circuit-breaker.enabled` - if equals to `true` circuit breaker will be used to make database client more robust. - `settings.database.circuit-breaker.opening-threshold` - the number of failures before opening the circuit. -- `settings.database.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. +- `settings.database.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. (Must be a multiple of 1000) - `settings.database.circuit-breaker.closing-interval-ms` - time spent in open state before attempting to re-try. For HTTP data source available next options: @@ -473,7 +473,7 @@ If not defined in config all other Health Checkers would be disabled and endpoin - `geolocation.enabled` - if equals to `true` the geo location service will be used to determine the country for client request. - `geolocation.circuit-breaker.enabled` - if equals to `true` circuit breaker will be used to make geo location client more robust. - `geolocation.circuit-breaker.opening-threshold` - the number of failures before opening the circuit. -- `geolocation.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. +- `geolocation.circuit-breaker.opening-interval-ms` - time interval for opening the circuit breaker if failures count reached. (Must be a multiple of 1000) - `geolocation.circuit-breaker.closing-interval-ms` - time spent in open state before attempting to re-try. - `geolocation.type` - set the geo location service provider, can be `maxmind` or custom provided by hosting company. - `geolocation.maxmind` - section for [MaxMind](https://www.maxmind.com) configuration as geo location service provider. diff --git a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanner.java b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanner.java index 1b3afe3092d..0fbe25832a2 100644 --- a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanner.java +++ b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/BidsScanner.java @@ -55,83 +55,50 @@ public void disableScan() { } public Future submitBids(RedisBidsData bids) { - final Promise scanResult = Promise.promise(); - final RedisAPI readRedisNodeAPI = this.readRedisNode.getRedisAPI(); - final boolean shouldSubmit = !isScanDisabled - && readRedisNodeAPI != null && !bids.getBresps().isEmpty(); - - if (shouldSubmit) { - readRedisNodeAPI.get("function_submit_bids", submitHash -> { - final Object submitHashResult = submitHash.result(); - if (submitHashResult != null) { - final List readArgs = List.of( - submitHashResult.toString(), - "0", - toBidsAsJson(bids), - apiKey, - "true"); - - readRedisNodeAPI.evalsha(readArgs, response -> { - if (response.result() != null) { - final BidsScanResult parserResult = redisParser - .parseBidsScanResult(response.result().toString()); - final boolean isAnyRoSkipped = parserResult.getBidScanResults() - .stream().anyMatch(BidScanResult::isRoSkipped); - - if (isAnyRoSkipped) { - reSubmitBidsToWriteNode(readArgs, scanResult); - } else { - scanResult.complete(parserResult); - } - } else { - scanResult.complete(getEmptyScanResult()); - } - }); - } else { - scanResult.complete(getEmptyScanResult()); - } - }); - - return scanResult.future(); + if (isScanDisabled || readRedisNodeAPI == null || bids.getBresps().isEmpty()) { + return Future.succeededFuture(getEmptyScanResult()); } - return Future.succeededFuture(getEmptyScanResult()); + return readRedisNodeAPI.get("function_submit_bids") + .map(Response::toString) + .map(response -> List.of(response, "0", toBidsAsJson(bids), apiKey, "true")) + .compose(args -> scanBids(args, readRedisNodeAPI)) + .otherwise(ignored -> getEmptyScanResult()); + } + + private Future scanBids(List args, RedisAPI redisAPI) { + return redisAPI.evalsha(args) + .map(Response::toString) + .map(redisParser::parseBidsScanResult) + .compose(parsedResult -> parsedResult.getBidScanResults() + .stream().anyMatch(BidScanResult::isRoSkipped) + ? reSubmitBidsToWriteNode(args) + : Future.succeededFuture(parsedResult)); } - private void reSubmitBidsToWriteNode(List readArgs, Promise scanResult) { + private Future reSubmitBidsToWriteNode(List readArgs) { final RedisAPI writeRedisAPI = this.writeRedisNode.getRedisAPI(); - if (writeRedisAPI != null) { - final List writeArgs = readArgs.stream().limit(4).toList(); - writeRedisAPI.evalsha(writeArgs, response -> { - if (response.result() != null) { - final BidsScanResult parserResult = redisParser - .parseBidsScanResult(response.result().toString()); - - scanResult.complete(parserResult); - } else { - scanResult.complete(getEmptyScanResult()); - } - }); - } else { - scanResult.complete(getEmptyScanResult()); + if (writeRedisAPI == null) { + return Future.succeededFuture(getEmptyScanResult()); } + + final List writeArgs = readArgs.stream().limit(4).toList(); + return writeRedisAPI.evalsha(writeArgs) + .map(Response::toString) + .map(redisParser::parseBidsScanResult); } public Future isScanDisabledFlag() { final RedisAPI redisAPI = this.readRedisNode.getRedisAPI(); - final Promise isDisabled = Promise.promise(); - - if (redisAPI != null) { - redisAPI.get("scan-disabled", scanDisabledValue -> { - final Response scanDisabled = scanDisabledValue.result(); - isDisabled.complete(scanDisabled != null && "true".equals(scanDisabled.toString())); - }); - - return isDisabled.future(); + if (redisAPI == null) { + return Future.succeededFuture(true); } - return Future.succeededFuture(true); + return redisAPI.get("scan-disabled") + .map(Response::toString) + .map(Boolean::parseBoolean) + .otherwise(false); } private String toBidsAsJson(RedisBidsData bids) { diff --git a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/RedisClient.java b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/RedisClient.java index d1b424f314e..60b910c632a 100644 --- a/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/RedisClient.java +++ b/extra/modules/confiant-ad-quality/src/main/java/org/prebid/server/hooks/modules/com/confiant/adquality/core/RedisClient.java @@ -61,7 +61,8 @@ public RedisAPI getRedisAPI() { */ private void createRedisClient(Handler> handler, boolean isReconnect) { Redis.createClient(vertx, options) - .connect(onConnect -> { + .connect() + .onComplete(onConnect -> { if (onConnect.succeeded()) { connection = onConnect.result(); connection.exceptionHandler(e -> { diff --git a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/DatabaseReaderFactory.java b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/DatabaseReaderFactory.java index 19155c86e8f..61b969eee6f 100644 --- a/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/DatabaseReaderFactory.java +++ b/extra/modules/greenbids-real-time-data/src/main/java/org/prebid/server/hooks/modules/greenbids/real/time/data/config/DatabaseReaderFactory.java @@ -4,7 +4,6 @@ import com.maxmind.geoip2.DatabaseReader; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.file.FileSystem; import io.vertx.core.file.OpenOptions; @@ -45,11 +44,10 @@ public DatabaseReaderFactory(GreenbidsRealTimeDataProperties properties, Vertx v } @Override - public void initialize(Promise initializePromise) { - downloadAndExtract() + public Future initialize() { + return downloadAndExtract() .onSuccess(databaseReaderRef::set) - .mapEmpty() - .onComplete(initializePromise); + .mapEmpty(); } private Future downloadAndExtract() { diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricher.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricher.java index ec9fe4ef0a7..de9b84c3422 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricher.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricher.java @@ -8,6 +8,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl; import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Audience; @@ -70,14 +71,15 @@ private ObjectNode targetingToObjectNode(List targeting) { for (Audience audience : targeting) { final List ids = audience.getIds(); - if (CollectionUtils.isEmpty(ids)) { + final String keyspace = audience.getKeyspace(); + if (CollectionUtils.isEmpty(ids) || StringUtils.isEmpty(keyspace)) { continue; } final String joinedIds = ids.stream() .map(AudienceId::getId) .collect(Collectors.joining(",")); - node.putIfAbsent(audience.getKeyspace(), TextNode.valueOf(joinedIds)); + node.putIfAbsent(keyspace, TextNode.valueOf(joinedIds)); } return node; diff --git a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImpl.java b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImpl.java index d31929f111f..e6e5510c40f 100644 --- a/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImpl.java +++ b/extra/modules/optable-targeting/src/main/java/org/prebid/server/hooks/modules/optable/targeting/v1/net/APIClientImpl.java @@ -3,7 +3,7 @@ import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Future; import io.vertx.core.MultiMap; -import io.vertx.core.http.impl.headers.HeadersMultiMap; +import io.vertx.core.http.HttpHeaders; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.execution.timeout.Timeout; @@ -69,7 +69,7 @@ private String resolveEndpoint(String tenant, String origin) { } private static MultiMap headers(OptableTargetingProperties properties, List ips, String userAgent) { - final MultiMap headers = HeadersMultiMap.headers() + final MultiMap headers = HttpHeaders.headers() .add(HttpUtil.ACCEPT_HEADER, "application/json"); if (userAgent != null) { diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java index 99f24ea4bc5..2ba8789c5c9 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/BaseOptableTest.java @@ -16,7 +16,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; -import io.vertx.core.http.impl.headers.HeadersMultiMap; +import io.vertx.core.http.HttpHeaders; import org.apache.commons.io.IOUtils; import org.apache.http.HttpStatus; import org.prebid.server.activity.infrastructure.ActivityInfrastructure; @@ -193,7 +193,7 @@ protected Device givenDevice() { } protected HttpClientResponse givenSuccessHttpResponse(String fileName) { - final MultiMap headers = HeadersMultiMap.headers().add("Content-Type", "application/json"); + final MultiMap headers = HttpHeaders.headers().add("Content-Type", "application/json"); return HttpClientResponse.of(HttpStatus.SC_OK, headers, givenBodyFromFile(fileName)); } diff --git a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricherTest.java b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricherTest.java index 8b2e4b14432..8d22f7d2fd8 100644 --- a/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricherTest.java +++ b/extra/modules/optable-targeting/src/test/java/org/prebid/server/hooks/modules/optable/targeting/v1/core/BidResponseEnricherTest.java @@ -1,6 +1,7 @@ package org.prebid.server.hooks.modules.optable.targeting.v1.core; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.iab.openrtb.response.BidResponse; import org.junit.jupiter.api.Test; import org.prebid.server.hooks.execution.v1.auction.AuctionResponsePayloadImpl; import org.prebid.server.hooks.modules.optable.targeting.model.openrtb.Audience; @@ -10,10 +11,30 @@ import java.util.List; +import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; public class BidResponseEnricherTest extends BaseOptableTest { + @Test + public void shouldSkipEmptyKeyspaceWhileEnrichingBidResponse() { + // given + final BidResponse bidResponse = givenBidResponse(); + final AuctionResponsePayload auctionResponsePayload = AuctionResponsePayloadImpl.of(bidResponse); + final List targeting = singletonList(new Audience( + "provider", + List.of(new AudienceId("audienceId"), new AudienceId("audienceId2")), + null, + 1)); + final BidResponseEnricher enricher = BidResponseEnricher.of(targeting, mapper, jsonMerger); + + // when + final AuctionResponsePayload result = enricher.apply(auctionResponsePayload); + + // then + assertThat(result.bidResponse()).isEqualTo(bidResponse); + } + @Test public void shouldEnrichBidResponseByTargetingKeywords() { // given diff --git a/extra/pom.xml b/extra/pom.xml index 1a43c1b8ace..f5d788d05d2 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -16,16 +16,17 @@ - 21 + 25 UTF-8 UTF-8 ${java.version} ${java.version} - 3.1.1 - 3.14.1 - 3.5.3 + 3.3.1 + 3.3.1 + 3.15.0 + 3.5.6 ${maven-surefire-plugin.version} 0.8.13 0.46.0 @@ -33,13 +34,13 @@ 10.17.0 - 3.5.10 - 4.5.20 + 4.0.6 + 5.1.0 2.0.1.Final 4.4 1.27.1 3.6.1 - 1.10.0 + 1.10.1 2.1 4.5.14 5.5.1 @@ -60,10 +61,12 @@ 4.2.30 - 3.12.1 - 2.4-M6-groovy-4.0 + 3.13.2 + 4.2.1 + 2.4-groovy-5.0 5.15.0 + 6.0.0 false @@ -79,6 +82,20 @@ + + org.apache.logging.log4j + log4j-bom + 2.25.4 + import + pom + + + org.slf4j + slf4j-bom + 2.0.17 + pom + import + io.vertx vertx-dependencies @@ -107,6 +124,18 @@ pom import + + io.rest-assured + rest-assured-bom + ${rest-assured-bom.version} + pom + import + + + org.wiremock.integrations + wiremock-spring-boot + ${wiremock-spring-boot.version} + org.wiremock wiremock-jetty12 @@ -350,6 +379,21 @@ + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + + + org.projectlombok + lombok + + + + diff --git a/pom.xml b/pom.xml index 8ef80350c78..eae2b9de331 100644 --- a/pom.xml +++ b/pom.xml @@ -25,7 +25,7 @@ 2.0.0 9.0.1 - 4.2.1 + 4.3.1 1.7.1 3.6.0 0.6.1 @@ -150,11 +150,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - com.fasterxml.jackson.dataformat - jackson-dataformat-xml - test - com.networknt json-schema-validator @@ -163,16 +158,6 @@ com.github.java-json-tools json-patch - - com.mysql - mysql-connector-j - test - - - org.postgresql - postgresql - test - software.amazon.awssdk s3 @@ -264,6 +249,16 @@ vertx-junit5 test + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + test + + + org.wiremock.integrations + wiremock-spring-boot + test + org.wiremock wiremock-jetty12 @@ -327,27 +322,37 @@ org.testcontainers - mockserver + testcontainers-mockserver test org.testcontainers - mysql + testcontainers-mysql test org.testcontainers - localstack + testcontainers-localstack test org.testcontainers - postgresql + testcontainers-postgresql test org.testcontainers - influxdb + testcontainers-influxdb + test + + + com.mysql + mysql-connector-j + test + + + org.postgresql + postgresql test @@ -382,6 +387,9 @@ maven-surefire-plugin ${maven-surefire-plugin.version} + + spock + false @@ -394,6 +402,7 @@ ${maven-failsafe-plugin.version} + none true @@ -562,7 +571,6 @@ ${spring.boot.version} false - true @@ -659,14 +667,6 @@ - - org.apache.maven.plugins - maven-compiler-plugin - - ${java.version} - ${java.version} - - diff --git a/src/main/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporter.java index ed99c241ee5..48aa9e5d3d8 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/agma/AgmaAnalyticsReporter.java @@ -12,7 +12,6 @@ import io.vertx.core.AsyncResult; 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.HttpHeaders; import io.vertx.core.http.HttpMethod; @@ -97,9 +96,9 @@ public AgmaAnalyticsReporter(AgmaAnalyticsProperties agmaAnalyticsProperties, } @Override - public void initialize(Promise initializePromise) { + public Future initialize() { vertx.setPeriodic(bufferTimeoutMs, ignored -> sendEvents(buffer.pollAll())); - initializePromise.complete(); + return Future.succeededFuture(); } @Override diff --git a/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java index 0bddcbe05ca..b2c947c3a9c 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporter.java @@ -1,8 +1,6 @@ package org.prebid.server.analytics.reporter.pubstack; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.BooleanUtils; @@ -117,21 +115,22 @@ public String name() { } @Override - public void initialize(Promise initializePromise) { + public Future initialize() { vertx.setPeriodic(configurationRefreshDelay, id -> fetchRemoteConfig()); - fetchRemoteConfig(); - initializePromise.tryComplete(); + return fetchRemoteConfig(); } void shutdown() { eventHandlers.values().forEach(PubstackEventHandler::reportEvents); } - private void fetchRemoteConfig() { + private Future fetchRemoteConfig() { logger.info("[pubstack] Updating config: {}", pubstackConfig); - httpClient.get(makeEventEndpointUrl(pubstackConfig.getEndpoint(), pubstackConfig.getScopeId()), timeout) + return httpClient.get(makeEventEndpointUrl(pubstackConfig.getEndpoint(), pubstackConfig.getScopeId()), timeout) .map(this::processRemoteConfigurationResponse) - .onComplete(this::updateConfigsOnChange); + .map(this::updateConfigsOnChange) + .onFailure(PubstackAnalyticsReporter::logError) + .mapEmpty(); } private PubstackConfig processRemoteConfigurationResponse(HttpClientResponse response) { @@ -148,15 +147,14 @@ private PubstackConfig processRemoteConfigurationResponse(HttpClientResponse res } } - private void updateConfigsOnChange(AsyncResult asyncConfigResult) { - if (asyncConfigResult.failed()) { - logger.error("[pubstask] Fail to fetch remote configuration: {}", asyncConfigResult.cause().getMessage()); - } else if (!Objects.equals(pubstackConfig, asyncConfigResult.result())) { - final PubstackConfig pubstackConfig = asyncConfigResult.result(); + private Void updateConfigsOnChange(PubstackConfig config) { + if (!Objects.equals(pubstackConfig, config)) { eventHandlers.values().forEach(PubstackEventHandler::reportEvents); - this.pubstackConfig = pubstackConfig; + this.pubstackConfig = config; updateHandlers(pubstackConfig); } + + return null; } private void updateHandlers(PubstackConfig pubstackConfig) { @@ -187,4 +185,8 @@ private String makeEventHandlerEndpoint(String endpoint, EventType eventType) { throw new PreBidException(message); } } + + private static void logError(Throwable throwable) { + logger.error("[pubstask] Fail to fetch remote configuration: {}", throwable.getCause().getMessage()); + } } diff --git a/src/main/java/org/prebid/server/currency/CurrencyConversionService.java b/src/main/java/org/prebid/server/currency/CurrencyConversionService.java index efcaf4ad7c2..ab398f877cd 100644 --- a/src/main/java/org/prebid/server/currency/CurrencyConversionService.java +++ b/src/main/java/org/prebid/server/currency/CurrencyConversionService.java @@ -2,7 +2,6 @@ import com.iab.openrtb.request.BidRequest; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.BooleanUtils; @@ -68,7 +67,7 @@ public CurrencyConversionService(ExternalConversionProperties externalConversion * Must be called on Vertx event loop thread. */ @Override - public void initialize(Promise initializePromise) { + public Future initialize() { if (externalConversionProperties != null) { final Long refreshPeriod = externalConversionProperties.getRefreshPeriodMs(); final Long defaultTimeout = externalConversionProperties.getDefaultTimeoutMs(); @@ -84,7 +83,7 @@ public void initialize(Promise initializePromise) { externalConversionProperties.getMetrics().createCurrencyRatesGauge(this::isRatesStale); } - initializePromise.tryComplete(); + return Future.succeededFuture(); } /** diff --git a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java index b1cc8c257b2..bbaeec77a4c 100644 --- a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java +++ b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java @@ -5,7 +5,6 @@ import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.http.HttpHeaders; -import io.vertx.core.impl.ConcurrentHashSet; import lombok.Value; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; @@ -37,6 +36,7 @@ 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.concurrent.TimeoutException; import java.util.regex.Matcher; @@ -79,7 +79,7 @@ public PriceFloorFetcher(ApplicationSettings applicationSettings, this.debugProperties = debugProperties; this.mapper = Objects.requireNonNull(mapper); - fetchInProgress = new ConcurrentHashSet<>(); + fetchInProgress = ConcurrentHashMap.newKeySet(); fetchedData = Caffeine.newBuilder() .maximumSize(MAXIMUM_CACHE_SIZE) .build() diff --git a/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java b/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java index f0fc0be3574..57d01997b96 100755 --- a/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java +++ b/src/main/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationService.java @@ -1,18 +1,17 @@ package org.prebid.server.geolocation; +import io.vertx.circuitbreaker.CircuitBreaker; +import io.vertx.circuitbreaker.CircuitBreakerOptions; +import io.vertx.circuitbreaker.CircuitBreakerState; import io.vertx.core.Future; import io.vertx.core.Vertx; import org.prebid.server.execution.timeout.Timeout; import org.prebid.server.geolocation.model.GeoInfo; -import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; 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 geolocation service with circuit breaker. @@ -20,8 +19,6 @@ 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 GeoLocationService geoLocationService; private final CircuitBreaker breaker; @@ -31,39 +28,26 @@ public CircuitBreakerSecuredGeoLocationService(Vertx vertx, Metrics metrics, int openingThreshold, long openingIntervalMs, - long closingIntervalMs, - Clock clock) { + long closingIntervalMs) { this.geoLocationService = Objects.requireNonNull(geoLocationService); - breaker = new CircuitBreaker("geo_cb", Objects.requireNonNull(vertx), - openingThreshold, openingIntervalMs, closingIntervalMs, Objects.requireNonNull(clock)) - .openHandler(ignored -> circuitOpened()) - .halfOpenHandler(ignored -> circuitHalfOpened()) - .closeHandler(ignored -> circuitClosed()); + breaker = CircuitBreaker.create( + "geo_cb", + Objects.requireNonNull(vertx), + new CircuitBreakerOptions() + .setNotificationPeriod(0) + .setMaxFailures(openingThreshold) + .setFailuresRollingWindow(openingIntervalMs) + .setResetTimeout(closingIntervalMs)); - metrics.createGeoLocationCircuitBreakerGauge(breaker::isOpen); + metrics.createGeoLocationCircuitBreakerGauge(() -> breaker.state() != CircuitBreakerState.CLOSED); logger.info("Initialized GeoLocation service with Circuit Breaker"); } @Override public Future lookup(String ip, Timeout timeout) { - return breaker.execute(promise -> geoLocationService.lookup(ip, timeout).onComplete(promise)); - } - - private void circuitOpened() { - conditionalLogger.warn( - "GeoLocation service is unavailable, circuit opened.", - LOG_PERIOD_SECONDS, - TimeUnit.SECONDS); - } - - private void circuitHalfOpened() { - logger.warn("GeoLocation service is ready to try again, circuit half-opened."); - } - - private void circuitClosed() { - logger.warn("GeoLocation service becomes working, circuit closed."); + return breaker.execute(() -> geoLocationService.lookup(ip, timeout)); } } diff --git a/src/main/java/org/prebid/server/handler/SetuidHandler.java b/src/main/java/org/prebid/server/handler/SetuidHandler.java index bce568db2d7..fb2e2bb581e 100644 --- a/src/main/java/org/prebid/server/handler/SetuidHandler.java +++ b/src/main/java/org/prebid/server/handler/SetuidHandler.java @@ -4,7 +4,6 @@ import io.vertx.core.AsyncResult; import io.vertx.core.CompositeFuture; import io.vertx.core.Future; -import io.vertx.core.http.Cookie; import io.vertx.core.http.HttpHeaders; import io.vertx.core.http.HttpMethod; import io.vertx.core.http.HttpServerRequest; @@ -333,7 +332,7 @@ private void respondWithCookie(SetuidContext setuidContext) { setuidContext.getUidsCookie(), bidder, uid); uidsCookieService.splitUidsIntoCookies(uidsCookieUpdateResult.getValue()) - .forEach(cookie -> addCookie(routingContext, cookie)); + .forEach(routingContext.response()::addCookie); if (uidsCookieUpdateResult.isUpdated()) { metrics.updateUserSyncSetsMetric(bidder); @@ -412,8 +411,4 @@ private void handleErrors(Throwable error, RoutingContext routingContext, TcfCon analyticsDelegator.processEvent(setuidEvent, tcfContext); } } - - private void addCookie(RoutingContext routingContext, Cookie cookie) { - routingContext.response().headers().add(HttpUtil.SET_COOKIE_HEADER, cookie.encode()); - } } diff --git a/src/main/java/org/prebid/server/json/JacksonMapper.java b/src/main/java/org/prebid/server/json/JacksonMapper.java index ec6d7f94d88..a56160e7aa8 100644 --- a/src/main/java/org/prebid/server/json/JacksonMapper.java +++ b/src/main/java/org/prebid/server/json/JacksonMapper.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.netty.buffer.ByteBufInputStream; import io.vertx.core.buffer.Buffer; +import io.vertx.core.internal.buffer.BufferInternal; import org.prebid.server.proto.openrtb.ext.FlexibleExtension; import java.io.IOException; @@ -66,7 +67,7 @@ public T decodeValue(String str, TypeReference type) throws DecodeExcepti public T decodeValue(Buffer buf, Class clazz) throws DecodeException { try { - return mapper.readValue((InputStream) new ByteBufInputStream(buf.getByteBuf()), clazz); + return mapper.readValue((InputStream) new ByteBufInputStream(((BufferInternal) buf).getByteBuf()), clazz); } catch (IOException e) { throw new DecodeException(FAILED_TO_DECODE.formatted(e.getMessage()), e); } @@ -74,7 +75,7 @@ public T decodeValue(Buffer buf, Class clazz) throws DecodeException { public T decodeValue(Buffer buf, TypeReference type) throws DecodeException { try { - return mapper.readValue(new ByteBufInputStream(buf.getByteBuf()), type); + return mapper.readValue(new ByteBufInputStream(((BufferInternal) buf).getByteBuf()), type); } catch (IOException e) { throw new DecodeException(FAILED_TO_DECODE.formatted(e.getMessage()), e); } diff --git a/src/main/java/org/prebid/server/log/CriteriaLogManager.java b/src/main/java/org/prebid/server/log/CriteriaLogManager.java index 75ca28f5f81..58e1f377ce9 100644 --- a/src/main/java/org/prebid/server/log/CriteriaLogManager.java +++ b/src/main/java/org/prebid/server/log/CriteriaLogManager.java @@ -2,18 +2,18 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.response.BidResponse; -import io.vertx.core.impl.ConcurrentHashSet; import org.prebid.server.json.EncodeException; import org.prebid.server.json.JacksonMapper; import java.util.Objects; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; public class CriteriaLogManager { private static final Logger logger = LoggerFactory.getLogger(CriteriaLogManager.class); - private final Set criterias = new ConcurrentHashSet<>(); + private final Set criterias = ConcurrentHashMap.newKeySet(); private final JacksonMapper mapper; 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 51c9b3e9252..2468828f9e9 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 @@ -3,7 +3,6 @@ import com.github.benmanes.caffeine.cache.Caffeine; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.FileProps; @@ -317,23 +316,15 @@ private VendorListResult processResponse(HttpClientResponse response * Saves given vendor list on file system. */ private Future> saveToFile(VendorListResult vendorListResult) { - final Promise> promise = Promise.promise(); final int version = vendorListResult.getVersion(); final String filepath = new File(cacheDir, version + JSON_SUFFIX).getPath(); - fileSystem.writeFile(filepath, Buffer.buffer(vendorListResult.getVendorListAsString()), result -> { - if (result.succeeded()) { - promise.complete(vendorListResult); - } else { - conditionalLogger.error( + return fileSystem.writeFile(filepath, Buffer.buffer(vendorListResult.getVendorListAsString())) + .map(vendorListResult) + .onFailure(error -> conditionalLogger.error( "Could not create new vendor list for version %s.%s, file: %s, trace: %s".formatted( - generationVersion, version, filepath, ExceptionUtils.getStackTrace(result.cause())), - logSamplingRate); - promise.fail(result.cause()); - } - }); - - return promise.future(); + generationVersion, version, filepath, ExceptionUtils.getStackTrace(error.getCause())), + logSamplingRate)); } private Void updateCache(VendorListResult vendorListResult) { diff --git a/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java b/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java index 7714243954d..9ace90196c2 100644 --- a/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java +++ b/src/main/java/org/prebid/server/settings/service/DatabasePeriodicRefreshService.java @@ -1,7 +1,6 @@ package org.prebid.server.settings.service; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.apache.commons.lang3.StringUtils; import org.prebid.server.execution.timeout.Timeout; @@ -104,12 +103,12 @@ public DatabasePeriodicRefreshService(String initQuery, } @Override - public void initialize(Promise initializePromise) { + public Future initialize() { getAll(); if (refreshPeriod > 0) { vertx.setPeriodic(refreshPeriod, aLong -> refresh()); } - initializePromise.tryComplete(); + return Future.succeededFuture(); } private void getAll() { diff --git a/src/main/java/org/prebid/server/settings/service/HttpPeriodicRefreshService.java b/src/main/java/org/prebid/server/settings/service/HttpPeriodicRefreshService.java index 7669074d455..b32773eb7ce 100644 --- a/src/main/java/org/prebid/server/settings/service/HttpPeriodicRefreshService.java +++ b/src/main/java/org/prebid/server/settings/service/HttpPeriodicRefreshService.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.prebid.server.exception.PreBidException; import org.prebid.server.json.DecodeException; @@ -91,13 +90,13 @@ public HttpPeriodicRefreshService(String refreshUrl, } @Override - public void initialize(Promise initializePromise) { + public Future initialize() { getAll(); if (refreshPeriod > 0) { vertx.setPeriodic(refreshPeriod, aLong -> refresh()); } - initializePromise.tryComplete(); + return Future.succeededFuture(); } private void getAll() { diff --git a/src/main/java/org/prebid/server/settings/service/S3PeriodicRefreshService.java b/src/main/java/org/prebid/server/settings/service/S3PeriodicRefreshService.java index 35ff2a6f55a..30688dd09cf 100644 --- a/src/main/java/org/prebid/server/settings/service/S3PeriodicRefreshService.java +++ b/src/main/java/org/prebid/server/settings/service/S3PeriodicRefreshService.java @@ -2,7 +2,6 @@ import io.vertx.core.CompositeFuture; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.prebid.server.auction.model.Tuple2; import org.prebid.server.log.Logger; @@ -73,15 +72,13 @@ public S3PeriodicRefreshService(S3AsyncClient asyncClient, } @Override - public void initialize(Promise initializePromise) { - fetchStoredDataResult(clock.millis(), MetricName.initialize) - .mapEmpty() - .onComplete(initializePromise); - + public Future initialize() { if (refreshPeriod > 0) { logger.info("Starting s3 periodic refresh for " + cacheType + " every " + refreshPeriod + " s"); vertx.setPeriodic(refreshPeriod, ignored -> fetchStoredDataResult(clock.millis(), MetricName.update)); } + + return fetchStoredDataResult(clock.millis(), MetricName.initialize).mapEmpty(); } private Future> fetchStoredDataResult(long startTime, MetricName metricName) { diff --git a/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java b/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java index bfb56b8c0c1..7058f06e903 100644 --- a/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/GeoLocationConfiguration.java @@ -30,7 +30,6 @@ import java.io.InputStreamReader; import java.io.Reader; import java.nio.charset.StandardCharsets; -import java.time.Clock; import java.time.ZoneId; import java.util.ArrayList; import java.util.List; @@ -70,13 +69,15 @@ CircuitBreakerSecuredGeoLocationService circuitBreakerSecuredGeoLocationService( Vertx vertx, Metrics metrics, FileSyncerProperties fileSyncerProperties, - @Qualifier("maxMindCircuitBreakerProperties") CircuitBreakerProperties circuitBreakerProperties, - Clock clock) { - - return new CircuitBreakerSecuredGeoLocationService(vertx, - createGeoLocationService(fileSyncerProperties, vertx), metrics, - circuitBreakerProperties.getOpeningThreshold(), circuitBreakerProperties.getOpeningIntervalMs(), - circuitBreakerProperties.getClosingIntervalMs(), clock); + @Qualifier("maxMindCircuitBreakerProperties") CircuitBreakerProperties circuitBreakerProperties) { + + return new CircuitBreakerSecuredGeoLocationService( + vertx, + createGeoLocationService(fileSyncerProperties, vertx), + metrics, + circuitBreakerProperties.getOpeningThreshold(), + circuitBreakerProperties.getOpeningIntervalMs(), + circuitBreakerProperties.getClosingIntervalMs()); } private GeoLocationService createGeoLocationService(FileSyncerProperties properties, Vertx vertx) { 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 64a8dc7614a..597feb1f1ac 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -5,6 +5,7 @@ import io.vertx.core.Vertx; import io.vertx.core.file.FileSystem; import io.vertx.core.http.HttpClientOptions; +import io.vertx.core.http.PoolOptions; import io.vertx.core.net.JksOptions; import lombok.Data; import org.apache.commons.lang3.ObjectUtils; @@ -659,8 +660,7 @@ CircuitBreakerSecuredHttpClient circuitBreakerSecuredHttpClient( Metrics metrics, HttpClientProperties httpClientProperties, @Qualifier("httpClientCircuitBreakerProperties") - HttpClientCircuitBreakerProperties circuitBreakerProperties, - Clock clock) { + HttpClientCircuitBreakerProperties circuitBreakerProperties) { final HttpClient httpClient = createBasicHttpClient(vertx, httpClientProperties); @@ -671,16 +671,17 @@ CircuitBreakerSecuredHttpClient circuitBreakerSecuredHttpClient( circuitBreakerProperties.getOpeningThreshold(), circuitBreakerProperties.getOpeningIntervalMs(), circuitBreakerProperties.getClosingIntervalMs(), - circuitBreakerProperties.getIdleExpireHours(), - clock); + circuitBreakerProperties.getIdleExpireHours()); } private static BasicHttpClient createBasicHttpClient(Vertx vertx, HttpClientProperties httpClientProperties) { + final PoolOptions poolOptions = new PoolOptions() + .setHttp1MaxSize(httpClientProperties.getMaxPoolSize()) + .setCleanerPeriod(httpClientProperties.getPoolCleanerPeriodMs()); + final HttpClientOptions options = new HttpClientOptions() - .setMaxPoolSize(httpClientProperties.getMaxPoolSize()) .setIdleTimeoutUnit(TimeUnit.MILLISECONDS) .setIdleTimeout(httpClientProperties.getIdleTimeoutMs()) - .setPoolCleanerPeriod(httpClientProperties.getPoolCleanerPeriodMs()) .setDecompressionSupported(httpClientProperties.getUseCompression()) .setConnectTimeout(httpClientProperties.getConnectTimeoutMs()) // Vert.x's HttpClientRequest needs this value to be 2 for redirections to be followed once, @@ -697,7 +698,7 @@ private static BasicHttpClient createBasicHttpClient(Vertx vertx, HttpClientProp .setKeyCertOptions(jksOptions); } - return new BasicHttpClient(vertx, vertx.createHttpClient(options)); + return new BasicHttpClient(vertx, vertx.createHttpClient(options, poolOptions)); } @Bean diff --git a/src/main/java/org/prebid/server/spring/config/VerticleStarter.java b/src/main/java/org/prebid/server/spring/config/VerticleStarter.java index cb519b88477..ae6500ba766 100644 --- a/src/main/java/org/prebid/server/spring/config/VerticleStarter.java +++ b/src/main/java/org/prebid/server/spring/config/VerticleStarter.java @@ -30,11 +30,10 @@ public void start() { continue; } - contextRunner.runBlocking(promise -> + contextRunner.runBlocking(() -> vertx.deployVerticle( definition.getFactory(), - new DeploymentOptions().setInstances(definition.getAmount()), - promise)); + new DeploymentOptions().setInstances(definition.getAmount()))); } } } diff --git a/src/main/java/org/prebid/server/spring/config/database/DatabaseConfiguration.java b/src/main/java/org/prebid/server/spring/config/database/DatabaseConfiguration.java index 6a1a1531f1c..ded875b91a7 100644 --- a/src/main/java/org/prebid/server/spring/config/database/DatabaseConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/database/DatabaseConfiguration.java @@ -1,6 +1,7 @@ package org.prebid.server.spring.config.database; import io.vertx.core.Vertx; +import io.vertx.core.net.NetClientOptions; import io.vertx.mysqlclient.MySQLBuilder; import io.vertx.mysqlclient.MySQLConnectOptions; import io.vertx.pgclient.PgBuilder; @@ -84,19 +85,20 @@ Pool mysqlConnectionPool(Vertx vertx, .setDatabase(databaseAddress.getDatabaseName()) .setUser(connectionPoolSettings.getUser()) .setPassword(connectionPoolSettings.getPassword()) - .setSsl(false) - .setTcpKeepAlive(true) .setCachePreparedStatements(connectionPoolSettings.getEnablePreparedStatementCaching()) - .setPreparedStatementCacheMaxSize(connectionPoolSettings.getMaxPreparedStatementCacheSize()) - .setIdleTimeout(connectionPoolSettings.getIdleTimeout()) - .setIdleTimeoutUnit(TimeUnit.SECONDS); + .setPreparedStatementCacheMaxSize(connectionPoolSettings.getMaxPreparedStatementCacheSize()); + + final NetClientOptions netClientOptions = new NetClientOptions() + .setTcpKeepAlive(true); final PoolOptions poolOptions = new PoolOptions() - .setMaxSize(connectionPoolSettings.getPoolSize()); + .setMaxSize(connectionPoolSettings.getPoolSize()) + .setIdleTimeout(connectionPoolSettings.getIdleTimeout()) + .setIdleTimeoutUnit(TimeUnit.SECONDS); - return MySQLBuilder - .pool() + return MySQLBuilder.pool() .with(poolOptions) + .with(netClientOptions) .connectingTo(sqlConnectOptions) .using(vertx) .build(); @@ -114,19 +116,20 @@ Pool postgresConnectionPool(Vertx vertx, .setDatabase(databaseAddress.getDatabaseName()) .setUser(connectionPoolSettings.getUser()) .setPassword(connectionPoolSettings.getPassword()) - .setSsl(false) - .setTcpKeepAlive(true) .setCachePreparedStatements(connectionPoolSettings.getEnablePreparedStatementCaching()) - .setPreparedStatementCacheMaxSize(connectionPoolSettings.getMaxPreparedStatementCacheSize()) - .setIdleTimeout(connectionPoolSettings.getIdleTimeout()) - .setIdleTimeoutUnit(TimeUnit.SECONDS); + .setPreparedStatementCacheMaxSize(connectionPoolSettings.getMaxPreparedStatementCacheSize()); + + final NetClientOptions netClientOptions = new NetClientOptions() + .setTcpKeepAlive(true); final PoolOptions poolOptions = new PoolOptions() - .setMaxSize(connectionPoolSettings.getPoolSize()); + .setMaxSize(connectionPoolSettings.getPoolSize()) + .setIdleTimeout(connectionPoolSettings.getIdleTimeout()) + .setIdleTimeoutUnit(TimeUnit.SECONDS); - return PgBuilder - .pool() + return PgBuilder.pool() .with(poolOptions) + .with(netClientOptions) .connectingTo(sqlConnectOptions) .using(vertx) .build(); @@ -164,8 +167,7 @@ CircuitBreakerSecuredDatabaseClient circuitBreakerSecuredAsyncDatabaseClient( metrics, circuitBreakerProperties.getOpeningThreshold(), circuitBreakerProperties.getOpeningIntervalMs(), - circuitBreakerProperties.getClosingIntervalMs(), - clock); + circuitBreakerProperties.getClosingIntervalMs()); } private static BasicDatabaseClient createBasicDatabaseClient(Pool pool, @@ -175,7 +177,7 @@ private static BasicDatabaseClient createBasicDatabaseClient(Pool pool, final BasicDatabaseClient basicDatabaseClient = new BasicDatabaseClient(pool, metrics, clock); - contextRunner.runBlocking(promise -> basicDatabaseClient.initialize().onComplete(promise)); + contextRunner.runBlocking(basicDatabaseClient::initialize); return basicDatabaseClient; } diff --git a/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java b/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java index f95980d1a60..6796f7e13f6 100644 --- a/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java +++ b/src/main/java/org/prebid/server/spring/config/server/admin/AdminServerAuthProvider.java @@ -1,17 +1,16 @@ package org.prebid.server.spring.config.server.admin; -import io.vertx.core.AsyncResult; import io.vertx.core.Future; -import io.vertx.core.Handler; import io.vertx.core.json.JsonObject; -import io.vertx.ext.auth.AuthProvider; import io.vertx.ext.auth.User; +import io.vertx.ext.auth.authentication.AuthenticationProvider; +import io.vertx.ext.auth.authentication.Credentials; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import java.util.Map; -public class AdminServerAuthProvider implements AuthProvider { +public class AdminServerAuthProvider implements AuthenticationProvider { private final Map credentials; @@ -20,20 +19,18 @@ public AdminServerAuthProvider(Map credentials) { } @Override - public void authenticate(JsonObject authInfo, Handler> resultHandler) { + public Future authenticate(Credentials userCredentials) { if (MapUtils.isEmpty(credentials)) { - resultHandler.handle(Future.failedFuture("Credentials not set in configuration.")); - return; + return Future.failedFuture("Credentials not set in configuration."); } - final String requestUsername = authInfo.getString("username"); - final String requestPassword = StringUtils.chomp(authInfo.getString("password")); - + final JsonObject principal = userCredentials.toJson(); + final String requestUsername = principal.getString("username"); + final String requestPassword = StringUtils.chomp(principal.getString("password")); final String storedPassword = credentials.get(requestUsername); - if (StringUtils.isNotBlank(requestPassword) && StringUtils.equals(storedPassword, requestPassword)) { - resultHandler.handle(Future.succeededFuture()); - } else { - resultHandler.handle(Future.failedFuture("No such user, or password incorrect.")); - } + + return StringUtils.isNotBlank(requestPassword) && StringUtils.equals(storedPassword, requestPassword) + ? Future.succeededFuture() + : Future.failedFuture("Password does not match."); } } diff --git a/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java b/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java index c6ae167ae94..a6b56622c42 100644 --- a/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java @@ -197,7 +197,7 @@ NoCacheHandler noCacheHandler() { @Bean CorsHandler corsHandler() { return CorsHandler.create() - .addRelativeOrigin(".*") + .addOriginWithRegex(".*") .allowCredentials(true) .allowedHeaders(new HashSet<>(Arrays.asList( HttpUtil.ORIGIN_HEADER.toString(), diff --git a/src/main/java/org/prebid/server/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index e08a276c6fa..95b686abf9b 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -181,13 +181,12 @@ public static Map cookiesAsMap(HttpRequestContext httpRequest) { } public static Map cookiesAsMap(RoutingContext routingContext) { - return routingContext.cookieMap().entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); + return routingContext.request().cookies().stream() + .collect(Collectors.toMap(Cookie::getName, Cookie::getValue)); } public static String createCookiesHeader(RoutingContext routingContext) { - return routingContext.cookieMap().entrySet().stream() - .map(entry -> Cookie.cookie(entry.getKey(), entry.getValue().getValue())) + return routingContext.request().cookies().stream() .map(Cookie::encode) .collect(Collectors.joining("; ")); } diff --git a/src/main/java/org/prebid/server/util/system/CpuLoadAverageStats.java b/src/main/java/org/prebid/server/util/system/CpuLoadAverageStats.java index 6be897cd1d4..0ff182c4ac7 100644 --- a/src/main/java/org/prebid/server/util/system/CpuLoadAverageStats.java +++ b/src/main/java/org/prebid/server/util/system/CpuLoadAverageStats.java @@ -1,6 +1,6 @@ package org.prebid.server.util.system; -import io.vertx.core.Promise; +import io.vertx.core.Future; import io.vertx.core.Vertx; import org.prebid.server.vertx.Initializable; import oshi.SystemInfo; @@ -31,10 +31,10 @@ public CpuLoadAverageStats(Vertx vertx, long measurementIntervalMillis) { } @Override - public void initialize(Promise initializePromise) { + public Future initialize() { measureCpuLoad(); vertx.setPeriodic(measurementIntervalMillis, timerId -> measureCpuLoad()); - initializePromise.tryComplete(); + return Future.succeededFuture(); } private void measureCpuLoad() { diff --git a/src/main/java/org/prebid/server/vertx/CircuitBreaker.java b/src/main/java/org/prebid/server/vertx/CircuitBreaker.java deleted file mode 100644 index 104545470f5..00000000000 --- a/src/main/java/org/prebid/server/vertx/CircuitBreaker.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.prebid.server.vertx; - -import io.vertx.circuitbreaker.CircuitBreakerOptions; -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 org.prebid.server.log.Logger; -import org.prebid.server.log.LoggerFactory; - -import java.time.Clock; -import java.util.Objects; - -/** - * Wrapper over Vert.x {@link io.vertx.circuitbreaker.CircuitBreaker} with functionality - * to reset failure counter to adjust open-circuit time frame. - */ -public class CircuitBreaker { - - private static final Logger logger = LoggerFactory.getLogger(CircuitBreaker.class); - - private final io.vertx.circuitbreaker.CircuitBreaker breaker; - private final Vertx vertx; - private final long openingIntervalMs; - private final Clock clock; - - private volatile long lastFailureTime; - - 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), - new CircuitBreakerOptions() - .setNotificationPeriod(0) - .setMaxFailures(openingThreshold) - .setResetTimeout(closingIntervalMs)); - - this.vertx = vertx; - this.openingIntervalMs = openingIntervalMs; - this.clock = Objects.requireNonNull(clock); - } - - /** - * Executes the given operation with the circuit breaker control. - */ - public Future execute(Handler> command) { - return breaker.execute(promise -> execute(command, promise)); - } - - /** - * Executes operation and handle result of it on given {@link Promise}. - */ - private void execute(Handler> command, Promise promise) { - final Promise passedPromise = Promise.promise(); - command.handle(passedPromise); - - passedPromise.future() - .compose(response -> succeedBreaker(response, promise)) - .recover(exception -> failBreaker(exception, promise)); - } - - /** - * Succeeds given {@link Promise} and returns corresponding {@link Future}. - */ - private static Future succeedBreaker(T result, Promise promise) { - promise.complete(result); - return promise.future(); - } - - /** - * Fails given {@link Promise} and returns corresponding {@link Future}. - */ - private Future failBreaker(Throwable exception, Promise promise) { - final Promise ensureStatePromise = Promise.promise(); - vertx.executeBlocking(this::ensureState, false, ensureStatePromise); - - return ensureStatePromise.future() - .recover(throwable -> { - logger.warn("Resetting circuit breaker state failed", throwable); - promise.fail(throwable); - return promise.future(); - }) - .compose(ignored -> { // ensuring state succeeded, propagate real error - promise.fail(exception); - return promise.future(); - }); - } - - /** - * Resets failure counter to adjust open-circuit time frame. - *

- * Note: the operations {@link io.vertx.circuitbreaker.CircuitBreaker#state()} - * 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(Promise executeBlockingPromise) { - final long currentTime = clock.millis(); - if (breaker.state() == CircuitBreakerState.CLOSED && lastFailureTime > 0 - && currentTime - lastFailureTime > openingIntervalMs) { - breaker.reset(); - } - - lastFailureTime = currentTime; - executeBlockingPromise.complete(); - } - - /** - * Sets a {@link Handler} invoked when the circuit breaker state switches to open. - */ - public CircuitBreaker openHandler(Handler handler) { - breaker.openHandler(handler); - return this; - } - - /** - * Sets a {@link Handler} invoked when the circuit breaker state switches to half-open. - */ - public CircuitBreaker halfOpenHandler(Handler handler) { - breaker.halfOpenHandler(handler); - return this; - } - - /** - * Sets a {@link Handler} invoked when the circuit breaker state switches to close. - */ - public CircuitBreaker closeHandler(Handler handler) { - breaker.closeHandler(handler); - return this; - } - - public boolean isOpen() { - return switch (breaker.state()) { - case OPEN, HALF_OPEN -> true; - case CLOSED -> false; - }; - } -} diff --git a/src/main/java/org/prebid/server/vertx/CloseableAdapter.java b/src/main/java/org/prebid/server/vertx/CloseableAdapter.java index 708796c63c7..6f714f8f0ae 100644 --- a/src/main/java/org/prebid/server/vertx/CloseableAdapter.java +++ b/src/main/java/org/prebid/server/vertx/CloseableAdapter.java @@ -1,7 +1,6 @@ package org.prebid.server.vertx; -import io.vertx.core.Future; -import io.vertx.core.Promise; +import io.vertx.core.Completable; import java.io.Closeable; import java.io.IOException; @@ -20,12 +19,12 @@ public CloseableAdapter(Closeable closeable) { } @Override - public void close(Promise promise) { + public void close(Completable completable) { try { closeable.close(); - promise.handle(Future.succeededFuture()); + completable.succeed(); } catch (IOException e) { - promise.handle(Future.failedFuture(e)); + completable.fail(e); } } } diff --git a/src/main/java/org/prebid/server/vertx/ContextRunner.java b/src/main/java/org/prebid/server/vertx/ContextRunner.java index 43dc35c3683..2c4f220549e 100644 --- a/src/main/java/org/prebid/server/vertx/ContextRunner.java +++ b/src/main/java/org/prebid/server/vertx/ContextRunner.java @@ -1,12 +1,12 @@ package org.prebid.server.vertx; import io.vertx.core.Future; -import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.Vertx; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; public class ContextRunner { @@ -18,7 +18,7 @@ public ContextRunner(Vertx vertx, long timeoutMs) { this.timeoutMs = timeoutMs; } - public void runBlocking(Handler> action) { + public void runBlocking(Supplier> action) { final CountDownLatch completionLatch = new CountDownLatch(1); final Promise promise = Promise.promise(); final Future future = promise.future(); @@ -26,7 +26,7 @@ public void runBlocking(Handler> action) { future.onComplete(ignored -> completionLatch.countDown()); vertx.runOnContext(v -> { try { - action.handle(promise); + action.get().onComplete(promise); } catch (RuntimeException 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 5c12c30e47d..3ecfe6e8037 100644 --- a/src/main/java/org/prebid/server/vertx/Initializable.java +++ b/src/main/java/org/prebid/server/vertx/Initializable.java @@ -1,7 +1,7 @@ package org.prebid.server.vertx; +import io.vertx.core.Future; import io.vertx.core.Handler; -import io.vertx.core.Promise; /** * Denotes components requiring initialization after they have been created. @@ -12,5 +12,5 @@ @FunctionalInterface public interface Initializable { - void initialize(Promise initializePromise); + Future initialize(); } diff --git a/src/main/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClient.java b/src/main/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClient.java index ea59c9f9670..867f2e8c67d 100644 --- a/src/main/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClient.java +++ b/src/main/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClient.java @@ -1,30 +1,27 @@ package org.prebid.server.vertx.database; +import io.vertx.circuitbreaker.CircuitBreaker; +import io.vertx.circuitbreaker.CircuitBreakerOptions; +import io.vertx.circuitbreaker.CircuitBreakerState; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.sqlclient.Row; import io.vertx.sqlclient.RowSet; import org.prebid.server.execution.timeout.Timeout; -import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; 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; /** - * Database Client wrapped by {@link CircuitBreaker} to achieve robust operating. + * Database Client wrapped by CircuitBreaker to achieve robust operating. */ public class CircuitBreakerSecuredDatabaseClient implements DatabaseClient { private static final Logger logger = LoggerFactory.getLogger(CircuitBreakerSecuredDatabaseClient.class); - private static final ConditionalLogger conditionalLogger = new ConditionalLogger(logger); - private static final int LOG_PERIOD_SECONDS = 5; private final DatabaseClient databaseClient; private final CircuitBreaker breaker; @@ -34,23 +31,20 @@ public CircuitBreakerSecuredDatabaseClient(Vertx vertx, Metrics metrics, int openingThreshold, long openingIntervalMs, - long closingIntervalMs, - Clock clock) { + long closingIntervalMs) { this.databaseClient = Objects.requireNonNull(databaseClient); - breaker = new CircuitBreaker( + breaker = CircuitBreaker.create( "db_cb", Objects.requireNonNull(vertx), - openingThreshold, - openingIntervalMs, - closingIntervalMs, - Objects.requireNonNull(clock)) - .openHandler(ignored -> circuitOpened()) - .halfOpenHandler(ignored -> circuitHalfOpened()) - .closeHandler(ignored -> circuitClosed()); + new CircuitBreakerOptions() + .setNotificationPeriod(0) + .setMaxFailures(openingThreshold) + .setFailuresRollingWindow(openingIntervalMs) + .setResetTimeout(closingIntervalMs)); - metrics.createDatabaseCircuitBreakerGauge(breaker::isOpen); + metrics.createDatabaseCircuitBreakerGauge(() -> breaker.state() != CircuitBreakerState.CLOSED); logger.info("Initialized database client with Circuit Breaker"); } @@ -61,19 +55,6 @@ public Future executeQuery(String query, Function, T> mapper, Timeout timeout) { - return breaker.execute( - promise -> databaseClient.executeQuery(query, params, mapper, timeout).onComplete(promise)); - } - - private void circuitOpened() { - conditionalLogger.warn("Database is unavailable, circuit opened.", LOG_PERIOD_SECONDS, TimeUnit.SECONDS); - } - - private void circuitHalfOpened() { - logger.warn("Database is ready to try again, circuit half-opened."); - } - - private void circuitClosed() { - logger.warn("Database becomes working, circuit closed."); + return breaker.execute(() -> databaseClient.executeQuery(query, params, mapper, timeout)); } } diff --git a/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java b/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java index 0843a04de12..7097be2de56 100644 --- a/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java +++ b/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java @@ -1,6 +1,9 @@ package org.prebid.server.vertx.httpclient; import com.github.benmanes.caffeine.cache.Caffeine; +import io.vertx.circuitbreaker.CircuitBreaker; +import io.vertx.circuitbreaker.CircuitBreakerOptions; +import io.vertx.circuitbreaker.CircuitBreakerState; import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.Vertx; @@ -10,12 +13,10 @@ import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; import org.prebid.server.metric.Metrics; -import org.prebid.server.vertx.CircuitBreaker; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.net.MalformedURLException; import java.net.URL; -import java.time.Clock; import java.util.Map; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -41,13 +42,12 @@ public CircuitBreakerSecuredHttpClient(Vertx vertx, int openingThreshold, long openingIntervalMs, long closingIntervalMs, - int idleExpireHours, - Clock clock) { + int idleExpireHours) { this.httpClient = Objects.requireNonNull(httpClient); circuitBreakerCreator = name -> createCircuitBreaker( - name, vertx, openingThreshold, openingIntervalMs, closingIntervalMs, clock, metrics); + name, vertx, openingThreshold, openingIntervalMs, closingIntervalMs, metrics); circuitBreakerByName = Caffeine.newBuilder() .expireAfterAccess(idleExpireHours, TimeUnit.HOURS) @@ -69,9 +69,7 @@ public Future request(HttpMethod method, long maxResponseSize) { return circuitBreakerByName.computeIfAbsent(nameFrom(url), circuitBreakerCreator) - .execute(promise -> - httpClient.request(method, url, headers, body, timeoutMs, maxResponseSize) - .onComplete(promise)); + .execute(() -> httpClient.request(method, url, headers, body, timeoutMs, maxResponseSize)); } @Override @@ -82,9 +80,7 @@ public Future request(HttpMethod method, long timeoutMs, long maxResponseSize) { return circuitBreakerByName.computeIfAbsent(nameFrom(url), circuitBreakerCreator) - .execute(promise -> - httpClient.request(method, url, headers, body, timeoutMs, maxResponseSize) - .onComplete(promise)); + .execute(() -> httpClient.request(method, url, headers, body, timeoutMs, maxResponseSize)); } private CircuitBreaker createCircuitBreaker(String name, @@ -92,16 +88,16 @@ private CircuitBreaker createCircuitBreaker(String name, int openingThreshold, long openingIntervalMs, long closingIntervalMs, - Clock clock, Metrics metrics) { - final CircuitBreaker circuitBreaker = new CircuitBreaker( - "http_cb_" + name, - Objects.requireNonNull(vertx), - openingThreshold, - openingIntervalMs, - closingIntervalMs, - Objects.requireNonNull(clock)) + final CircuitBreakerOptions options = new CircuitBreakerOptions() + .setNotificationPeriod(0) + .setMaxFailures(openingThreshold) + .setFailuresRollingWindow(openingIntervalMs) + .setResetTimeout(closingIntervalMs); + + final CircuitBreaker circuitBreaker = CircuitBreaker.create( + "http_cb_" + name, Objects.requireNonNull(vertx), options) .openHandler(ignored -> circuitOpened(name)) .halfOpenHandler(ignored -> circuitHalfOpened(name)) .closeHandler(ignored -> circuitClosed(name)); @@ -112,7 +108,8 @@ private CircuitBreaker createCircuitBreaker(String name, } private void createCircuitBreakerGauge(String name, CircuitBreaker circuitBreaker, Metrics metrics) { - metrics.createHttpClientCircuitBreakerGauge(idFrom(name), circuitBreaker::isOpen); + metrics.createHttpClientCircuitBreakerGauge( + idFrom(name), () -> circuitBreaker.state() != CircuitBreakerState.CLOSED); } private void removeCircuitBreakerGauge(String name, Metrics metrics) { diff --git a/src/main/java/org/prebid/server/vertx/verticles/server/DaemonVerticle.java b/src/main/java/org/prebid/server/vertx/verticles/server/DaemonVerticle.java index c6175ccaafa..e64a3eab5d1 100644 --- a/src/main/java/org/prebid/server/vertx/verticles/server/DaemonVerticle.java +++ b/src/main/java/org/prebid/server/vertx/verticles/server/DaemonVerticle.java @@ -11,10 +11,8 @@ import org.prebid.server.vertx.CloseableAdapter; import org.prebid.server.vertx.Initializable; -import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.function.Consumer; import java.util.function.Function; public class DaemonVerticle extends AbstractVerticle { @@ -33,31 +31,26 @@ public DaemonVerticle(List initializables, List startPromise) { - all(initializables, initializable -> initializable::initialize).onComplete(startPromise); + all(initializables, Initializable::initialize, true).onComplete(startPromise); } @Override public void stop(Promise stopPromise) { - all(closeables, closeable -> closeable::close).onComplete(stopPromise); + all(closeables, closeable -> Future.future(closeable::close), false).onComplete(stopPromise); } - private static Future all(Collection entries, - Function>> entryToPromiseConsumerMapper) { + private static Future all( + Collection entries, + Function> entryToFutureMapper, + boolean start) { - final List> entriesFutures = new ArrayList<>(); - - for (E entry : entries) { - final Promise entryPromise = Promise.promise(); - entriesFutures.add(entryPromise.future()); - - entryToPromiseConsumerMapper.apply(entry).accept(entryPromise); - } - - return Future.all(entriesFutures) + return Future.all(entries.stream().map(entryToFutureMapper).toList()) .onSuccess(r -> logger.info( - "Successfully started {} instance on thread: {}", + "Successfully {} {} instance on thread: {}", + start ? "started" : "stopped", DaemonVerticle.class.getSimpleName(), Thread.currentThread().getName())) .mapEmpty(); } + } diff --git a/src/main/java/org/prebid/server/vertx/verticles/server/ServerVerticle.java b/src/main/java/org/prebid/server/vertx/verticles/server/ServerVerticle.java index 147de2210c4..c496b0baa85 100644 --- a/src/main/java/org/prebid/server/vertx/verticles/server/ServerVerticle.java +++ b/src/main/java/org/prebid/server/vertx/verticles/server/ServerVerticle.java @@ -1,7 +1,6 @@ package org.prebid.server.vertx.verticles.server; import io.vertx.core.AbstractVerticle; -import io.vertx.core.AsyncResult; import io.vertx.core.Promise; import io.vertx.core.http.HttpServer; import io.vertx.core.http.HttpServerOptions; @@ -55,19 +54,13 @@ public void start(Promise startPromise) { server.exceptionHandler(exceptionHandler); } - server.listen(address, result -> onServerStarted(result, startPromise)); - } - - private void onServerStarted(AsyncResult result, Promise startPromise) { - if (result.succeeded()) { - startPromise.tryComplete(); - logger.info( - "Successfully started {} instance on address: {}, thread: {}", - name, - address, - Thread.currentThread().getName()); - } else { - startPromise.tryFail(result.cause()); - } + server.listen(address) + .mapEmpty() + .onComplete(startPromise) + .onSuccess(ignored -> logger.info( + "Successfully started {} instance on address: {}, thread: {}", + name, + address, + Thread.currentThread().getName())); } } diff --git a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy index 702918fa886..8971403ffed 100644 --- a/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/bidder/BidderName.groovy @@ -29,7 +29,7 @@ enum BidderName { MEDIANET("medianet"), AMX("amx"), AMX_CAMEL_CASE("AmX"), - AMX_UPPER_CASE("AMX"), + AMX_UPPER_CASE("AMX") @JsonValue final String value diff --git a/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderImp.groovy b/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderImp.groovy deleted file mode 100644 index c1889dc51bc..00000000000 --- a/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderImp.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package org.prebid.server.functional.model.bidderspecific - -import groovy.transform.EqualsAndHashCode -import groovy.transform.ToString -import org.prebid.server.functional.model.request.auction.Imp - -@EqualsAndHashCode -@ToString(includeNames = true, ignoreNulls = true) -class BidderImp extends Imp { - - BidderImpExt ext -} diff --git a/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderImpExt.groovy b/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderImpExt.groovy deleted file mode 100644 index d07ca31ad9d..00000000000 --- a/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderImpExt.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package org.prebid.server.functional.model.bidderspecific - -import groovy.transform.ToString -import org.prebid.server.functional.model.bidder.GeneralBidderAdapter -import org.prebid.server.functional.model.request.auction.ImpExt - -@ToString(includeNames = true, ignoreNulls = true) -class BidderImpExt extends ImpExt { - - GeneralBidderAdapter bidder - Rp rp -} diff --git a/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderRequest.groovy b/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderRequest.groovy deleted file mode 100644 index 25176aaed0f..00000000000 --- a/src/test/groovy/org/prebid/server/functional/model/bidderspecific/BidderRequest.groovy +++ /dev/null @@ -1,12 +0,0 @@ -package org.prebid.server.functional.model.bidderspecific - -import groovy.transform.EqualsAndHashCode -import groovy.transform.ToString -import org.prebid.server.functional.model.request.auction.BidRequest - -@EqualsAndHashCode -@ToString(includeNames = true, ignoreNulls = true) -class BidderRequest extends BidRequest { - - List imp -} diff --git a/src/test/groovy/org/prebid/server/functional/model/privacy/Metric.groovy b/src/test/groovy/org/prebid/server/functional/model/privacy/Metric.groovy index 80d779e069d..9b238bc322a 100644 --- a/src/test/groovy/org/prebid/server/functional/model/privacy/Metric.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/privacy/Metric.groovy @@ -11,7 +11,7 @@ enum Metric { ACCOUNT_PROCESSED_RULES_COUNT("requests.activity.processedrules.count"), TEMPLATE_ADAPTER_DISALLOWED_COUNT("adapter.{bidderName}.activity.{activityType}.disallowed.count"), TEMPLATE_ACCOUNT_DISALLOWED_COUNT("account.{accountId}.activity.{activityType}.disallowed.count"), - TEMPLATE_REQUEST_DISALLOWED_COUNT("requests.activity.{activityType}.disallowed.count"), + TEMPLATE_REQUEST_DISALLOWED_COUNT("requests.activity.{activityType}.disallowed.count") final String value diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy index 649c539e794..1530e4de21d 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/AuctionEnvironment.groovy @@ -7,10 +7,10 @@ enum AuctionEnvironment { NOT_SUPPORTED(0), DEVICE_ORCHESTRATED(1), SERVER_ORCHESTRATED(3), - UNKNOWN(Integer.MAX_VALUE), + UNKNOWN(Integer.MAX_VALUE) @JsonValue - private int value + final int value AuctionEnvironment(Integer value) { this.value = value diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/BidRounding.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/BidRounding.groovy index ba612ce9f87..c44f1100248 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/BidRounding.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/BidRounding.groovy @@ -8,9 +8,9 @@ enum BidRounding { DOWN("down"), TRUE("true"), TIME_SPLIT("timesplit"), - UNKNOWN("unknown"), + UNKNOWN("unknown") - private String value + final String value BidRounding(String value) { this.value = value diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/DeviceExt.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/DeviceExt.groovy index 72337563b4b..6f4b6e2f8c1 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/DeviceExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/DeviceExt.groovy @@ -14,10 +14,10 @@ class DeviceExt { UNKNOWN(0), RESTRICTED(1), DENIED(2), - AUTHORIZED(3), + AUTHORIZED(3) @JsonValue - int value + final int value Atts(int value) { this.value = value diff --git a/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy b/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy index a9d72718e9a..e66d0137c5e 100644 --- a/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/request/auction/ImpExt.groovy @@ -4,8 +4,10 @@ import com.fasterxml.jackson.annotation.JsonProperty import groovy.transform.EqualsAndHashCode import groovy.transform.ToString import org.prebid.server.functional.model.bidder.AppNexus +import org.prebid.server.functional.model.bidder.GeneralBidderAdapter import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.bidder.Rubicon +import org.prebid.server.functional.model.bidderspecific.Rp @ToString(includeNames = true, ignoreNulls = true) @EqualsAndHashCode @@ -31,6 +33,8 @@ class ImpExt { @JsonProperty("igs") InterestGroupAuctionSupport interestGroupAuctionSupports AnyUnsupportedBidder anyUnsupportedBidder + GeneralBidderAdapter bidder + Rp rp static ImpExt getDefaultImpExt() { new ImpExt().tap { diff --git a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy index 80f504a05ec..975aa9c710a 100644 --- a/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy +++ b/src/test/groovy/org/prebid/server/functional/model/response/auction/ErrorType.groovy @@ -16,7 +16,7 @@ enum ErrorType { IX("ix"), OPENX("openx"), AMX("amx"), - AMX_UPPER_CASE("AMX"), + AMX_UPPER_CASE("AMX") @JsonValue final String value diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy index 02a8d315b84..a46adc3effe 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/PbsConfig.groovy @@ -48,7 +48,7 @@ LIMIT 1 "analytics.pubstack.scopeid" : scopeId, "analytics.pubstack.configuration-refresh-delay-ms": "1000", "analytics.pubstack.buffers.size-bytes" : "1", - "analytics.pubstack.timeout-ms" : "100"].asImmutable() + "analytics.pubstack.timeout-ms" : "1000"].asImmutable() } static Map getHttpSettingsConfig(String rootUri = networkServiceContainer.rootUri) { diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy index 70509252af6..a886a2a3fb2 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/container/PrebidServerContainer.groovy @@ -11,13 +11,14 @@ import static org.prebid.server.functional.testcontainers.PbsConfig.DEFAULT_ENV class PrebidServerContainer extends GenericContainer { - private static final int PROMETHEUS_PORT = 8070 + public static final String ADMIN_ENDPOINT_USERNAME = "admin" + public static final String ADMIN_ENDPOINT_PASSWORD = "admin" + public static final String APP_WORKDIR = "/app/prebid-server/" + public static final int PROMETHEUS_PORT = 8070 + private static final int DEFAULT_PORT = 8080 private static final int DEFAULT_ADMIN_PORT = 8060 private static final int DEFAULT_DEBUG_PORT = 8000 - private static final String ADMIN_ENDPOINT_USERNAME = "admin" - private static final String ADMIN_ENDPOINT_PASSWORD = "admin" - private static final String APP_WORKDIR = "/app/prebid-server/" private static final int PORT = SystemProperties.getPropertyOrDefault("port", DEFAULT_PORT) private static final int ADMIN_PORT = SystemProperties.getPropertyOrDefault("admin.port", DEFAULT_ADMIN_PORT) private static final int DEBUG_PORT = SystemProperties.getPropertyOrDefault("debug.port", DEFAULT_DEBUG_PORT) @@ -30,8 +31,8 @@ class PrebidServerContainer extends GenericContainer { withFixedPorts() withStartupAttempts(3) waitingFor(Wait.forHttp("/status") - .forPort(PORT) - .forStatusCode(200)) + .forPort(PORT) + .forStatusCode(200)) withDebug() withNetwork(Dependencies.network) def commonConfig = [:] << DEFAULT_ENV diff --git a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/Bidder.groovy b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/Bidder.groovy index 05d6fcfa3d7..25e0354c5d5 100644 --- a/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/Bidder.groovy +++ b/src/test/groovy/org/prebid/server/functional/testcontainers/scaffolding/Bidder.groovy @@ -4,7 +4,6 @@ import org.mockserver.matchers.TimeToLive import org.mockserver.matchers.Times import org.mockserver.model.HttpRequest import org.mockserver.model.HttpResponse -import org.prebid.server.functional.model.bidderspecific.BidderRequest import org.prebid.server.functional.model.request.auction.Banner import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.request.auction.Format @@ -26,7 +25,7 @@ class Bidder extends NetworkScaffolding { @Override protected HttpRequest getRequest(String bidRequestId) { request().withPath(endpoint) - .withBody(jsonPath("\$[?(@.id == '$bidRequestId')]")) + .withBody(jsonPath("\$[?(@.id == '$bidRequestId')]")) } @Override @@ -36,22 +35,24 @@ class Bidder extends NetworkScaffolding { HttpRequest getRequest(String bidRequestId, String requestMatchPath) { request().withPath(endpoint) - .withBody(jsonPath("\$[?(@.$requestMatchPath == '$bidRequestId')]")) + .withBody(jsonPath("\$[?(@.$requestMatchPath == '$bidRequestId')]")) } @Override void setResponse() { mockServerClient.when(request().withPath(endpoint), Times.unlimited(), TimeToLive.unlimited(), -10) - .respond {request -> request.withPath(endpoint) - ? response().withStatusCode(OK_200.code()).withBody(getBodyByRequest(request)) - : HttpResponse.notFoundResponse()} + .respond { request -> + request.withPath(endpoint) + ? response().withStatusCode(OK_200.code()).withBody(getBodyByRequest(request)) + : HttpResponse.notFoundResponse() + } } - List getBidderRequests(String bidRequestId) { - getRecordedRequestsBody(bidRequestId).collect { decode(it, BidderRequest) } + List getBidderRequests(String bidRequestId) { + getRecordedRequestsBody(bidRequestId).collect { decode(it, BidRequest) } } - BidderRequest getBidderRequest(String bidRequestId) { + BidRequest getBidderRequest(String bidRequestId) { def bidderRequests = getBidderRequests(bidRequestId) def bidderCallCount = bidderRequests.size() @@ -76,7 +77,8 @@ class Bidder extends NetworkScaffolding { new Imp(id: it.get("id").asText(), banner: formatNode != null ? new Banner(format: [new Format(width: formatNode.first().get("w").asInt(), height: formatNode.first().get("h").asInt())]) - : null)} + : null) + } def bidRequest = new BidRequest(id: id, imp: imps) def response = BidResponse.getDefaultBidResponse(bidRequest) encode(response) diff --git a/src/test/groovy/org/prebid/server/functional/tests/AnalyticsSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/AnalyticsSpec.groovy index b113f649834..9aa86da7e42 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/AnalyticsSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/AnalyticsSpec.groovy @@ -20,6 +20,11 @@ class AnalyticsSpec extends BaseSpec { private static final String SCOPE_ID = UUID.randomUUID() private static final Map ENABLED_DEBUG_LOG_MODE = ["logging.level.root": "debug"] + + private static final PubStackAnalytics analytics = new PubStackAnalytics(Dependencies.networkServiceContainer).tap { + it.setResponse(PubStackResponse.getDefaultPubStackResponse(SCOPE_ID, Dependencies.networkServiceContainer.rootUri)) + } + private static final PrebidServerService pbsService = pbsServiceFactory.getService(PbsConfig.getPubstackAnalyticsConfig(SCOPE_ID)) private static final PrebidServerService pbsServiceWithLogAnalytics = pbsServiceFactory.getService( ENABLED_DEBUG_LOG_MODE + ['analytics.log.enabled' : 'true', @@ -28,12 +33,6 @@ class AnalyticsSpec extends BaseSpec { ENABLED_DEBUG_LOG_MODE + ['analytics.log.enabled' : 'true', 'analytics.global.adapters': '']) - - @Shared - PubStackAnalytics analytics = new PubStackAnalytics(Dependencies.networkServiceContainer).tap { - it.setResponse(PubStackResponse.getDefaultPubStackResponse(SCOPE_ID, Dependencies.networkServiceContainer.rootUri)) - } - @Ignore("Currently impossible to make this test pass 100% of the time") def "PBS should send PubStack analytics when analytics.pubstack.enabled=true"() { given: "Basic bid request" diff --git a/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy index 13479030d1d..880b4ab5636 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/BaseSpec.groovy @@ -1,6 +1,6 @@ package org.prebid.server.functional.tests -import org.prebid.server.functional.model.bidderspecific.BidderRequest +import org.prebid.server.functional.model.request.auction.BidRequest import org.prebid.server.functional.model.response.amp.AmpResponse import org.prebid.server.functional.model.response.auction.Bid import org.prebid.server.functional.model.response.auction.BidMediaType @@ -99,7 +99,7 @@ abstract class BaseSpec extends Specification implements ObjectMapperWrapper { roundWithDefaultPrecisionAndRoundingType(value, UP) } - protected static Map> getRequests(BidResponse bidResponse) { + protected static Map> getRequests(BidResponse bidResponse) { bidResponse.ext.debug.bidders.collectEntries { bidderName, bidderCalls -> collectRequestByBidderName(bidderName, bidderCalls) } @@ -109,15 +109,15 @@ abstract class BaseSpec extends Specification implements ObjectMapperWrapper { bidResponse.seatbid*.bid.collectMany { it }.findAll { it.mediaType == mediaType } } - protected static Map> getRequests(AmpResponse ampResponse) { + protected static Map> getRequests(AmpResponse ampResponse) { ampResponse.ext.debug.bidders.collectEntries { bidderName, bidderCalls -> collectRequestByBidderName(bidderName, bidderCalls) } } - private static LinkedHashMap> collectRequestByBidderName(String bidderName, + private static LinkedHashMap> collectRequestByBidderName(String bidderName, List bidderCalls) { - [(bidderName): bidderCalls.collect { bidderCall -> decode(bidderCall.requestBody as String, BidderRequest) }] + [(bidderName): bidderCalls.collect { bidderCall -> decode(bidderCall.requestBody as String, BidRequest) }] } private static GString roundWithDefaultPrecisionAndRoundingType(BigDecimal value, RoundingMode roundingMode) { diff --git a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy index ce17a673424..c5974022061 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/CacheSpec.groovy @@ -574,10 +574,10 @@ class CacheSpec extends BaseSpec { verifyAll(bidResponse?.seatbid[0]?.bid[0]?.ext?.prebid?.targeting as Map) { it.get("hb_cache_id") it.get("hb_cache_id_generic") - it.get("hb_cache_path") == CACHE_PATH - it.get("hb_cache_host") == CACHE_HOST - it.get("hb_cache_path_generic") == CACHE_PATH - it.get("hb_cache_host_generic") == CACHE_HOST + it.get("hb_cache_path") == this.CACHE_PATH + it.get("hb_cache_host") == this.CACHE_HOST + it.get("hb_cache_path_generic") == this.CACHE_PATH + it.get("hb_cache_host_generic") == this.CACHE_HOST } and: "Debug should contain http call" @@ -610,9 +610,9 @@ class CacheSpec extends BaseSpec { verifyAll(bidResponse.seatbid[0].bid[0].ext.prebid.targeting) { it.get("hb_cache_id") it.get("hb_cache_id_generic") - it.get("hb_cache_path") == INTERNAL_CACHE_PATH + it.get("hb_cache_path") == this.INTERNAL_CACHE_PATH it.get("hb_cache_host") == networkServiceContainer.hostAndPort.toString() - it.get("hb_cache_path_generic") == INTERNAL_CACHE_PATH + it.get("hb_cache_path_generic") == this.INTERNAL_CACHE_PATH it.get("hb_cache_host_generic") == networkServiceContainer.hostAndPort.toString() } diff --git a/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy index 7e9eff9ebd3..a64bbc21086 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/SetUidSpec.groovy @@ -514,7 +514,7 @@ class SetUidSpec extends BaseSpec { } List getSetUidsHeaders(SetuidResponse response, boolean includeEmpty = false) { - response.headers.get("Set-Cookie").findAll { cookie -> + response.headers.get("set-cookie").findAll { cookie -> includeEmpty || !(cookie =~ /\buids\d*=\s*;/) } } diff --git a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy index b586688398b..29d23897ed4 100644 --- a/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy +++ b/src/test/groovy/org/prebid/server/functional/tests/pricefloors/PriceFloorsRulesSpec.groovy @@ -3,7 +3,6 @@ package org.prebid.server.functional.tests.pricefloors import org.prebid.server.functional.model.ChannelType import org.prebid.server.functional.model.bidder.Generic import org.prebid.server.functional.model.bidder.Openx -import org.prebid.server.functional.model.bidderspecific.BidderRequest import org.prebid.server.functional.model.config.AlternateBidderCodes import org.prebid.server.functional.model.config.BidderConfig import org.prebid.server.functional.model.db.StoredImp @@ -1220,7 +1219,7 @@ class PriceFloorsRulesSpec extends PriceFloorsBaseSpec { assert seatNonBid.nonBid.size() == bidResponse.seatbid[0].bid.size() } - private static Map impIdToBidderCallImp(List bidderRequests) { + private static Map impIdToBidderCallImp(List bidderRequests) { bidderRequests.imp.flatten().collectEntries { [it.id, it] } as Map } } diff --git a/src/test/groovy/org/prebid/server/functional/util/privacy/TcfConsent.groovy b/src/test/groovy/org/prebid/server/functional/util/privacy/TcfConsent.groovy index cdb6fce665b..1d5a28af2c4 100644 --- a/src/test/groovy/org/prebid/server/functional/util/privacy/TcfConsent.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/privacy/TcfConsent.groovy @@ -143,7 +143,7 @@ class TcfConsent implements ConsentString { TCF_POLICY_V2(2), TCF_POLICY_V4(4), - TCF_POLICY_V5(5), + TCF_POLICY_V5(5) final int value diff --git a/src/test/groovy/org/prebid/server/functional/util/privacy/gpp/GppConsent.groovy b/src/test/groovy/org/prebid/server/functional/util/privacy/gpp/GppConsent.groovy index e4bc73c6410..72203ca7d32 100644 --- a/src/test/groovy/org/prebid/server/functional/util/privacy/gpp/GppConsent.groovy +++ b/src/test/groovy/org/prebid/server/functional/util/privacy/gpp/GppConsent.groovy @@ -70,7 +70,7 @@ abstract class GppConsent implements ConsentString { US_VA_V1(UsVa.NAME, UsVa.VERSION), //9 US_CO_V1(UsCo.NAME, UsCo.VERSION), //10 US_UT_V1(UsUt.NAME, UsUt.VERSION), //11 - US_CT_V1(UsCt.NAME, UsCt.VERSION), //12 + US_CT_V1(UsCt.NAME, UsCt.VERSION) //12 final String name final int version diff --git a/src/test/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporterTest.java b/src/test/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporterTest.java index ef1e488e81e..55753587562 100644 --- a/src/test/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporterTest.java +++ b/src/test/java/org/prebid/server/analytics/reporter/pubstack/PubstackAnalyticsReporterTest.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -26,6 +25,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.TimeUnit; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -92,7 +92,7 @@ public void initializeShouldFetchConfigAndSetPeriodicTimerForConfigUpdate() thro Future.succeededFuture(HttpClientResponse.of(200, null, mapper.writeValueAsString(pubstackConfig)))); // when - pubstackAnalyticsReporter.initialize(Promise.promise()); + pubstackAnalyticsReporter.initialize(); // then verify(vertx).setPeriodic(anyLong(), any()); @@ -106,14 +106,18 @@ public void initializeShouldFetchConfigAndSetPeriodicTimerForConfigUpdate() thro @Test public void initializeShouldFailUpdateSendBuffersAndSetTimerWhenEndpointFromRemoteConfigIsNotValid() throws JsonProcessingException { + // given final PubstackConfig pubstackConfig = PubstackConfig.of("newScopeId", "invalid", Collections.singletonMap(EventType.auction, true)); given(httpClient.get(anyString(), anyLong())).willReturn( Future.succeededFuture(HttpClientResponse.of(200, null, mapper.writeValueAsString(pubstackConfig)))); - // when and then - assertThatThrownBy(() -> pubstackAnalyticsReporter.initialize(Promise.promise())) + // when + final Future result = pubstackAnalyticsReporter.initialize(); + + // then + assertThatThrownBy(() -> result.await(5, TimeUnit.SECONDS)) .hasMessage("[pubstack] Failed to create event report url for endpoint: invalid") .isInstanceOf(PreBidException.class); verify(auctionHandler).reportEvents(); @@ -132,8 +136,8 @@ public void initializeShouldNotUpdateEventsIfFetchedConfigIsSameAsPrevious() thr Future.succeededFuture(HttpClientResponse.of(200, null, mapper.writeValueAsString(pubstackConfig)))); // when - pubstackAnalyticsReporter.initialize(Promise.promise()); - pubstackAnalyticsReporter.initialize(Promise.promise()); + pubstackAnalyticsReporter.initialize(); + pubstackAnalyticsReporter.initialize(); // then verify(httpClient, times(2)).get(anyString(), anyLong()); @@ -151,7 +155,7 @@ public void initializeShouldNotSendEventsAndUpdateConfigsWhenResponseStatusIsNot Future.succeededFuture(HttpClientResponse.of(400, null, null))); // when - pubstackAnalyticsReporter.initialize(Promise.promise()); + pubstackAnalyticsReporter.initialize(); // then verify(vertx).setPeriodic(anyLong(), any()); @@ -167,7 +171,7 @@ public void initializeShouldNotSendEventsAndUpdateConfigsWhenCantParseResponse() Future.succeededFuture(HttpClientResponse.of(200, null, "{\"endpoint\" : {}}"))); // when - pubstackAnalyticsReporter.initialize(Promise.promise()); + pubstackAnalyticsReporter.initialize(); // then verify(vertx).setPeriodic(anyLong(), any()); diff --git a/src/test/java/org/prebid/server/auction/CurrencyConversionServiceTest.java b/src/test/java/org/prebid/server/auction/CurrencyConversionServiceTest.java index 61a28789710..ed9030c493f 100644 --- a/src/test/java/org/prebid/server/auction/CurrencyConversionServiceTest.java +++ b/src/test/java/org/prebid/server/auction/CurrencyConversionServiceTest.java @@ -4,7 +4,6 @@ import com.iab.openrtb.request.BidRequest; import io.vertx.core.Future; import io.vertx.core.Handler; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -397,7 +396,7 @@ private CurrencyConversionService createInitializedService(String url, clock, jacksonMapper)); - currencyService.initialize(Promise.promise()); + currencyService.initialize(); return currencyService; } diff --git a/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java b/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java index 291dd35d415..b1964100edd 100644 --- a/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/criteo/CriteoBidderTest.java @@ -71,7 +71,10 @@ public void makeHttpRequestsShouldEncodePassedBidRequest() { .body(jacksonMapper.encodeToBytes(bidRequest)) .payload(bidRequest) .build()); - assertThat(result.getValue()).usingRecursiveComparison().isEqualTo(expectedResult.getValue()); + + assertThat(result.getValue()).usingRecursiveComparison() + .withEqualsForType((a, b) -> a.entries().equals(b.entries()), MultiMap.class) + .isEqualTo(expectedResult.getValue()); assertThat(result.getErrors()).isEmpty(); } diff --git a/src/test/java/org/prebid/server/bidder/gothamads/GothamAdsBidderTest.java b/src/test/java/org/prebid/server/bidder/gothamads/GothamAdsBidderTest.java index 41c38db12ad..f0f02e9c9ad 100644 --- a/src/test/java/org/prebid/server/bidder/gothamads/GothamAdsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/gothamads/GothamAdsBidderTest.java @@ -103,7 +103,10 @@ public void makeHttpRequestsShouldMakeCorrectRequest() { .build() ); - assertThat(result.getValue()).usingRecursiveComparison().isEqualTo(expectedResult.getValue()); + assertThat(result.getValue()) + .usingRecursiveComparison() + .withEqualsForType((a, b) -> a.entries().equals(b.entries()), MultiMap.class) + .isEqualTo(expectedResult.getValue()); assertThat(result.getErrors()).isEmpty(); } diff --git a/src/test/java/org/prebid/server/bidder/gumgum/GumgumBidderTest.java b/src/test/java/org/prebid/server/bidder/gumgum/GumgumBidderTest.java index 2b00840ed26..b0982cdd3b3 100644 --- a/src/test/java/org/prebid/server/bidder/gumgum/GumgumBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/gumgum/GumgumBidderTest.java @@ -39,10 +39,10 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.tuple; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; @@ -123,7 +123,7 @@ public void testMakeHttpRequestsShouldNotSetTagIdFromZoneWhenAdUnitIdIsMissing() final Imp modifiedImp = modifiedRequest.getImp().get(0); assertNull(modifiedImp.getTagid()); - assertEquals("test-site", modifiedRequest.getSite().getId(), "zone123"); + assertEquals("zone123", modifiedRequest.getSite().getId()); } @Test diff --git a/src/test/java/org/prebid/server/bidder/pwbid/PwbidBidderTest.java b/src/test/java/org/prebid/server/bidder/pwbid/PwbidBidderTest.java index b790ad9033f..22f479a4836 100644 --- a/src/test/java/org/prebid/server/bidder/pwbid/PwbidBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pwbid/PwbidBidderTest.java @@ -72,7 +72,10 @@ public void makeHttpRequestsShouldReturnExpectedHttpRequest() { .payload(bidRequest) .build()); - assertThat(result.getValue()).usingRecursiveComparison().isEqualTo(expectedResults.getValue()); + assertThat(result.getValue()) + .usingRecursiveComparison() + .withEqualsForType((a, b) -> a.entries().equals(b.entries()), MultiMap.class) + .isEqualTo(expectedResults.getValue()); assertThat(result.getErrors()).isEmpty(); } diff --git a/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java b/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java index 111d4f441f5..da03b34ec0e 100644 --- a/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java +++ b/src/test/java/org/prebid/server/cookie/CookieDeprecationServiceTest.java @@ -5,6 +5,7 @@ import com.iab.openrtb.request.Device; import io.vertx.core.http.Cookie; import io.vertx.core.http.CookieSameSite; +import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.BeforeEach; @@ -26,6 +27,7 @@ import org.prebid.server.settings.model.AccountPrivacySandboxCookieDeprecationConfig; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.UnaryOperator; @@ -41,18 +43,22 @@ public class CookieDeprecationServiceTest extends VertxTest { @Mock(strictness = LENIENT) private RoutingContext routingContext; + @Mock(strictness = LENIENT) + private HttpServerRequest request; + private final CookieDeprecationService target = new CookieDeprecationService(); @BeforeEach public void before() { - given(routingContext.cookieMap()).willReturn(Map.of()); + given(routingContext.request()).willReturn(request); + given(request.cookies()).willReturn(Collections.emptySet()); } @Test public void makeCookieShouldReturnNullWhenRequestContainsDeprecationCookie() { // given - given(routingContext.cookieMap()) - .willReturn(Map.of("receive-cookie-deprecation", Cookie.cookie("receive-cookie-deprecation", "1"))); + given(routingContext.request().cookies()) + .willReturn(Collections.singleton(Cookie.cookie("receive-cookie-deprecation", "1"))); // when final PartitionedCookie actualCookie = target.makeCookie( @@ -66,8 +72,8 @@ public void makeCookieShouldReturnNullWhenRequestContainsDeprecationCookie() { @Test public void makeCookieShouldReturnNullWhenRequestContainsDeprecationCookieAndAccountIsEmpty() { // given - given(routingContext.cookieMap()) - .willReturn(Map.of("receive-cookie-deprecation", Cookie.cookie("receive-cookie-deprecation", "1"))); + given(request.cookies()).willReturn( + Collections.singleton(Cookie.cookie("receive-cookie-deprecation", "1"))); // when final PartitionedCookie actualCookie = target.makeCookie(Account.builder().build(), routingContext); diff --git a/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java b/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java index c73ee163935..2f930fdf0de 100644 --- a/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java +++ b/src/test/java/org/prebid/server/cookie/UidsCookieServiceTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.http.Cookie; import io.vertx.core.http.CookieSameSite; +import io.vertx.core.http.HttpServerRequest; import io.vertx.ext.web.RoutingContext; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.BeforeEach; @@ -25,15 +26,19 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import static java.util.Collections.emptyMap; +import static java.util.Collections.emptySet; +import static java.util.Collections.singleton; 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.within; import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; +import static org.mockito.Mock.Strictness.LENIENT; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; @@ -49,8 +54,10 @@ public class UidsCookieServiceTest extends VertxTest { // Zero means size checking is disabled private static final int MAX_COOKIE_SIZE_BYTES = 0; - @Mock + @Mock(strictness = LENIENT) private RoutingContext routingContext; + @Mock(strictness = LENIENT) + private HttpServerRequest request; @Mock private PrioritizedCoopSyncProvider prioritizedCoopSyncProvider; @Mock @@ -72,6 +79,8 @@ public void setUp() { prioritizedCoopSyncProvider, metrics, jacksonMapper); + + given(routingContext.request()).willReturn(request); } @Test @@ -145,12 +154,13 @@ public void shouldReturnNonEmptyUidsCookie() { // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", // "expires": "2023-12-05T19:00:05.103329-03:00" } } } - given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie( - "tempUIDs", - "eyAidGVtcFVJRHMiOnsgInJ1Ymljb24iOnsgInVpZCI6ICJKNVZMQ1dRUC0yNi1DV0ZUIiwg" - + "ImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS4xMDMzMjktMDM6MDAiIH0sICJhZG5" - + "4cyI6eyAidWlkIjogIjEyMzQ1IiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS" - + "4xMDMzMjktMDM6MDAiIH0gfSB9"))); + given(request.cookies()).willReturn(singleton( + Cookie.cookie( + "uids", + "eyAidGVtcFVJRHMiOnsgInJ1Ymljb24iOnsgInVpZCI6ICJKNVZMQ1dRUC0yNi1DV0ZUIiwg" + + "ImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS4xMDMzMjktMDM6MDAiIH0sICJhZG5" + + "4cyI6eyAidWlkIjogIjEyMzQ1IiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS" + + "4xMDMzMjktMDM6MDAiIH0gfSB9"))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -173,7 +183,7 @@ public void shouldReturnNonNullUidsCookieIfUidsCookieIsMissing() { @Test public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonBase64() { // given - given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie("uids", "abcde"))); + given(request.cookies()).willReturn(singleton(Cookie.cookie("uids", "abcde"))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -186,7 +196,7 @@ public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonBase64() { public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonJson() { // given // this uids cookie value stands for "abcde" - given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie("tempUIDs", "bm9uLWpzb24="))); + given(request.cookies()).willReturn(singleton(Cookie.cookie("uids", "bm9uLWpzb24="))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -198,8 +208,8 @@ public void shouldReturnNonNullUidsCookieIfUidsCookieIsNonJson() { @Test public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsMissingAndOptoutCookieHasExpectedValue() { // given - given(routingContext.cookieMap()).willReturn( - singletonMap(OPT_OUT_COOKIE_NAME, Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE))); + given(request.cookies()).willReturn( + singleton(Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -211,19 +221,18 @@ public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsMissingAndOptoutCo @Test public void shouldReturnUidsCookieWithOptoutTrueIfUidsCookieIsPresentAndOptoutCookieHasExpectedValue() { // given - final Map cookies = new HashMap<>(); - // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", - // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", - // "expires": "2023-12-05T19:00:05.103329-03:00" } } } - cookies.put("uids", + final Set cookies = Set.of( + // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", + // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", + // "expires": "2023-12-05T19:00:05.103329-03:00" } } } Cookie.cookie("uids", "eyAidGVtcFVJRHMiOnsgInJ1Ymljb24iOnsgInVpZCI6ICJKNVZMQ1dRUC0yNi1DV0" + "ZUIiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS4xMDMzMjktMDM6MDAiIH0sICJhZG5" + "4cyI6eyAidWlkIjogIjEyMzQ1IiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS" - + "4xMDMzMjktMDM6MDAiIH0gfSB9")); + + "4xMDMzMjktMDM6MDAiIH0gfSB9"), - cookies.put(OPT_OUT_COOKIE_NAME, Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE)); + Cookie.cookie(OPT_OUT_COOKIE_NAME, OPT_OUT_COOKIE_VALUE)); - given(routingContext.cookieMap()).willReturn(cookies); + given(request.cookies()).willReturn(cookies); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -285,19 +294,20 @@ public void aliveCookieShouldSetPath() { @Test public void shouldReturnUidsCookieWithOptoutFalseIfOptoutCookieHasNotExpectedValue() { // given - final Map cookies = new HashMap<>(); - // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", - // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", - // "expires": "2023-12-05T19:00:05.103329-03:00" } } } - cookies.put("uids", Cookie.cookie( - "tempUIDs", - "eyAidGVtcFVJRHMiOnsgInJ1Ymljb24iOnsgInVpZCI6ICJKNVZMQ1dRUC0yNi1DV0ZUIiwg" - + "ImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS4xMDMzMjktMDM6MDAiIH0sICJhZG5" - + "4cyI6eyAidWlkIjogIjEyMzQ1IiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS" - + "4xMDMzMjktMDM6MDAiIH0gfSB9")); - cookies.put(OPT_OUT_COOKIE_NAME, Cookie.cookie(OPT_OUT_COOKIE_NAME, "dummy")); + final Set cookies = Set.of( + // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", + // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", + // "expires": "2023-12-05T19:00:05.103329-03:00" } } } + Cookie.cookie( + "uids", + "eyAidGVtcFVJRHMiOnsgInJ1Ymljb24iOnsgInVpZCI6ICJKNVZMQ1dRUC0yNi1DV0ZUIiwg" + + "ImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS4xMDMzMjktMDM6MDAiIH0sICJhZG5" + + "4cyI6eyAidWlkIjogIjEyMzQ1IiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS" + + "4xMDMzMjktMDM6MDAiIH0gfSB9"), - given(routingContext.cookieMap()).willReturn(cookies); + Cookie.cookie(OPT_OUT_COOKIE_NAME, "dummy")); + + given(request.cookies()).willReturn(cookies); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -323,8 +333,9 @@ public void shouldReturnUidsCookieWithOptoutFalseIfOptoutCookieNameNotSpecified( prioritizedCoopSyncProvider, metrics, jacksonMapper); - given(routingContext.cookieMap()).willReturn( - singletonMap(OPT_OUT_COOKIE_NAME, Cookie.cookie("trp_optout", "true"))); + + given(request.cookies()).willReturn( + singleton(Cookie.cookie(OPT_OUT_COOKIE_NAME, "true"))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -348,8 +359,9 @@ public void shouldReturnUidsCookieWithOptoutFalseIfOptoutCookieValueNotSpecified prioritizedCoopSyncProvider, metrics, jacksonMapper); - given(routingContext.cookieMap()).willReturn( - singletonMap(OPT_OUT_COOKIE_NAME, Cookie.cookie("trp_optout", "true"))); + + given(request.cookies()).willReturn( + singleton(Cookie.cookie(OPT_OUT_COOKIE_NAME, "true"))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -373,7 +385,8 @@ public void shouldReturnRubiconCookieValueFromHostCookieWhenUidValueIsAbsent() { prioritizedCoopSyncProvider, metrics, jacksonMapper); - given(routingContext.cookieMap()).willReturn(singletonMap("khaos", Cookie.cookie("khaos", "abc123"))); + + given(request.cookies()).willReturn(singleton(Cookie.cookie("khaos", "abc123"))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -398,18 +411,18 @@ public void shouldReturnRubiconCookieValueFromHostCookieWhenUidValueIsPresentBut metrics, jacksonMapper); - final Map cookies = new HashMap<>(); - // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", - // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", - // "expires": "2023-12-05T19:00:05.103329-03:00" } } } - cookies.put("uids", + final Set cookies = Set.of( + // this uids cookie value stands for { "tempUIDs":{ "rubicon":{ "uid": "J5VLCWQP-26-CWFT", + // "expires": "2023-12-05T19:00:05.103329-03:00" }, "adnxs":{ "uid": "12345", + // "expires": "2023-12-05T19:00:05.103329-03:00" } } } Cookie.cookie("uids", "eyAidGVtcFVJRHMiOnsgInJ1Ymljb24iOnsgInVpZCI6ICJKNVZMQ1dRUC0yNi1DV0" + "ZUIiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS4xMDMzMjktMDM6MDAiIH0sICJhZG5" + "4cyI6eyAidWlkIjogIjEyMzQ1IiwgImV4cGlyZXMiOiAiMjAyMy0xMi0wNVQxOTowMDowNS" - + "4xMDMzMjktMDM6MDAiIH0gfSB9")); - cookies.put("khaos", Cookie.cookie("khaos", "abc123")); + + "4xMDMzMjktMDM6MDAiIH0gfSB9"), + + Cookie.cookie("khaos", "abc123")); - given(routingContext.cookieMap()).willReturn(cookies); + given(request.cookies()).willReturn(cookies); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -427,7 +440,7 @@ public void shouldSkipFacebookSentinelFromUidsCookie() throws JsonProcessingExce final Uids uids = Uids.builder().uids(uidsWithExpiry).build(); final String encodedUids = encodeUids(uids); - given(routingContext.cookieMap()).willReturn(singletonMap("uids", Cookie.cookie("uids", encodedUids))); + given(request.cookies()).willReturn(singleton(Cookie.cookie("uids", encodedUids))); // when final UidsCookie uidsCookie = target.parseFromRequest(routingContext); @@ -594,11 +607,11 @@ public void hostCookieUidToSyncShouldReturnHostCookieUidWhenHostCookieUidIsAbsen jacksonMapper); final String uidsCookieBase64 = Base64.getUrlEncoder().encodeToString(uidsCookie.toJson().getBytes()); - final Map cookieMap = Map.of( - "khaos", Cookie.cookie("khaos", "hostCookieUid"), - "uids", Cookie.cookie("uids", uidsCookieBase64)); + final Set cookies = Set.of( + Cookie.cookie("khaos", "hostCookieUid"), + Cookie.cookie("uids", uidsCookieBase64)); - given(routingContext.cookieMap()).willReturn(cookieMap); + given(request.cookies()).willReturn(cookies); // when final String result = target.hostCookieUidToSync(routingContext, RUBICON); @@ -623,7 +636,7 @@ public void hostCookieUidToSyncShouldReturnNullWhenUidsCookieHasNoUidForHostCook metrics, jacksonMapper); - given(routingContext.cookieMap()).willReturn(emptyMap()); + given(request.cookies()).willReturn(emptySet()); // when final String result = target.hostCookieUidToSync(routingContext, RUBICON); @@ -653,11 +666,11 @@ public void hostCookieUidToSyncShouldReturnNullWhenUidInUidsCookieSameAsUidInHos jacksonMapper); final String uidsCookieBase64 = Base64.getUrlEncoder().encodeToString(uidsCookie.toJson().getBytes()); - final Map cookieMap = Map.of( - "khaos", Cookie.cookie("khaos", "hostCookieUid"), - "uids", Cookie.cookie("uids", uidsCookieBase64)); + final Set cookies = Set.of( + Cookie.cookie("khaos", "hostCookieUid"), + Cookie.cookie("uids", uidsCookieBase64)); - given(routingContext.cookieMap()).willReturn(cookieMap); + given(request.cookies()).willReturn(cookies); // when final String result = target.hostCookieUidToSync(routingContext, RUBICON); diff --git a/src/test/java/org/prebid/server/execution/file/syncer/FileSyncerTest.java b/src/test/java/org/prebid/server/execution/file/syncer/FileSyncerTest.java index 39a8e8ae966..454a2f6f834 100644 --- a/src/test/java/org/prebid/server/execution/file/syncer/FileSyncerTest.java +++ b/src/test/java/org/prebid/server/execution/file/syncer/FileSyncerTest.java @@ -4,6 +4,7 @@ import io.vertx.core.Handler; import io.vertx.core.Promise; import io.vertx.core.Vertx; +import org.apache.commons.lang3.NotImplementedException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,7 +17,6 @@ import org.prebid.server.execution.retry.FixedIntervalRetryPolicy; import org.prebid.server.execution.retry.NonRetryable; import org.prebid.server.execution.retry.RetryPolicy; -import org.testcontainers.shaded.org.apache.commons.lang3.NotImplementedException; import java.util.concurrent.Callable; diff --git a/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java b/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java index 2da614c4e50..33bef039bab 100644 --- a/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java +++ b/src/test/java/org/prebid/server/execution/file/syncer/RemoteFileSyncerTest.java @@ -207,7 +207,7 @@ public void syncForFilepathShouldNotUpdateWhenHeadRequestReturnInvalidHead() { verify(fileSystem, times(2)).exists(eq(FILE_PATH)); verify(httpClient).request(any()); verify(fileProcessor).setDataPath(any()); - verify(fileSystem, never()).move(eq(TMP_FILE_PATH), eq(FILE_PATH), any(), any()); + verify(fileSystem, never()).move(eq(TMP_FILE_PATH), eq(FILE_PATH), any()); verify(vertx).setPeriodic(eq(UPDATE_INTERVAL), any()); verifyNoMoreInteractions(httpClient); } @@ -376,9 +376,7 @@ public void syncForFilepathShouldRetryWhenFileOpeningFailed() { given(vertx.setTimer(eq(RETRY_INTERVAL), any())) .willAnswer(withReturnObjectAndPassObjectToHandler(0L, 10L, 1)); - given(fileSystem.delete(any(), any())) - .willAnswer(withSelfAndPassObjectToHandler(Future.succeededFuture())) - .willAnswer(withSelfAndPassObjectToHandler(Future.failedFuture(new RuntimeException()))); + given(fileSystem.delete(any())).willReturn(Future.failedFuture(new RuntimeException())); given(fileProcessor.setDataPath(anyString())) .willReturn(Future.succeededFuture()); @@ -528,7 +526,7 @@ public void syncShouldNotUpdateFileWhenServerRespondsWithNonOkStatusCode() { verify(fileSystem, times(1)).exists(eq(FILE_PATH)); verify(fileSystem, never()).open(any(), any()); verify(fileSystem, never()).delete(any()); - verify(fileSystem, never()).move(any(), any(), any(), any()); + verify(fileSystem, never()).move(any(), any(), any()); verify(asyncFile, never()).close(); verify(httpClient, times(1)).request(any()); verify(httpClientResponse).statusCode(); diff --git a/src/test/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationServiceTest.java b/src/test/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationServiceTest.java index 084d64d1bcf..49061688f3b 100644 --- a/src/test/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationServiceTest.java +++ b/src/test/java/org/prebid/server/geolocation/CircuitBreakerSecuredGeoLocationServiceTest.java @@ -16,9 +16,6 @@ import org.prebid.server.geolocation.model.GeoInfo; import org.prebid.server.metric.Metrics; -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; import java.util.function.BooleanSupplier; import static org.assertj.core.api.Assertions.assertThat; @@ -33,7 +30,6 @@ public class CircuitBreakerSecuredGeoLocationServiceTest { private Vertx vertx; - private Clock clock; @Mock private GeoLocationService wrappedGeoLocationService; @Mock @@ -44,14 +40,13 @@ public class CircuitBreakerSecuredGeoLocationServiceTest { @BeforeEach public void setUp() { vertx = Vertx.vertx(); - clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); geoLocationService = new CircuitBreakerSecuredGeoLocationService(vertx, wrappedGeoLocationService, metrics, 1, - 100L, 200L, clock); + 1000L, 200L); } @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test @@ -143,7 +138,7 @@ public void lookupShouldSucceedsIfCircuitIsHalfOpenedAndWrappedGeoLocationSuccee public void lookupShouldFailsWithOriginalExceptionIfOpeningIntervalExceeds() { // given geoLocationService = new CircuitBreakerSecuredGeoLocationService(vertx, wrappedGeoLocationService, metrics, 2, - 100L, 200L, clock); + 100L, 200L); givenWrappedGeoLocationReturning( Future.failedFuture(new RuntimeException("exception1")), diff --git a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java index ed88f7f6fdd..8cb36af2a28 100644 --- a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java @@ -1,5 +1,6 @@ package org.prebid.server.handler; +import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.http.Cookie; @@ -55,7 +56,6 @@ import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; import static java.util.Collections.emptyMap; import static java.util.Collections.singleton; @@ -64,6 +64,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.anyInt; 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.Mock.Strictness.LENIENT; @@ -344,7 +345,7 @@ public void shouldRespondWithoutCookieIfGdprProcessingPreventsCookieSetting() { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); + verify(httpResponse, never()).addCookie(any(Cookie.class)); verify(httpResponse).setStatusCode(eq(451)); verify(httpResponse).end(eq("The gdpr_consent param prevents cookies from being saved")); verify(metrics).updateUserSyncTcfBlockedMetric(RUBICON); @@ -368,7 +369,7 @@ public void shouldRespondWithBadRequestStatusIfGdprProcessingFailsWithInvalidReq setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); + verify(httpResponse, never()).addCookie(any(Cookie.class)); verify(httpResponse).setStatusCode(eq(400)); verify(httpResponse).end(eq("Invalid request format: gdpr exception")); @@ -391,8 +392,8 @@ public void shouldRespondWithInternalServerErrorStatusIfGdprProcessingFailsWithU setuidHandler.handle(routingContext); // then - verify(httpResponse, never()).sendFile(any()); - verify(routingContext, never()).addCookie(any(Cookie.class)); + verify(httpResponse, never()).sendFile(anyString()); + verify(httpResponse, never()).addCookie(any(Cookie.class)); verify(httpResponse).setStatusCode(eq(500)); verify(httpResponse).end(eq("Unexpected setuid processing error: unexpected error TCF")); } @@ -452,11 +453,13 @@ public void shouldPassAccountToPrivacyEnforcementServiceWhenAccountIsNotFound() public void shouldRespondWithCookieFromRequestParam() throws IOException { // given final UidsCookie uidsCookie = emptyUidsCookie(); + final UidsCookie updatedUidsCookie = uidsCookie.updateUid(RUBICON, "J5VLCWQP-26-CWFT"); + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(uidsCookie); given(uidsCookieService.updateUidsCookie(uidsCookie, RUBICON, "J5VLCWQP-26-CWFT")) - .willReturn(updated(uidsCookie.updateUid(RUBICON, "J5VLCWQP-26-CWFT"))); + .willReturn(updated(updatedUidsCookie)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); @@ -465,21 +468,19 @@ public void shouldRespondWithCookieFromRequestParam() throws IOException { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - final String encodedUidsCookie = getUidsCookie(); - final Uids decodedUids = decodeUids(encodedUidsCookie); - assertThat(decodedUids.getUids()).hasSize(1); - assertThat(decodedUids.getUids().get(RUBICON).getUid()).isEqualTo("J5VLCWQP-26-CWFT"); + verify(httpResponse).addCookie(equalToUidsCookie(updatedUidsCookie)); } @Test public void shouldRespondWithCookieFromRequestParamWhenBidderAndCookieFamilyAreDifferent() throws IOException { // given final UidsCookie uidsCookie = emptyUidsCookie(); + final UidsCookie updatedUidsCookie = uidsCookie.updateUid(ADNXS, "J5VLCWQP-26-CWFT"); + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(uidsCookie); given(uidsCookieService.updateUidsCookie(uidsCookie, ADNXS, "J5VLCWQP-26-CWFT")) - .willReturn(updated(uidsCookie.updateUid(ADNXS, "J5VLCWQP-26-CWFT"))); + .willReturn(updated(updatedUidsCookie)); given(httpRequest.getParam("bidder")).willReturn(ADNXS); given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); @@ -488,21 +489,18 @@ public void shouldRespondWithCookieFromRequestParamWhenBidderAndCookieFamilyAreD setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - final String encodedUidsCookie = getUidsCookie(); - final Uids decodedUids = decodeUids(encodedUidsCookie); - assertThat(decodedUids.getUids()).hasSize(1); - assertThat(decodedUids.getUids().get(ADNXS).getUid()).isEqualTo("J5VLCWQP-26-CWFT"); + verify(httpResponse).addCookie(equalToUidsCookie(updatedUidsCookie)); } @Test - public void shouldSendPixelWhenFParamIsEqualToIWhenTypeIsIframe() { + public void shouldSendPixelWhenFParamIsEqualToIWhenTypeIsIframe() throws JsonProcessingException { // given - given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) - .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); + final UidsCookie uidsCookie = emptyUidsCookie(); + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) + .willReturn(uidsCookie); given(uidsCookieService.updateUidsCookie(any(), any(), any())) - .willReturn(updated(emptyUidsCookie())); + .willReturn(updated(uidsCookie)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(httpRequest.getParam("f")).willReturn("i"); @@ -512,12 +510,12 @@ public void shouldSendPixelWhenFParamIsEqualToIWhenTypeIsIframe() { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - verify(httpResponse).sendFile(any()); + verify(httpResponse).sendFile(anyString()); + verify(httpResponse).addCookie(equalToUidsCookie(uidsCookie)); } @Test - public void shouldSendEmptyResponseWhenFParamIsEqualToBWhenTypeIsRedirect() { + public void shouldSendEmptyResponseWhenFParamIsEqualToBWhenTypeIsRedirect() throws JsonProcessingException { // given given(tcfDefinerService.getGdprHostVendorId()).willReturn(null); @@ -551,14 +549,14 @@ public void shouldSendEmptyResponseWhenFParamIsEqualToBWhenTypeIsRedirect() { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - verify(httpResponse, never()).sendFile(any()); + verify(httpResponse, never()).sendFile(anyString()); + verify(httpResponse).addCookie(equalToUidsCookie(uidsCookie)); verify(httpResponse).putHeader(eq(HttpHeaders.CONTENT_LENGTH), eq("0")); verify(httpResponse).putHeader(eq(HttpHeaders.CONTENT_TYPE), eq(HttpHeaders.TEXT_HTML)); } @Test - public void shouldSendEmptyResponseWhenFParamNotDefinedAndTypeIsIframe() { + public void shouldSendEmptyResponseWhenFParamNotDefinedAndTypeIsIframe() throws JsonProcessingException { // given given(tcfDefinerService.getGdprHostVendorId()).willReturn(null); @@ -591,14 +589,14 @@ public void shouldSendEmptyResponseWhenFParamNotDefinedAndTypeIsIframe() { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - verify(httpResponse, never()).sendFile(any()); + verify(httpResponse, never()).sendFile(anyString()); + verify(httpResponse).addCookie(equalToUidsCookie(uidsCookie)); verify(httpResponse).putHeader(eq(HttpHeaders.CONTENT_LENGTH), eq("0")); verify(httpResponse).putHeader(eq(HttpHeaders.CONTENT_TYPE), eq(HttpHeaders.TEXT_HTML)); } @Test - public void shouldSendPixelWhenFParamNotDefinedAndTypeIsRedirect() { + public void shouldSendPixelWhenFParamNotDefinedAndTypeIsRedirect() throws JsonProcessingException { // given given(tcfDefinerService.getGdprHostVendorId()).willReturn(null); @@ -631,8 +629,8 @@ public void shouldSendPixelWhenFParamNotDefinedAndTypeIsRedirect() { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - verify(httpResponse).sendFile(any()); + verify(httpResponse).sendFile(anyString()); + verify(httpResponse).addCookie(equalToUidsCookie(uidsCookie)); } @Test @@ -642,11 +640,12 @@ public void shouldInCookieWithRequestValue() throws IOException { RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"), ADNXS, UidWithExpiry.live("12345")); final UidsCookie uidsCookie = new UidsCookie(Uids.builder().uids(uids).build(), jacksonMapper); + final UidsCookie updatedUidsCookie = uidsCookie.updateUid(RUBICON, "updatedUid"); given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(uidsCookie); given(uidsCookieService.updateUidsCookie(uidsCookie, RUBICON, "updatedUid")) - .willReturn(updated(uidsCookie.updateUid(RUBICON, "updatedUid"))); + .willReturn(updated(updatedUidsCookie)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(httpRequest.getParam("uid")).willReturn("updatedUid"); @@ -655,18 +654,12 @@ public void shouldInCookieWithRequestValue() throws IOException { setuidHandler.handle(routingContext); // then - verify(httpResponse).sendFile(any()); - verify(routingContext, never()).addCookie(any(Cookie.class)); - - final String encodedUidsCookie = getUidsCookie(); - final Uids decodedUids = decodeUids(encodedUidsCookie); - assertThat(decodedUids.getUids()).hasSize(2); - assertThat(decodedUids.getUids().get(RUBICON).getUid()).isEqualTo("updatedUid"); - assertThat(decodedUids.getUids().get(ADNXS).getUid()).isEqualTo("12345"); + verify(httpResponse).sendFile(anyString()); + verify(httpResponse).addCookie(equalToUidsCookie(updatedUidsCookie)); } @Test - public void shouldReturnMultipleCookies() throws IOException { + public void shouldReturnMultipleCookies() { // given final Map uids = Map.of( RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"), @@ -694,23 +687,11 @@ public void shouldReturnMultipleCookies() throws IOException { setuidHandler.handle(routingContext); // then - verify(httpResponse).sendFile(any()); - verify(routingContext, never()).addCookie(any(Cookie.class)); - - final Map encodedUidsCookie = httpResponse.headers().getAll("Set-Cookie").stream() - .collect(Collectors.toMap(value -> value.split("=")[0], value -> value.split("=")[1])); - - assertThat(encodedUidsCookie).hasSize(2); - final Uids decodedUids1 = mapper.readValue(Base64.getUrlDecoder() - .decode(encodedUidsCookie.get("uids")), Uids.class); - final Uids decodedUids2 = mapper.readValue(Base64.getUrlDecoder() - .decode(encodedUidsCookie.get("uids2")), Uids.class); - - assertThat(decodedUids1.getUids()).hasSize(1); - assertThat(decodedUids1.getUids().get(RUBICON).getUid()).isEqualTo("updatedUid"); - - assertThat(decodedUids2.getUids()).hasSize(1); - assertThat(decodedUids2.getUids().get(ADNXS).getUid()).isEqualTo("12345"); + verify(httpResponse).sendFile(anyString()); + verify(httpResponse).addCookie( + cookieEqualTo("uids", "eyJ0ZW1wVUlEcyI6eyJydWJpY29uIjp7InVpZCI6InVwZGF0ZWRVaWQifX19")); + verify(httpResponse).addCookie( + cookieEqualTo("uids2", "eyJ0ZW1wVUlEcyI6eyJhZG54cyI6eyJ1aWQiOiIxMjM0NSJ9fX0")); } @Test @@ -720,10 +701,12 @@ public void shouldRespondWithCookieIfUserIsNotInGdprScope() throws IOException { .willReturn(Future.succeededFuture(TcfResponse.of(false, emptyMap(), null))); final UidsCookie uidsCookie = emptyUidsCookie(); + final UidsCookie updatedUidsCookie = uidsCookie.updateUid(RUBICON, "J5VLCWQP-26-CWFT"); + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(uidsCookie); given(uidsCookieService.updateUidsCookie(uidsCookie, RUBICON, "J5VLCWQP-26-CWFT")) - .willReturn(updated(uidsCookie.updateUid(RUBICON, "J5VLCWQP-26-CWFT"))); + .willReturn(updated(updatedUidsCookie)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); @@ -732,13 +715,8 @@ public void shouldRespondWithCookieIfUserIsNotInGdprScope() throws IOException { setuidHandler.handle(routingContext); // then - verify(routingContext, never()).addCookie(any(Cookie.class)); - verify(httpResponse).sendFile(any()); - - final String encodedUidsCookie = getUidsCookie(); - final Uids decodedUids = decodeUids(encodedUidsCookie); - assertThat(decodedUids.getUids()).hasSize(1); - assertThat(decodedUids.getUids().get(RUBICON).getUid()).isEqualTo("J5VLCWQP-26-CWFT"); + verify(httpResponse).addCookie(equalToUidsCookie(updatedUidsCookie)); + verify(httpResponse).sendFile(anyString()); } @Test @@ -761,10 +739,12 @@ public void shouldSkipTcfChecksAndRespondWithCookieIfHostVendorIdNotDefined() th given(tcfDefinerService.getGdprHostVendorId()).willReturn(null); final UidsCookie uidsCookie = emptyUidsCookie(); + final UidsCookie updatedUidsCookie = uidsCookie.updateUid(RUBICON, "J5VLCWQP-26-CWFT"); + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(uidsCookie); given(uidsCookieService.updateUidsCookie(uidsCookie, RUBICON, "J5VLCWQP-26-CWFT")) - .willReturn(updated(uidsCookie.updateUid(RUBICON, "J5VLCWQP-26-CWFT"))); + .willReturn(updated(updatedUidsCookie)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); given(httpRequest.getParam("uid")).willReturn("J5VLCWQP-26-CWFT"); @@ -774,13 +754,8 @@ public void shouldSkipTcfChecksAndRespondWithCookieIfHostVendorIdNotDefined() th // then verify(tcfDefinerService, never()).resultForVendorIds(anySet(), any()); - verify(routingContext, never()).addCookie(any(Cookie.class)); - verify(httpResponse).sendFile(any()); - - final String encodedUidsCookie = getUidsCookie(); - final Uids decodedUids = decodeUids(encodedUidsCookie); - assertThat(decodedUids.getUids()).hasSize(1); - assertThat(decodedUids.getUids().get(RUBICON).getUid()).isEqualTo("J5VLCWQP-26-CWFT"); + verify(httpResponse).sendFile(anyString()); + verify(httpResponse).addCookie(equalToUidsCookie(updatedUidsCookie)); } @Test @@ -877,13 +852,15 @@ public void shouldThrowExceptionInCaseOfBaseBidderCookieFamilyNameDuplicates() { assertThat(values).containsExactlyInAnyOrder("audienceNetwork", "rubicon"); } - private String getUidsCookie() { - return httpResponse.headers().get("Set-Cookie"); + private static Cookie equalToUidsCookie(UidsCookie uidsCookie) throws JsonProcessingException { + final String value = Base64.getUrlEncoder() + .encodeToString(mapper.writeValueAsBytes(uidsCookie.getCookieUids())); + + return cookieEqualTo("uids", value); } - private static Uids decodeUids(String value) throws IOException { - final String uids = value.substring(5).split(";")[0]; - return mapper.readValue(Base64.getUrlDecoder().decode(uids), Uids.class); + private static Cookie cookieEqualTo(String name, String value) { + return argThat(cookie -> cookie.getName().equals(name) && cookie.getValue().equals(value)); } private SetuidEvent captureSetuidEvent() { diff --git a/src/test/java/org/prebid/server/hooks/execution/HookStageExecutorTest.java b/src/test/java/org/prebid/server/hooks/execution/HookStageExecutorTest.java index 24210ae6b72..fc67149a747 100644 --- a/src/test/java/org/prebid/server/hooks/execution/HookStageExecutorTest.java +++ b/src/test/java/org/prebid/server/hooks/execution/HookStageExecutorTest.java @@ -150,7 +150,7 @@ public void setUp() { @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test diff --git a/src/test/java/org/prebid/server/it/ApplicationTest.java b/src/test/java/org/prebid/server/it/ApplicationTest.java index 3a3710c6e6e..b80221891a6 100644 --- a/src/test/java/org/prebid/server/it/ApplicationTest.java +++ b/src/test/java/org/prebid/server/it/ApplicationTest.java @@ -85,7 +85,7 @@ public void testOpenrtb2AuctionCoreFunctionality() throws IOException, JSONExcep // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/generic-exchange")) .withHeader("Accept", equalTo("application/json")) - .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) + .withHeader("Content-Type", equalTo("application/json;charset=utf-8")) .withRequestBody(equalToJson( jsonFrom("openrtb2/generic_core_functionality/test-generic-bid-request.json"))) .willReturn(aResponse().withBody( diff --git a/src/test/java/org/prebid/server/it/ConnectAdTest.java b/src/test/java/org/prebid/server/it/ConnectAdTest.java index 45b60d2e431..657ba1a0a19 100644 --- a/src/test/java/org/prebid/server/it/ConnectAdTest.java +++ b/src/test/java/org/prebid/server/it/ConnectAdTest.java @@ -21,7 +21,7 @@ public void openrtb2AuctionShouldRespondWithBidsFromConnectAd() throws IOExcepti // given WIRE_MOCK_RULE.stubFor(post(urlPathEqualTo("/connectad-exchange")) .withHeader("Accept", equalTo("application/json")) - .withHeader("Content-Type", equalTo("application/json;charset=UTF-8")) + .withHeader("Content-Type", equalTo("application/json;charset=utf-8")) .withHeader("User-Agent", equalTo("userAgent")) .withHeader("X-Forwarded-For", equalTo("193.168.244.1")) .withHeader("DNT", equalTo("0")) diff --git a/src/test/java/org/prebid/server/it/StartioTest.java b/src/test/java/org/prebid/server/it/StartioTest.java index 217b9ebfc2b..8a1fcbea12b 100644 --- a/src/test/java/org/prebid/server/it/StartioTest.java +++ b/src/test/java/org/prebid/server/it/StartioTest.java @@ -3,9 +3,7 @@ import io.restassured.response.Response; import org.json.JSONException; import org.junit.jupiter.api.Test; -import org.junit.runner.RunWith; import org.prebid.server.model.Endpoint; -import org.springframework.test.context.junit4.SpringRunner; import java.io.IOException; @@ -15,7 +13,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; import static java.util.Collections.singletonList; -@RunWith(SpringRunner.class) public class StartioTest extends IntegrationTest { @Test diff --git a/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java b/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java index c1e6c56cf13..3839310ce85 100644 --- a/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java +++ b/src/test/java/org/prebid/server/log/ConditionalLoggerTest.java @@ -37,7 +37,7 @@ public void setUp() { @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test diff --git a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java index 82ef85987d2..6476487c340 100644 --- a/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java +++ b/src/test/java/org/prebid/server/privacy/gdpr/vendorlist/VendorListServiceTest.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.Future; -import io.vertx.core.Handler; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.file.FileSystem; @@ -12,7 +11,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.mockito.stubbing.Answer; import org.prebid.server.VertxTest; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.exception.PreBidException; @@ -293,7 +291,7 @@ public void shouldNotPerformHttpRequestIfVendorListNotFoundAndFetchNotAllowed() // then verify(httpClient, never()).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -306,7 +304,7 @@ public void shouldNotAskToSaveFileIfReadingHttpResponseFails() { // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -319,7 +317,7 @@ public void shouldNotAskToSaveFileIfResponseCodeIsNot200() { // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -332,7 +330,7 @@ public void shouldNotAskToSaveFileIfResponseBodyCouldNotBeParsed() { // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -346,7 +344,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidVendorListVersion // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -360,7 +358,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasInvalidLastUpdated() thr // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -374,7 +372,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasNoVendors() throws JsonP // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -388,7 +386,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasEmptyVendors() throws Js // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } @Test @@ -402,7 +400,7 @@ public void shouldNotAskToSaveFileIfFetchedVendorListHasAtLeastOneInvalidVendor( // then verify(httpClient).get(anyString(), anyLong()); - verify(fileSystem, never()).writeFile(any(), any(), any()); + verify(fileSystem, never()).writeFile(any(), any()); } // File system related tests @@ -419,7 +417,7 @@ public void shouldSaveFileWithExpectedPathAndContentIfVendorListNotFound() throw target.forVersion(1); // then - verify(fileSystem).writeFile(eq(filePath), eq(Buffer.buffer(vendorListAsString)), any()); + verify(fileSystem).writeFile(eq(filePath), eq(Buffer.buffer(vendorListAsString))); } // In-memory cache related tests @@ -456,8 +454,7 @@ public void shouldReturnVendorListFromCache() throws JsonProcessingException { // given givenHttpClientReturnsResponse(200, mapper.writeValueAsString(givenVendorList())); - given(fileSystem.writeFile(anyString(), any(), any())) - .willAnswer(withSelfAndPassObjectToHandler(Future.succeededFuture())); + given(fileSystem.writeFile(anyString(), any())).willReturn(Future.succeededFuture()); // when target.forVersion(1); // populate cache @@ -504,8 +501,8 @@ public void shouldKeepPurposesForAllVendors() throws JsonProcessingException { final VendorList vendorList = VendorList.of(1, new Date(), idToVendor); givenHttpClientReturnsResponse(200, mapper.writeValueAsString(vendorList)); - given(fileSystem.writeFile(anyString(), any(), any())) - .willAnswer(withSelfAndPassObjectToHandler(Future.succeededFuture())); + given(fileSystem.writeFile(anyString(), any())) + .willReturn(Future.succeededFuture()); // when target.forVersion(1); // populate cache @@ -572,8 +569,7 @@ public void shouldIncrementVendorListErrorMetricWhenFileIsNotSaved() throws Json // given givenHttpClientReturnsResponse(200, mapper.writeValueAsString(givenVendorList())); - given(fileSystem.writeFile(anyString(), any(), any())) - .willAnswer(withSelfAndPassObjectToHandler(Future.failedFuture("error"))); + given(fileSystem.writeFile(anyString(), any())).willReturn(Future.failedFuture("error")); // when target.forVersion(1); @@ -587,8 +583,7 @@ public void shouldIncrementVendorListOkMetric() throws JsonProcessingException { // given givenHttpClientReturnsResponse(200, mapper.writeValueAsString(givenVendorList())); - given(fileSystem.writeFile(anyString(), any(), any())) - .willAnswer(withSelfAndPassObjectToHandler(Future.succeededFuture())); + given(fileSystem.writeFile(anyString(), any())).willReturn(Future.succeededFuture()); // when target.forVersion(1); @@ -635,13 +630,4 @@ 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/S3ApplicationSettingsTest.java b/src/test/java/org/prebid/server/settings/S3ApplicationSettingsTest.java index 13fda67839e..830017fb272 100644 --- a/src/test/java/org/prebid/server/settings/S3ApplicationSettingsTest.java +++ b/src/test/java/org/prebid/server/settings/S3ApplicationSettingsTest.java @@ -74,7 +74,7 @@ public void setUp() { @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test diff --git a/src/test/java/org/prebid/server/settings/service/DatabasePeriodicRefreshServiceTest.java b/src/test/java/org/prebid/server/settings/service/DatabasePeriodicRefreshServiceTest.java index bae78c111b4..626fffa58b7 100644 --- a/src/test/java/org/prebid/server/settings/service/DatabasePeriodicRefreshServiceTest.java +++ b/src/test/java/org/prebid/server/settings/service/DatabasePeriodicRefreshServiceTest.java @@ -2,7 +2,6 @@ import io.vertx.core.Future; import io.vertx.core.Handler; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -156,7 +155,7 @@ private void createAndInitService(long refresh) { metrics, clock); - databasePeriodicRefreshService.initialize(Promise.promise()); + databasePeriodicRefreshService.initialize(); } @SuppressWarnings("unchecked") 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 3cb36048ffb..0cd1643fe2b 100644 --- a/src/test/java/org/prebid/server/settings/service/HttpPeriodicRefreshServiceTest.java +++ b/src/test/java/org/prebid/server/settings/service/HttpPeriodicRefreshServiceTest.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.Future; import io.vertx.core.Handler; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -174,7 +173,7 @@ private static void createAndInitService(CacheNotificationListener notif final HttpPeriodicRefreshService httpPeriodicRefreshService = new HttpPeriodicRefreshService( url, refreshPeriod, timeout, notificationListener, vertx, httpClient, jacksonMapper); - httpPeriodicRefreshService.initialize(Promise.promise()); + httpPeriodicRefreshService.initialize(); } @SuppressWarnings("unchecked") diff --git a/src/test/java/org/prebid/server/settings/service/S3PeriodicRefreshServiceTest.java b/src/test/java/org/prebid/server/settings/service/S3PeriodicRefreshServiceTest.java index b46587f01a8..3b6ae88be3d 100644 --- a/src/test/java/org/prebid/server/settings/service/S3PeriodicRefreshServiceTest.java +++ b/src/test/java/org/prebid/server/settings/service/S3PeriodicRefreshServiceTest.java @@ -1,7 +1,6 @@ package org.prebid.server.settings.service; import io.vertx.core.Future; -import io.vertx.core.Promise; import io.vertx.core.Vertx; import io.vertx.junit5.VertxExtension; import io.vertx.junit5.VertxTestContext; @@ -96,7 +95,7 @@ public void setUp() { @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test @@ -167,8 +166,6 @@ private Future createAndInitService(long refreshPeriod) { metrics, vertx); - final Promise init = Promise.promise(); - s3PeriodicRefreshService.initialize(init); - return init.future(); + return s3PeriodicRefreshService.initialize(); } } diff --git a/src/test/java/org/prebid/server/util/HttpUtilTest.java b/src/test/java/org/prebid/server/util/HttpUtilTest.java index 7926e05ed46..e02a8bf6577 100644 --- a/src/test/java/org/prebid/server/util/HttpUtilTest.java +++ b/src/test/java/org/prebid/server/util/HttpUtilTest.java @@ -3,6 +3,7 @@ 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.RoutingContext; import org.junit.jupiter.api.BeforeEach; @@ -16,7 +17,7 @@ import java.util.Map; import java.util.function.Consumer; -import static java.util.Collections.singletonMap; +import static java.util.Collections.singleton; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.entry; @@ -35,11 +36,14 @@ public class HttpUtilTest { @Mock(strictness = LENIENT) private RoutingContext routingContext; + @Mock(strictness = LENIENT) + private HttpServerRequest httpRequest; @Mock private HttpServerResponse httpResponse; @BeforeEach public void setUp() { + given(routingContext.request()).willReturn(httpRequest); given(routingContext.response()).willReturn(httpResponse); } @@ -131,7 +135,7 @@ public void getHostFromUrlShouldReturnNullIfUrlIsMalformed() { @Test public void cookiesAsMapShouldReturnExpectedResult() { // given - given(routingContext.cookieMap()).willReturn(singletonMap("name", Cookie.cookie("name", "value"))); + given(httpRequest.cookies()).willReturn(singleton(Cookie.cookie("name", "value"))); // when final Map cookies = HttpUtil.cookiesAsMap(routingContext); diff --git a/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java b/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java deleted file mode 100644 index 12984132eae..00000000000 --- a/src/test/java/org/prebid/server/vertx/CircuitBreakerTest.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.prebid.server.vertx; - -import io.vertx.core.Future; -import io.vertx.core.Handler; -import io.vertx.core.Promise; -import io.vertx.core.Vertx; -import io.vertx.junit5.VertxExtension; -import io.vertx.junit5.VertxTestContext; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; - -import static org.assertj.core.api.Assertions.assertThat; - -@ExtendWith(MockitoExtension.class) -@ExtendWith(VertxExtension.class) -public class CircuitBreakerTest { - - private Vertx vertx; - - private Clock clock; - - private CircuitBreaker circuitBreaker; - - @BeforeEach - public void setUp() { - vertx = Vertx.vertx(); - clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); - circuitBreaker = new CircuitBreaker("name", vertx, 1, 100L, 200L, clock); - } - - @AfterEach - public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); - } - - @Test - public void executeShouldSucceedsIfOperationSucceeds() { - // when - final Future future = executeWithSuccess("value"); - - // then - assertThat(future.succeeded()).isTrue(); - assertThat(future.result()).isEqualTo("value"); - } - - @Test - public void executeShouldFailsIfCircuitIsClosedAndOperationFails() { - // when - final Future future = executeWithFail("exception"); - - // then - assertThat(future.failed()).isTrue(); - assertThat(future.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception"); - } - - @Test - public void executeShouldFailsIfCircuitIsHalfOpenedAndOperationFailsAndClosingTimeIsNotPassedBy() { - // when - final Future future1 = executeWithFail("exception1"); - final Future future2 = executeWithFail(null); - - // then - assertThat(future1.failed()).isTrue(); - assertThat(future1.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception1"); - - assertThat(future2.failed()).isTrue(); - assertThat(future2.cause()).isInstanceOf(RuntimeException.class).hasMessage("open circuit"); - } - - @Test - public void executeShouldFailsIfCircuitIsHalfOpenedAndOperationFails() { - // when - final Future future1 = executeWithFail("exception1"); - final Future future2 = executeWithFail(null); - waitForClosingInterval(); - final Future future3 = executeWithFail("exception3"); - - // then - assertThat(future1.failed()).isTrue(); - assertThat(future1.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception1"); - - assertThat(future2.failed()).isTrue(); - assertThat(future2.cause()).isInstanceOf(RuntimeException.class).hasMessage("open circuit"); - - assertThat(future3.failed()).isTrue(); - assertThat(future3.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception3"); - } - - @Test - public void executeShouldSucceedsIfCircuitIsHalfOpenedAndOperationSucceeds() { - // when - final Future future1 = executeWithFail("exception1"); - final Future future2 = executeWithFail("exception2"); - waitForClosingInterval(); - final Future future3 = executeWithSuccess("value after half-open"); - - // then - assertThat(future1.failed()).isTrue(); - assertThat(future1.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception1"); - - assertThat(future2.failed()).isTrue(); - assertThat(future2.cause()).isInstanceOf(RuntimeException.class).hasMessage("open circuit"); - - assertThat(future3.succeeded()).isTrue(); - assertThat(future3.result()).isEqualTo("value after half-open"); - } - - @Test - public void executeShouldFailsWithOriginalExceptionIfOpeningIntervalExceeds() { - // given - circuitBreaker = new CircuitBreaker("name", vertx, 2, 100L, 200L, clock); - - // when - final Future future1 = executeWithFail("exception1"); - waitForOpeningInterval(); - final Future future2 = executeWithFail("exception2"); - - // then - assertThat(future1.failed()).isTrue(); - assertThat(future1.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception1"); - - assertThat(future2.failed()).isTrue(); - assertThat(future2.cause()).isInstanceOf(RuntimeException.class).hasMessage("exception2"); - } - - private Future executeWithSuccess(String result) { - return execute(operationPromise -> operationPromise.complete(result)); - } - - private Future executeWithFail(String errorMessage) { - return execute(operationPromise -> operationPromise.fail(new RuntimeException(errorMessage))); - } - - private Future execute(Handler> handler) { - final Future future = circuitBreaker.execute(handler); - - final Promise promise = Promise.promise(); - future.onComplete(ar -> promise.complete()); - promise.future().toCompletionStage().toCompletableFuture().join(); - - return future; - } - - private void waitForOpeningInterval() { - waitForInterval(150L); - } - - private void waitForClosingInterval() { - waitForInterval(250L); - } - - private void waitForInterval(long timeout) { - final Promise promise = Promise.promise(); - vertx.setTimer(timeout, id -> promise.complete()); - promise.future().toCompletionStage().toCompletableFuture().join(); - } -} diff --git a/src/test/java/org/prebid/server/vertx/CloseableAdapterTest.java b/src/test/java/org/prebid/server/vertx/CloseableAdapterTest.java index 5b8cafd5251..dc3284b4cf0 100644 --- a/src/test/java/org/prebid/server/vertx/CloseableAdapterTest.java +++ b/src/test/java/org/prebid/server/vertx/CloseableAdapterTest.java @@ -1,6 +1,5 @@ package org.prebid.server.vertx; -import io.vertx.core.Future; import io.vertx.core.Promise; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -11,8 +10,6 @@ import java.io.IOException; import static org.assertj.core.api.Assertions.assertThatNullPointerException; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.verify; @@ -35,7 +32,7 @@ public void closeShouldInvokeHandlerWithSuccededFuture() { new CloseableAdapter(closeable).close(completionPromise); // then - verify(completionPromise).handle(eq(Future.succeededFuture())); + verify(completionPromise).succeed(); } @Test @@ -48,6 +45,6 @@ public void closeShouldInvokeHandlerWithFailedFutureIfIOExceptionThrown() throws new CloseableAdapter(closeable).close(completionPromise); // then - verify(completionPromise).handle(argThat(future -> future.failed() && future.cause() == exception)); + verify(completionPromise).fail(exception); } } diff --git a/src/test/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClientTest.java b/src/test/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClientTest.java index abc2d8af479..f1746d438b7 100644 --- a/src/test/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClientTest.java +++ b/src/test/java/org/prebid/server/vertx/database/CircuitBreakerSecuredDatabaseClientTest.java @@ -40,7 +40,6 @@ public class CircuitBreakerSecuredDatabaseClientTest { private Vertx vertx; - private Clock clock; @Mock private DatabaseClient wrappedDatabaseClient; @Mock @@ -53,15 +52,14 @@ public class CircuitBreakerSecuredDatabaseClientTest { @BeforeEach public void setUp() { vertx = Vertx.vertx(); - clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); - timeout = new TimeoutFactory(clock).create(500L); + timeout = new TimeoutFactory(Clock.fixed(Instant.now(), ZoneId.systemDefault())).create(500L); - target = new CircuitBreakerSecuredDatabaseClient(vertx, wrappedDatabaseClient, metrics, 1, 100L, 200L, clock); + target = new CircuitBreakerSecuredDatabaseClient(vertx, wrappedDatabaseClient, metrics, 1, 1000L, 200L); } @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test @@ -184,7 +182,7 @@ public void executeQueryShouldReturnResultIfCircuitIsHalfOpenedAndQuerySucceeded @Test public void executeQueryShouldFailsWithOriginalExceptionIfOpeningIntervalExceeds(VertxTestContext context) { // given - target = new CircuitBreakerSecuredDatabaseClient(vertx, wrappedDatabaseClient, metrics, 2, 100L, 200L, clock); + target = new CircuitBreakerSecuredDatabaseClient(vertx, wrappedDatabaseClient, metrics, 2, 100L, 200L); givenExecuteQueryReturning(asList( Future.failedFuture(new RuntimeException("exception1")), diff --git a/src/test/java/org/prebid/server/vertx/httpclient/BasicHttpClientTest.java b/src/test/java/org/prebid/server/vertx/httpclient/BasicHttpClientTest.java index 61618b362ea..3c3ab67bf39 100644 --- a/src/test/java/org/prebid/server/vertx/httpclient/BasicHttpClientTest.java +++ b/src/test/java/org/prebid/server/vertx/httpclient/BasicHttpClientTest.java @@ -40,6 +40,8 @@ @ExtendWith(VertxExtension.class) public class BasicHttpClientTest { + private static final String CRLF = "\r\n"; + @Mock private Vertx vertx; @Mock(strictness = LENIENT) @@ -203,12 +205,12 @@ private static void startServer(int port, long entireResponseDelay, long bodyRes } out.write("HTTP/1.1 200 OK"); - out.newLine(); + out.write(CRLF); out.write("Content-Length: 6"); // set body size greater then length of "start" word - out.newLine(); + out.write(CRLF); - out.newLine(); + out.write(CRLF); out.write("start"); out.flush(); diff --git a/src/test/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClientTest.java b/src/test/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClientTest.java index 75f2b8c6a52..4b4c3f16e67 100644 --- a/src/test/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClientTest.java +++ b/src/test/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClientTest.java @@ -18,9 +18,6 @@ import org.prebid.server.metric.Metrics; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.time.Clock; -import java.time.Instant; -import java.time.ZoneId; import java.util.function.BooleanSupplier; import java.util.function.LongSupplier; @@ -40,7 +37,6 @@ public class CircuitBreakerSecuredHttpClientTest { private Vertx vertx; - private Clock clock; @Mock private HttpClient wrappedHttpClient; @Mock @@ -51,13 +47,12 @@ public class CircuitBreakerSecuredHttpClientTest { @BeforeEach public void setUp() { vertx = Vertx.vertx(); - clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); - httpClient = new CircuitBreakerSecuredHttpClient(vertx, wrappedHttpClient, metrics, 1, 100L, 200L, 24, clock); + httpClient = new CircuitBreakerSecuredHttpClient(vertx, wrappedHttpClient, metrics, 1, 1000L, 200L, 24); } @AfterEach public void tearDown(VertxTestContext context) { - vertx.close(context.succeedingThenComplete()); + vertx.close().onComplete(context.succeedingThenComplete()); } @Test @@ -169,7 +164,7 @@ public void requestShouldSucceedIfCircuitIsHalfOpenedAndWrappedHttpClientSucceed @Test public void requestShouldFailWithOriginalExceptionIfOpeningIntervalExceeds() { // given - httpClient = new CircuitBreakerSecuredHttpClient(vertx, wrappedHttpClient, metrics, 2, 100L, 200L, 24, clock); + httpClient = new CircuitBreakerSecuredHttpClient(vertx, wrappedHttpClient, metrics, 2, 100L, 200L, 24); givenHttpClientReturning(new RuntimeException("exception1"), new RuntimeException("exception2")); @@ -192,6 +187,8 @@ public void requestShouldFailWithOriginalExceptionIfOpeningIntervalExceeds() { @Test public void circuitBreakerNumberGaugeShouldReportActualNumber() { // when + givenHttpClientReturning(new RuntimeException("exception")); + doRequest(); // then