diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b8d227a..4b9f1f0 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,48 +1,56 @@ -name: "CodeQL" +name: CodeQL on: push: - branches: [ "master" ] + branches: [ 'master' ] pull_request: - branches: [ "master" ] + branches: [ 'master' ] + schedule: + - cron: '0 3 * * 1' + +permissions: + security-events: write + packages: read + actions: read + contents: read jobs: analyze: - name: Analyze + name: Analyze (${{ matrix.language }}) runs-on: ubuntu-latest strategy: fail-fast: false matrix: - language: [ 'java' ] + include: + - language: actions + build-mode: none + - language: java-kotlin + build-mode: manual steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Set up JDK - uses: actions/setup-java@v3 - with: - distribution: 'temurin' - java-version: 21 - - - name: Cache Maven packages - uses: actions/cache@v3 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven- - - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - - - name: Build with Maven - run: mvn -B package - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 - with: - category: "/language:${{ matrix.language }}" + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Set up JDK + if: matrix.language == 'java-kotlin' + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + cache: 'maven' + java-version: 25 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - name: Build with Maven + if: matrix.build-mode == 'manual' + run: mvn -B compile --file pom.xml + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: '/language:${{ matrix.language }}' diff --git a/.github/workflows/pr-functional-tests.yml b/.github/workflows/pr-functional-tests.yml index fb8f30a..3c95fb3 100644 --- a/.github/workflows/pr-functional-tests.yml +++ b/.github/workflows/pr-functional-tests.yml @@ -17,13 +17,13 @@ jobs: strategy: matrix: - java: [ 21 ] + java: [ 25 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'temurin' cache: 'maven' diff --git a/.github/workflows/pr-java-ci.yml b/.github/workflows/pr-java-ci.yml index de6b7d5..75cb7f1 100644 --- a/.github/workflows/pr-java-ci.yml +++ b/.github/workflows/pr-java-ci.yml @@ -17,13 +17,13 @@ jobs: strategy: matrix: - java: [ 21 ] + java: [ 25 ] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v5 - name: Set up JDK - uses: actions/setup-java@v3 + uses: actions/setup-java@v5 with: distribution: 'temurin' cache: 'maven' diff --git a/Dockerfile b/Dockerfile index 8fbfc20..e372bc4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM amazoncorretto:21.0.6-al2023 +FROM amazoncorretto:25.0.3-al2023-headless WORKDIR /app/prebid-cache diff --git a/README.md b/README.md index 705c94b..d17c189 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,29 @@ ### This is the Java version of Prebid Cache. See the Prebid Server [Feature List](https://docs.prebid.org/prebid-server/features/pbs-feature-idx.html) and [FAQ entry](https://docs.prebid.org/faq/prebid-server-faq.html#why-are-there-two-versions-of-prebid-server-are-they-kept-in-sync) to understand the differences between PBS-Java and [PBS-Go](https://github.com/prebid/prebid-cache). # _Prebid Cache Java_ -Prebid Cache provides the caching service component for the Prebid Server project. Currently, the API supports both the GET and POST endpoints. Prebid Cache Java provides a Redis and Aerospike implementation for the cache. By default it uses Aerospike. How to switch between Redis And Aerospike described at Cache Configuration section. However, Prebid Cache is designed to support any cache implementation. + +Prebid Cache provides the caching service component for the Prebid Server project. Currently, the API supports both the +GET and POST endpoints. Prebid Cache Java provides a Redis and Aerospike implementation for the cache. By default it +uses Aerospike. How to switch between Redis And Aerospike described at Cache Configuration section. However, Prebid +Cache is designed to support any cache implementation. ## Integration Guide + Project configuration is managed through the use of YAML configuration (see resources folder). ### _Requirements_ + This section covers the mandatory pre-requisites needed to be able to run the application. * Windows, Linux, AWS, GCP or macOS -* JDK 8+ +* JDK 25 (the higher versions haven't been tested) * Maven * Git * Redis (or a custom cache implementation) * Aerospike ### _Quick Install_ + This section describes how to download, install and run the application. ###### A. Using Maven on macOS (recommended installation method) @@ -28,23 +35,32 @@ git clone https://github.com/prebid/prebid-cache-java.git ``` (2). Start Repo Locally: -If you have installed [Redis](https://redis.io/docs/install/install-redis/) or [Aerospike](https://aerospike.com/docs/server/operations/install) or [Apache Ignite](https://ignite.apache.org/docs/latest/installation/deb-rpm) locally, you may start them both (or separately, depends on your needs) via bash: +If you have installed [Redis](https://redis.io/docs/install/install-redis/) +or [Aerospike](https://aerospike.com/docs/server/operations/install) +or [Apache Ignite](https://ignite.apache.org/docs/latest/installation/deb-rpm) locally, you may start them both +(or separately, depends on your needs) via bash: + ```bash sudo systemctl start redis sudo systemctl start aerospike sudo systemctl start apache-ignite ``` + Alternatively, you may start DB as Docker image. You should install [Docker Engine](https://docs.docker.com/engine/install/) if you don't have one. (2.1) Redis via Docker + 1. Pull [Redis docker image](https://hub.docker.com/_/redis) of an appropriate version + ```bash docker pull redis: ``` + 2. Run Redis container - - the `` should correspond to the pulled image version - - the `` should correspond to the `spring.redis.port` property values of the Prebid Cache + - the `` should correspond to the pulled image version + - the `` should correspond to the `spring.redis.port` property values of the Prebid Cache + ```bash docker run -d --name redis -p : redis: @@ -53,14 +69,18 @@ docker run -d --name redis -p 6379:6379 redis:7.2.4 ``` (2.2) Aerospike via Docker + 1. Pull [Aerospike docker image](https://hub.docker.com/_/aerospike) of an appropriate version + ```bash docker pull aerospike: ``` + 2. Run Aerospike container (the following instruction is enough for the Community Edition only) - - the `` should correspond to the pulled image version - - the `` should correspond to the `spring.aerospike.port` property values of the Prebid Cache - - the `` should correspond to the spring.aerospike.namespace property value of the Prebid Cache + - the `` should correspond to the pulled image version + - the `` should correspond to the `spring.aerospike.port` property values of the Prebid Cache + - the `` should correspond to the spring.aerospike.namespace property value of the Prebid Cache + ```bash docker run -d --name aerospike -e "NAMESPACE=" -p : aerospike: @@ -69,15 +89,21 @@ docker run -d --name aerospike -e "NAMESPACE=prebid_cache" -p 3000:3000 aerospik ``` (2.3) Apache Ignite via Docker -1. Pull [Apache Ignite docker image](https://ignite.apache.org/docs/latest/installation/installing-using-docker) of an appropriate version + +1. Pull [Apache Ignite docker image](https://ignite.apache.org/docs/latest/installation/installing-using-docker) of an + appropriate version + ```bash docker pull apacheignite/ignite: ``` + 2. Run Apache Ignite container - the `` should correspond to the pulled image version - - the `OPTION_LIBS=ignite-rest-http` corresponds to the library that enables REST API access to the server (i.e. to create a cache inside Apache Ignite) - - the `-p 10800:10800` exposes the default port `10800` that will be a connection port for the Prebid Cache + - the `OPTION_LIBS=ignite-rest-http` corresponds to the library that enables REST API access to the server (i.e. to + create a cache inside Apache Ignite) + - the `-p 10800:10800` exposes the default port `10800` that will be a connection port for the Prebid Cache - the host will be the `localhost` + ```bash docker run -d \ --name apache-ignite @@ -85,12 +111,15 @@ docker run -d \ -p 8080:8080 -p 10800:10800 -p 11211:11211 -p 47100:47100 -p 47500:47500 \ apacheignite/ignite: ``` + 3. Create a cache via Rest Api + ```bash GET http://localhost:10800/ignite?cmd=getorcreate&cacheName= ``` (2.4) Make sure that the Aerospike, Redis and/or Apache Ignite is up and running + ```bash docker ps ``` @@ -113,8 +142,11 @@ mvn clean package (4). Run Spring Boot JAR (_from project root_) +Note: at least one storage backend must be configured to make the application start up successfully. For the local +start-up the `local` profile has the Aerospike configured with default settings. + ```bash -java -jar target/prebid-cache.jar +java -Dspring.profiles.active=manage,local -jar target/prebid-cache.jar ``` ### _Spring Profiles_ @@ -124,6 +156,7 @@ This section shows examples of the various runtime environment configuration(s). (1). Localhost with log4j and management endpoints enabled: _VM Options:_ + ```bash java -Dspring.profiles.active=manage,local -Dlog.dir=/app/prebid-cache-java/log/ -jar prebid-cache.jar ``` @@ -131,12 +164,14 @@ java -Dspring.profiles.active=manage,local -Dlog.dir=/app/prebid-cache-java/log/ (2). Production with log4j and management endpoints disabled: _VM Options:_ + ```bash java -Dspring.profiles.active=prod -Dlog.dir=/app/prebid-cache-java/log/ -jar prebid-cache.jar ``` _Note_ The `Apache Ignite` requires additional VM parameters to be added to support Java 17+ + ```bash --add-opens=java.base/jdk.internal.access=ALL-UNNAMED --add-opens=java.base/jdk.internal.misc=ALL-UNNAMED @@ -165,15 +200,18 @@ The `Apache Ignite` requires additional VM parameters to be added to support Jav ``` ### _Cache Configuration_ -Prebid cache uses Aerospike as a default cache implementation but also supports Redis and Apache Ignite. For switching from Aerospike -to Redis replace next: -_application.yml:_ +Enable **one and only one** backend in your application properties (Redis, Aerospike, or Apache Ignite). If none or more +than one are configured, startup will fail. +Prebid cache uses Aerospike as a default cache implementation. + +Pick exactly one of the following in the _application.yml:_ + ```yaml spring.aerospike.host: value ``` -with +or ```yaml spring.redis.host: value @@ -185,27 +223,52 @@ or spring.ignite.host: value ``` -For configuring single redis node, please use next properties: +For configuring Aerospike backend, you can start with the following local-profile default properties: ```yaml spring: - redis: - host: host - timeout: value - port: value + aerospike: + port: 3000 + host: localhost + cores: 4 + password: + first_backoff: 300 + max_backoff: 1000 + max_retry: 3 + namespace: "prebid_cache" + prevent_UUID_duplication: true + socket_timeout: 30000 + total_timeout: 1000 + connect_timeout: 0 + min_conns_per_node: 0 + max_conns_per_node: 100 + read_policy: sequence +``` + +For configuring single Redis node, please use next properties: + +```yaml + spring: + redis: + host: host + timeout: value + port: value ``` -or +For configuring Ignite backend, please use next properties: + ```yaml spring: - ignite: - host: host - port: port - cache-name: cacheName + ignite: + host: host + port: port + cache-name: cacheName ``` ### Providing your own configuration -It is possible to override the default YAML configuration by supplying a custom configuration. This is done using the `spring.config.additional-location` property. + +It is possible to override the default YAML configuration by supplying a custom configuration. This is done using the +`spring.config.additional-location` property. ```bash java -jar prebid-cache.jar --spring.config.additional-location=path-to-your-conf.yaml @@ -215,76 +278,88 @@ java -jar prebid-cache.jar --spring.config.additional-location=path-to-your-conf Redis cluster settings _application-default.yml:_ + ```yaml spring: - redis: - cluster: - nodes: - - host_1:port_1 - - host_2:port_2 - - host_3:port_3 - timeout: 300 + redis: + cluster: + nodes: + - host_1:port_1 + - host_2:port_2 + - host_3:port_3 + timeout: 300 ``` + Aerospike cluster settings _application-default.yml:_ + ```yaml spring.aerospike.host: aerospike_host_1:port,aerospike_host_2:port,aerospike_host_3:port ``` Apache Ignite cluster settings _application-default.yml:_ + ```yaml spring.ignite.host: ignite_host_1:port,ignite_host_2:port,ignite_host_3:port ``` ### _Optional: Bring Your Own (BYO) Cache Implementation_ -Prebid Cache can support any cache implementation, although Redis is provided as default. Spring injects the cache repository bean instances during context initialization, or application startup. This section describes how to setup a custom cache repository. +Prebid Cache can support any cache implementation, although Redis is provided as default. Spring injects the cache +repository bean instances during context initialization, or application startup. This section describes how to setup a +custom cache repository. ###### A. ReactiveRepository Interface + The custom cache implementation must contain a class that conforms to the _ReactiveRepository_ interface. _CustomRepositoryImpl_: -```java -public class CustomRepositoryImpl implements ReactiveRepository -{ - Mono save(final PayloadWrapper wrapper) { - // You must implement save method - } - Mono findById(final String id) { - // You must implement findById method - } +```java +public class CustomRepositoryImpl implements ReactiveRepository { + Mono save(final PayloadWrapper wrapper) { + // You must implement save method + } + + Mono findById(final String id) { + // You must implement findById method + } } ``` ###### B. Repository Configuration -A configuration object should be passed into the constructor of your custom repository implementation. At minimum, this configuration object would contain the caching service _host_ and _port_ details. - _CustomRepositoryImpl:_ +A configuration object should be passed into the constructor of your custom repository implementation. At minimum, this +configuration object would contain the caching service _host_ and _port_ details. + +_CustomRepositoryImpl:_ + ```java - public class CustomRepositoryImpl implements ReactiveRepository - { - private final CustomPropertyConfiguration config; - - @Autowired - public CustomRepositoryImpl(final CustomPropertyConfiguration config) { - this.config = config; - } - } + public class CustomRepositoryImpl implements ReactiveRepository { + private final CustomPropertyConfiguration config; + + @Autowired + public CustomRepositoryImpl(final CustomPropertyConfiguration config) { + this.config = config; + } +} ``` - Here is an example definition of a custom configuration property class. It is important to replace _'custom'_ with the correct cache implementation name (e.g. redis, memcached, aerospike, etc...). If Spring already provides a predefined configuration property prefix, please use that instead. +Here is an example definition of a custom configuration property class. It is important to replace _'custom'_ with the +correct cache implementation name (e.g. redis, memcached, aerospike, etc...). If Spring already provides a predefined +configuration property prefix, please use that instead. _CustomPropertyConfiguration_: + ```java + @Data @NoArgsConstructor @AllArgsConstructor @Configuration -@ConfigurationProperties(prefix="spring.custom") -public class CustomPropertyConfiguration -{ +@ConfigurationProperties(prefix = "spring.custom") +public class CustomPropertyConfiguration { private String host; private int port; } @@ -295,9 +370,11 @@ public class CustomPropertyConfiguration Metrics are collected and exported using _Micrometer_. For more information, see: https://micrometer.io -###### A. Durations (timers) and Rates (meters) +###### A. Durations (timers) and Rates (meters) + +Alongside the default application health metrics exported by the Spring Actuator, the metrics repository supports +collection on these types: -Alongside the default application health metrics exported by the Spring Actuator, the metrics repository supports collection on these types: * _request and request duration_ * _json request_ * _xml request_ @@ -306,31 +383,35 @@ Alongside the default application health metrics exported by the Spring Actuator * _invalid request error_ * _internal server error_ - ###### B. Micrometer YAML Configuration -The full list of supported monitoring systems that Micrometer can export to can be found here: https://micrometer.io/docs +The full list of supported monitoring systems that Micrometer can export to can be found +here: https://micrometer.io/docs Please keep in mind that for some of them, additional dependencies may be needed in pom.xml _src/main/resources/repository.yml_: + ```yaml management: - metrics: - export: - graphite: - enabled: false - host: http://graphite.yourdomain.com - port: 2003 - tags-as-prefix: - - prebid + metrics: + export: + graphite: + enabled: false + host: http://graphite.yourdomain.com + port: 2003 + tags-as-prefix: + - prebid ``` ### _Logging_ -Since logging is environment specific, log configuration and settings should be defined in the dev, qa, and prod profile sections of application.yml. + +Since logging is environment specific, log configuration and settings should be defined in the dev, qa, and prod profile +sections of application.yml. ###### A. Dev Environment _src/main/resources/application.yml_: + ```yaml # dev spring.profiles: dev @@ -339,6 +420,7 @@ logging.config: classpath:log4j2-dev.xml ``` _src/main/resources/log4j-dev.xml_: + ```xml @@ -366,7 +448,7 @@ _src/main/resources/log4j-dev.xml_: ${logPattern} - + @@ -377,42 +459,51 @@ _src/main/resources/log4j-dev.xml_: - + ``` ### _Circuit Breaker_ -To make prebid-cache more robust in face of network disruption or dependent services outage circuit breaker is available and should be configured at application.yml. + +To make prebid-cache more robust in face of network disruption or dependent services outage circuit breaker is available +and should be configured at application.yml. _src/main/resources/application.yml_: + ```yaml # dev circuitbreaker: - failure_rate_threshold: 50 - open_state_duration: 60000 - closed_state_calls_number: 5 - half_open_state_calls_number: 3 + failure_rate_threshold: 50 + open_state_duration: 60000 + closed_state_calls_number: 5 + half_open_state_calls_number: 3 ``` + where: -* _failure_rate_threshold_ is the failure rate threshold in percentage above which the CircuitBreaker should trip open and start short-circuiting calls +* _failure_rate_threshold_ is the failure rate threshold in percentage above which the CircuitBreaker should trip open + and start short-circuiting calls -* _open_state_duration_ is the wait duration which specifies how long the CircuitBreaker should stay open, before it switches to half open +* _open_state_duration_ is the wait duration which specifies how long the CircuitBreaker should stay open, before it + switches to half open * _closed_state_calls_number_ is the size of the ring buffer when the CircuitBreaker is closed * _half_open_state_calls_number_ is the size of the ring buffer when the CircuitBreaker is half open - ### _Services (DevOps)_ -This section contains instructions on how to run the app as a service in various different ways. DevOps should find this section relevant and useful. By default, the packaged JAR is setup to be fully executable. + +This section contains instructions on how to run the app as a service in various different ways. DevOps should find this +section relevant and useful. By default, the packaged JAR is setup to be fully executable. ###### A. Executable JAR _pom.xml_: + ```xml + org.springframework.boot spring-boot-maven-plugin @@ -423,15 +514,18 @@ _pom.xml_: ``` + Note: A custom launch script is needed as a fix due to a Spring Boot issue (#12188): https://github.com/spring-projects/spring-boot/issues/12188 -To launch the JAR from the command line (UNIX/Linux): +To launch the JAR from the command line (UNIX/Linux): + ```bash ./prebid-cache.jar ``` For security reasons, it is recommended to run the service as a non-root user: + ```bash sudo useradd prebid-cache sudo passwd prebid-cache @@ -442,6 +536,7 @@ sudo chmod 500 prebid-cache.jar ###### B. System V Init Symbolic link JAR to init.d: + ```bash sudo ln -s /app/prebid-cache.jar /etc/init.d/prebid-cache ``` @@ -454,6 +549,7 @@ sudo service prebid-cache restart # restart service ``` Following these steps will allow for: + * Non-root users to run the service * PID management (/var/run/) * Console logs (/var/log/) @@ -461,6 +557,7 @@ Following these steps will allow for: ###### C. Systemd /etc/systemd/system/prebid-cache.service: + ```text [Unit] Description=Prebid Cache Service @@ -474,45 +571,55 @@ SuccessExitStatus=143 [Install] WantedBy=multi-user.target ``` + Now you can manage this service with systemctl: + ```bash systemctl start prebid-cache.service # start service systemctl stop prebid-cache.service # stop service systemctl status prebid-cache.service # check status ``` + For more details please refer to man pages for systemctl. ###### D. AWS - Amazon Web Services + This section describes how to run the app in an Elastic Beanstalk environment with ElastiCache. ##### Prepare Artifact: (1). Go to the project root: + ```bash cd prebid-cache-java ``` (2). Update codebase : + ```bash git pull ``` (3). Rebuild sources with Maven + ```bash mvn clean gplus:execute package ``` (4). Create folder in work directory: + ```bash mkdir aws-prebid-cache ``` (5). Copy jar file from prebid-cache-java/target to created directory: + ```bash cp prebid-cache-java/target/prebid-cache.jar aws-prebid-cache ``` (6). Create Procfile in aws-prebid-cache directory: + ```bash sudo nano Procfile @@ -520,9 +627,11 @@ web: java -Dspring.profiles.active=aws -jar prebid-cache.jar ``` (7). Zip aws-prebid-cache directory + ```bash zip -r eb-prebid-cache-new.zip eb-prebid-cache-new ``` + Artifact is ready for deploy to Elastic Beanstalk. For more information, see https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/java-se-platform.html. @@ -548,41 +657,46 @@ For more information, see https://docs.aws.amazon.com/elasticbeanstalk/latest/dg (10). Select subnet for EC2 instance and click next. -(11). Press Launch button on review page for launching environment and application. +(11). Press Launch button on review page for launching environment and application. ##### ElastiCache w/Redis: -(1). After cluster configuration is complete, we will need to login, https://console.aws.amazon.com/elasticbeanstalk/. +(1). After cluster configuration is complete, we will need to login, https://console.aws.amazon.com/elasticbeanstalk/. (2). Go to the environment with application and press configuration. (3). Choose software configuration and add SPRING_REDIS_HOST system property with host of the ElastiCache redis cluster. -To learn more about how to create an Elastic Cache cluster and the configuration with Elastic Beanstalk, see https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.ElastiCache.html. - - +To learn more about how to create an Elastic Cache cluster and the configuration with Elastic Beanstalk, +see https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.ElastiCache.html. ### _Sample_ ###### A. Request + ```json { - "puts": [ - { - "type": "json", - "value": { - "adm": "\n
\"\"
\n\n\n\"\"
\n", - "width": 300, - "height": 250 - }, - "key" : "a8db2208-d085-444c-9721-c1161d7f09ce", - "expiry" : 800 - }, - {"type" : "xml", "value":"\r\n \r\n <\/html>\r\n ]]>\r\n <\/creativeCode>\r\n<\/xml>"} - ] + "puts": [ + { + "type": "json", + "value": { + "adm": "\n
\"\"
\n\n\n\"\"
\n", + "width": 300, + "height": 250 + }, + "key": "a8db2208-d085-444c-9721-c1161d7f09ce", + "expiry": 800 + }, + { + "type": "xml", + "value": "\r\n \r\n <\/html>\r\n ]]>\r\n <\/creativeCode>\r\n<\/xml>" + } + ] } ``` + ###### B. Response + ```json { "responses": [ @@ -597,21 +711,26 @@ To learn more about how to create an Elastic Cache cluster and the configuration ``` ### _Staying Up-To-Date_ ### + For using the latest version of prebid cache, perform next steps: (1). Go to the project root: + ```bash cd prebid-cache-java ``` (2). Update codebase: + ```bash git pull ``` (3). Rebuild sources with Maven + ```bash mvn clean gplus:execute package ``` -If there are any questions, issues, or concerns, please submit them to https://github.com/prebid/prebid-cache-java/issues/. +If there are any questions, issues, or concerns, please submit them +to https://github.com/prebid/prebid-cache-java/issues/. diff --git a/pom.xml b/pom.xml index 53f202a..873f964 100644 --- a/pom.xml +++ b/pom.xml @@ -21,19 +21,18 @@ org.springframework.boot spring-boot-starter-parent - 3.2.3 - + 3.5.15 + + 25 + org.prebid.cache.PBCacheApplication + false false false - src/main/resources - org.prebid.cache.PBCacheApplication - 5.9.2 - 0 manual @@ -41,43 +40,33 @@ manual yyyy-MM-dd HH:mm - 21 UTF-8 UTF-8 3.2.1 - 3.2.0 - 3.2.5 - 3.11.0 + 3.5.0 + 3.5.6 + 3.15.0 3.0.0-M5 - 0.1.4 - 3.2.3 - 6.5.1.RELEASE 2.10.1 - 32.0.0-jre - 3.1.8 3.4.4 - 1.18.30 + 1.18.46 4.2.17 - 3.0.0 - 0.10.2 - 9.0.5 - 2.17.0 + 9.3.0 + 2.18.0 3.5.1 - 3.3.1 - 3.3.0 - 10.12.1 - 0.8.12 + 3.6.0 + 13.5.0 + 0.8.15 4.2.0 2.1.0 2.20.0 - 2.0.1.Final - 5.8.0 - 1.9.22 - 1.8.0 - 1.20.0 + 5.9.1 + 2.4.0 + 1.11.0 + 1.21.4 5.15.0 2.3.13 2.16.1 @@ -120,21 +109,11 @@ org.springframework.boot spring-boot-starter-data-redis - - io.lettuce - lettuce-core - ${lettuce-core.version} - com.google.code.gson gson ${gson.version} - - com.google.guava - guava - ${guava.version} - com.github.ben-manes.caffeine caffeine @@ -157,11 +136,6 @@ micrometer-registry-graphite ${micrometer.version} - - javax.el - javax.el-api - ${javax.el-api.version} - io.github.resilience4j resilience4j-reactor @@ -169,24 +143,16 @@ io.github.resilience4j - resilience4j-spring-boot2 + resilience4j-spring-boot3 ${resilience4j.version} - org.springframework.boot - spring-boot-starter-test - test - - - org.junit.jupiter - junit-jupiter-engine - ${junit-jupiter.version} - test + org.apache.commons + commons-lang3 - org.junit.jupiter - junit-jupiter-params - ${junit-jupiter.version} + org.springframework.boot + spring-boot-starter-test test @@ -200,17 +166,6 @@ ${wiremock.version} test - - com.github.cjnygard - rest-maven-plugin - ${rest-maven-plugin.version} - - - org.reflections - reflections - ${reflections.version} - test - com.aerospike aerospike-client-jdk21 @@ -300,7 +255,6 @@ ${jackson-kotlin-module.version} test - @@ -320,7 +274,6 @@ checkstyle.xml - UTF-8 true true @@ -359,6 +312,9 @@ false + + kotest + @@ -366,14 +322,19 @@ maven-compiler-plugin ${maven-compiler-plugin.version} - ${java.version} - ${java.version} + ${java.version} + + + org.projectlombok + lombok + ${lombok.version} + + org.springframework.boot spring-boot-maven-plugin - ${spring-boot-maven-plugin.version} diff --git a/src/main/java/org/prebid/cache/PBCacheApplication.java b/src/main/java/org/prebid/cache/PBCacheApplication.java index 5c319a3..219405d 100644 --- a/src/main/java/org/prebid/cache/PBCacheApplication.java +++ b/src/main/java/org/prebid/cache/PBCacheApplication.java @@ -1,7 +1,6 @@ package org.prebid.cache; import org.prebid.cache.config.CorsConfig; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.reactive.config.CorsRegistry; @@ -11,7 +10,6 @@ public class PBCacheApplication implements WebFluxConfigurer { private final CorsConfig corsConfig; - @Autowired public PBCacheApplication(final CorsConfig corsConfig) { this.corsConfig = corsConfig; } @@ -30,4 +28,3 @@ public void addCorsMappings(CorsRegistry registry) { } } } - diff --git a/src/main/java/org/prebid/cache/builders/PrebidServerResponseBuilder.java b/src/main/java/org/prebid/cache/builders/PrebidServerResponseBuilder.java index 8836e92..162282d 100644 --- a/src/main/java/org/prebid/cache/builders/PrebidServerResponseBuilder.java +++ b/src/main/java/org/prebid/cache/builders/PrebidServerResponseBuilder.java @@ -1,6 +1,5 @@ package org.prebid.cache.builders; -import com.google.common.net.HttpHeaders; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.prebid.cache.model.ErrorResponse; @@ -20,6 +19,9 @@ import java.util.List; import java.util.function.Predicate; +import static org.springframework.http.HttpHeaders.ACCEPT_ENCODING; +import static org.springframework.http.HttpHeaders.CONNECTION; +import static org.springframework.http.HttpHeaders.DATE; import static org.springframework.web.reactive.function.BodyInserters.fromValue; import static org.springframework.web.reactive.function.server.ServerResponse.status; @@ -46,10 +48,10 @@ public Mono createResponseMono(final ServerRequest request, private ServerResponse.BodyBuilder ok(final ServerRequest request, final MediaType mediaType) { final String now = ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME); ServerResponse.BodyBuilder builder = ServerResponse.ok() - .contentType(mediaType) - .header(HttpHeaders.DATE, now) - .varyBy(HttpHeaders.ACCEPT_ENCODING) - .cacheControl(CacheControl.noCache()); + .contentType(mediaType) + .header(DATE, now) + .varyBy(ACCEPT_ENCODING) + .cacheControl(CacheControl.noCache()); applyHeaders(builder, request); return builder; } @@ -60,13 +62,13 @@ public Mono error(final Mono monoError, .flatMap(translation -> addHeaders(status(translation.getHttpStatus()), request) .body(Mono.just( - ErrorResponse.builder() - .error(translation.getHttpStatus().getReasonPhrase()) - .status(translation.getHttpStatus().value()) - .path(request.path()) - .message(translation.getErrorMessage()) - .timestamp(new Date()) - .build()), + ErrorResponse.builder() + .error(translation.getHttpStatus().getReasonPhrase()) + .status(translation.getHttpStatus().value()) + .path(request.path()) + .message(translation.getErrorMessage()) + .timestamp(new Date()) + .build()), ErrorResponse.class) ); } @@ -74,8 +76,8 @@ public Mono error(final Mono monoError, private static ServerResponse.BodyBuilder addHeaders(final ServerResponse.BodyBuilder builder, final ServerRequest request) { ServerResponse.BodyBuilder headers = - builder.header(HttpHeaders.DATE, ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)) - .varyBy(HttpHeaders.ACCEPT_ENCODING) + builder.header(DATE, ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)) + .varyBy(ACCEPT_ENCODING) .cacheControl(CacheControl.noCache()); return applyHeaders(headers, request); @@ -84,20 +86,20 @@ private static ServerResponse.BodyBuilder addHeaders(final ServerResponse.BodyBu private static ServerResponse.BodyBuilder applyHeaders(final ServerResponse.BodyBuilder builder, final ServerRequest request) { - final List connectionHeaders = request.headers().header(HttpHeaders.CONNECTION); + final List connectionHeaders = request.headers().header(CONNECTION); if (hasConnectionValue(connectionHeaders, HEADER_CONNECTION_KEEPALIVE)) { - builder.header(HttpHeaders.CONNECTION, HEADER_CONNECTION_KEEPALIVE); + builder.header(CONNECTION, HEADER_CONNECTION_KEEPALIVE); } if (hasConnectionValue(connectionHeaders, HEADER_CONNECTION_CLOSE)) { - builder.header(HttpHeaders.CONNECTION, HEADER_CONNECTION_CLOSE); + builder.header(CONNECTION, HEADER_CONNECTION_CLOSE); } return builder; } private static boolean hasConnectionValue(List connectionHeaders, String value) { return !connectionHeaders.isEmpty() && connectionHeaders.stream() - .map(String::toLowerCase) - .allMatch(Predicate.isEqual(value)); + .map(String::toLowerCase) + .allMatch(Predicate.isEqual(value)); } } diff --git a/src/main/java/org/prebid/cache/handlers/ErrorHandler.java b/src/main/java/org/prebid/cache/handlers/ErrorHandler.java index 4652719..3aaa087 100644 --- a/src/main/java/org/prebid/cache/handlers/ErrorHandler.java +++ b/src/main/java/org/prebid/cache/handlers/ErrorHandler.java @@ -5,7 +5,6 @@ import org.prebid.cache.exceptions.BadRequestException; import org.prebid.cache.exceptions.ResourceNotFoundException; import org.prebid.cache.metrics.MetricsRecorder; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; @@ -19,7 +18,6 @@ public class ErrorHandler extends MetricsHandler { private static final String INVALID_PARAMETERS = "Invalid Parameter(s): uuid not found or is empty."; private static final String NO_ELEMENTS_FOUND = "No Elements Found."; - @Autowired public ErrorHandler(final MetricsRecorder metricsRecorder, final PrebidServerResponseBuilder builder) { this.metricsRecorder = metricsRecorder; this.builder = builder; diff --git a/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java index 78d603a..35ecfeb 100644 --- a/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java +++ b/src/main/java/org/prebid/cache/handlers/cache/GetCacheHandler.java @@ -7,7 +7,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.http.client.utils.URIBuilder; import org.prebid.cache.builders.PrebidServerResponseBuilder; import org.prebid.cache.exceptions.UnsupportedMediaTypeException; import org.prebid.cache.handlers.ErrorHandler; @@ -20,7 +19,6 @@ import org.prebid.cache.repository.CacheConfig; import org.prebid.cache.repository.ReactiveRepository; import org.prebid.cache.routers.ApiConfig; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; @@ -30,6 +28,7 @@ import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import org.springframework.web.util.UriComponentsBuilder; import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; import reactor.netty.http.client.HttpClient; @@ -49,7 +48,6 @@ public class GetCacheHandler extends CacheHandler { private final Map clientsCache; private static final String UNSUPPORTED_MEDIATYPE = "Unsupported Media Type."; - @Autowired public GetCacheHandler(final ReactiveRepository repository, final CacheConfig config, final ApiConfig apiConfig, @@ -108,10 +106,11 @@ private Mono fetch(final ServerRequest request, private String resolveCacheUrl(final ServerRequest request) { final var cacheHostParam = request.queryParam(CACHE_HOST_KEY).orElse(null); if (StringUtils.isNotBlank(cacheHostParam)) { - return new URIBuilder() - .setHost(cacheHostParam) - .setPath(apiConfig.getCachePath()) - .setScheme(config.getHostParamProtocol()) + return UriComponentsBuilder.newInstance() + .host(cacheHostParam) + .path(apiConfig.getCachePath()) + .scheme(config.getHostParamProtocol()) + .build(false) .toString(); } @@ -181,7 +180,7 @@ private Mono processRequest(final ServerRequest request, final S private Mono createServerResponse(final PayloadWrapper wrapper, final ServerRequest request) { if (wrapper.getPayload().getType().equals(PayloadType.JSON.toString())) { metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.JSON); - return builder.createResponseMono(request, MediaType.APPLICATION_JSON_UTF8, wrapper); + return builder.createResponseMono(request, MediaType.APPLICATION_JSON, wrapper); } else if (wrapper.getPayload().getType().equals(PayloadType.XML.toString())) { metricsRecorder.markMeterForTag(this.metricTagPrefix, MeasurementTag.XML); return builder.createResponseMono(request, MediaType.APPLICATION_XML, wrapper); diff --git a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java index e027b14..21eecfe 100644 --- a/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java +++ b/src/main/java/org/prebid/cache/handlers/cache/PostCacheHandler.java @@ -1,7 +1,6 @@ package org.prebid.cache.handlers.cache; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.ImmutableMap; import io.github.resilience4j.circuitbreaker.CircuitBreaker; import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator; import io.netty.channel.ChannelOption; @@ -26,7 +25,6 @@ import org.prebid.cache.repository.CacheConfig; import org.prebid.cache.repository.ReactiveRepository; import org.prebid.cache.routers.ApiConfig; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -63,13 +61,12 @@ public class PostCacheHandler extends CacheHandler { private final ReactiveRepository repository; private final CacheConfig config; private final Function> payloadWrapperToMapTransformer = payload -> - ImmutableMap.of(UUID_KEY, payload.getId()); + Map.of(UUID_KEY, payload.getId()); private final Map webClients = new HashMap<>(); private final ObjectMapper objectMapper = new ObjectMapper(); private final CircuitBreaker circuitBreaker; private final ApiConfig apiConfig; - @Autowired public PostCacheHandler(final ReactiveRepository repository, final CacheConfig config, final MetricsRecorder metricsRecorder, @@ -145,7 +142,7 @@ public Mono save(final ServerRequest request) { if (response.getResponses().isEmpty()) { return ErrorHandler.createNoElementsFound(); } else { - return builder.createResponseMono(request, MediaType.APPLICATION_JSON_UTF8, response); + return builder.createResponseMono(request, MediaType.APPLICATION_JSON, response); } }); diff --git a/src/main/java/org/prebid/cache/repository/aerospike/AerospikeRepositoryImpl.java b/src/main/java/org/prebid/cache/repository/aerospike/AerospikeRepositoryImpl.java index 089649f..660f3ba 100644 --- a/src/main/java/org/prebid/cache/repository/aerospike/AerospikeRepositoryImpl.java +++ b/src/main/java/org/prebid/cache/repository/aerospike/AerospikeRepositoryImpl.java @@ -97,8 +97,8 @@ private Retry getRetryPolicy() { return Retry.backoff(maxAttempts, minBackoff) .maxBackoff(maxBackoff) - .filter(e -> e instanceof AerospikeException - && getRetryCodes().contains(((AerospikeException) e).getResultCode())) + .filter(e -> e instanceof AerospikeException ae + && getRetryCodes().contains(ae.getResultCode())) .doAfterRetry(signal -> log.warn("Retrying context {}", signal.retryContextView())); } diff --git a/src/main/java/org/prebid/cache/repository/redis/module/storage/ModuleCompositeRepositoryConfiguration.java b/src/main/java/org/prebid/cache/repository/redis/module/storage/ModuleCompositeRepositoryConfiguration.java index 0e26aa8..ce8888d 100644 --- a/src/main/java/org/prebid/cache/repository/redis/module/storage/ModuleCompositeRepositoryConfiguration.java +++ b/src/main/java/org/prebid/cache/repository/redis/module/storage/ModuleCompositeRepositoryConfiguration.java @@ -13,6 +13,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.Collections; import java.util.Map; import java.util.stream.Collectors; @@ -21,8 +22,14 @@ public class ModuleCompositeRepositoryConfiguration { @Bean ModuleCompositeRepository moduleCompositeRepository(ModuleCompositeRedisConfigurationProperties properties) { - final Map> applicationToSource = properties.getRedis() - .entrySet().stream() + final Map redisConfig = properties.getRedis(); + + if (redisConfig == null || redisConfig.isEmpty()) { + return new ModuleCompositeRepository(Collections.emptyMap()); + } + + final Map> applicationToSource = redisConfig.entrySet() + .stream() .map(entry -> Map.entry(entry.getKey(), getReactiveRepository(entry.getValue()))) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); diff --git a/src/main/java/org/prebid/cache/translators/ThrowableTranslator.java b/src/main/java/org/prebid/cache/translators/ThrowableTranslator.java index e6f021a..48ea5c6 100644 --- a/src/main/java/org/prebid/cache/translators/ThrowableTranslator.java +++ b/src/main/java/org/prebid/cache/translators/ThrowableTranslator.java @@ -28,8 +28,8 @@ private ThrowableTranslator(final Throwable throwable) { } private HttpStatus getStatus(final Throwable error) { - if (error instanceof ErrorResponse) { - return Optional.of((ErrorResponse) error) + if (error instanceof ErrorResponse response) { + return Optional.of(response) .map(ErrorResponse::getStatusCode) .map(HttpStatusCode::value) .map(HttpStatus::resolve) diff --git a/src/main/resources/application-aws.yml b/src/main/resources/application-aws.yml index da26d75..c7ec559 100644 --- a/src/main/resources/application-aws.yml +++ b/src/main/resources/application-aws.yml @@ -1,4 +1,4 @@ server.port: 5000 # redis -spring.redis.host: ${SPRING_REDIS_HOST} +spring.data.redis.host: ${SPRING_REDIS_HOST} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1d13ca8..f60600e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -64,18 +64,18 @@ circuitbreaker: # endpoint actuators management.health.defaults.enabled: false -management.endpoints.enabled-by-default: false +management.endpoints.access.default: none management.endpoints.web.base-path: / management.health.diskspace.enabled: true management.health.redis.enabled: false management.endpoints.web.exposure.include: info, health, metrics, env, configprops -management.endpoint.info.enabled: true -management.endpoint.health.enabled: true -management.endpoint.metrics.enabled: true -management.endpoint.env.enabled: true -management.endpoint.configprops.enabled: true +management.endpoint.info.access: read-only +management.endpoint.health.access: read-only +management.endpoint.metrics.access: read-only +management.endpoint.env.access: read-only +management.endpoint.configprops.access: read-only management.endpoint.health.show-details: always -management.endpoint.shutdown.enabled: false +management.endpoint.shutdown.access: none management.endpoint.configprops.keys-to-sanitize: password,secret,key,token,.*credentials.*,vcap_services management.endpoint.info.cache.time-to-live: 5s management.endpoint.health.cache.time-to-live: 5s @@ -146,8 +146,8 @@ logging.config: classpath:log4j2-qa.xml --- # prod spring.config.activate.on-profile: prod -management.endpoint.metrics.enabled: false -management.endpoint.env.enabled: false -management.endpoint.configprops.enabled: false +management.endpoint.metrics.access: none +management.endpoint.env.access: none +management.endpoint.configprops.access: none logging.level.root: warn logging.config: classpath:log4j2-prod.xml diff --git a/src/test/java/org/prebid/cache/builders/PrebidServerResponseBuilderTests.java b/src/test/java/org/prebid/cache/builders/PrebidServerResponseBuilderTests.java index a46b06d..ede6755 100644 --- a/src/test/java/org/prebid/cache/builders/PrebidServerResponseBuilderTests.java +++ b/src/test/java/org/prebid/cache/builders/PrebidServerResponseBuilderTests.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.prebid.cache.exceptions.BadRequestException; import org.prebid.cache.exceptions.RepositoryException; import org.prebid.cache.exceptions.ResourceNotFoundException; @@ -16,7 +15,6 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; @@ -31,7 +29,6 @@ import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8; import static org.springframework.http.MediaType.APPLICATION_XML; -@ExtendWith(SpringExtension.class) @ContextConfiguration(classes={PrebidServerResponseBuilder.class, ApiConfig.class}) @SpringBootTest class PrebidServerResponseBuilderTests extends PayloadWrapperResponseTests { diff --git a/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java b/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java index c8e37be..eb2b019 100644 --- a/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java +++ b/src/test/java/org/prebid/cache/handlers/GetCacheHandlerTests.java @@ -5,7 +5,6 @@ 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.prebid.cache.builders.PrebidServerResponseBuilder; import org.prebid.cache.config.CircuitBreakerPropertyConfiguration; import org.prebid.cache.handlers.cache.GetCacheHandler; @@ -19,13 +18,10 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import reactor.core.publisher.Signal; @@ -44,8 +40,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.BDDMockito.given; import static org.springframework.http.HttpHeaders.CONTENT_TYPE; +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { GetCacheHandler.class, PrebidServerResponseBuilder.class, @@ -75,7 +71,7 @@ class GetCacheHandlerTests extends CacheHandlerTests { @Autowired PrebidServerResponseBuilder responseBuilder; - @MockBean + @MockitoBean ReactiveRepository repository; @Value("${sampling.rate:2.0}") @@ -132,12 +128,12 @@ void testVerifyFetch() { @Test void testVerifyFetchWithCacheHostParam() { serverMock.stubFor(get(urlPathEqualTo("/cache")) - .willReturn(aResponse().withHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=utf-8") + .willReturn(aResponse().withHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE) .withBody("{\"uuid\":\"2be04ba5-8f9b-4a1e-8100-d573c40312f8\"}"))); final var requestMono = MockServerRequest.builder() .method(HttpMethod.GET) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .queryParam("uuid", "a8db2208-d085-444c-9721-c1161d7f09ce") .queryParam("ch", "localhost:8080") .build(); @@ -153,7 +149,7 @@ void testVerifyFetchWithCacheHostParam() { verify(getRequestedFor(urlPathEqualTo("/cache")) .withQueryParam("uuid", equalTo("a8db2208-d085-444c-9721-c1161d7f09ce")) - .withHeader(HttpHeaders.CONTENT_TYPE, equalToIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .withHeader(CONTENT_TYPE, equalToIgnoreCase(APPLICATION_JSON_VALUE)) ); } @@ -178,13 +174,13 @@ void testVerifyFailForNotFoundResourceWithCacheHostParam() { void testVerifyFetchReturnsBadRequestWhenResponseStatusIsNotOk() { serverMock.stubFor(get(urlPathEqualTo("/cache")) - .willReturn(aResponse().withHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=utf-8") + .willReturn(aResponse().withHeader(CONTENT_TYPE, APPLICATION_JSON_VALUE) .withStatus(201) .withBody("{\"uuid\":\"2be04ba5-8f9b-4a1e-8100-d573c40312f8\"}"))); final var requestMono = MockServerRequest.builder() .method(HttpMethod.GET) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .queryParam("uuid", "a8db2208-d085-444c-9721-c1161d7f09ce") .queryParam("ch", "localhost:8080") .build(); @@ -200,7 +196,7 @@ void testVerifyFetchReturnsBadRequestWhenResponseStatusIsNotOk() { verify(getRequestedFor(urlPathEqualTo("/cache")) .withQueryParam("uuid", equalTo("a8db2208-d085-444c-9721-c1161d7f09ce")) - .withHeader(HttpHeaders.CONTENT_TYPE, equalToIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE)) + .withHeader(CONTENT_TYPE, equalToIgnoreCase(APPLICATION_JSON_VALUE)) ); } @@ -208,7 +204,7 @@ void testVerifyFetchReturnsBadRequestWhenResponseStatusIsNotOk() { void testVerifyFetchReturnsBadRequestWhenNoUuid() { final var requestMono = MockServerRequest.builder() .method(HttpMethod.GET) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .build(); final var responseMono = handler.fetch(requestMono); @@ -223,7 +219,7 @@ void testVerifyFetchReturnsBadRequestWhenNoUuid() { void testVerifyFetchReturnsBadRequestWhenUuidIsEmpty() { final var requestMono = MockServerRequest.builder() .method(HttpMethod.GET) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, APPLICATION_JSON_VALUE) .queryParam("uuid", "") .build(); diff --git a/src/test/java/org/prebid/cache/handlers/GetStorageHandlerTests.java b/src/test/java/org/prebid/cache/handlers/GetStorageHandlerTests.java index ed6a1a6..4d533be 100644 --- a/src/test/java/org/prebid/cache/handlers/GetStorageHandlerTests.java +++ b/src/test/java/org/prebid/cache/handlers/GetStorageHandlerTests.java @@ -4,7 +4,6 @@ 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.prebid.cache.builders.PrebidServerResponseBuilder; import org.prebid.cache.handlers.storage.GetStorageHandler; import org.prebid.cache.model.Payload; @@ -14,18 +13,16 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpMethod; import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.BDDMockito.given; -@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { GetStorageHandler.class, PrebidServerResponseBuilder.class, @@ -41,7 +38,7 @@ public class GetStorageHandlerTests { @Autowired PrebidServerResponseBuilder responseBuilder; - @MockBean + @MockitoBean ModuleCompositeRepository moduleCompositeRepository; GetStorageHandler handler; diff --git a/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java b/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java index 0503cb7..f2dfdb5 100644 --- a/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java +++ b/src/test/java/org/prebid/cache/handlers/PostCacheHandlerTests.java @@ -6,7 +6,6 @@ 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.prebid.cache.builders.PrebidServerResponseBuilder; import org.prebid.cache.config.CircuitBreakerPropertyConfiguration; import org.prebid.cache.exceptions.DuplicateKeyException; @@ -22,13 +21,12 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -49,7 +47,6 @@ import static org.prebid.cache.util.AwaitilityUtil.awaitAndVerify; import static org.springframework.http.HttpHeaders.CONTENT_TYPE; -@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { PostCacheHandler.class, PrebidServerResponseBuilder.class, @@ -75,13 +72,13 @@ class PostCacheHandlerTests extends CacheHandlerTests { @Autowired CircuitBreaker webClientCircuitBreaker; - @MockBean + @MockitoBean Supplier currentDateProvider; - @MockBean + @MockitoBean ReactiveRepository repository; - @MockBean + @MockitoBean ApiConfig apiConfig; @Value("${sampling.rate:2.0}") @@ -125,7 +122,7 @@ void testVerifySave() { final Mono request = Mono.just(RequestObject.of(Collections.singletonList(PAYLOAD_TRANSFER))); final MockServerRequest requestMono = MockServerRequest.builder() .method(HttpMethod.POST) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(request); final Mono responseMono = handler.save(requestMono); @@ -153,7 +150,7 @@ void testSecondaryCacheSuccess() { final Mono request = Mono.just(RequestObject.of(Collections.singletonList(PAYLOAD_TRANSFER))); final MockServerRequest requestMono = MockServerRequest.builder() .method(HttpMethod.POST) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(request); final Mono responseMono = handler.save(requestMono); @@ -195,7 +192,7 @@ void testExternalUUIDInvalid() { final Mono request = Mono.just(RequestObject.of(Collections.singletonList(PAYLOAD_TRANSFER))); final MockServerRequest requestMono = MockServerRequest.builder() .method(HttpMethod.POST) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(request); final Mono responseMono = handler.save(requestMono); @@ -235,7 +232,7 @@ void testUUIDDuplication() { final Mono request = Mono.just(RequestObject.of(Collections.singletonList(PAYLOAD_TRANSFER))); final MockServerRequest requestMono = MockServerRequest.builder() .method(HttpMethod.POST) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(request); final Mono responseMono = handler.save(requestMono); @@ -300,7 +297,7 @@ void testUuidAuthorizationWithoutValidApiKey() { final var request = Mono.just(RequestObject.of(Collections.singletonList(PAYLOAD_TRANSFER))); final var requestMono = MockServerRequest.builder() .method(HttpMethod.POST) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .body(request); StepVerifier.create(handler.save(requestMono)) @@ -328,7 +325,7 @@ void testUuidAuthorizationWithValidApiKey() { final var request = Mono.just(RequestObject.of(Collections.singletonList(PAYLOAD_TRANSFER))); final var requestMono = MockServerRequest.builder() .method(HttpMethod.POST) - .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE) + .header(CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) .header("x-pbc-api-key", "api-key") .body(request); diff --git a/src/test/java/org/prebid/cache/handlers/PostStorageHandlerTests.java b/src/test/java/org/prebid/cache/handlers/PostStorageHandlerTests.java index 9c8428e..d5fe562 100644 --- a/src/test/java/org/prebid/cache/handlers/PostStorageHandlerTests.java +++ b/src/test/java/org/prebid/cache/handlers/PostStorageHandlerTests.java @@ -5,7 +5,6 @@ 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.prebid.cache.builders.PrebidServerResponseBuilder; import org.prebid.cache.config.StorageConfig; import org.prebid.cache.handlers.storage.PostStorageHandler; @@ -17,11 +16,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.HttpMethod; import org.springframework.mock.web.reactive.function.server.MockServerRequest; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.bean.override.mockito.MockitoBean; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -31,7 +29,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.given; -@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = { PrebidServerResponseBuilder.class, ApiConfig.class @@ -46,13 +43,13 @@ class PostStorageHandlerTests { @Autowired PrebidServerResponseBuilder responseBuilder; - @MockBean + @MockitoBean StorageConfig storageConfig; - @MockBean + @MockitoBean ModuleCompositeRepository moduleCompositeRepository; - @MockBean + @MockitoBean Validator validator; PostStorageHandler handler; diff --git a/src/test/java/org/prebid/cache/metrics/MetricsRecorderTest.java b/src/test/java/org/prebid/cache/metrics/MetricsRecorderTest.java index 2f3eccd..dc04764 100644 --- a/src/test/java/org/prebid/cache/metrics/MetricsRecorderTest.java +++ b/src/test/java/org/prebid/cache/metrics/MetricsRecorderTest.java @@ -5,8 +5,10 @@ import io.micrometer.core.instrument.simple.SimpleConfig; import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; +@Configuration public class MetricsRecorderTest { @Bean diff --git a/src/test/kotlin/org/prebid/cache/functional/RedisCacheSpec.kt b/src/test/kotlin/org/prebid/cache/functional/RedisCacheSpec.kt index d3d4401..40fd66a 100644 --- a/src/test/kotlin/org/prebid/cache/functional/RedisCacheSpec.kt +++ b/src/test/kotlin/org/prebid/cache/functional/RedisCacheSpec.kt @@ -50,7 +50,7 @@ class RedisCacheSpec : ShouldSpec({ // then: Internal Server Error exception is thrown assertSoftly { exception.statusCode shouldBe INTERNAL_SERVER_ERROR.value() - exception.responseBody shouldContain "\"message\":\"ERR invalid expire time in setex\"" + exception.responseBody shouldContain "\"message\":\"ERR invalid expire time in 'setex' command\"" } // cleanup diff --git a/src/test/kotlin/org/prebid/cache/functional/StorageSpec.kt b/src/test/kotlin/org/prebid/cache/functional/StorageSpec.kt index 09600ca..7f43cbf 100644 --- a/src/test/kotlin/org/prebid/cache/functional/StorageSpec.kt +++ b/src/test/kotlin/org/prebid/cache/functional/StorageSpec.kt @@ -297,7 +297,7 @@ class StorageSpec : ShouldSpec({ assertSoftly { exception.statusCode shouldBe INTERNAL_SERVER_ERROR.value() exception.responseBody shouldContain "\"path\":\"/storage\"" - exception.responseBody shouldContain "\"message\":\"ERR invalid expire time in setex" + exception.responseBody shouldContain "\"message\":\"ERR invalid expire time in 'setex' command\"" } } diff --git a/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt b/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt index d4a4888..8dc07c1 100644 --- a/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt +++ b/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt @@ -11,9 +11,9 @@ import org.testcontainers.utility.DockerImageName abstract class ContainerDependencies { companion object { - private const val redisImageName = "redis:6.2.6-alpine" - private const val aerospikeImageName = "aerospike:ce-5.7.0.11" - private const val apacheIgniteImageName = "apacheignite/ignite:2.16.0" + private const val redisImageName = "redis:8.8.0-alpine" + private const val aerospikeImageName = "aerospike:ce-8.1.2.2" + private const val apacheIgniteImageName = "apacheignite/ignite:2.18.0" private const val prebidCacheImageName = "prebid-cache:latest" private const val mockServerImageVersion = "mockserver/mockserver:5.15.0" diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index a135060..10e47bb 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -31,21 +31,21 @@ logging.level.root=info logging.config=classpath:log4j2-console.xml # metrics -management.metrics.export.graphite.enabled=false +management.graphite.metrics.export.enabled=false # endpoint actuators management.health.defaults.enabled=false -management.endpoints.enabled-by-default=false +management.endpoints.access.default=none management.endpoints.web.base-path=/ management.health.diskspace.enabled=true management.endpoints.web.exposure.include=info, health, metrics, env, configprops -management.endpoint.info.enabled=true -management.endpoint.health.enabled=true -management.endpoint.metrics.enabled=true -management.endpoint.env.enabled=true -management.endpoint.configprops.enabled=true +management.endpoint.info.access=read-only +management.endpoint.health.access=read-only +management.endpoint.metrics.access=read-only +management.endpoint.env.access=read-only +management.endpoint.configprops.access=read-only management.endpoint.health.show-details=always -management.endpoint.shutdown.enabled=false +management.endpoint.shutdown.access=none management.endpoint.configprops.keys-to-sanitize=password,secret,key,token,.*credentials.*,vcap_services management.endpoint.info.cache.time-to-live=5s management.endpoint.health.cache.time-to-live=5s