From f9977e4e537034a3206fbcc0b02610222ac15dec Mon Sep 17 00:00:00 2001 From: ggivo Date: Tue, 14 Jan 2025 16:19:32 +0200 Subject: [PATCH] Introduces test matrix based on Redis versions [8.0-M02, 7.4.1, 7.2.6, 6.2.16] (#4015) * Introduces test matrix based on Redis versions [8.0-M1, 7.4.1, 7.2.6, 6.2.16] Use docker composer to bring up the test env using `redislabs/client-libs-test` image. When run against older Redis version some tests are using commands available only in newer Redis server versions. To resolve this we are introducing two new annotations/rules - Introduce `SinceRedisVersion` annotation/Rule - for conditionally running tests based on Redis server version contacted - Introduce `EnableOnCommad` annotation/Rule - for conditionally running tests based on command availability on the server And mark respective tests with the least Redis Version required by the test - SinceRedisVersion ("7.4.0") - Mark tests using commands/modifiers introduced with Redis 7.4.0 - SinceRedisVersion ("7.2.0") - Mark tests using commands/modifiers introduced with Redis 7.2.0 - SinceRedisVersion ("7.0.0") - Mark tests using commands/modifiers introduced with Redis 7.0.0 The same approach used to mark CSC tests - Disabled client-side caching tests for versions below 7.4 - Test env migrated to use native Redis server TLS instead of using stunnel Not all tests were migrated - Disable Modules test in containerized test env ModuleTest uses custom test module to test load/unload/sendCommand. Requires pre-build test module on the same os like test container to avoid errors - Disable UDS tests in containerized test env No easy way to make unix sockets work on MAC with docker --------- Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com> --- .github/CONTRIBUTING.md | 47 +++ .github/workflows/integration.yml | 1 + .github/workflows/test-on-docker.yml | 124 +++++++ .gitignore | 2 + Makefile | 168 +++++++--- .../test/annotations/EnabledOnCommand.java | 11 + .../test/annotations/SinceRedisVersion.java | 11 + .../java/io/redis/test/utils/RedisInfo.java | 67 ++++ .../io/redis/test/utils/RedisVersion.java | 92 ++++++ .../redis/clients/jedis/ACLJedisPoolTest.java | 15 +- .../jedis/ACLJedisSentinelPoolTest.java | 20 +- .../redis/clients/jedis/ACLJedisTest.java | 5 +- .../clients/jedis/ClusterPipeliningTest.java | 29 +- .../redis/clients/jedis/EndpointConfig.java | 21 +- .../redis/clients/jedis/JedisClusterTest.java | 4 +- .../clients/jedis/JedisClusterTestBase.java | 8 + .../java/redis/clients/jedis/JedisTest.java | 3 + .../clients/jedis/SSLACLJedisClusterTest.java | 130 ++++---- .../redis/clients/jedis/SSLACLJedisTest.java | 30 +- .../clients/jedis/SSLJedisClusterTest.java | 91 ++++-- .../jedis/SSLJedisSentinelPoolTest.java | 15 +- .../redis/clients/jedis/SSLJedisTest.java | 136 +------- .../jedis/SSLOptionsJedisClusterTest.java | 79 +++-- .../jedis/SSLOptionsJedisPooledTest.java | 25 +- .../SSLOptionsJedisSentinelPoolTest.java | 22 +- .../clients/jedis/SSLOptionsJedisTest.java | 24 +- .../java/redis/clients/jedis/UdsTest.java | 9 + .../TokenBasedAuthenticationUnitTests.java | 2 +- .../CommandObjectsBitmapCommandsTest.java | 3 + .../CommandObjectsGenericCommandsTest.java | 19 ++ .../CommandObjectsHashCommandsTest.java | 12 + .../CommandObjectsListCommandsTest.java | 3 + .../CommandObjectsScriptingCommandsTest.java | 27 ++ .../CommandObjectsSetCommandsTest.java | 2 + .../CommandObjectsSortedSetCommandsTest.java | 9 + .../CommandObjectsStandaloneTestBase.java | 8 + .../CommandObjectsStringCommandsTest.java | 3 + .../CommandObjectsTestBase.java | 9 +- .../jedis/AccessControlListCommandsTest.java | 45 ++- .../jedis/AllKindOfValuesCommandsTest.java | 16 +- .../jedis/commands/jedis/BitCommandsTest.java | 13 + .../commands/jedis/ClientCommandsTest.java | 4 + .../commands/jedis/ClusterCommandsTest.java | 19 +- .../jedis/ClusterJedisCommandsTestBase.java | 25 +- .../jedis/ClusterScriptingCommandsTest.java | 3 + ...erShardedPublishSubscribeCommandsTest.java | 3 + .../commands/jedis/ControlCommandsTest.java | 12 +- .../jedis/commands/jedis/GeoCommandsTest.java | 4 +- .../commands/jedis/HashesCommandsTest.java | 23 ++ .../commands/jedis/JedisCommandsTestBase.java | 11 + .../commands/jedis/ListCommandsTest.java | 3 + .../jedis/commands/jedis/ModuleTest.java | 11 +- .../commands/jedis/ScriptingCommandsTest.java | 20 +- .../jedis/commands/jedis/SetCommandsTest.java | 2 + .../commands/jedis/SlowlogCommandsTest.java | 31 +- .../commands/jedis/SortedSetCommandsTest.java | 6 + .../commands/jedis/SortingCommandsTest.java | 2 + .../commands/jedis/StreamsCommandsTest.java | 44 ++- .../jedis/StringValuesCommandsTest.java | 3 + .../AllKindOfValuesCommandsTestBase.java | 9 + .../commands/unified/BitCommandsTestBase.java | 4 + .../commands/unified/GeoCommandsTestBase.java | 10 +- .../unified/HashesCommandsTestBase.java | 14 + .../unified/ListCommandsTestBase.java | 3 + .../commands/unified/SetCommandsTestBase.java | 2 + .../unified/SortedSetCommandsTestBase.java | 6 + .../unified/StringValuesCommandsTestBase.java | 3 + .../ClusterAllKindOfValuesCommandsTest.java | 15 + .../cluster/ClusterBitCommandsTest.java | 18 +- .../cluster/ClusterHashesCommandsTest.java | 15 + .../cluster/ClusterListCommandsTest.java | 18 ++ .../cluster/ClusterSetCommandsTest.java | 17 + .../cluster/ClusterSortedSetCommandsTest.java | 17 + .../ClusterStringValuesCommandsTest.java | 17 + .../pipeline/GeoPipelineCommandsTest.java | 9 +- .../pipeline/ListPipelineCommandsTest.java | 3 + .../pipeline/PipelineCommandsTestBase.java | 11 +- .../pipeline/SetPipelineCommandsTest.java | 2 + .../SortedSetPipelineCommandsTest.java | 5 + .../pipeline/StreamsPipelineCommandsTest.java | 16 +- .../PooledAllKindOfValuesCommandsTest.java | 8 + .../unified/pooled/PooledBitCommandsTest.java | 8 + .../pooled/PooledCommandsTestHelper.java | 2 +- .../pooled/PooledHashesCommandsTest.java | 8 + .../pooled/PooledListCommandsTest.java | 8 + .../pooled/PooledMiscellaneousTest.java | 13 +- .../unified/pooled/PooledSetCommandsTest.java | 8 + .../pooled/PooledSortedSetCommandsTest.java | 8 + .../PooledStringValuesCommandsTest.java | 8 + .../csc/ClientSideCacheFunctionalityTest.java | 20 +- .../jedis/csc/ClientSideCacheTestBase.java | 19 +- .../csc/JedisClusterClientSideCacheTest.java | 8 +- .../csc/JedisPooledClientSideCacheTest.java | 9 +- .../JedisSentineledClientSideCacheTest.java | 13 + .../SSLJedisPooledClientSideCacheTest.java | 28 +- .../modules/RedisModuleCommandsTestBase.java | 14 +- .../jedis/modules/search/AggregationTest.java | 2 + .../jedis/modules/search/SearchTest.java | 19 +- .../modules/search/SearchWithParamsTest.java | 108 +++++-- .../modules/timeseries/TimeSeriesTest.java | 10 +- .../jedis/util/EnabledOnCommandRule.java | 123 +++++++ .../jedis/util/GeoCoordinateMatcher.java | 31 +- .../jedis/util/GeoRadiusResponseMatcher.java | 55 ++++ .../clients/jedis/util/RedisVersionRule.java | 104 ++++++ .../clients/jedis/util/RedisVersionUtil.java | 60 ++-- .../redis/clients/jedis/util/TestEnvUtil.java | 23 ++ .../redis/clients/jedis/util/TlsUtil.java | 304 ++++++++++++++++++ src/test/resources/endpoints.json | 4 +- src/test/resources/env/.env | 7 + src/test/resources/env/.env.v6.2.16 | 5 + src/test/resources/env/.env.v7.2.6 | 2 + src/test/resources/env/.env.v7.4.1 | 2 + .../config/node-7379-8379/redis.conf | 9 + .../config/node-7380-8380/redis.conf | 8 + .../config/node-7381-8381/redis.conf | 9 + .../config/node-7382-8382/redis.conf | 9 + .../config/node-7383-8383/redis.conf | 9 + .../node-sentinel-26381-36381/redis.conf | 9 + src/test/resources/env/docker-compose.yml | 167 ++++++++++ .../env/redis-uds/config/node-0/redis.conf | 2 + .../config/node-6379-6390/redis.conf | 11 + .../config/node-6380/redis.conf | 8 + .../config/node-6383-6391/redis.conf | 9 + .../config/node-6386/redis.conf | 6 + .../node-sentinel-26379-36379/redis.conf | 8 + .../redis10-11/config/node-6388/redis.conf | 3 + .../redis10-11/config/node-6389/redis.conf | 4 + .../config/node-6381-16381/redis.conf | 6 + .../config/node-6382-16382/redis.conf | 7 + .../node-sentinel-26380-36380/redis.conf | 8 + .../node-sentinel-26382-36382/redis.conf | 8 + .../config/node-6384/redis.conf | 5 + .../config/node-6385/redis.conf | 6 + .../node-sentinel-26381-36381/redis.conf | 7 + .../config/node-6387-16387/redis.conf | 9 + .../node-sentinel-26383-36383/redis.conf | 12 + src/test/resources/private.crt | 21 ++ src/test/resources/private.key | 28 ++ 138 files changed, 2690 insertions(+), 539 deletions(-) create mode 100644 .github/workflows/test-on-docker.yml create mode 100644 src/test/java/io/redis/test/annotations/EnabledOnCommand.java create mode 100644 src/test/java/io/redis/test/annotations/SinceRedisVersion.java create mode 100644 src/test/java/io/redis/test/utils/RedisInfo.java create mode 100644 src/test/java/io/redis/test/utils/RedisVersion.java create mode 100644 src/test/java/redis/clients/jedis/util/EnabledOnCommandRule.java create mode 100644 src/test/java/redis/clients/jedis/util/GeoRadiusResponseMatcher.java create mode 100644 src/test/java/redis/clients/jedis/util/RedisVersionRule.java create mode 100644 src/test/java/redis/clients/jedis/util/TestEnvUtil.java create mode 100644 src/test/java/redis/clients/jedis/util/TlsUtil.java create mode 100644 src/test/resources/env/.env create mode 100644 src/test/resources/env/.env.v6.2.16 create mode 100644 src/test/resources/env/.env.v7.2.6 create mode 100644 src/test/resources/env/.env.v7.4.1 create mode 100644 src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf create mode 100644 src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf create mode 100644 src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf create mode 100644 src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf create mode 100644 src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf create mode 100644 src/test/resources/env/config/redis6-7/node-sentinel-26381-36381/redis.conf create mode 100644 src/test/resources/env/docker-compose.yml create mode 100644 src/test/resources/env/redis-uds/config/node-0/redis.conf create mode 100644 src/test/resources/env/redis1-2-5-8-sentinel/config/node-6379-6390/redis.conf create mode 100644 src/test/resources/env/redis1-2-5-8-sentinel/config/node-6380/redis.conf create mode 100644 src/test/resources/env/redis1-2-5-8-sentinel/config/node-6383-6391/redis.conf create mode 100644 src/test/resources/env/redis1-2-5-8-sentinel/config/node-6386/redis.conf create mode 100644 src/test/resources/env/redis1-2-5-8-sentinel/config/node-sentinel-26379-36379/redis.conf create mode 100644 src/test/resources/env/redis10-11/config/node-6388/redis.conf create mode 100644 src/test/resources/env/redis10-11/config/node-6389/redis.conf create mode 100644 src/test/resources/env/redis3-4-sentinel/config/node-6381-16381/redis.conf create mode 100644 src/test/resources/env/redis3-4-sentinel/config/node-6382-16382/redis.conf create mode 100644 src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26380-36380/redis.conf create mode 100644 src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26382-36382/redis.conf create mode 100644 src/test/resources/env/redis6-7-sentinel/config/node-6384/redis.conf create mode 100644 src/test/resources/env/redis6-7-sentinel/config/node-6385/redis.conf create mode 100644 src/test/resources/env/redis6-7-sentinel/config/node-sentinel-26381-36381/redis.conf create mode 100644 src/test/resources/env/redis9-sentinel/config/node-6387-16387/redis.conf create mode 100644 src/test/resources/env/redis9-sentinel/config/node-sentinel-26383-36383/redis.conf create mode 100644 src/test/resources/private.crt create mode 100644 src/test/resources/private.key diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index e1bb6dcefa..244a724d19 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -25,6 +25,53 @@ Jedis unit tests use many Redis instances, so we use a ```Makefile``` to prepare Start unit tests with ```make test```. Set up test environments with ```make start```, tear down those environments with ```make stop``` and clean up the environment files with ```make cleanup```. + +# Jedis Test Environment Using Docker + +This guide explains how to bootstrap and manage a test environment for Jedis using Docker Compose. + +## Workflow Steps +1. **Start the test environment** by running the following command (examples below). + - For instance, to start the environment with Redis 8.0-M02, use `make start-test-env`. +2. **Run tests** through your IDE, Maven, or other testing tools as needed. +3. **Stop the test environment** by running the following command: + - `make stop-test-env` + - This will stop and tear down the Docker containers running the Redis service + +# Start the Test Environment Using Docker + +You can bootstrap the test environment for supported versions of Redis using the provided `make` targets. + +## Option 1: Using `make` Targets +To bring up the test environment for a specific Redis version (8.0-M02, 7.4.1, 7.2.6, or 6.2.16), use the following command: +```bash +make start-test-env version=8.0-M02 # Replace with desired version +``` +To stop test environment: +```bash +make stop-test-env +``` +To run tests using dockerized environment: +```bash +make test-on-docker +``` + +## Option 2: Using docker compose commands directly +Docker compose file can be found in `src/test/resources/env` folder. +- **Redis 8.0-M02** +```bash +rm -rf /tmp/redis-env-work +export REDIS_VERSION=8.0-M02 +docker compose up +``` +- **Redis 7.4.1, 7.2.6, 6.2.16,** +```bash +rm -rf /tmp/redis-env-work +export REDIS_VERSION=6.2.16 +docker compose --env-file .env --env-file .env.v6.2.16 up +``` + + # Some rules of Jedis source code ## Code Convention diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml index 3df4e12271..016eabc9bc 100644 --- a/.github/workflows/integration.yml +++ b/.github/workflows/integration.yml @@ -51,6 +51,7 @@ jobs: mvn javadoc:jar - name: Run tests run: | + export TEST_ENV_PROVIDER=local make test env: JVM_OPTS: -Xmx3200m diff --git a/.github/workflows/test-on-docker.yml b/.github/workflows/test-on-docker.yml new file mode 100644 index 0000000000..985b9cc45b --- /dev/null +++ b/.github/workflows/test-on-docker.yml @@ -0,0 +1,124 @@ +--- + +name: Build and Test using containerized environment + +on: + push: + paths-ignore: + - 'docs/**' + - '**/*.md' + - '**/*.rst' + branches: + - master + - '[0-9].*' + pull_request: + branches: + - master + - '[0-9].*' + schedule: + - cron: '0 1 * * *' # nightly build + workflow_dispatch: + inputs: + specific_test: + description: 'Run specific test(s) (optional)' + required: false + default: '' +jobs: + + build: + name: Build and Test + runs-on: ubuntu-latest + env: + REDIS_ENV_WORK_DIR: ${{ github.workspace }}/redis-env-work + REDIS_ENV_CONF_DIR: ${{ github.workspace }}/src/test/resources/env + CLIENT_LIBS_IMAGE_PREFIX: "redislabs/client-libs-test" + strategy: + fail-fast: false + matrix: + redis_version: + - "8.0-M02" + - "7.4.1" + - "7.2.6" + # - "6.2.16" + steps: + - uses: actions/checkout@v2 + - name: Set up publishing to maven central + uses: actions/setup-java@v2 + with: + java-version: '8' + distribution: 'temurin' + - name: System setup + run: | + sudo apt update + sudo apt install -y make + make compile-module + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository + /var/cache/apt + key: jedis-${{hashFiles('**/pom.xml')}} + # Set up Docker Compose environment + - name: Set up Docker Compose environment + run: | + mkdir -m 777 $REDIS_ENV_WORK_DIR + export REDIS_VERSION="${{ matrix.redis_version }}" + make start-test-env version=$REDIS_VERSION + - name: Maven offline + run: | + mvn -q dependency:go-offline + - name: Build docs + run: | + mvn javadoc:jar + # Run Tests + - name: Run Maven tests + run: | + export TEST_ENV_PROVIDER=docker + export TEST_WORK_FOLDER=$REDIS_ENV_WORK_DIR + echo $TEST_WORK_FOLDER + if [ -z "$TESTS" ]; then + mvn clean compile test + else + mvn -Dtest=$TESTS clean compile test + fi + env: + TESTS: ${{ github.event.inputs.specific_test || '' }} + - name: Publish Test Results + uses: EnricoMi/publish-unit-test-result-action@v2 + if: always() + with: + files: | + target/surefire-reports/**/*.xml + # Collect logs on failure + - name: Collect logs on failure + if: failure() # This runs only if the previous steps failed + run: | + echo "Collecting logs from $WORK_DIR..." + ls -la $REDIS_ENV_WORK_DIR + # Upload logs as artifacts + - name: Upload logs on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: redis-env-work-logs-${{ matrix.redis_version }} + path: ${{ env.REDIS_ENV_WORK_DIR }} + # Bring down the Docker Compose test environment + - name: Tear down Docker Compose environment + if: always() + run: | + docker compose $COMPOSE_ENV_FILES -f src/test/resources/env/docker-compose.yml down + continue-on-error: true + # Upload code coverage + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + fail_ci_if_error: false + token: ${{ secrets.CODECOV_TOKEN }} + - name: Upload test results to Codecov + if: ${{ github.event_name == 'schedule' || (github.event_name == 'push') || github.event_name == 'workflow_dispatch'}} + uses: codecov/test-results-action@v1 + with: + fail_ci_if_error: false + files: ./target/surefire-reports/TEST* + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 8cb08a2658..5477116e12 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,9 @@ build/ bin/ tags .idea +.run *.aof *.rdb redis-git appendonlydir/ +.DS_Store diff --git a/Makefile b/Makefile index 1800f00d7e..275ea7e58c 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,28 @@ PATH := ./redis-git/src:${PATH} -STUNNEL_BIN := $(shell which stunnel) + +# Supported test env versions +SUPPORTED_TEST_ENV_VERSIONS := 8.0-M02 7.4.1 7.2.6 6.2.16 +DEFAULT_TEST_ENV_VERSION := 8.0-M02 +REDIS_ENV_WORK_DIR := $(or ${REDIS_ENV_WORK_DIR},/tmp/redis-env-work) define REDIS1_CONF daemonize yes protected-mode no port 6379 +tls-port 6390 requirepass foobared user acljedis on allcommands allkeys >fizzbuzz +user deploy on allcommands allkeys >verify pidfile /tmp/redis1.pid logfile /tmp/redis1.log save "" appendonly no enable-module-command yes client-output-buffer-limit pubsub 256k 128k 5 +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS2_CONF @@ -30,18 +40,24 @@ define REDIS3_CONF daemonize yes protected-mode no port 6381 +tls-port 16381 requirepass foobared masterauth foobared pidfile /tmp/redis3.pid logfile /tmp/redis3.log save "" appendonly no +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS4_CONF daemonize yes protected-mode no port 6382 +tls-port 16382 requirepass foobared masterauth foobared pidfile /tmp/redis4.pid @@ -49,6 +65,10 @@ logfile /tmp/redis4.log save "" appendonly no slaveof localhost 6381 +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS5_CONF @@ -104,6 +124,7 @@ define REDIS9_CONF daemonize yes protected-mode no port 6387 +tls-port 16387 user default off user acljedis on allcommands allkeys >fizzbuzz pidfile /tmp/redis9.pid @@ -111,6 +132,10 @@ logfile /tmp/redis9.log save "" appendonly no client-output-buffer-limit pubsub 256k 128k 5 +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS10_CONF @@ -137,6 +162,7 @@ endef # SENTINELS define REDIS_SENTINEL1 port 26379 +tls-port 36379 daemonize yes protected-mode no sentinel monitor mymaster 127.0.0.1 6379 1 @@ -146,10 +172,15 @@ sentinel failover-timeout mymaster 120000 sentinel parallel-syncs mymaster 1 pidfile /tmp/sentinel1.pid logfile /tmp/sentinel1.log +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_SENTINEL2 port 26380 +tls-port 36380 daemonize yes protected-mode no sentinel monitor mymaster 127.0.0.1 6381 1 @@ -159,6 +190,10 @@ sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 120000 pidfile /tmp/sentinel2.pid logfile /tmp/sentinel2.log +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_SENTINEL3 @@ -176,6 +211,7 @@ endef define REDIS_SENTINEL4 port 26382 +tls-port 36382 daemonize yes protected-mode no sentinel monitor mymaster 127.0.0.1 6381 1 @@ -185,10 +221,15 @@ sentinel parallel-syncs mymaster 1 sentinel failover-timeout mymaster 120000 pidfile /tmp/sentinel4.pid logfile /tmp/sentinel4.log +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_SENTINEL5 port 26383 +tls-port 36383 daemonize yes protected-mode no user default off @@ -201,6 +242,10 @@ sentinel failover-timeout aclmaster 120000 sentinel parallel-syncs aclmaster 1 pidfile /tmp/sentinel5.pid logfile /tmp/sentinel5.log +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef # CLUSTER REDIS NODES @@ -209,6 +254,7 @@ daemonize yes protected-mode no requirepass cluster port 7379 +tls-port 8379 cluster-node-timeout 15000 pidfile /tmp/redis_cluster_node1.pid logfile /tmp/redis_cluster_node1.log @@ -216,6 +262,10 @@ save "" appendonly no cluster-enabled yes cluster-config-file /tmp/redis_cluster_node1.conf +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_CLUSTER_NODE2_CONF @@ -223,6 +273,7 @@ daemonize yes protected-mode no requirepass cluster port 7380 +tls-port 8380 cluster-node-timeout 15000 pidfile /tmp/redis_cluster_node2.pid logfile /tmp/redis_cluster_node2.log @@ -230,6 +281,10 @@ save "" appendonly no cluster-enabled yes cluster-config-file /tmp/redis_cluster_node2.conf +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_CLUSTER_NODE3_CONF @@ -237,6 +292,7 @@ daemonize yes protected-mode no requirepass cluster port 7381 +tls-port 8381 cluster-node-timeout 15000 pidfile /tmp/redis_cluster_node3.pid logfile /tmp/redis_cluster_node3.log @@ -244,6 +300,10 @@ save "" appendonly no cluster-enabled yes cluster-config-file /tmp/redis_cluster_node3.conf +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_CLUSTER_NODE4_CONF @@ -251,6 +311,7 @@ daemonize yes protected-mode no requirepass cluster port 7382 +tls-port 8382 cluster-node-timeout 15000 pidfile /tmp/redis_cluster_node4.pid logfile /tmp/redis_cluster_node4.log @@ -258,6 +319,10 @@ save "" appendonly no cluster-enabled yes cluster-config-file /tmp/redis_cluster_node4.conf +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef define REDIS_CLUSTER_NODE5_CONF @@ -265,6 +330,7 @@ daemonize yes protected-mode no requirepass cluster port 7383 +tls-port 8383 cluster-node-timeout 15000 pidfile /tmp/redis_cluster_node5.pid logfile /tmp/redis_cluster_node5.log @@ -272,6 +338,10 @@ save "" appendonly no cluster-enabled yes cluster-config-file /tmp/redis_cluster_node5.conf +tls-auth-clients no +tls-cert-file "src/test/resources/private.crt" +tls-key-file "src/test/resources/private.key" +tls-ca-cert-file "src/test/resources/private.crt" endef # STABLE CLUSTER REDIS NODES @@ -342,42 +412,6 @@ save "" appendonly no endef -#STUNNEL -define STUNNEL_CONF -cert = src/test/resources/private.pem -pid = /tmp/stunnel.pid -[redis_1] -accept = 127.0.0.1:6390 -connect = 127.0.0.1:6379 -[redis_3] -accept = 127.0.0.1:16381 -connect = 127.0.0.1:6381 -[redis_4] -accept = 127.0.0.1:16382 -connect = 127.0.0.1:6382 -[redis_9] -accept = 127.0.0.1:16387 -connect = 127.0.0.1:6387 -[redis_cluster_1] -accept = 127.0.0.1:8379 -connect = 127.0.0.1:7379 -[redis_cluster_2] -accept = 127.0.0.1:8380 -connect = 127.0.001:7380 -[redis_cluster_3] -accept = 127.0.0.1:8381 -connect = 127.0.001:7381 -[redis_cluster_4] -accept = 127.0.0.1:8382 -connect = 127.0.0.1:7382 -[redis_cluster_5] -accept = 127.0.0.1:8383 -connect = 127.0.0.1:7383 -[redis_sentinel_5] -accept = 127.0.0.1:36383 -connect = 127.0.0.1:26383 -endef - export REDIS1_CONF export REDIS2_CONF export REDIS3_CONF @@ -404,16 +438,9 @@ export REDIS_STABLE_CLUSTER_NODE2_CONF export REDIS_STABLE_CLUSTER_NODE3_CONF export REDIS_UDS export REDIS_UNAVAILABLE_CONF -export STUNNEL_CONF -export STUNNEL_BIN -ifndef STUNNEL_BIN - SKIP_SSL := !SSL*, -endif -export SKIP_SSL - -start: stunnel cleanup compile-module +start: cleanup compile-module echo "$$REDIS1_CONF" | redis-server - echo "$$REDIS2_CONF" | redis-server - echo "$$REDIS3_CONF" | redis-server - @@ -450,12 +477,11 @@ start: stunnel cleanup compile-module cleanup: - rm -vf /tmp/redis_cluster_node*.conf 2>/dev/null + - rm -vf /tmp/redis_stable_cluster_node*.conf 2>/dev/null + - rm -vf /tmp/redis_cluster_node*.log 2>/dev/null + - rm -vf /tmp/redis_stable_cluster_node*.log 2>/dev/null - rm dump.rdb appendonly.aof - 2>/dev/null -stunnel: - @if [ -e "$$STUNNEL_BIN" ]; then\ - echo "$$STUNNEL_CONF" | stunnel -fd 0;\ - fi stop: kill `cat /tmp/redis1.pid` @@ -483,7 +509,6 @@ stop: kill `cat /tmp/redis_stable_cluster_node2.pid` kill `cat /tmp/redis_stable_cluster_node3.pid` kill `cat /tmp/redis_uds.pid` || true - kill `cat /tmp/stunnel.pid` || true [ -f /tmp/redis_unavailable.pid ] && kill `cat /tmp/redis_unavailable.pid` || true rm -f /tmp/sentinel1.conf rm -f /tmp/sentinel2.conf @@ -503,7 +528,7 @@ stop: test: | start mvn-test stop mvn-test: - mvn -Dtest=${SKIP_SSL}${TEST} clean compile test + mvn -Dtest=${TEST} clean compile test package: | start mvn-package stop @@ -526,13 +551,50 @@ mvn-release: mvn release:perform -DskipTests system-setup: - sudo apt install -y gcc g++ + # Install gcc with Homebrew (macOS) or apt (Linux) + if [ "$(shell uname)" = "Darwin" ]; then \ + brew install gcc || true; \ + else \ + sudo apt install -y gcc g++; \ + fi [ ! -e redis-git ] && git clone https://github.com/redis/redis.git --branch unstable --single-branch redis-git || true $(MAKE) -C redis-git clean - $(MAKE) -C redis-git + $(MAKE) -C redis-git BUILD_TLS=yes compile-module: gcc -shared -o /tmp/testmodule.so -fPIC src/test/resources/testmodule.c +# Start test environment with specific version using predefined docker compose setup + +start-test-env: + @if [ -z "$(version)" ]; then \ + version=$(arg); \ + if [ -z "$$version" ]; then \ + version="$(DEFAULT_TEST_ENV_VERSION)"; \ + fi; \ + fi; \ + if ! echo "$(SUPPORTED_TEST_ENV_VERSIONS)" | grep -qw "$$version"; then \ + echo "Error: Invalid version '$$version'. Supported versions are: $(SUPPORTED_TEST_ENV_VERSIONS)."; \ + exit 1; \ + fi; \ + default_env_file="src/test/resources/env/.env"; \ + custom_env_file="src/test/resources/env/.env.v$$version"; \ + env_files="--env-file $$default_env_file"; \ + if [ -f "$$custom_env_file" ]; then \ + env_files="$$env_files --env-file $$custom_env_file"; \ + fi; \ + rm -rf "$(REDIS_ENV_WORK_DIR)"; \ + mkdir -p "$(REDIS_ENV_WORK_DIR)"; \ + export REDIS_VERSION=$$version && \ + docker compose $$env_files -f src/test/resources/env/docker-compose.yml up -d; \ + echo "Started test environment with Redis version $$version." + +# Stop the test environment +stop-test-env: + docker compose -f src/test/resources/env/docker-compose.yml down; \ + rm -rf "$(REDIS_ENV_WORK_DIR)"; \ + echo "Stopped test environment and performed cleanup." + +test-on-docker: | start-test-env mvn-test stop-test-env .PHONY: test diff --git a/src/test/java/io/redis/test/annotations/EnabledOnCommand.java b/src/test/java/io/redis/test/annotations/EnabledOnCommand.java new file mode 100644 index 0000000000..1d3a963766 --- /dev/null +++ b/src/test/java/io/redis/test/annotations/EnabledOnCommand.java @@ -0,0 +1,11 @@ +package io.redis.test.annotations; + +import java.lang.annotation.*; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface EnabledOnCommand { + String value(); + String subCommand() default ""; +} \ No newline at end of file diff --git a/src/test/java/io/redis/test/annotations/SinceRedisVersion.java b/src/test/java/io/redis/test/annotations/SinceRedisVersion.java new file mode 100644 index 0000000000..9ae1d3f353 --- /dev/null +++ b/src/test/java/io/redis/test/annotations/SinceRedisVersion.java @@ -0,0 +1,11 @@ +package io.redis.test.annotations; + +import java.lang.annotation.*; + +@Inherited +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.METHOD, ElementType.TYPE}) +public @interface SinceRedisVersion { + String value(); + String message() default ""; +} diff --git a/src/test/java/io/redis/test/utils/RedisInfo.java b/src/test/java/io/redis/test/utils/RedisInfo.java new file mode 100644 index 0000000000..fa69432fb2 --- /dev/null +++ b/src/test/java/io/redis/test/utils/RedisInfo.java @@ -0,0 +1,67 @@ +package io.redis.test.utils; + +import java.util.HashMap; +import java.util.Map; + +public class RedisInfo { + private final Map infoMap; + + public RedisInfo() { + this.infoMap = new HashMap<>(); + } + + public void setField(String key, String value) { + infoMap.put(key, value); + } + + public String getField(String key) { + return infoMap.get(key); + } + + public String getRedisVersion() { + return infoMap.get("redis_version"); + } + + public String getOs() { + return infoMap.get("os"); + } + + public String getMode() { + return infoMap.get("redis_mode"); + } + + public String getPorts() { + return infoMap.get("tcp_port"); // Assuming "tcp_port" is the key for ports + } + + @Override + public String toString() { + return "RedisInfo{" + + "infoMap=" + infoMap + + '}'; + } + + public static RedisInfo parseInfoServer(String infoOutput) { + RedisInfo redisInfo = new RedisInfo(); + + String[] lines = infoOutput.split("\n"); + + for (String line : lines) { + // Only parse lines that contain a colon (indicating a key-value pair) + if (line.contains(":")) { + String[] parts = line.split(":", 2); + if (parts.length == 2) { + redisInfo.setField(parts[0].trim(), parts[1].trim()); + } + } + } + + // You can still check for required fields if necessary + // Example: Ensure that specific fields are set + if (redisInfo.getField("redis_version") == null || redisInfo.getField("redis_mode") == null) { + throw new IllegalArgumentException("Missing required fields in Redis server info."); + } + + return redisInfo; + } +} \ No newline at end of file diff --git a/src/test/java/io/redis/test/utils/RedisVersion.java b/src/test/java/io/redis/test/utils/RedisVersion.java new file mode 100644 index 0000000000..a87d60262e --- /dev/null +++ b/src/test/java/io/redis/test/utils/RedisVersion.java @@ -0,0 +1,92 @@ +package io.redis.test.utils; + +public class RedisVersion implements Comparable{ + public static final RedisVersion V6_0_0 = RedisVersion.of("6.0.0"); + public static final RedisVersion V7_0_0 = RedisVersion.of("7.0.0"); + public static final RedisVersion V7_2_0 = RedisVersion.of("7.2.0"); + public static final RedisVersion V7_4 = RedisVersion.of("7.4"); + public static final RedisVersion V8_0_0 = RedisVersion.of("8.0.0"); + + private final int major; + private final int minor; + private final int patch; + + // Private constructor to enforce use of the static factory method + private RedisVersion(int major, int minor, int patch) { + this.major = major; + this.minor = minor; + this.patch = patch; + } + + // Static method to create a RedisVersion from a version string + public static RedisVersion of(String version) { + // Check for the "redis_version:" prefix and remove it if present + if (version.startsWith("redis_version:")) { + version = version.substring("redis_version:".length()); + } + + // Split the version string by the '.' character + String[] parts = version.split("\\."); + + // Parse each component, setting defaults for missing parts + int major = parts.length > 0 ? Integer.parseInt(parts[0]) : 0; + int minor = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; + int patch = parts.length > 2 ? Integer.parseInt(parts[2]) : 0; + + return new RedisVersion(major, minor, patch); + } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } + + public int getPatch() { + return patch; + } + + @Override + public String toString() { + return "RedisVersion{" + + "major=" + major + + ", minor=" + minor + + ", patch=" + patch + + '}'; + } + + @Override + public int compareTo(RedisVersion other) { + // Compare major, minor, and patch versions + if (this.major != other.major) { + return Integer.compare(this.major, other.major); + } + if (this.minor != other.minor) { + return Integer.compare(this.minor, other.minor); + } + return Integer.compare(this.patch, other.patch); + } + + public boolean isLessThanOrEqualTo(RedisVersion other) { + return this.compareTo(other) <= 0; + } + + public boolean isLessThan(RedisVersion other) { + return this.compareTo(other) < 0; + } + + public boolean isGreaterThanOrEqualTo(RedisVersion other) { + return this.compareTo(other) >= 0; + } + + public boolean isGreaterThan(RedisVersion other) { + return this.compareTo(other) > 0; + } + + // Static method to compare two RedisVersion instances + public static int compare(RedisVersion v1, RedisVersion v2) { + return v1.compareTo(v2); + } +} \ No newline at end of file diff --git a/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java b/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java index 5d7579b367..df2422393a 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisPoolTest.java @@ -7,30 +7,29 @@ import java.net.URI; import java.net.URISyntaxException; + +import io.redis.test.annotations.SinceRedisVersion; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; import redis.clients.jedis.exceptions.InvalidURIException; import redis.clients.jedis.exceptions.JedisException; -import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.RedisVersionRule; /** * This test class is a copy of {@link JedisPoolTest}. *

* This test is only executed when the server/cluster is Redis 6. or more. */ +@SinceRedisVersion("6.0.0") public class ACLJedisPoolTest { private static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl"); private static final EndpointConfig endpointWithDefaultUser = HostAndPorts.getRedisEndpoint("standalone0"); - @BeforeClass - public static void prepare() throws Exception { - // Use to check if the ACL test should be ran. ACL are available only in 6.0 and later - org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); - } + @ClassRule + public static RedisVersionRule versionRule = new RedisVersionRule(endpoint); @Test public void checkConnections() { diff --git a/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java index b62809f0bb..6ea2ba32ce 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisSentinelPoolTest.java @@ -5,21 +5,23 @@ import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; + +import io.redis.test.annotations.SinceRedisVersion; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; -import org.junit.After; import org.junit.Before; -import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisException; -import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.RedisVersionRule; /** * This test class is mostly a copy of {@link JedisSentinelPoolTest}. *

* This tests are only executed when the server/cluster is Redis 6 or more. */ +@SinceRedisVersion("6.0.0") public class ACLJedisSentinelPoolTest { private static final String MASTER_NAME = "aclmaster"; @@ -28,12 +30,8 @@ public class ACLJedisSentinelPoolTest { protected Set sentinels = new HashSet<>(); - @BeforeClass - public static void prepare() throws Exception { - EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone2-primary"); - org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); - } + @ClassRule + public static RedisVersionRule versionRule = new RedisVersionRule(HostAndPorts.getRedisEndpoint("standalone2-primary")); @Before public void setUp() throws Exception { @@ -41,10 +39,6 @@ public void setUp() throws Exception { sentinels.add(sentinel1); } - @After - public void tearDown() throws Exception { - } - private static Set toStrings(Set hostAndPorts) { return hostAndPorts.stream().map(hap -> hap.toString()).collect(Collectors.toSet()); } diff --git a/src/test/java/redis/clients/jedis/ACLJedisTest.java b/src/test/java/redis/clients/jedis/ACLJedisTest.java index d1ef40b95b..b9b35326e1 100644 --- a/src/test/java/redis/clients/jedis/ACLJedisTest.java +++ b/src/test/java/redis/clients/jedis/ACLJedisTest.java @@ -1,7 +1,9 @@ package redis.clients.jedis; import static org.junit.Assert.assertEquals; +import static redis.clients.jedis.util.RedisVersionUtil.getRedisVersion; +import io.redis.test.utils.RedisVersion; import java.net.URISyntaxException; import org.junit.BeforeClass; import org.junit.Test; @@ -9,7 +11,6 @@ import org.junit.runners.Parameterized; import redis.clients.jedis.commands.jedis.JedisCommandsTestBase; -import redis.clients.jedis.util.RedisVersionUtil; /** * This test class is a copy of {@link JedisTest}. @@ -28,7 +29,7 @@ public class ACLJedisTest extends JedisCommandsTestBase { @BeforeClass public static void prepare() throws Exception { org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); + getRedisVersion(endpoint).isGreaterThanOrEqualTo(RedisVersion.of("6.0.0"))); } public ACLJedisTest(RedisProtocol redisProtocol) { diff --git a/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java b/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java index 2edcb67456..e186702e81 100644 --- a/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java +++ b/src/test/java/redis/clients/jedis/ClusterPipeliningTest.java @@ -1,5 +1,7 @@ package redis.clients.jedis; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.*; import static redis.clients.jedis.Protocol.CLUSTER_HASHSLOTS; @@ -21,6 +23,8 @@ import redis.clients.jedis.resps.StreamEntry; import redis.clients.jedis.resps.Tuple; import redis.clients.jedis.util.AssertUtil; +import redis.clients.jedis.util.GeoCoordinateMatcher; +import redis.clients.jedis.util.GeoRadiusResponseMatcher; import redis.clients.jedis.util.JedisClusterTestUtil; import redis.clients.jedis.util.SafeEncoder; @@ -693,10 +697,6 @@ public void clusterPipelineGeo() { hm.put("place1", new GeoCoordinate(2.1909389952632, 41.433791470673)); hm.put("place2", new GeoCoordinate(2.1873744593677, 41.406342043777)); - List values = new ArrayList<>(); - values.add(new GeoCoordinate(2.19093829393386841, 41.43379028184083523)); - values.add(new GeoCoordinate(2.18737632036209106, 41.40634178640635099)); - List hashValues = new ArrayList<>(); hashValues.add("sp3e9yg3kd0"); hashValues.add("sp3e9cbc3t0"); @@ -706,11 +706,6 @@ public void clusterPipelineGeo() { GeoRadiusParam params2 = new GeoRadiusParam().count(1, true); GeoRadiusStoreParam storeParams = new GeoRadiusStoreParam().store("radius{#}"); - GeoRadiusResponse expectedResponse = new GeoRadiusResponse("place1".getBytes()); - expectedResponse.setCoordinate(new GeoCoordinate(2.19093829393386841, 41.43379028184083523)); - expectedResponse.setDistance(0.0881); - expectedResponse.setRawScore(3471609698139488L); - ClusterConnectionProvider provider = new ClusterConnectionProvider(nodes, DEFAULT_CLIENT_CONFIG); ClusterPipeline p = new ClusterPipeline(provider); @@ -738,11 +733,21 @@ public void clusterPipelineGeo() { assertEquals(Double.valueOf(3067.4157), r2.get()); assertEquals(Double.valueOf(3.0674), r3.get()); assertEquals(hashValues, r4.get()); - assertEquals(values, r5.get()); + assertThat(r5.get(), contains( + GeoCoordinateMatcher.atCoordinates(2.19093829393386841, 41.43379028184083523), + GeoCoordinateMatcher.atCoordinates(2.18737632036209106, 41.40634178640635099)) + ); assertTrue(r6.get().size() == 1 && r6.get().get(0).getMemberByString().equals("place1")); assertTrue(r7.get().size() == 1 && r7.get().get(0).getMemberByString().equals("place1")); - assertEquals(expectedResponse, r8.get().get(0)); - assertEquals(expectedResponse, r9.get().get(0)); + + GeoRadiusResponse expectedResponse = new GeoRadiusResponse("place1".getBytes()); + expectedResponse.setCoordinate(new GeoCoordinate(2.19093829393386841, 41.43379028184083523)); + expectedResponse.setDistance(0.0881); + expectedResponse.setRawScore(3471609698139488L); + + assertThat(r8.get().get(0), GeoRadiusResponseMatcher.ofResponse(expectedResponse)); + assertThat(r9.get().get(0), GeoRadiusResponseMatcher.ofResponse(expectedResponse)); + assertEquals(Long.valueOf(1), r10.get()); assertTrue(r11.get().size() == 1 && r11.get().contains("place1")); assertTrue(r12.get().size() == 2 && r12.get().get(0).getMemberByString().equals("place2")); diff --git a/src/test/java/redis/clients/jedis/EndpointConfig.java b/src/test/java/redis/clients/jedis/EndpointConfig.java index 68f927be0e..fbb2b085f2 100644 --- a/src/test/java/redis/clients/jedis/EndpointConfig.java +++ b/src/test/java/redis/clients/jedis/EndpointConfig.java @@ -3,11 +3,15 @@ import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; import com.google.gson.reflect.TypeToken; import redis.clients.jedis.util.JedisURIHelper; +import redis.clients.jedis.util.TlsUtil; import java.io.FileReader; import java.net.URI; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; public class EndpointConfig { @@ -17,14 +21,17 @@ public class EndpointConfig { private final String password; private final int bdbId; private final List endpoints; + @SerializedName("certificatesLocation") + private final String certificatesLocation; - public EndpointConfig(HostAndPort hnp, String username, String password, boolean tls) { + public EndpointConfig(HostAndPort hnp, String username, String password, boolean tls, String certificatesLocation) { this.tls = tls; this.username = username; this.password = password; this.bdbId = 0; this.endpoints = Collections.singletonList( URI.create(getURISchema(tls) + hnp.getHost() + ":" + hnp.getPort())); + this.certificatesLocation = certificatesLocation; } public HostAndPort getHostAndPort() { @@ -51,6 +58,14 @@ public int getPort() { return getHostAndPort().getPort(); } + public Boolean isTls() { + return tls; + } + + public Path getCertificatesLocation() { + return Paths.get(certificatesLocation); + } + public int getBdbId() { return bdbId; } public URI getURI() { @@ -112,6 +127,10 @@ public DefaultJedisClientConfig.Builder getClientConfigBuilder() { DefaultJedisClientConfig.Builder builder = DefaultJedisClientConfig.builder() .password(password).ssl(tls); + if (tls && certificatesLocation != null) { + builder.sslSocketFactory(TlsUtil.sslSocketFactoryForEnv(Paths.get(certificatesLocation))); + } + if (username != null) { return builder.user(username); } diff --git a/src/test/java/redis/clients/jedis/JedisClusterTest.java b/src/test/java/redis/clients/jedis/JedisClusterTest.java index f3dfe630e5..32fce366f8 100644 --- a/src/test/java/redis/clients/jedis/JedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/JedisClusterTest.java @@ -26,6 +26,7 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import io.redis.test.annotations.SinceRedisVersion; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.Test; @@ -667,7 +668,8 @@ public void testInvalidStartNodeNotAdded() { } @Test - public void clusterLinks2() throws InterruptedException { + @SinceRedisVersion("7.0.0") + public void clusterLinks2() { Set mapKeys = new HashSet<>(Arrays.asList("direction", "node", "create-time", "events", "send-buffer-allocated", "send-buffer-used")); diff --git a/src/test/java/redis/clients/jedis/JedisClusterTestBase.java b/src/test/java/redis/clients/jedis/JedisClusterTestBase.java index bb6656a812..05e8f3bb70 100644 --- a/src/test/java/redis/clients/jedis/JedisClusterTestBase.java +++ b/src/test/java/redis/clients/jedis/JedisClusterTestBase.java @@ -2,8 +2,11 @@ import static redis.clients.jedis.Protocol.CLUSTER_HASHSLOTS; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import redis.clients.jedis.args.ClusterResetType; import redis.clients.jedis.util.JedisClusterTestUtil; @@ -23,6 +26,11 @@ public abstract class JedisClusterTestBase { protected static final String LOCAL_IP = "127.0.0.1"; + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(nodeInfo1,DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(nodeInfo1, DefaultJedisClientConfig.builder().password("cluster").build()); + @Before public void setUp() throws InterruptedException { node1 = new Jedis(nodeInfo1); diff --git a/src/test/java/redis/clients/jedis/JedisTest.java b/src/test/java/redis/clients/jedis/JedisTest.java index 560c5a0577..7e353d3441 100644 --- a/src/test/java/redis/clients/jedis/JedisTest.java +++ b/src/test/java/redis/clients/jedis/JedisTest.java @@ -16,6 +16,7 @@ import java.util.HashMap; import java.util.Map; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -308,6 +309,7 @@ public void checkDisconnectOnQuit() { } @Test + @SinceRedisVersion(value = "7.2.0", message = "see https://redis.io/docs/latest/commands/client-setinfo/") public void clientSetInfoDefault() { try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() .clientSetInfoConfig(ClientSetInfoConfig.DEFAULT).build())) { @@ -330,6 +332,7 @@ public void clientSetInfoDisabled() { } @Test + @SinceRedisVersion(value = "7.2.0", message = "@see https://redis.io/docs/latest/commands/client-setinfo/") public void clientSetInfoLibNameSuffix() { final String libNameSuffix = "for-redis"; ClientSetInfoConfig setInfoConfig = ClientSetInfoConfig.withLibNameSuffix(libNameSuffix); diff --git a/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java b/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java index fbe57f66f7..cd48cd2411 100644 --- a/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/SSLACLJedisClusterTest.java @@ -2,85 +2,105 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static redis.clients.jedis.util.TlsUtil.*; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; +import java.util.List; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocketFactory; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; -import redis.clients.jedis.exceptions.JedisClusterOperationException; -import redis.clients.jedis.SSLJedisTest.BasicHostnameVerifier; import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.TlsUtil; +import redis.clients.jedis.exceptions.JedisClusterOperationException; +@SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after tests are fixed.") public class SSLACLJedisClusterTest extends JedisClusterTestBase { private static final int DEFAULT_REDIRECTIONS = 5; private static final ConnectionPoolConfig DEFAULT_POOL_CONFIG = new ConnectionPoolConfig(); - private final HostAndPortMapper hostAndPortMap = (HostAndPort hostAndPort) -> { + // legacy test env bootstrap uses stunnel causing redis server to report non-tls port instead tls one containerised + // test env enables tls directly on Redis nodes and in this case tls_port is correctly reported + // TODO : remove stunnel from legacy env + // static int tlsPortOffset = 0; + private final HostAndPortMapper hostAndPortMap = (hostAndPort) -> { String host = hostAndPort.getHost(); int port = hostAndPort.getPort(); - if (host.equals("127.0.0.1")) { + + if ("127.0.0.1".equals(host)) { host = "localhost"; - port = port + 1000; } return new HostAndPort(host, port); }; // don't map IP addresses so that we try to connect with host 127.0.0.1 - private final HostAndPortMapper portMap = (HostAndPort hostAndPort) -> { + private final HostAndPortMapper portMap = (hostAndPort) -> { if ("localhost".equals(hostAndPort.getHost())) { return hostAndPort; } - return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort() + 1000); + return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort() /* + tlsPortOffset */); }; + private static final String trustStoreName = SSLACLJedisClusterTest.class.getSimpleName(); + @BeforeClass public static void prepare() { - // TODO(imalinovskyi): Remove hardcoded connection settings - // once this test is refactored to support RE - org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6, - new EndpointConfig(new HostAndPort("localhost", 8379), - "default", "cluster", true))); - - // We need to set up certificates first before connecting to the endpoint with enabled TLS - SSLJedisTest.setupTrustStore(); + List trustedCertLocation = Collections.singletonList(Paths.get("cluster-unbound/work/tls")); + Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + + TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); } @AfterClass - public static void unprepare() { - SSLJedisTest.cleanupTrustStore(); + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); } @Test public void testSSLDiscoverNodesAutomatically() { + DefaultJedisClientConfig config = DefaultJedisClientConfig.builder() + .user("default").password("cluster").ssl(true) + .hostAndPortMapper(hostAndPortMap).build(); + try (JedisCluster jc = new JedisCluster(Collections.singleton(new HostAndPort("localhost", 8379)), - DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true) - .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { - Map clusterNodes = jc.getClusterNodes(); + config, DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { + Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + + /** + * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and + * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns + * the regular (non-TLS) port rather than the TLS port. + */ + if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { + assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + } else { + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); + } jc.get("foo"); } try (JedisCluster jc2 = new JedisCluster(new HostAndPort("localhost", 8379), - DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true) - .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { + config, DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { Map clusterNodes = jc2.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); jc2.get("foo"); } } @@ -90,18 +110,28 @@ public void testSSLWithoutPortMap() { try (JedisCluster jc = new JedisCluster(Collections.singleton(new HostAndPort("localhost", 8379)), DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// Map clusterNodes = jc.getClusterNodes(); Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + /** + * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and + * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns + * the regular (non-TLS) port rather than the TLS port. + */ + if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { + assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + } else { + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); + } } } @Test public void connectByIpAddress() { - try (JedisCluster jc = new JedisCluster(new HostAndPort("127.0.0.1", 7379), + try (JedisCluster jc = new JedisCluster(new HostAndPort("127.0.0.1", 8379), DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { @@ -161,8 +191,8 @@ public void connectByIpAddressFailsWithSSLParameters() { @Test public void connectWithCustomHostNameVerifier() { - HostnameVerifier hostnameVerifier = new BasicHostnameVerifier(); - HostnameVerifier localhostVerifier = new LocalhostVerifier(); + HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); + HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true) @@ -200,12 +230,11 @@ public void connectWithCustomHostNameVerifier() { } @Test - public void connectWithCustomSocketFactory() throws Exception { - final SSLSocketFactory sslSocketFactory = SSLJedisTest.createTrustStoreSslSocketFactory(); - + public void connectWithCustomSocketFactory() { try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true) - .sslSocketFactory(sslSocketFactory).hostAndPortMapper(portMap).build(), + .sslSocketFactory(sslSocketFactoryForEnv(Paths.get("cluster-unbound/work/tls"))) + .hostAndPortMapper(portMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { assertEquals(3, jc.getClusterNodes().size()); } @@ -213,11 +242,10 @@ public void connectWithCustomSocketFactory() throws Exception { @Test public void connectWithEmptyTrustStore() throws Exception { - final SSLSocketFactory sslSocketFactory = SSLJedisTest.createTrustNoOneSslSocketFactory(); - try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(true) - .sslSocketFactory(sslSocketFactory).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { + .sslSocketFactory(createTrustNoOneSslSocketFactory()).build(), + DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { // jc.get("key"); // Assert.fail("There should be no reachable node in cluster."); //// } catch (JedisNoReachableClusterNodeException e) { @@ -234,21 +262,11 @@ public void defaultHostAndPortUsedIfMapReturnsNull() { try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 7379), DefaultJedisClientConfig.builder().user("default").password("cluster").ssl(false) .hostAndPortMapper(nullHostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { - Map clusterNodes = jc.getClusterNodes(); + Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); } } - - public class LocalhostVerifier extends BasicHostnameVerifier { - @Override - public boolean verify(String hostname, SSLSession session) { - if (hostname.equals("127.0.0.1")) { - hostname = "localhost"; - } - return super.verify(hostname, session); - } - } } diff --git a/src/test/java/redis/clients/jedis/SSLACLJedisTest.java b/src/test/java/redis/clients/jedis/SSLACLJedisTest.java index a6b2d4c059..6e185c6505 100644 --- a/src/test/java/redis/clients/jedis/SSLACLJedisTest.java +++ b/src/test/java/redis/clients/jedis/SSLACLJedisTest.java @@ -2,35 +2,49 @@ import static org.junit.Assert.*; +import io.redis.test.annotations.SinceRedisVersion; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; + import org.junit.AfterClass; import org.junit.BeforeClass; +import org.junit.ClassRule; import org.junit.Test; -import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.RedisVersionRule; +import redis.clients.jedis.util.TlsUtil; /** * This test class is a copy of {@link SSLJedisTest}. *

* This test is only executed when the server/cluster is Redis 6. or more. */ +@SinceRedisVersion(value = "6.0.0", message = "Not running ACL test on this version of Redis") public class SSLACLJedisTest { protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-acl-tls"); protected static final EndpointConfig endpointWithDefaultUser = HostAndPorts.getRedisEndpoint("standalone0-tls"); + @ClassRule + public static RedisVersionRule versionRule = new RedisVersionRule(endpoint); + + private static final String trustStoreName = SSLACLJedisTest.class.getSimpleName(); + @BeforeClass public static void prepare() { - // We need to set up certificates first before connecting to the endpoint with enabled TLS - SSLJedisTest.setupTrustStore(); - // Use to check if the ACL test should be ran. ACL are available only in 6.0 and later - org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); + List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(), + endpointWithDefaultUser.getCertificatesLocation()); + Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation, + "changeit"); + + TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); } @AfterClass - public static void unprepare() { - SSLJedisTest.cleanupTrustStore(); + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); } @Test diff --git a/src/test/java/redis/clients/jedis/SSLJedisClusterTest.java b/src/test/java/redis/clients/jedis/SSLJedisClusterTest.java index bc43bff7b6..44807427cf 100644 --- a/src/test/java/redis/clients/jedis/SSLJedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/SSLJedisClusterTest.java @@ -2,22 +2,28 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static redis.clients.jedis.util.TlsUtil.*; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; +import java.util.List; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLSocketFactory; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.junit.AfterClass; +import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.TlsUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import redis.clients.jedis.exceptions.JedisClusterOperationException; -import redis.clients.jedis.SSLJedisTest.BasicHostnameVerifier; -import redis.clients.jedis.SSLJedisTest.LocalhostVerifier; +@SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after test is fixed.") public class SSLJedisClusterTest extends JedisClusterTestBase { private static final int DEFAULT_REDIRECTIONS = 5; @@ -28,7 +34,6 @@ public class SSLJedisClusterTest extends JedisClusterTestBase { int port = hostAndPort.getPort(); if (host.equals("127.0.0.1")) { host = "localhost"; - port = port + 1000; } return new HostAndPort(host, port); }; @@ -38,17 +43,22 @@ public class SSLJedisClusterTest extends JedisClusterTestBase { if ("localhost".equals(hostAndPort.getHost())) { return hostAndPort; } - return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort() + 1000); + return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort()); }; + private static final String trustStoreName = SSLJedisClusterTest.class.getSimpleName(); + @BeforeClass public static void prepare() { - SSLJedisTest.setupTrustStore(); // set up trust store for SSL tests + List trustedCertLocation = Collections.singletonList(Paths.get("cluster-unbound/work/tls")); + Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + + TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); } @AfterClass - public static void unprepare() { - SSLJedisTest.cleanupTrustStore(); + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); } @Test @@ -56,12 +66,22 @@ public void testSSLDiscoverNodesAutomatically() { try (JedisCluster jc = new JedisCluster(Collections.singleton(new HostAndPort("localhost", 8379)), DefaultJedisClientConfig.builder().password("cluster").ssl(true) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// Map clusterNodes = jc.getClusterNodes(); Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + /** + * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and + * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns + * the regular (non-TLS) port rather than the TLS port. + */ + if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { + assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + } else { + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); + } jc.get("foo"); } @@ -69,12 +89,11 @@ public void testSSLDiscoverNodesAutomatically() { try (JedisCluster jc2 = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().password("cluster").ssl(true) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// Map clusterNodes = jc2.getClusterNodes(); Map clusterNodes = jc2.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); jc2.get("foo"); } } @@ -84,18 +103,28 @@ public void testSSLWithoutPortMap() { try (JedisCluster jc = new JedisCluster(Collections.singleton(new HostAndPort("localhost", 8379)), DefaultJedisClientConfig.builder().password("cluster").ssl(true).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// Map clusterNodes = jc.getClusterNodes(); Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + /** + * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and + * non-TLS ports for CLUSTER SLOTS. When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns + * the regular (non-TLS) port rather than the TLS port. + */ + if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { + assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + } else { + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); + } } } @Test public void connectByIpAddress() { - try (JedisCluster jc = new JedisCluster(new HostAndPort("127.0.0.1", 7379), + try (JedisCluster jc = new JedisCluster(new HostAndPort("127.0.0.1", 8379), DefaultJedisClientConfig.builder().password("cluster").ssl(true) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { @@ -123,6 +152,7 @@ public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after test is fixed.") public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { final SSLParameters sslParameters = new SSLParameters(); sslParameters.setEndpointIdentificationAlgorithm("HTTPS"); @@ -155,8 +185,8 @@ public void connectByIpAddressFailsWithSSLParameters() { @Test public void connectWithCustomHostNameVerifier() { - HostnameVerifier hostnameVerifier = new BasicHostnameVerifier(); - HostnameVerifier localhostVerifier = new LocalhostVerifier(); + HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); + HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().password("cluster").ssl(true) @@ -195,11 +225,10 @@ public void connectWithCustomHostNameVerifier() { @Test public void connectWithCustomSocketFactory() throws Exception { - final SSLSocketFactory sslSocketFactory = SSLJedisTest.createTrustStoreSslSocketFactory(); - try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().password("cluster").ssl(true) - .sslSocketFactory(sslSocketFactory).hostAndPortMapper(portMap).build(), + .sslSocketFactory(sslSocketFactoryForEnv(Paths.get("cluster-unbound/work/tls"))) + .hostAndPortMapper(portMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { assertEquals(3, jc.getClusterNodes().size()); } @@ -207,16 +236,11 @@ public void connectWithCustomSocketFactory() throws Exception { @Test public void connectWithEmptyTrustStore() throws Exception { - final SSLSocketFactory sslSocketFactory = SSLJedisTest.createTrustNoOneSslSocketFactory(); - try (JedisCluster jc = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().password("cluster").ssl(true) - .sslSocketFactory(sslSocketFactory).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// jc.get("key"); -// Assert.fail("There should be no reachable node in cluster."); -//// } catch (JedisNoReachableClusterNodeException e) { + .sslSocketFactory(createTrustNoOneSslSocketFactory()).build(), + DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { } catch (JedisClusterOperationException e) { -// assertEquals("No reachable node in cluster.", e.getMessage()); assertEquals("Could not initialize cluster slots cache.", e.getMessage()); } } @@ -229,7 +253,6 @@ public void defaultHostAndPortUsedIfMapReturnsNull() { DefaultJedisClientConfig.builder().password("cluster").ssl(false) .hostAndPortMapper(nullHostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { -// Map clusterNodes = jc.getClusterNodes(); Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); diff --git a/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java index 4fda9646c3..f753394945 100644 --- a/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/SSLJedisSentinelPoolTest.java @@ -1,11 +1,17 @@ package redis.clients.jedis; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; + import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.util.TlsUtil; public class SSLJedisSentinelPoolTest { @@ -17,17 +23,20 @@ public class SSLJedisSentinelPoolTest { -> new HostAndPort(hap.getHost(), hap.getPort() + 10000); private static final GenericObjectPoolConfig POOL_CONFIG = new GenericObjectPoolConfig<>(); + private static final String trustStoreName = SSLJedisSentinelPoolTest.class.getSimpleName(); @BeforeClass public static void prepare() { - SSLJedisTest.setupTrustStore(); + List trustedCertLocation = Collections.singletonList(Paths.get("redis9-sentinel/work/tls")); + Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); sentinels.add(HostAndPorts.getSentinelServers().get(4)); } @AfterClass - public static void unprepare() { - SSLJedisTest.cleanupTrustStore(); + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); } @Test diff --git a/src/test/java/redis/clients/jedis/SSLJedisTest.java b/src/test/java/redis/clients/jedis/SSLJedisTest.java index b0c11a4aab..f0abeaeb2c 100644 --- a/src/test/java/redis/clients/jedis/SSLJedisTest.java +++ b/src/test/java/redis/clients/jedis/SSLJedisTest.java @@ -1,61 +1,34 @@ package redis.clients.jedis; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyStore; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.util.TlsUtil; + public class SSLJedisTest { protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone0-tls"); - public static void setupTrustStore() { - setJvmTrustStore("src/test/resources/truststore.jceks", "jceks"); - } - - private static void setJvmTrustStore(String trustStoreFilePath, String trustStoreType) { - assertTrue(String.format("Could not find trust store at '%s'.", trustStoreFilePath), - new File(trustStoreFilePath).exists()); - System.setProperty("javax.net.ssl.trustStore", trustStoreFilePath); - System.setProperty("javax.net.ssl.trustStoreType", trustStoreType); - } - - public static void cleanupTrustStore() { - clearJvmTrustStore(); - } - - private static void clearJvmTrustStore() { - System.clearProperty("javax.net.ssl.trustStore"); - System.clearProperty("javax.net.ssl.trustStoreType"); - } + private static final String trustStoreName = SSLJedisTest.class.getSimpleName(); @BeforeClass public static void prepare() { - setupTrustStore(); + List trustedCertLocation = Collections.singletonList(endpoint.getCertificatesLocation()); + Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + + TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); } @AfterClass - public static void unprepare() { - cleanupTrustStore(); + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); } @Test @@ -113,87 +86,4 @@ public void connectWithUri() { } } - /** - * Creates an SSLSocketFactory that trusts all certificates in truststore.jceks. - */ - static SSLSocketFactory createTrustStoreSslSocketFactory() throws Exception { - - KeyStore trustStore = KeyStore.getInstance("jceks"); - - try (InputStream inputStream = new FileInputStream("src/test/resources/truststore.jceks")) { - trustStore.load(inputStream, null); - } - - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); - trustManagerFactory.init(trustStore); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, trustManagers, new SecureRandom()); - return sslContext.getSocketFactory(); - } - - /** - * Creates an SSLSocketFactory with a trust manager that does not trust any certificates. - */ - static SSLSocketFactory createTrustNoOneSslSocketFactory() throws Exception { - TrustManager[] unTrustManagers = new TrustManager[] { new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - - public void checkClientTrusted(X509Certificate[] chain, String authType) { - throw new RuntimeException(new InvalidAlgorithmParameterException()); - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) { - throw new RuntimeException(new InvalidAlgorithmParameterException()); - } - } }; - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, unTrustManagers, new SecureRandom()); - return sslContext.getSocketFactory(); - } - - /** - * Very basic hostname verifier implementation for testing. NOT recommended for production. - */ - static class BasicHostnameVerifier implements HostnameVerifier { - - private static final String COMMON_NAME_RDN_PREFIX = "CN="; - - @Override - public boolean verify(String hostname, SSLSession session) { - X509Certificate peerCertificate; - try { - peerCertificate = (X509Certificate) session.getPeerCertificates()[0]; - } catch (SSLPeerUnverifiedException e) { - throw new IllegalStateException("The session does not contain a peer X.509 certificate.", e); - } - String peerCertificateCN = getCommonName(peerCertificate); - return hostname.equals(peerCertificateCN); - } - - private String getCommonName(X509Certificate peerCertificate) { - String subjectDN = peerCertificate.getSubjectDN().getName(); - String[] dnComponents = subjectDN.split(","); - for (String dnComponent : dnComponents) { - dnComponent = dnComponent.trim(); - if (dnComponent.startsWith(COMMON_NAME_RDN_PREFIX)) { - return dnComponent.substring(COMMON_NAME_RDN_PREFIX.length()); - } - } - throw new IllegalArgumentException("The certificate has no common name."); - } - } - - static class LocalhostVerifier extends BasicHostnameVerifier { - @Override - public boolean verify(String hostname, SSLSession session) { - if (hostname.equals("127.0.0.1")) { - hostname = "localhost"; - } - return super.verify(hostname, session); - } - } } diff --git a/src/test/java/redis/clients/jedis/SSLOptionsJedisClusterTest.java b/src/test/java/redis/clients/jedis/SSLOptionsJedisClusterTest.java index bc568791c1..1eb9b48925 100644 --- a/src/test/java/redis/clients/jedis/SSLOptionsJedisClusterTest.java +++ b/src/test/java/redis/clients/jedis/SSLOptionsJedisClusterTest.java @@ -3,19 +3,25 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; +import java.util.List; import java.util.Map; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLParameters; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Test; import redis.clients.jedis.exceptions.JedisClusterOperationException; -import redis.clients.jedis.SSLJedisTest.BasicHostnameVerifier; -import redis.clients.jedis.SSLJedisTest.LocalhostVerifier; +import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.TlsUtil; +@SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x returns non-tls port in CLUSTER SLOTS command. Enable for 6.2.x after test is fixed.") public class SSLOptionsJedisClusterTest extends JedisClusterTestBase { private static final int DEFAULT_REDIRECTIONS = 5; @@ -26,7 +32,6 @@ public class SSLOptionsJedisClusterTest extends JedisClusterTestBase { int port = hostAndPort.getPort(); if (host.equals("127.0.0.1")) { host = "localhost"; - port = port + 1000; } return new HostAndPort(host, port); }; @@ -36,23 +41,42 @@ public class SSLOptionsJedisClusterTest extends JedisClusterTestBase { if ("localhost".equals(hostAndPort.getHost())) { return hostAndPort; } - return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort() + 1000); + return new HostAndPort(hostAndPort.getHost(), hostAndPort.getPort()); }; + private static final String trustStoreName = SSLOptionsJedisClusterTest.class.getSimpleName(); + private static Path trustStorePath; + + @BeforeClass + public static void prepare() { + List trustedCertLocation = Collections.singletonList(Paths.get("cluster-unbound/work/tls")); + trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + } + @Test public void testSSLDiscoverNodesAutomatically() { try (JedisCluster jc2 = new JedisCluster(new HostAndPort("localhost", 8379), DefaultJedisClientConfig.builder().password("cluster") .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks").build()) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { Map clusterNodes = jc2.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + /* + * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and non-TLS ports for CLUSTER SLOTS. + * When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns the regular (non-TLS) port rather than the TLS port. + */ + if (RedisVersionUtil.getRedisVersion(jc2.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { + assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + } else { + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); + } jc2.get("foo"); } } @@ -62,23 +86,34 @@ public void testSSLWithoutPortMap() { try (JedisCluster jc = new JedisCluster(Collections.singleton(new HostAndPort("localhost", 8379)), DefaultJedisClientConfig.builder().password("cluster") .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) - .trustStoreType("jceks").build()) + .truststore(trustStorePath.toFile()) + .trustStoreType("jceks") + .sslVerifyMode(SslVerifyMode.CA).build()) .build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { Map clusterNodes = jc.getClusterNodes(); assertEquals(3, clusterNodes.size()); - assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); - assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + /** + * In versions prior to Redis 7.x, Redis does not natively support automatic port switching between TLS and non-TLS ports for CLUSTER SLOTS. + * When using Redis 6.2.16 in a cluster mode with TLS, CLUSTER command returns the regular (non-TLS) port rather than the TLS port. + */ + if (RedisVersionUtil.getRedisVersion(jc.getConnectionFromSlot(0)).isLessThanOrEqualTo(RedisVersion.V7_0_0)) { + assertTrue(clusterNodes.containsKey("127.0.0.1:7379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:7381")); + } else { + assertTrue(clusterNodes.containsKey("127.0.0.1:8379")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8380")); + assertTrue(clusterNodes.containsKey("127.0.0.1:8381")); + } } } @Test public void connectByIpAddress() { - try (JedisCluster jc = new JedisCluster(new HostAndPort("127.0.0.1", 7379), + try (JedisCluster jc = new JedisCluster(new HostAndPort("127.0.0.1", 8379), DefaultJedisClientConfig.builder().password("cluster") .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks").build()) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { @@ -95,7 +130,7 @@ public void connectToNodesFailsWithSSLParametersAndNoHostMapping() { DefaultJedisClientConfig.builder().password("cluster") .sslOptions(SslOptions.builder() .sslParameters(sslParameters) - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks").build()) .hostAndPortMapper(portMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { @@ -117,7 +152,7 @@ public void connectToNodesSucceedsWithSSLParametersAndHostMapping() { DefaultJedisClientConfig.builder().password("cluster") .sslOptions(SslOptions.builder() .sslParameters(sslParameters) - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks").build()) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { @@ -134,7 +169,7 @@ public void connectByIpAddressFailsWithSSLParameters() { DefaultJedisClientConfig.builder().password("cluster") .sslOptions(SslOptions.builder() .sslParameters(sslParameters) - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks").build()) .hostAndPortMapper(hostAndPortMap).build(), DEFAULT_REDIRECTIONS, DEFAULT_POOL_CONFIG)) { @@ -145,11 +180,11 @@ public void connectByIpAddressFailsWithSSLParameters() { @Test public void connectWithCustomHostNameVerifier() { - HostnameVerifier hostnameVerifier = new BasicHostnameVerifier(); - HostnameVerifier localhostVerifier = new LocalhostVerifier(); + HostnameVerifier hostnameVerifier = new TlsUtil.BasicHostnameVerifier(); + HostnameVerifier localhostVerifier = new TlsUtil.LocalhostVerifier(); SslOptions sslOptions = SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .sslVerifyMode(SslVerifyMode.CA).build(); diff --git a/src/test/java/redis/clients/jedis/SSLOptionsJedisPooledTest.java b/src/test/java/redis/clients/jedis/SSLOptionsJedisPooledTest.java index 9aea9b945b..76065f0486 100644 --- a/src/test/java/redis/clients/jedis/SSLOptionsJedisPooledTest.java +++ b/src/test/java/redis/clients/jedis/SSLOptionsJedisPooledTest.java @@ -2,9 +2,13 @@ import static org.junit.Assert.assertEquals; -import java.io.File; - +import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.util.TlsUtil; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; public class SSLOptionsJedisPooledTest { @@ -12,12 +16,23 @@ public class SSLOptionsJedisPooledTest { protected static final EndpointConfig aclEndpoint = HostAndPorts.getRedisEndpoint("standalone0-acl-tls"); + private static final String trustStoreName = SSLACLJedisTest.class.getSimpleName(); + private static Path trustStorePath; + + @BeforeClass + public static void prepare() { + List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(), + aclEndpoint.getCertificatesLocation()); + trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation, + "changeit"); + } + @Test public void connectWithClientConfig() { try (JedisPooled jedis = new JedisPooled(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { assertEquals("PONG", jedis.ping()); @@ -41,7 +56,7 @@ public void connectWithSslContextProtocol() { endpoint.getClientConfigBuilder() .sslOptions(SslOptions.builder() .sslProtocol("SSL") - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { assertEquals("PONG", jedis.ping()); @@ -53,7 +68,7 @@ public void connectWithAcl() { try (JedisPooled jedis = new JedisPooled(aclEndpoint.getHostAndPort(), aclEndpoint.getClientConfigBuilder() .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { assertEquals("PONG", jedis.ping()); diff --git a/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java b/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java index 062ef49052..4552c3fd95 100644 --- a/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java +++ b/src/test/java/redis/clients/jedis/SSLOptionsJedisSentinelPoolTest.java @@ -1,11 +1,15 @@ package redis.clients.jedis; -import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.util.TlsUtil; public class SSLOptionsJedisSentinelPoolTest { @@ -18,8 +22,14 @@ public class SSLOptionsJedisSentinelPoolTest { private static final GenericObjectPoolConfig POOL_CONFIG = new GenericObjectPoolConfig<>(); + private static final String trustStoreName = SSLOptionsJedisSentinelPoolTest.class.getSimpleName(); + private static Path trustStorePath; + @BeforeClass public static void prepare() { + List trustedCertLocation = Collections.singletonList(Paths.get("redis9-sentinel/work/tls")); + trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + sentinels.add(HostAndPorts.getSentinelServers().get(4)); } @@ -29,7 +39,7 @@ public void sentinelWithoutSslConnectsToRedisWithSsl() { DefaultJedisClientConfig masterConfig = DefaultJedisClientConfig.builder() .user("acljedis").password("fizzbuzz").clientName("master-client") .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .sslVerifyMode(SslVerifyMode.CA).build()) .hostAndPortMapper(SSL_PORT_MAPPER).build(); @@ -56,7 +66,7 @@ public void sentinelWithSslConnectsToRedisWithoutSsl() { DefaultJedisClientConfig sentinelConfig = DefaultJedisClientConfig.builder() .user("sentinel").password("foobared").clientName("sentinel-client") .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .sslVerifyMode(SslVerifyMode.CA).build()) .hostAndPortMapper(SSL_PORT_MAPPER).build(); @@ -75,9 +85,9 @@ public void sentinelWithSslConnectsToRedisWithoutSsl() { public void sentinelWithSslConnectsToRedisWithSsl() { SslOptions sslOptions = SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) - .trustStoreType("jceks") - .sslVerifyMode(SslVerifyMode.CA).build(); + .truststore(trustStorePath.toFile()) + .trustStoreType("jceks") + .sslVerifyMode(SslVerifyMode.CA).build(); DefaultJedisClientConfig masterConfig = DefaultJedisClientConfig.builder() .user("acljedis").password("fizzbuzz").clientName("master-client").sslOptions(sslOptions) diff --git a/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java b/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java index cc0f7f598e..d336b3d41d 100644 --- a/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java +++ b/src/test/java/redis/clients/jedis/SSLOptionsJedisTest.java @@ -2,9 +2,13 @@ import static org.junit.Assert.assertEquals; -import java.io.File; - +import org.junit.BeforeClass; import org.junit.Test; +import redis.clients.jedis.util.TlsUtil; + +import java.nio.file.Path; +import java.util.Arrays; +import java.util.List; public class SSLOptionsJedisTest { @@ -12,12 +16,20 @@ public class SSLOptionsJedisTest { protected static final EndpointConfig aclEndpoint = HostAndPorts.getRedisEndpoint("standalone0-acl-tls"); + private static final String trustStoreName = SSLOptionsJedisTest.class.getSimpleName(); + private static Path trustStorePath; + @BeforeClass + public static void prepare() { + List trustedCertLocation = Arrays.asList(endpoint.getCertificatesLocation(),aclEndpoint.getCertificatesLocation()); + trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + } + @Test public void connectWithSsl() { try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), DefaultJedisClientConfig.builder() .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { jedis.auth(endpoint.getPassword()); @@ -30,7 +42,7 @@ public void connectWithClientConfig() { try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder() .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { assertEquals("PONG", jedis.ping()); @@ -54,7 +66,7 @@ public void connectWithSslContextProtocol() { endpoint.getClientConfigBuilder() .sslOptions(SslOptions.builder() .sslProtocol("SSL") - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { assertEquals("PONG", jedis.ping()); @@ -66,7 +78,7 @@ public void connectWithAcl() { try (Jedis jedis = new Jedis(aclEndpoint.getHostAndPort(), aclEndpoint.getClientConfigBuilder() .sslOptions(SslOptions.builder() - .truststore(new File("src/test/resources/truststore.jceks")) + .truststore(trustStorePath.toFile()) .trustStoreType("jceks") .build()).build())) { assertEquals("PONG", jedis.ping()); diff --git a/src/test/java/redis/clients/jedis/UdsTest.java b/src/test/java/redis/clients/jedis/UdsTest.java index e29c65dedd..a79529d990 100644 --- a/src/test/java/redis/clients/jedis/UdsTest.java +++ b/src/test/java/redis/clients/jedis/UdsTest.java @@ -3,15 +3,24 @@ import java.io.File; import java.io.IOException; import java.net.Socket; + +import org.junit.Assume; +import org.junit.BeforeClass; import org.junit.Test; import org.newsclub.net.unix.AFUNIXSocket; import org.newsclub.net.unix.AFUNIXSocketAddress; import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.util.TestEnvUtil; import static org.junit.Assert.assertEquals; public class UdsTest { + @BeforeClass + public static void checkDockerEnvironment() { + Assume.assumeFalse("Unix sockets tests not supported against dockerised test env yet!", TestEnvUtil.isContainerEnv()); + } + @Test public void jedisConnectsToUds() { try (Jedis jedis = new Jedis(new UdsJedisSocketFactory())) { diff --git a/src/test/java/redis/clients/jedis/authentication/TokenBasedAuthenticationUnitTests.java b/src/test/java/redis/clients/jedis/authentication/TokenBasedAuthenticationUnitTests.java index 802dda2b86..d3f02fb2c8 100644 --- a/src/test/java/redis/clients/jedis/authentication/TokenBasedAuthenticationUnitTests.java +++ b/src/test/java/redis/clients/jedis/authentication/TokenBasedAuthenticationUnitTests.java @@ -39,7 +39,7 @@ public class TokenBasedAuthenticationUnitTests { private HostAndPort hnp = new HostAndPort("localhost", 6379); - private EndpointConfig endpoint = new EndpointConfig(hnp, null, null, false); + private EndpointConfig endpoint = new EndpointConfig(hnp, null, null, false, null); @Test public void testJedisAuthXManagerInstance() { diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java index 5427447100..3c511fa823 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsBitmapCommandsTest.java @@ -6,6 +6,7 @@ import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.BitCountOption; @@ -52,6 +53,7 @@ public void testSetbitAndGetbitBinary() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Starting with Redis version 7.0.0: Added the BYTE|BIT option.") public void testBitcount() { String key = "bitcountKey"; byte[] keyBytes = key.getBytes(); @@ -82,6 +84,7 @@ public void testBitcount() { } @Test + @SinceRedisVersion(value = "7.0.0", message="Starting with Redis version 7.0.0: Added the BYTE|BIT option.") public void testBitpos() { String key = "bitposKey"; byte[] keyBytes = key.getBytes(); diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java index f558a4f686..d9072d9736 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsGenericCommandsTest.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.RedisProtocol; @@ -202,6 +203,7 @@ public void testDumpAndRestoreBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireAndExpireTime() { String key = "expireKey"; String value = "value"; @@ -221,6 +223,7 @@ public void testExpireAndExpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireAndExpireTimeBinary() { byte[] key = "expireKey".getBytes(); byte[] value = "value".getBytes(); @@ -240,6 +243,7 @@ public void testExpireAndExpireTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireWithExpiryOption() { String key = "expireWithOptionKey"; String value = "value"; @@ -263,6 +267,7 @@ public void testExpireWithExpiryOption() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireWithExpiryOptionTimeBinary() { byte[] key = "expireWithOptionKey".getBytes(); byte[] value = "value".getBytes(); @@ -286,6 +291,7 @@ public void testExpireWithExpiryOptionTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testPexpireAndPexpireTime() { String key = "pexpireKey"; String value = "value"; @@ -305,6 +311,7 @@ public void testPexpireAndPexpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testPexpireAndPexpireTimeBinary() { byte[] key = "pexpireKey".getBytes(); byte[] value = "value".getBytes(); @@ -324,6 +331,7 @@ public void testPexpireAndPexpireTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testPexpireWithOptionsAndPexpireTime() { String key = "pexpireWithOptionsKey"; String value = "value"; @@ -349,6 +357,7 @@ public void testPexpireWithOptionsAndPexpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void testPexpireWithOptionsAndPexpireTimeBinary() { byte[] key = "pexpireWithOptionsKey".getBytes(); byte[] value = "value".getBytes(); @@ -374,6 +383,7 @@ public void testPexpireWithOptionsAndPexpireTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireAtAndExpireTime() { String key = "expireAtKey"; String value = "value"; @@ -399,6 +409,7 @@ public void testExpireAtAndExpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireAtAndExpireTimeBinary() { byte[] key = "expireAtKey".getBytes(); byte[] value = "value".getBytes(); @@ -424,6 +435,7 @@ public void testExpireAtAndExpireTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireAtWithOptionsAndExpireTime() { String key = "expireAtWithOptionsKey"; String value = "value"; @@ -456,6 +468,7 @@ public void testExpireAtWithOptionsAndExpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testExpireAtWithOptionsAndExpireTimeBinary() { byte[] key = "expireAtWithOptionsKey".getBytes(); byte[] value = "value".getBytes(); @@ -488,6 +501,7 @@ public void testExpireAtWithOptionsAndExpireTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testPexpireAtAndPexpireTime() { String key = "pexpireAtKey"; String value = "value"; @@ -512,6 +526,7 @@ public void testPexpireAtAndPexpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testPexpireAtAndPexpireTimeBinary() { byte[] key = "pexpireAtKey".getBytes(); byte[] value = "value".getBytes(); @@ -536,6 +551,7 @@ public void testPexpireAtAndPexpireTimeBinary() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void testPexpireAtWithOptionsAndPexpireTime() { String key = "pexpireAtWithOptionsKey"; String value = "value"; @@ -568,6 +584,7 @@ public void testPexpireAtWithOptionsAndPexpireTime() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testPexpireAtWithOptionsAndPexpireTimeBinary() { byte[] key = "pexpireAtWithOptionsKey".getBytes(); byte[] value = "value".getBytes(); @@ -812,6 +829,7 @@ public void testSortWithParamsAndStoreBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testSortReadonly() { String listKey = "readonlySortList"; @@ -824,6 +842,7 @@ public void testSortReadonly() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testSortReadonlyBinary() { byte[] listKey = "readonlySortList".getBytes(); diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java index a8de3122ab..73013bb24e 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsHashCommandsTest.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.ExpiryOption; @@ -351,6 +352,7 @@ public void testHashRandfield() { } @Test + @SinceRedisVersion("7.4.0") public void testHscan() { String key = "testHashScan"; byte[] bkey = key.getBytes(); @@ -416,6 +418,7 @@ public void testHashStrlen() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAndHttl() { long seconds1 = 20; long seconds2 = 10; @@ -433,6 +436,7 @@ public void hexpireAndHttl() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAndHttlBinary() { long seconds1 = 20; long seconds2 = 10; @@ -450,6 +454,7 @@ public void hexpireAndHttlBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAndHpttl() { long millis1 = 20_000; long millis2 = 10_000; @@ -465,6 +470,7 @@ public void hpexpireAndHpttl() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAndHpttlBinary() { long millis1 = 20_000; long millis2 = 10_000; @@ -480,6 +486,7 @@ public void hpexpireAndHpttlBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAtAndExpireTime() { long currSeconds = System.currentTimeMillis() / 1000; long seconds1 = currSeconds + 20; @@ -498,6 +505,7 @@ public void hexpireAtAndExpireTime() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAtAndExpireTimeBinary() { long currSeconds = System.currentTimeMillis() / 1000; long seconds1 = currSeconds + 20; @@ -516,6 +524,7 @@ public void hexpireAtAndExpireTimeBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAtAndPexpireTime() { long currMillis = System.currentTimeMillis(); long unixMillis = currMillis + 20_000; @@ -531,6 +540,7 @@ public void hpexpireAtAndPexpireTime() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAtAndPexpireTimeBinary() { long currMillis = System.currentTimeMillis(); long unixMillis = currMillis + 20_000; @@ -546,6 +556,7 @@ public void hpexpireAtAndPexpireTimeBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpersist() { long seconds = 20; @@ -560,6 +571,7 @@ public void hpersist() { } @Test + @SinceRedisVersion("7.4.0") public void hpersistBinary() { long seconds = 20; diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java index c7f84157d1..9ea0c1534f 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsListCommandsTest.java @@ -9,6 +9,7 @@ import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.ListDirection; @@ -608,6 +609,7 @@ public void testLmoveAndBlmoveBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testLmpopAndBlmpop() { String key1 = "list1"; String key2 = "list2"; @@ -635,6 +637,7 @@ public void testLmpopAndBlmpop() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testLmpopAndBlmpopBinary() { byte[] key1 = "list1".getBytes(); byte[] key2 = "list2".getBytes(); diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java index 7b6c1feae9..e1a808e18c 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsScriptingCommandsTest.java @@ -18,6 +18,9 @@ import java.util.List; import java.util.Map; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; +import org.junit.Before; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.FlushMode; @@ -25,6 +28,7 @@ import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.resps.FunctionStats; import redis.clients.jedis.resps.LibraryInfo; +import redis.clients.jedis.util.RedisVersionUtil; /** * Tests related to Scripting commands. @@ -35,6 +39,15 @@ public CommandObjectsScriptingCommandsTest(RedisProtocol protocol) { super(protocol); } + @Before + @Override + public void setUp() { + super.setUp(); + if (RedisVersionUtil.getRedisVersion(endpoint).isGreaterThanOrEqualTo(RedisVersion.V7_0_0)) { + assertThat(exec(commandObjects.functionFlush(FlushMode.SYNC)), equalTo("OK")); + } + } + @Test public void testEvalWithOnlyScript() { String set = exec(commandObjects.set("foo", "bar")); @@ -146,6 +159,7 @@ public void testEvalWithScriptKeysAndArgsList() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testEvalReadonlyWithScriptKeysAndArgsList() { exec(commandObjects.set("readonlyKey1", "readonlyValue1")); exec(commandObjects.set("readonlyKey2", "readonlyValue2")); @@ -282,6 +296,7 @@ public void testEvalWithScriptKeysAndArgsListSha() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testEvalReadonlyWithScriptKeysAndArgsListSha() { exec(commandObjects.set("readonlyKey1", "readonlyValue1")); exec(commandObjects.set("readonlyKey2", "readonlyValue2")); @@ -468,6 +483,7 @@ public void testScriptKill() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testSumValuesFunction() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args)\n" + @@ -517,6 +533,7 @@ public void testSumValuesFunction() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testSumValuesFunctionReadonly() { String luaScript = "#!lua name=mylib\n" + "redis.register_function{function_name='sumValues', callback=function(keys, args)\n" + @@ -550,6 +567,7 @@ public void testSumValuesFunctionReadonly() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionDeletion() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args) return 42 end)"; @@ -572,6 +590,7 @@ public void testFunctionDeletion() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionDeletionBinary() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args) return 42 end)"; @@ -594,6 +613,7 @@ public void testFunctionDeletionBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionListing() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args) return 42 end)"; @@ -651,6 +671,7 @@ public void testFunctionListing() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionReload() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('dummy', function(keys, args) return 42 end)"; @@ -672,6 +693,7 @@ public void testFunctionReload() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionReloadBinary() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('dummy', function(keys, args) return 42 end)"; @@ -693,6 +715,7 @@ public void testFunctionReloadBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionStats() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('dummy', function(keys, args) return 42 end)"; @@ -719,6 +742,7 @@ public void testFunctionStats() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionDumpFlushRestore() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args) return 42 end)"; @@ -752,6 +776,7 @@ public void testFunctionDumpFlushRestore() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionDumpFlushRestoreWithPolicy() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args) return 42 end)"; @@ -785,6 +810,7 @@ public void testFunctionDumpFlushRestoreWithPolicy() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionFlushWithMode() { String luaScript = "#!lua name=mylib\n" + "redis.register_function('sumValues', function(keys, args) return 42 end)"; @@ -807,6 +833,7 @@ public void testFunctionFlushWithMode() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testFunctionKill() { JedisException e = assertThrows(JedisException.class, () -> exec(commandObjects.functionKill())); diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java index 6a6874ef4d..84c82ac78f 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSetCommandsTest.java @@ -13,6 +13,7 @@ import java.util.List; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.params.ScanParams; @@ -228,6 +229,7 @@ public void testSdiffstoreBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testSinterAndSinterCard() { String key1 = "testSetInter1"; String key2 = "testSetInter2"; diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java index 21a573c8db..292ed25572 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsSortedSetCommandsTest.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.Map; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.SortedSetOption; @@ -328,6 +329,7 @@ public void testZrankAndZrevrank() { } @Test + @SinceRedisVersion(value = "7.2.0") public void testZrankWithScoreAndZrevrankWithScore() { String key = "zset"; String member1 = "one"; @@ -1198,6 +1200,7 @@ public void testZdiffStoreBinary() { } @Test + @SinceRedisVersion(value = "7.2.0") public void testZinterAndZintercard() { ZParams params = new ZParams().aggregate(ZParams.Aggregate.SUM).weights(1, 2); @@ -1419,6 +1422,7 @@ public void testZunionstoreBinary() { } @Test + @SinceRedisVersion(value = "7.2.0") public void testZmpopAndZmpopWithCount() { String key1 = "sortedSet1"; String key2 = "sortedSet2"; @@ -1444,6 +1448,7 @@ public void testZmpopAndZmpopWithCount() { } @Test + @SinceRedisVersion(value = "7.2.0") public void testZmpopAndZmpopWithCountBinary() { byte[] key1 = "sortedSet1".getBytes(); byte[] key2 = "sortedSet2".getBytes(); @@ -1469,6 +1474,7 @@ public void testZmpopAndZmpopWithCountBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testBzmpop() { String key1 = "sortedSet1"; String key2 = "sortedSet2"; @@ -1496,6 +1502,7 @@ public void testBzmpop() { } @Test + @SinceRedisVersion(value = "7.2.0") public void testBzmpopBinary() { byte[] key1 = "sortedSet1".getBytes(); byte[] key2 = "sortedSet2".getBytes(); @@ -1523,6 +1530,7 @@ public void testBzmpopBinary() { } @Test + @SinceRedisVersion(value = "7.2.0") public void testBzmpopCount() { String key1 = "sortedSet1"; String key2 = "sortedSet2"; @@ -1542,6 +1550,7 @@ public void testBzmpopCount() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testBzmpopCountBinary() { byte[] key1 = "sortedSet1".getBytes(); byte[] key2 = "sortedSet2".getBytes(); diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java index 128642d2a7..707db79bb2 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStandaloneTestBase.java @@ -1,5 +1,8 @@ package redis.clients.jedis.commands.commandobjects; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; +import org.junit.Rule; import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; @@ -8,6 +11,11 @@ */ public abstract class CommandObjectsStandaloneTestBase extends CommandObjectsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(endpoint); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(endpoint); + public CommandObjectsStandaloneTestBase(RedisProtocol protocol) { super(protocol, HostAndPorts.getRedisEndpoint("standalone0")); } diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java index 9a35cd88e4..a192a462d9 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsStringCommandsTest.java @@ -10,6 +10,7 @@ import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.params.GetExParams; @@ -298,6 +299,7 @@ public void testIncrementOperationsBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testLcs() { String keyA = "keyA"; String keyB = "keyB"; @@ -338,6 +340,7 @@ public void testLcs() { } @Test + @SinceRedisVersion(value = "7.0.0") public void testLcsBinary() { byte[] keyA = "keyA".getBytes(); byte[] keyB = "keyB".getBytes(); diff --git a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java index 45e0c71ad4..d0501d533c 100644 --- a/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/commandobjects/CommandObjectsTestBase.java @@ -9,7 +9,6 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.*; -import redis.clients.jedis.args.FlushMode; import redis.clients.jedis.commands.CommandsTestsParameters; import redis.clients.jedis.executors.CommandExecutor; import redis.clients.jedis.executors.DefaultCommandExecutor; @@ -80,13 +79,7 @@ public void setUp() { commandExecutor = new DefaultCommandExecutor(connectionProvider); // Cleanup before each test. - assertThat( - commandExecutor.executeCommand(commandObjects.flushAll()), - equalTo("OK")); - - assertThat( - commandExecutor.executeCommand(commandObjects.functionFlush(FlushMode.SYNC)), - equalTo("OK")); + assertThat(exec(commandObjects.flushAll()), equalTo("OK")); } /** diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java index 150211383e..d0059a61a3 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AccessControlListCommandsTest.java @@ -11,9 +11,13 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static redis.clients.jedis.util.RedisVersionUtil.getRedisVersion; import java.util.Arrays; import java.util.List; + +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.hamcrest.Matchers; import org.junit.After; import org.junit.BeforeClass; @@ -30,7 +34,6 @@ import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.resps.AccessControlLogEntry; import redis.clients.jedis.resps.AccessControlUser; -import redis.clients.jedis.util.RedisVersionUtil; import redis.clients.jedis.util.SafeEncoder; /** @@ -41,12 +44,13 @@ public class AccessControlListCommandsTest extends JedisCommandsTestBase { public static final String USER_NAME = "newuser"; public static final String USER_PASSWORD = "secret"; + public static final String USER_ANTIREZ = "antirez"; @BeforeClass public static void prepare() throws Exception { // Use to check if the ACL test should be ran. ACL are available only in 6.0 and later org.junit.Assume.assumeTrue("Not running ACL test on this version of Redis", - RedisVersionUtil.checkRedisMajorVersionNumber(6, endpoint)); + getRedisVersion(endpoint).isGreaterThanOrEqualTo(RedisVersion.V6_0_0)); } public AccessControlListCommandsTest(RedisProtocol protocol) { @@ -58,6 +62,7 @@ public AccessControlListCommandsTest(RedisProtocol protocol) { public void tearDown() throws Exception { try { jedis.aclDelUser(USER_NAME); + jedis.aclDelUser(USER_ANTIREZ); } catch (Exception e) { } super.tearDown(); } @@ -95,13 +100,15 @@ public void addAndRemoveUser() { @Test public void aclUsers() { List users = jedis.aclUsers(); - assertEquals(2, users.size()); + assertEquals(3, users.size()); assertThat(users, Matchers.hasItem("default")); - - assertEquals(2, jedis.aclUsersBinary().size()); // Test binary + assertThat(users, Matchers.hasItem("deploy")); + assertThat(users, Matchers.hasItem("acljedis")); + assertEquals(3, jedis.aclUsersBinary().size()); // Test binary } @Test + @SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x misses [~]>") public void aclGetUser() { // get default user information AccessControlUser userInfo = jedis.aclGetUser("default"); @@ -219,13 +226,14 @@ public void aclExcudeSingleCommand() { fail("Should throw a NOPERM exception"); } catch (JedisAccessControlException e) { assertThat(e.getMessage(), startsWith("NOPERM ")); - assertThat(e.getMessage(), endsWith(" has no permissions to run the 'ping' command")); + assertThat(e.getMessage(), containsString(" has no permissions to run the 'ping' command")); } jedis2.close(); } @Test + @SinceRedisVersion("7.0.0") public void aclDryRun() { jedis.aclSetUser(USER_NAME, "nopass", "allkeys", "+set", "-get"); @@ -240,6 +248,7 @@ public void aclDryRun() { } @Test + @SinceRedisVersion("7.0.0") public void aclDryRunBinary() { byte[] username = USER_NAME.getBytes(); @@ -284,7 +293,7 @@ public void basicPermissionsTest() { fail("Should throw a NOPERM exception"); } catch (JedisAccessControlException e) { assertThat(e.getMessage(), startsWith("NOPERM ")); - assertThat(e.getMessage(), endsWith(" has no permissions to run the 'set' command")); + assertThat(e.getMessage(), containsString(" has no permissions to run the 'set' command")); } // change permissions of the user @@ -305,7 +314,7 @@ public void basicPermissionsTest() { } // allow user to access a subset of the key - jedis.aclSetUser(USER_NAME, "allcommands", "~foo:*", "~bar:*"); // TODO : Define a DSL + jedis.aclSetUser(USER_NAME, "allcommands", "~foo:*", "~bar:*"); // TODO : a DSL // create key foo, bar and zap jedis2.set("foo:1", "a"); @@ -347,9 +356,9 @@ public void aclLogTest() { assertTrue(jedis.aclLog().isEmpty()); // create new user and cconnect - jedis.aclSetUser("antirez", ">foo", "on", "+set", "~object:1234"); - jedis.aclSetUser("antirez", "+eval", "+multi", "+exec"); - jedis.auth("antirez", "foo"); + jedis.aclSetUser(USER_ANTIREZ, ">foo", "on", "+set", "~object:1234"); + jedis.aclSetUser(USER_ANTIREZ, "+eval", "+multi", "+exec"); + jedis.auth(USER_ANTIREZ, "foo"); // generate an error (antirez user does not have the permission to access foo) try { @@ -364,7 +373,7 @@ public void aclLogTest() { List aclEntries = jedis.aclLog(); assertEquals("Number of log messages ", 1, aclEntries.size()); assertEquals(1, aclEntries.get(0).getCount()); - assertEquals("antirez", aclEntries.get(0).getUsername()); + assertEquals(USER_ANTIREZ, aclEntries.get(0).getUsername()); assertEquals("toplevel", aclEntries.get(0).getContext()); assertEquals("command", aclEntries.get(0).getReason()); assertEquals("get", aclEntries.get(0).getObject()); @@ -373,7 +382,7 @@ public void aclLogTest() { jedis.aclLogReset(); assertTrue(jedis.aclLog().isEmpty()); - jedis.auth("antirez", "foo"); + jedis.auth(USER_ANTIREZ, "foo"); for (int i = 0; i < 10; i++) { // generate an error (antirez user does not have the permission to access foo) @@ -391,7 +400,7 @@ public void aclLogTest() { assertEquals("get", jedis.aclLog().get(0).getObject()); // Generate another type of error - jedis.auth("antirez", "foo"); + jedis.auth(USER_ANTIREZ, "foo"); try { jedis.set("somekeynotallowed", "1234"); fail("Should have thrown an JedisAccessControlException: user does not have the permission to set(\"somekeynotallowed\", \"1234\")"); @@ -408,7 +417,7 @@ public void aclLogTest() { jedis.aclLogReset(); assertTrue(jedis.aclLog().isEmpty()); - jedis.auth("antirez", "foo"); + jedis.auth(USER_ANTIREZ, "foo"); Transaction t = jedis.multi(); t.incr("foo"); try { @@ -425,7 +434,7 @@ public void aclLogTest() { assertEquals("incr", jedis.aclLog().get(0).getObject()); // ACL LOG can accept a numerical argument to show less entries - jedis.auth("antirez", "foo"); + jedis.auth(USER_ANTIREZ, "foo"); for (int i = 0; i < 5; i++) { try { jedis.incr("foo"); @@ -451,10 +460,11 @@ public void aclLogTest() { String status = jedis.aclLogReset(); assertEquals(status, "OK"); - jedis.aclDelUser("antirez"); + jedis.aclDelUser(USER_ANTIREZ); } @Test + @SinceRedisVersion(value = "7.2.0", message = "Starting with Redis version 7.2.0: Added entry ID, timestamp created, and timestamp last updated.") public void aclLogWithEntryID() { try { jedis.auth("wronguser", "wrongpass"); @@ -497,6 +507,7 @@ public void aclGenPassBinary() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Redis 6.2.x skips [&]>") public void aclBinaryCommandsTest() { jedis.aclSetUser(USER_NAME.getBytes()); assertNotNull(jedis.aclGetUser(USER_NAME)); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java index 868195961e..be3d7e09ba 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/AllKindOfValuesCommandsTest.java @@ -14,9 +14,13 @@ import static redis.clients.jedis.params.ScanParams.SCAN_POINTER_START; import static redis.clients.jedis.params.ScanParams.SCAN_POINTER_START_BINARY; +import java.time.Duration; import java.util.*; + +import io.redis.test.annotations.SinceRedisVersion; import org.hamcrest.Matchers; import org.junit.Assume; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -35,6 +39,9 @@ @RunWith(Parameterized.class) public class AllKindOfValuesCommandsTest extends JedisCommandsTestBase { + + private static final long TIME_SKEW = Duration.ofMillis(5).toMillis(); + final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; final byte[] bfoo1 = { 0x01, 0x02, 0x03, 0x04, 0x0A }; final byte[] bfoo2 = { 0x01, 0x02, 0x03, 0x04, 0x0B }; @@ -305,6 +312,7 @@ public void dbSize() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void expire() { assertEquals(0, jedis.expire("foo", 20L)); @@ -321,6 +329,7 @@ public void expire() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void expireAt() { long unixTime = (System.currentTimeMillis() / 1000L) + 20; @@ -341,6 +350,7 @@ public void expireAt() { } @Test + @SinceRedisVersion(value = "7.0.0") public void expireTime() { long unixTime; @@ -597,6 +607,7 @@ public void dumpAndRestore() { } @Test + @Ignore(value = "TODO: Regression in 8.0-M02 discarding restore idle time.") public void restoreParams() { // take a separate instance Jedis jedis2 = new Jedis(endpoint.getHost(), endpoint.getPort(), 500); @@ -626,7 +637,8 @@ public void restoreParams() { assertTrue(jedis2.pttl("foo") <= 1000); jedis2.restore("bar", System.currentTimeMillis() + 1000, serialized, RestoreParams.restoreParams().replace().absTtl()); - assertTrue(jedis2.pttl("bar") <= 1000); + assertThat(jedis2.pttl("bar"), Matchers.lessThanOrEqualTo(1000l + TIME_SKEW)); + jedis2.restore("bar1", 1000, serialized, RestoreParams.restoreParams().replace().idleTime(1000)); assertEquals(1000, jedis2.objectIdletime("bar1").longValue()); @@ -639,6 +651,7 @@ public void restoreParams() { } @Test + @SinceRedisVersion(value = "7.0.0") public void pexpire() { assertEquals(0, jedis.pexpire("foo", 10000)); @@ -680,6 +693,7 @@ public void pexpireAt() { } @Test + @SinceRedisVersion(value = "7.0.0") public void pexpireTime() { long unixTime = (System.currentTimeMillis()) + 10000; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/BitCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/BitCommandsTest.java index 01cc61b3c9..d74c848081 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/BitCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/BitCommandsTest.java @@ -7,6 +7,8 @@ import static org.junit.Assert.fail; import java.util.List; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -146,6 +148,7 @@ public void bitposWithNoMatchingBitExistWithinRange() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "7.0.0 Added the BYTE|BIT option.") public void bitposModifier() { jedis.set("mykey", "\\x00\\xff\\xf0"); assertEquals(0, jedis.bitpos("mykey", false)); @@ -160,6 +163,7 @@ public void bitposModifier() { } @Test + @SinceRedisVersion("7.0.0") public void setAndgetrange() { jedis.set("key1", "Hello World"); assertEquals(11, jedis.setrange("key1", 6, "Jedis")); @@ -182,6 +186,15 @@ public void bitCount() { assertEquals(3, (long) jedis.bitcount("foo", 2L, 5L)); assertEquals(3, (long) jedis.bitcount("foo".getBytes(), 2L, 5L)); + } + + @Test + @SinceRedisVersion("7.0.0") + public void bitCountModifier() { + jedis.setbit("foo", 16, true); + jedis.setbit("foo", 24, true); + jedis.setbit("foo", 40, true); + jedis.setbit("foo", 56, true); assertEquals(3, (long) jedis.bitcount("foo", 2L, 5L, BitCountOption.BYTE)); assertEquals(3, (long) jedis.bitcount("foo".getBytes(), 2L, 5L, BitCountOption.BYTE)); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java index 1b221cfc55..181ec65da3 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClientCommandsTest.java @@ -15,6 +15,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -38,6 +39,7 @@ public class ClientCommandsTest extends JedisCommandsTestBase { private Jedis client; + public ClientCommandsTest(RedisProtocol protocol) { super(protocol); } @@ -73,6 +75,7 @@ public void nameBinary() { } @Test + @SinceRedisVersion("7.2.0") public void clientSetInfoCommand() { String libName = "Jedis::A-Redis-Java-library"; String libVersion = "999.999.999"; @@ -243,6 +246,7 @@ public void killUser() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "MAXAGE (since Redis 7.4)") public void killMaxAge() throws InterruptedException { long maxAge = 2; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java index 7e5c5db875..adae4b9c2b 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClusterCommandsTest.java @@ -9,14 +9,12 @@ import java.util.List; import java.util.Map; +import io.redis.test.annotations.SinceRedisVersion; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.*; +import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.args.ClusterResetType; @@ -26,6 +24,7 @@ import redis.clients.jedis.resps.ClusterShardNodeInfo; import redis.clients.jedis.util.JedisClusterCRC16; import redis.clients.jedis.util.JedisClusterTestUtil; +import redis.clients.jedis.util.RedisVersionRule; public class ClusterCommandsTest { @@ -35,6 +34,10 @@ public class ClusterCommandsTest { private static HostAndPort nodeInfo1 = HostAndPorts.getClusterServers().get(0); private static HostAndPort nodeInfo2 = HostAndPorts.getClusterServers().get(1); + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(nodeInfo1, + DefaultJedisClientConfig.builder().password("cluster").build()); + @Before public void setUp() throws Exception { node1 = new Jedis(nodeInfo1); @@ -124,6 +127,7 @@ public void clusterInfo() { } @Test + @SinceRedisVersion("7.0.0") public void addAndDelSlotsRange() { // test add assertEquals("OK", node1.clusterAddSlotsRange(100, 105)); @@ -203,6 +207,7 @@ public void clusterSlots() { } @Test + @SinceRedisVersion("7.0.0") public void clusterShards() { assertEquals("OK", node1.clusterAddSlots(3100, 3101, 3102, 3105)); @@ -224,7 +229,7 @@ public void clusterShards() { assertNotNull(nodeInfo.getIp()); assertNull(nodeInfo.getHostname()); assertNotNull(nodeInfo.getPort()); - assertNull(nodeInfo.getTlsPort()); + assertNotNull(nodeInfo.getTlsPort()); // currently we are always starting Redis server with `tls-port` assertNotNull(nodeInfo.getRole()); assertNotNull(nodeInfo.getReplicationOffset()); assertNotNull(nodeInfo.getHealth()); @@ -234,6 +239,7 @@ public void clusterShards() { } @Test + @SinceRedisVersion("7.0.0") public void clusterLinks() throws InterruptedException { List> links = node1.clusterLinks(); assertNotNull(links); @@ -264,6 +270,7 @@ public void clusterMyId() { } @Test + @SinceRedisVersion("7.2.0") public void clusterMyShardId() { MatcherAssert.assertThat(node1.clusterMyShardId(), Matchers.not(Matchers.isEmptyOrNullString())); } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClusterJedisCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/jedis/ClusterJedisCommandsTestBase.java index 8cd4b8379d..9db81d5651 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClusterJedisCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClusterJedisCommandsTestBase.java @@ -8,12 +8,16 @@ import org.junit.After; import org.junit.AfterClass; import org.junit.Before; +import org.junit.Rule; +import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.util.EnabledOnCommandRule; import redis.clients.jedis.util.JedisClusterCRC16; +import redis.clients.jedis.util.RedisVersionRule; public abstract class ClusterJedisCommandsTestBase { @@ -27,6 +31,11 @@ public abstract class ClusterJedisCommandsTestBase { private final Set jedisClusterNode = new HashSet<>(); JedisCluster cluster; + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(nodeInfo1, DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(nodeInfo1, DefaultJedisClientConfig.builder().password("cluster").build()); + @Before public void setUp() throws InterruptedException { node1 = new Jedis(nodeInfo1); @@ -53,7 +62,6 @@ public void setUp() throws InterruptedException { int[] node1Slots = new int[slotsPerNode]; int[] node2Slots = new int[slotsPerNode + 1]; int[] node3Slots = new int[slotsPerNode]; -// for (int i = 0, slot1 = 0, slot2 = 0, slot3 = 0; i < JedisCluster.HASHSLOTS; i++) { for (int i = 0, slot1 = 0, slot2 = 0, slot3 = 0; i < CLUSTER_HASHSLOTS; i++) { if (i < slotsPerNode) { node1Slots[slot1++] = i; @@ -71,28 +79,25 @@ public void setUp() throws InterruptedException { waitForClusterReady(); jedisClusterNode.add(new HostAndPort("127.0.0.1", 7379)); -// cluster = new JedisCluster(jedisClusterNode, 2000, 2000, 5, "cluster", new JedisPoolConfig()); -// cluster = new JedisCluster(jedisClusterNode, DefaultJedisClientConfig.builder().password("cluster").build(), 5); cluster = new JedisCluster(jedisClusterNode, null, "cluster"); - } @AfterClass public static void cleanUp() { int slotTest = JedisClusterCRC16.getSlot("test"); int slot51 = JedisClusterCRC16.getSlot("51"); - String node3Id = getNodeId(node3.clusterNodes()); - node2.clusterSetSlotNode(slotTest, node3Id); - node2.clusterSetSlotNode(slot51, node3Id); - node2.clusterDelSlots(slotTest, slot51); + if (node3 != null) { + String node3Id = getNodeId(node3.clusterNodes()); + node2.clusterSetSlotNode(slotTest, node3Id); + node2.clusterSetSlotNode(slot51, node3Id); + node2.clusterDelSlots(slotTest, slot51); + } } @After public void tearDown() { // clear all slots -// int[] slotsToDelete = new int[JedisCluster.HASHSLOTS]; int[] slotsToDelete = new int[CLUSTER_HASHSLOTS]; -// for (int i = 0; i < JedisCluster.HASHSLOTS; i++) { for (int i = 0; i < CLUSTER_HASHSLOTS; i++) { slotsToDelete[i] = i; } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java index 503337683e..bb5e4c4688 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClusterScriptingCommandsTest.java @@ -10,6 +10,8 @@ import java.util.Collections; import java.util.List; import java.util.Map; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.HostAndPort; @@ -115,6 +117,7 @@ public void broadcast() { } @Test + @SinceRedisVersion("7.0.0") public void broadcastWithError() { JedisBroadcastException error = assertThrows(JedisBroadcastException.class, () -> cluster.functionDelete("xyz")); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ClusterShardedPublishSubscribeCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ClusterShardedPublishSubscribeCommandsTest.java index 65d36fd5df..4eba70413c 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ClusterShardedPublishSubscribeCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ClusterShardedPublishSubscribeCommandsTest.java @@ -7,6 +7,8 @@ import java.util.HashMap; import java.util.Map; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.BinaryJedisShardedPubSub; @@ -16,6 +18,7 @@ import redis.clients.jedis.util.JedisClusterCRC16; import redis.clients.jedis.util.SafeEncoder; +@SinceRedisVersion(value = "7.0.0", message = "Sharded Pub/Sub") public class ClusterShardedPublishSubscribeCommandsTest extends ClusterJedisCommandsTestBase { private void publishOne(final String channel, final String message) { diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java index d79eb2086f..a90699f19d 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ControlCommandsTest.java @@ -21,6 +21,7 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import io.redis.test.annotations.SinceRedisVersion; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Test; @@ -253,6 +254,7 @@ public void configSetBinary() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Starting with Redis version 7.0.0: Added the ability to pass multiple pattern parameters in one call") public void configGetSetMulti() { String[] params = new String[]{"hash-max-listpack-entries", "set-max-intset-entries", "zset-max-listpack-entries"}; Map info = jedis.configGet(params); @@ -272,6 +274,7 @@ public void waitReplicas() { } @Test + @SinceRedisVersion("7.2.0") public void waitAof() { assertEquals(KeyValue.of(0L, 0L), jedis.waitAOF(0L, 0L, 100L)); } @@ -379,12 +382,14 @@ public void clientUnpause() { } @Test + @SinceRedisVersion("7.0.0") public void clientNoEvict() { assertEquals("OK", jedis.clientNoEvictOn()); assertEquals("OK", jedis.clientNoEvictOff()); } @Test + @SinceRedisVersion("7.2.0") public void clientNoTouch() { assertEquals("OK", jedis.clientNoTouchOn()); assertEquals("OK", jedis.clientNoTouchOff()); @@ -475,6 +480,7 @@ public void commandCount() { } @Test + @SinceRedisVersion("7.0.0") public void commandDocs() { Map docs = jedis.commandDocs("SORT", "SET"); @@ -492,6 +498,7 @@ public void commandDocs() { } @Test + @SinceRedisVersion("7.0.0") public void commandGetKeys() { List keys = jedis.commandGetKeys("SORT", "mylist", "ALPHA", "STORE", "outlist"); assertEquals(2, keys.size()); @@ -501,8 +508,8 @@ public void commandGetKeys() { assertEquals(2, keySandFlags.get(0).getValue().size()); } - @Test + @SinceRedisVersion("7.0.0") public void commandNoArgs() { Map infos = jedis.command(); @@ -524,6 +531,7 @@ public void commandNoArgs() { } @Test + @SinceRedisVersion("7.0.0") public void commandInfo() { Map infos = jedis.commandInfo("GET", "foo", "SET"); @@ -543,6 +551,7 @@ public void commandInfo() { } @Test // GitHub Issue #4020 + @SinceRedisVersion("7.0.0") public void commandInfoAcl() { Map infos = jedis.commandInfo("ACL"); assertThat(infos, Matchers.aMapWithSize(1)); @@ -564,6 +573,7 @@ public void commandInfoAcl() { } @Test + @SinceRedisVersion("7.0.0") public void commandList() { List commands = jedis.commandList(); assertTrue(commands.size() > 100); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java index be00a4d665..1b60c8e1ac 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/GeoCommandsTest.java @@ -19,6 +19,7 @@ import redis.clients.jedis.params.GeoAddParams; import redis.clients.jedis.params.GeoRadiusParam; import redis.clients.jedis.params.GeoRadiusStoreParam; +import redis.clients.jedis.util.GeoCoordinateMatcher; import redis.clients.jedis.util.SafeEncoder; @RunWith(Parameterized.class) @@ -532,7 +533,8 @@ public void geosearch() { assertEquals(1, members.size()); assertEquals("place1", members.get(0).getMemberByString()); assertEquals(0.0881, members.get(0).getDistance(), 10); - assertEquals(new GeoCoordinate(2.19093829393386841, 41.43379028184083523), members.get(0).getCoordinate()); + assertThat(members.get(0).getCoordinate(), + GeoCoordinateMatcher.atCoordinates(2.19093829393386841, 41.43379028184083523)); } @Test diff --git a/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java index 88ca543fc4..15c177fba4 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/HashesCommandsTest.java @@ -31,6 +31,8 @@ import java.util.Set; import java.util.stream.Collectors; +import io.redis.test.annotations.SinceRedisVersion; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -43,9 +45,17 @@ import redis.clients.jedis.resps.ScanResult; import redis.clients.jedis.util.AssertUtil; import redis.clients.jedis.util.JedisByteHashMap; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class HashesCommandsTest extends JedisCommandsTestBase { + + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(endpoint); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(endpoint); + final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; final byte[] bbar = { 0x05, 0x06, 0x07, 0x08 }; final byte[] bcar = { 0x09, 0x0A, 0x0B, 0x0C }; @@ -479,6 +489,7 @@ public void hscanCount() { } @Test + @SinceRedisVersion("7.4.0") public void hscanNoValues() { jedis.hset("foo", "b", "y"); jedis.hset("foo", "a", "x"); @@ -502,6 +513,7 @@ public void hscanNoValues() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "NOVALUES flag (since Redis 7.4)") public void hscanNoValuesMatch() { ScanParams params = new ScanParams(); params.match("a*"); @@ -534,6 +546,7 @@ public void hscanNoValuesMatch() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "NOVALUES flag (since Redis 7.4)") public void hscanNoValuesCount() { ScanParams params = new ScanParams(); params.count(2); @@ -653,6 +666,7 @@ public void hrandfield() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAndHttl() { long seconds1 = 20; long seconds2 = 10; @@ -670,6 +684,7 @@ public void hexpireAndHttl() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAndHttlBinary() { long seconds1 = 20; long seconds2 = 10; @@ -687,6 +702,7 @@ public void hexpireAndHttlBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAndHpttl() { long millis1 = 20_000; long millis2 = 10_000; @@ -702,6 +718,7 @@ public void hpexpireAndHpttl() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAndHpttlBinary() { long millis1 = 20_000; long millis2 = 10_000; @@ -717,6 +734,7 @@ public void hpexpireAndHpttlBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAtAndExpireTime() { long currSeconds = System.currentTimeMillis() / 1000; long seconds1 = currSeconds + 20; @@ -735,6 +753,7 @@ public void hexpireAtAndExpireTime() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAtAndExpireTimeBinary() { long currSeconds = System.currentTimeMillis() / 1000; long seconds1 = currSeconds + 20; @@ -753,6 +772,7 @@ public void hexpireAtAndExpireTimeBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAtAndPexpireTime() { long currMillis = System.currentTimeMillis(); long unixMillis = currMillis + 20_000; @@ -768,6 +788,7 @@ public void hpexpireAtAndPexpireTime() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAtAndPexpireTimeBinary() { long currMillis = System.currentTimeMillis(); long unixMillis = currMillis + 20_000; @@ -783,6 +804,7 @@ public void hpexpireAtAndPexpireTimeBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpersist() { long seconds = 20; @@ -797,6 +819,7 @@ public void hpersist() { } @Test + @SinceRedisVersion("7.4.0") public void hpersistBinary() { long seconds = 20; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java index cec36a0866..d3951f0638 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/JedisCommandsTestBase.java @@ -4,12 +4,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runners.Parameterized.Parameters; + import redis.clients.jedis.*; import redis.clients.jedis.commands.CommandsTestsParameters; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; public abstract class JedisCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getRedisEndpoint("standalone0")); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getRedisEndpoint("standalone0")); + /** * Input data for parameterized tests. In principle all subclasses of this * class should be parameterized tests, to run with several versions of RESP. diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ListCommandsTest.java index b55452b796..f8f59214b4 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ListCommandsTest.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -864,6 +865,7 @@ public void blmove() { } @Test + @SinceRedisVersion("7.0.0") public void lmpop() { String mylist1 = "mylist1"; String mylist2 = "mylist2"; @@ -889,6 +891,7 @@ public void lmpop() { } @Test + @SinceRedisVersion("7.0.0") public void blmpopSimple() { String mylist1 = "mylist1"; String mylist2 = "mylist2"; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java index bef13001ef..2bf7c6da1d 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ModuleTest.java @@ -5,6 +5,10 @@ import java.util.Collections; import java.util.List; + +import org.junit.Assume; +import org.junit.BeforeClass; +import redis.clients.jedis.util.TestEnvUtil; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -17,6 +21,11 @@ @RunWith(Parameterized.class) public class ModuleTest extends JedisCommandsTestBase { + @BeforeClass + public static void checkDockerEnvironment() { + Assume.assumeFalse("Module tests not supported against dockerised test env yet!", TestEnvUtil.isContainerEnv()); + } + static enum ModuleCommand implements ProtocolCommand { SIMPLE("testmodule.simple"); @@ -40,7 +49,7 @@ public ModuleTest(RedisProtocol protocol) { @Test public void testModules() { try { - assertEquals("OK", jedis.moduleLoad("/tmp/testmodule.so")); + assertEquals("OK", jedis.moduleLoad(TestEnvUtil.testModuleSoPath())); List modules = jedis.moduleList(); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java index 9f4c60de0b..410627d9bf 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/ScriptingCommandsTest.java @@ -8,6 +8,8 @@ import java.util.List; import java.util.Map; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Before; @@ -26,6 +28,7 @@ import redis.clients.jedis.resps.LibraryInfo; import redis.clients.jedis.util.ClientKillerUtil; import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.RedisVersionUtil; import redis.clients.jedis.util.SafeEncoder; @RunWith(Parameterized.class) @@ -39,7 +42,10 @@ public ScriptingCommandsTest(RedisProtocol redisProtocol) { @Override public void setUp() throws Exception { super.setUp(); - jedis.functionFlush(); + if (RedisVersionUtil.getRedisVersion(jedis) + .isGreaterThanOrEqualTo(RedisVersion.V7_0_0)) { + jedis.functionFlush(); + } } final byte[] bfoo = { 0x01, 0x02, 0x03, 0x04 }; @@ -142,6 +148,7 @@ public void evalNoArgs() { } @Test + @SinceRedisVersion(value = "7.0.0") public void evalReadonly() { String script = "return KEYS[1]"; List keys = new ArrayList(); @@ -165,6 +172,7 @@ public void evalsha() { } @Test + @SinceRedisVersion(value = "7.0.0") public void evalshaReadonly() { jedis.set("foo", "bar"); jedis.eval("return redis.call('get','foo')"); @@ -185,6 +193,7 @@ public void evalshaBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void evalshaReadonlyBinary() { jedis.set(SafeEncoder.encode("foo"), SafeEncoder.encode("bar")); jedis.eval(SafeEncoder.encode("return redis.call('get','foo')")); @@ -335,6 +344,7 @@ public void emptyLuaTableReply() { } @Test + @SinceRedisVersion(value = "7.0.0") public void functionLoadAndDelete() { String engine = "Lua"; String library = "mylib"; @@ -354,6 +364,7 @@ public void functionLoadAndDelete() { } @Test + @SinceRedisVersion(value = "7.0.0") public void functionFlush() { String engine = "Lua"; String library = "mylib"; @@ -369,6 +380,7 @@ public void functionFlush() { } @Test + @SinceRedisVersion(value = "7.0.0") public void functionList() { String engine = "LUA"; String library = "mylib"; @@ -436,6 +448,7 @@ public void functionList() { } @Test + @SinceRedisVersion(value = "7.0.0") public void functionDumpRestore() { String engine = "Lua"; String library = "mylib"; @@ -455,6 +468,7 @@ public void functionDumpRestore() { } @Test + @SinceRedisVersion(value = "7.0.0") public void functionStatsWithoutRunning() { String engine = "Lua"; String library = "mylib"; @@ -490,6 +504,7 @@ public void functionStatsWithoutRunning() { // } @Test + @SinceRedisVersion(value = "7.0.0") public void functionKillWithoutRunningFunction() { String engine = "Lua"; String library = "mylib"; @@ -505,6 +520,7 @@ public void functionKillWithoutRunningFunction() { } @Test + @SinceRedisVersion(value = "7.0.0") public void fcall() { String engine = "Lua"; String library = "mylib"; @@ -516,6 +532,7 @@ public void fcall() { } @Test + @SinceRedisVersion(value = "7.0.0") public void fcallBinary() { String engine = "Lua"; String library = "mylib"; @@ -527,6 +544,7 @@ public void fcallBinary() { } @Test + @SinceRedisVersion(value = "7.0.0") public void fcallReadonly() { String engine = "Lua"; String library = "mylib"; diff --git a/src/test/java/redis/clients/jedis/commands/jedis/SetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/SetCommandsTest.java index d2b660b5b4..67ede2b75c 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/SetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/SetCommandsTest.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -364,6 +365,7 @@ public void sinterstore() { } @Test + @SinceRedisVersion("7.0.0") public void sintercard() { jedis.sadd("foo", "a"); jedis.sadd("foo", "b"); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java index 0377c481b4..63d6b009af 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/SlowlogCommandsTest.java @@ -5,8 +5,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import java.util.Arrays; -import java.util.List; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.*; + import org.hamcrest.Matchers; import org.junit.After; import org.junit.Before; @@ -22,8 +25,6 @@ @RunWith(Parameterized.class) public class SlowlogCommandsTest extends JedisCommandsTestBase { - private static final List LOCAL_IPS = Arrays.asList("127.0.0.1", "[::1]"); - private static final String SLOWLOG_TIME_PARAM = "slowlog-log-slower-than"; private static final String ZERO_STRING = "0"; @@ -81,7 +82,7 @@ public void slowlog() { @Test public void slowlogObjectDetails() { - final String clientName = "slowlog-object-client"; + final String clientName = "slowlog-object-client-" + UUID.randomUUID(); jedis.clientSetname(clientName); jedis.slowlogReset(); jedis.configSet(SLOWLOG_TIME_PARAM, ZERO_STRING); @@ -90,6 +91,7 @@ public void slowlogObjectDetails() { //assertEquals(1, logs.size()); assertThat(logs.size(), Matchers.allOf(Matchers.greaterThanOrEqualTo(1), Matchers.lessThanOrEqualTo(2))); Slowlog log = logs.get(0); + assertEquals(clientName, log.getClientName()); assertThat(log.getId(), Matchers.greaterThan(0L)); assertThat(log.getTimeStamp(), Matchers.greaterThan(0L)); assertThat(log.getExecutionTime(), Matchers.greaterThanOrEqualTo(0L)); @@ -98,9 +100,8 @@ public void slowlogObjectDetails() { assertEquals(SafeEncoder.encode(Protocol.Keyword.SET.getRaw()), log.getArgs().get(1)); assertEquals(SLOWLOG_TIME_PARAM, log.getArgs().get(2)); assertEquals(ZERO_STRING, log.getArgs().get(3)); - assertThat(log.getClientIpPort().getHost(), Matchers.in(LOCAL_IPS)); + assertThat(log.getClientIpPort().getHost(), Matchers.in(getAllLocalIps())); assertThat(log.getClientIpPort().getPort(), Matchers.greaterThan(0)); - assertEquals(clientName, log.getClientName()); } @Test @@ -127,4 +128,20 @@ public void slowlogBinaryObjectDetails() { assertThat(((byte[]) log.get(4)).length, Matchers.greaterThanOrEqualTo(10)); // 'IP:PORT' assertArrayEquals(clientName, (byte[]) log.get(5)); } + + private static Set getAllLocalIps() { + Set allLocalIps = new HashSet<>(); + try { + for (NetworkInterface netIf : Collections.list(NetworkInterface.getNetworkInterfaces())) { + for (InetAddress addr : Collections.list(netIf.getInetAddresses())) { + allLocalIps.add(addr.getHostAddress()); + } + } + } catch (SocketException e) { + throw new RuntimeException(e); + } + //ipv6 loopback + allLocalIps.add("[::1]"); + return allLocalIps; + } } diff --git a/src/test/java/redis/clients/jedis/commands/jedis/SortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/SortedSetCommandsTest.java index 9e4cd71a53..d98941dc5b 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/SortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/SortedSetCommandsTest.java @@ -7,6 +7,8 @@ import static redis.clients.jedis.util.AssertUtil.assertByteArrayListEquals; import java.util.*; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -400,6 +402,7 @@ public void zrank() { } @Test + @SinceRedisVersion("7.2.0") public void zrankWithScore() { jedis.zadd("foo", 1d, "a"); jedis.zadd("foo", 2d, "b"); @@ -1416,6 +1419,7 @@ public void zintertoreParams() { } @Test + @SinceRedisVersion("7.0.0") public void zintercard() { jedis.zadd("foo", 1, "a"); jedis.zadd("foo", 2, "b"); @@ -1658,6 +1662,7 @@ private Double getScoreFromByteMap(Map bhash, byte[] key) { } @Test + @SinceRedisVersion("7.0.0") public void zmpop() { jedis.zadd("foo", 1d, "a", ZAddParams.zAddParams().nx()); jedis.zadd("foo", 10d, "b", ZAddParams.zAddParams().nx()); @@ -1673,6 +1678,7 @@ public void zmpop() { } @Test + @SinceRedisVersion("7.0.0") public void bzmpopSimple() { jedis.zadd("foo", 1d, "a", ZAddParams.zAddParams().nx()); jedis.zadd("foo", 10d, "b", ZAddParams.zAddParams().nx()); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/SortingCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/SortingCommandsTest.java index 1d0a976f41..91410ce344 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/SortingCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/SortingCommandsTest.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; +import io.redis.test.annotations.EnabledOnCommand; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -324,6 +325,7 @@ public void sortStore() { } @Test + @EnabledOnCommand("SORT_RO") public void sort_ro() { jedis.rpush("foo", "1", "3", "2"); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java index 0ac12f9d05..604911ad9d 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/StreamsCommandsTest.java @@ -18,6 +18,8 @@ import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; @@ -34,6 +36,7 @@ import redis.clients.jedis.exceptions.JedisException; import redis.clients.jedis.params.*; import redis.clients.jedis.resps.*; +import redis.clients.jedis.util.RedisVersionUtil; import redis.clients.jedis.util.SafeEncoder; @RunWith(Parameterized.class) @@ -157,6 +160,7 @@ public void xaddWithParams() { } @Test + @SinceRedisVersion(value = "7.0.0") public void xaddParamsId() { StreamEntryID id; String key = "kk"; @@ -348,6 +352,31 @@ public void xreadAsMap() { assertEquals(2, streams2.size()); assertEquals(id1, streams2.get(stream1).get(0).getID()); assertEquals(id2, streams2.get(stream2).get(0).getID()); + } + + @Test + @SinceRedisVersion(value = "7.4.0", message = "From Redis 7.4, you can use the + sign as a special ID to request last entry") + public void xreadAsMapLastEntry() { + + final String stream1 = "xread-stream1"; + final String stream2 = "xread-stream2"; + + Map streamQeury1 = singletonMap(stream1, new StreamEntryID()); + + // Before creating Stream + assertNull(jedis.xreadAsMap(XReadParams.xReadParams().block(1), streamQeury1)); + assertNull(jedis.xreadAsMap(XReadParams.xReadParams(), streamQeury1)); + + Map map = new HashMap<>(); + map.put("f1", "v1"); + StreamEntryID id1 = new StreamEntryID(1); + StreamEntryID id2 = new StreamEntryID(2); + StreamEntryID id3 = new StreamEntryID(3); + + assertEquals(id1, jedis.xadd(stream1, id1, map)); + assertEquals(id2, jedis.xadd(stream2, id2, map)); + assertEquals(id3, jedis.xadd(stream1, id3, map)); + // Read from last entry Map streamQueryLE = singletonMap(stream1, StreamEntryID.XREAD_LAST_ENTRY); @@ -880,6 +909,8 @@ public void xinfo() throws InterruptedException { final String MY_CONSUMER = "myConsumer"; final String MY_CONSUMER2 = "myConsumer2"; + final RedisVersion redisVersion = RedisVersionUtil.getRedisVersion(jedis); + Map map1 = new HashMap<>(); map1.put(F1, V1); StreamEntryID id1 = jedis.xadd(STREAM_NAME, (StreamEntryID) null, map1); @@ -942,7 +973,10 @@ public void xinfo() throws InterruptedException { assertEquals(MY_CONSUMER, consumersInfo.get(0).getName()); assertEquals(0L, consumersInfo.get(0).getPending()); assertThat(consumersInfo.get(0).getIdle(), Matchers.greaterThanOrEqualTo(0L)); - assertThat(consumersInfo.get(0).getInactive(), Matchers.any(Long.class)); + + if ( redisVersion.isGreaterThanOrEqualTo(RedisVersion.V7_2_0)) { + assertThat(consumersInfo.get(0).getInactive(), Matchers.any(Long.class)); + } // Consumer info test assertEquals(MY_CONSUMER, @@ -954,7 +988,9 @@ public void xinfo() throws InterruptedException { assertEquals(MY_CONSUMER, consumerInfo.get(0).getName()); assertEquals(0L, consumerInfo.get(0).getPending()); assertThat(consumerInfo.get(0).getIdle(), Matchers.greaterThanOrEqualTo(0L)); - assertThat(consumerInfo.get(0).getInactive(), Matchers.any(Long.class)); + if (redisVersion.isGreaterThanOrEqualTo(RedisVersion.V7_2_0)) { + assertThat(consumerInfo.get(0).getInactive(), Matchers.any(Long.class)); + } // test with more groups and consumers jedis.xgroupCreate(STREAM_NAME, G2, StreamEntryID.XGROUP_LAST_ENTRY, false); @@ -1028,7 +1064,9 @@ public void xinfoStreamFullWithPending() { StreamConsumerFullInfo consumer = group.getConsumers().get(0); assertEquals("xreadGroup-consumer", consumer.getName()); assertThat(consumer.getSeenTime(), Matchers.greaterThanOrEqualTo(0L)); - assertThat(consumer.getActiveTime(), Matchers.greaterThanOrEqualTo(0L)); + if (RedisVersionUtil.getRedisVersion(jedis).isGreaterThanOrEqualTo(RedisVersion.V7_2_0)) { + assertThat(consumer.getActiveTime(), Matchers.greaterThanOrEqualTo(0L)); + } assertEquals(1, consumer.getPending().size()); List consumerPendingEntry = consumer.getPending().get(0); assertEquals(id1, consumerPendingEntry.get(0)); diff --git a/src/test/java/redis/clients/jedis/commands/jedis/StringValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/jedis/StringValuesCommandsTest.java index 44525e072f..12bcd8aebe 100644 --- a/src/test/java/redis/clients/jedis/commands/jedis/StringValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/jedis/StringValuesCommandsTest.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.List; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -247,6 +249,7 @@ public void psetex() { } @Test + @SinceRedisVersion("7.0.0") public void lcs() { jedis.mset("key1", "ohmytext", "key2", "mynewtext"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java index f31c100988..0ae434238e 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/AllKindOfValuesCommandsTestBase.java @@ -29,8 +29,11 @@ import java.util.HashSet; import java.util.List; import java.util.Set; + +import io.redis.test.annotations.SinceRedisVersion; import org.hamcrest.Matchers; import org.junit.Assume; +import org.junit.Ignore; import org.junit.Test; import redis.clients.jedis.RedisProtocol; @@ -286,6 +289,7 @@ public void dbSize() { } @Test + @SinceRedisVersion(value="7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void expire() { assertEquals(0, jedis.expire("foo", 20L)); @@ -302,6 +306,7 @@ public void expire() { } @Test + @SinceRedisVersion(value="7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void expireAt() { long unixTime = (System.currentTimeMillis() / 1000L) + 20; @@ -322,6 +327,7 @@ public void expireAt() { } @Test + @SinceRedisVersion(value="7.0.0") public void expireTime() { long unixTime; @@ -427,6 +433,7 @@ public void dumpAndRestore() { } @Test + @Ignore(value = "TODO: Regression in 8.0-M02 discarding restore idle time.") public void restoreParams() { jedis.set("foo", "bar"); jedis.set("from", "a"); @@ -458,6 +465,7 @@ public void restoreParams() { } @Test + @SinceRedisVersion(value="7.0.0", message = "Starting with Redis version 7.0.0: Added options: NX, XX, GT and LT.") public void pexpire() { assertEquals(0, jedis.pexpire("foo", 10000)); @@ -499,6 +507,7 @@ public void pexpireAt() { } @Test + @SinceRedisVersion(value="7.0.0") public void pexpireTime() { long unixTime = (System.currentTimeMillis()) + 10000; diff --git a/src/test/java/redis/clients/jedis/commands/unified/BitCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/BitCommandsTestBase.java index 2101900889..1465edea5b 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/BitCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/BitCommandsTestBase.java @@ -7,6 +7,8 @@ import static org.junit.Assert.fail; import java.util.List; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.Protocol; @@ -143,6 +145,7 @@ public void bitposWithNoMatchingBitExistWithinRange() { } @Test + @SinceRedisVersion(value="7.0.0", message="Starting with Redis version 7.0.0: Added the BYTE|BIT option.") public void bitposModifier() { jedis.set("mykey", "\\x00\\xff\\xf0"); assertEquals(0, jedis.bitpos("mykey", false)); @@ -168,6 +171,7 @@ public void setAndgetrange() { } @Test + @SinceRedisVersion(value="7.0.0", message="Starting with Redis version 7.0.0: Added the BYTE|BIT option.") public void bitCount() { jedis.setbit("foo", 16, true); jedis.setbit("foo", 24, true); diff --git a/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java index e05a5f99cf..292d3d5ee2 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/GeoCommandsTestBase.java @@ -1,7 +1,6 @@ package redis.clients.jedis.commands.unified; import static org.junit.Assert.*; -import static redis.clients.jedis.util.AssertUtil.assertByteArrayListEquals; import java.util.ArrayList; import java.util.HashMap; @@ -17,6 +16,8 @@ import redis.clients.jedis.params.GeoAddParams; import redis.clients.jedis.params.GeoRadiusParam; import redis.clients.jedis.params.GeoRadiusStoreParam; +import redis.clients.jedis.util.AssertUtil; +import redis.clients.jedis.util.GeoCoordinateMatcher; import redis.clients.jedis.util.SafeEncoder; public abstract class GeoCommandsTestBase extends UnifiedJedisCommandsTestBase { @@ -303,7 +304,7 @@ public void georadiusStoreBinary() { List bexpected = new ArrayList<>(); bexpected.add(bA); bexpected.add(bB); - assertByteArrayListEquals(bexpected, jedis.zrange("SicilyStore".getBytes(), 0, -1)); + AssertUtil.assertByteArrayListEquals(bexpected, jedis.zrange("SicilyStore".getBytes(), 0, -1)); } @Test @@ -447,7 +448,7 @@ public void georadiusByMemberStoreBinary() { List bexpected = new ArrayList<>(); bexpected.add(bA); bexpected.add(bB); - assertByteArrayListEquals(bexpected, jedis.zrange("SicilyStore".getBytes(), 0, -1)); + AssertUtil.assertByteArrayListEquals(bexpected, jedis.zrange("SicilyStore".getBytes(), 0, -1)); } @Test @@ -529,7 +530,8 @@ public void geosearch() { assertEquals(1, members.size()); assertEquals("place1", members.get(0).getMemberByString()); assertEquals(0.0881, members.get(0).getDistance(), 10); - assertEquals(new GeoCoordinate(2.19093829393386841, 41.43379028184083523), members.get(0).getCoordinate()); + assertThat(members.get(0).getCoordinate(), + GeoCoordinateMatcher.atCoordinates(2.19093829393386841, 41.43379028184083523)); } @Test diff --git a/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java index f84b0c2cc6..231b1c8aea 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/HashesCommandsTestBase.java @@ -31,6 +31,7 @@ import java.util.Set; import java.util.stream.Collectors; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; @@ -451,6 +452,7 @@ public void hscanCount() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "NOVALUES flag (since Redis 7.4)") public void hscanNoValues() { jedis.hset("foo", "b", "y"); jedis.hset("foo", "a", "x"); @@ -474,6 +476,7 @@ public void hscanNoValues() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "NOVALUES flag (since Redis 7.4)") public void hscanNoValuesMatch() { ScanParams params = new ScanParams(); params.match("a*"); @@ -506,6 +509,7 @@ public void hscanNoValuesMatch() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "NOVALUES flag (since Redis 7.4)") public void hscanNoValuesCount() { ScanParams params = new ScanParams(); params.count(2); @@ -625,6 +629,7 @@ public void hrandfield() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAndHttl() { long seconds1 = 20; long seconds2 = 10; @@ -642,6 +647,7 @@ public void hexpireAndHttl() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAndHttlBinary() { long seconds1 = 20; long seconds2 = 10; @@ -659,6 +665,7 @@ public void hexpireAndHttlBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAndHpttl() { long millis1 = 20_000; long millis2 = 10_000; @@ -674,6 +681,7 @@ public void hpexpireAndHpttl() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAndHpttlBinary() { long millis1 = 20_000; long millis2 = 10_000; @@ -689,6 +697,7 @@ public void hpexpireAndHpttlBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAtAndExpireTime() { long currSeconds = System.currentTimeMillis() / 1000; long seconds1 = currSeconds + 20; @@ -707,6 +716,7 @@ public void hexpireAtAndExpireTime() { } @Test + @SinceRedisVersion("7.4.0") public void hexpireAtAndExpireTimeBinary() { long currSeconds = System.currentTimeMillis() / 1000; long seconds1 = currSeconds + 20; @@ -725,6 +735,7 @@ public void hexpireAtAndExpireTimeBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAtAndPexpireTime() { long currMillis = System.currentTimeMillis(); long unixMillis = currMillis + 20_000; @@ -740,6 +751,7 @@ public void hpexpireAtAndPexpireTime() { } @Test + @SinceRedisVersion("7.4.0") public void hpexpireAtAndPexpireTimeBinary() { long currMillis = System.currentTimeMillis(); long unixMillis = currMillis + 20_000; @@ -755,6 +767,7 @@ public void hpexpireAtAndPexpireTimeBinary() { } @Test + @SinceRedisVersion("7.4.0") public void hpersist() { long seconds = 20; @@ -769,6 +782,7 @@ public void hpersist() { } @Test + @SinceRedisVersion("7.4.0") public void hpersistBinary() { long seconds = 20; diff --git a/src/test/java/redis/clients/jedis/commands/unified/ListCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/ListCommandsTestBase.java index d8f74b4765..04f4d04b90 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/ListCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/ListCommandsTestBase.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -848,6 +849,7 @@ public void blmove() { } @Test + @SinceRedisVersion(value="7.0.0") public void lmpop() { String mylist1 = "mylist1"; String mylist2 = "mylist2"; @@ -873,6 +875,7 @@ public void lmpop() { } @Test + @SinceRedisVersion(value="7.0.0") public void blmpopSimple() { String mylist1 = "mylist1"; String mylist2 = "mylist2"; diff --git a/src/test/java/redis/clients/jedis/commands/unified/SetCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/SetCommandsTestBase.java index d4c1456218..3f21a2f9f5 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/SetCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/SetCommandsTestBase.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; @@ -361,6 +362,7 @@ public void sinterstore() { } @Test + @SinceRedisVersion(value="7.0.0") public void sintercard() { jedis.sadd("foo", "a"); jedis.sadd("foo", "b"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/SortedSetCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/SortedSetCommandsTestBase.java index 126a884993..000a005eb6 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/SortedSetCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/SortedSetCommandsTestBase.java @@ -7,6 +7,8 @@ import static redis.clients.jedis.util.AssertUtil.assertByteArrayListEquals; import java.util.*; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; @@ -454,6 +456,7 @@ public void zrank() { } @Test + @SinceRedisVersion(value="7.2.0") public void zrankWithScore() { jedis.zadd("foo", 1d, "a"); jedis.zadd("foo", 2d, "b"); @@ -1402,6 +1405,7 @@ public void zintertoreParams() { } @Test + @SinceRedisVersion(value="7.0.0") public void zintercard() { jedis.zadd("foo", 1, "a"); jedis.zadd("foo", 2, "b"); @@ -1644,6 +1648,7 @@ private Double getScoreFromByteMap(Map bhash, byte[] key) { } @Test + @SinceRedisVersion(value="7.0.0") public void zmpop() { jedis.zadd("foo", 1d, "a", ZAddParams.zAddParams().nx()); jedis.zadd("foo", 10d, "b", ZAddParams.zAddParams().nx()); @@ -1659,6 +1664,7 @@ public void zmpop() { } @Test + @SinceRedisVersion(value="7.0.0") public void bzmpopSimple() { jedis.zadd("foo", 1d, "a", ZAddParams.zAddParams().nx()); jedis.zadd("foo", 10d, "b", ZAddParams.zAddParams().nx()); diff --git a/src/test/java/redis/clients/jedis/commands/unified/StringValuesCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/StringValuesCommandsTestBase.java index 8309978fad..f21876979e 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/StringValuesCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/StringValuesCommandsTestBase.java @@ -6,6 +6,8 @@ import java.util.ArrayList; import java.util.List; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import redis.clients.jedis.RedisProtocol; @@ -244,6 +246,7 @@ public void psetex() { } @Test + @SinceRedisVersion(value="7.0.0") public void lcs() { jedis.mset("key1", "ohmytext", "key2", "mynewtext"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterAllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterAllKindOfValuesCommandsTest.java index e0f5c7af26..f6b575086e 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterAllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterAllKindOfValuesCommandsTest.java @@ -12,17 +12,32 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.AllKindOfValuesCommandsTestBase; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class ClusterAllKindOfValuesCommandsTest extends AllKindOfValuesCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + public ClusterAllKindOfValuesCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterBitCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterBitCommandsTest.java index 078e8d8851..fa98a7d106 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterBitCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterBitCommandsTest.java @@ -2,12 +2,13 @@ import static org.junit.Assert.assertEquals; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; +import org.junit.*; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.BitOP; import redis.clients.jedis.commands.unified.BitCommandsTestBase; @@ -16,6 +17,15 @@ @RunWith(Parameterized.class) public class ClusterBitCommandsTest extends BitCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + public ClusterBitCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java index a5590a2730..bdefea6791 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterHashesCommandsTest.java @@ -2,14 +2,29 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.HashesCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class ClusterHashesCommandsTest extends HashesCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster") .build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + public ClusterHashesCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterListCommandsTest.java index 666752050b..644953e335 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterListCommandsTest.java @@ -10,23 +10,39 @@ import java.util.Collections; import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.args.ListDirection; import redis.clients.jedis.commands.unified.ListCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class ClusterListCommandsTest extends ListCommandsTestBase { private final Logger logger = LoggerFactory.getLogger(getClass()); + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + public ClusterListCommandsTest(RedisProtocol protocol) { super(protocol); } @@ -259,6 +275,7 @@ public void blmove() { } @Test + @SinceRedisVersion(value="7.0.0") public void lmpop() { String mylist1 = "mylist1{.}"; String mylist2 = "mylist2{.}"; @@ -284,6 +301,7 @@ public void lmpop() { } @Test + @SinceRedisVersion(value="7.0.0") public void blmpopSimple() { String mylist1 = "mylist1{.}"; String mylist2 = "mylist2{.}"; diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSetCommandsTest.java index 75d2b6bbdc..9560ef0f67 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSetCommandsTest.java @@ -5,13 +5,20 @@ import java.util.HashSet; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.SetCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class ClusterSetCommandsTest extends SetCommandsTestBase { @@ -26,6 +33,15 @@ public ClusterSetCommandsTest(RedisProtocol protocol) { super(protocol); } + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Before public void setUp() { jedis = ClusterCommandsTestHelper.getCleanCluster(protocol); @@ -178,6 +194,7 @@ public void sdiffstore() { } @Test + @SinceRedisVersion(value="7.0.0") public void sintercard() { jedis.sadd("foo{.}", "a"); jedis.sadd("foo{.}", "b"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSortedSetCommandsTest.java index b08d7b1773..af2e18357d 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterSortedSetCommandsTest.java @@ -10,11 +10,16 @@ import java.util.Collections; import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.SortedSetCommandsTestBase; import redis.clients.jedis.params.ZAddParams; @@ -22,6 +27,8 @@ import redis.clients.jedis.params.ZRangeParams; import redis.clients.jedis.resps.Tuple; import redis.clients.jedis.util.KeyValue; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class ClusterSortedSetCommandsTest extends SortedSetCommandsTestBase { @@ -32,6 +39,15 @@ public class ClusterSortedSetCommandsTest extends SortedSetCommandsTestBase { final byte[] bb = { 0x0B }; final byte[] bc = { 0x0C }; + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + public ClusterSortedSetCommandsTest(RedisProtocol protocol) { super(protocol); } @@ -234,6 +250,7 @@ public void zrangestore() { } @Test + @SinceRedisVersion(value="7.0.0") public void zintercard() { jedis.zadd("foo{.}", 1, "a"); jedis.zadd("foo{.}", 2, "b"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterStringValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterStringValuesCommandsTest.java index a8f980bd9a..4200887cb6 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterStringValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/cluster/ClusterStringValuesCommandsTest.java @@ -5,15 +5,22 @@ import java.util.ArrayList; import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + +import redis.clients.jedis.DefaultJedisClientConfig; +import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.StringValuesCommandsTestBase; import redis.clients.jedis.params.LCSParams; import redis.clients.jedis.resps.LCSMatchResult; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class ClusterStringValuesCommandsTest extends StringValuesCommandsTestBase { @@ -22,6 +29,15 @@ public ClusterStringValuesCommandsTest(RedisProtocol protocol) { super(protocol); } + @Rule + public RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule( + HostAndPorts.getStableClusterServers().get(0), + DefaultJedisClientConfig.builder().password("cluster").build()); + @Before public void setUp() { jedis = ClusterCommandsTestHelper.getCleanCluster(protocol); @@ -84,6 +100,7 @@ public void msetnx() { } @Test + @SinceRedisVersion(value="7.0.0") public void lcs() { jedis.mset("key1{.}", "ohmytext", "key2{.}", "mynewtext"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java index d8b7443a8f..61c686fbb0 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/GeoPipelineCommandsTest.java @@ -6,7 +6,6 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static redis.clients.jedis.util.GeoCoordinateMatcher.atCoordinates; @@ -19,11 +18,11 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + import redis.clients.jedis.GeoCoordinate; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.Response; import redis.clients.jedis.args.GeoUnit; -import redis.clients.jedis.exceptions.JedisDataException; import redis.clients.jedis.params.GeoAddParams; import redis.clients.jedis.params.GeoRadiusParam; import redis.clients.jedis.params.GeoRadiusStoreParam; @@ -180,14 +179,12 @@ public void geopos() { pipe.sync(); - assertThat(coordinates.get(), contains( - atCoordinates(3.0, 4.0), + assertThat(coordinates.get(), contains(atCoordinates(3.0, 4.0), atCoordinates(2.0, 3.0), null )); - assertThat(bcoordinates.get(), contains( - atCoordinates(3.0, 4.0), + assertThat(bcoordinates.get(), contains(atCoordinates(3.0, 4.0), atCoordinates(2.0, 3.0), null )); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/ListPipelineCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/ListPipelineCommandsTest.java index 7cb8778a93..7bb8e26464 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/ListPipelineCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/ListPipelineCommandsTest.java @@ -9,6 +9,7 @@ import java.util.List; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -954,6 +955,7 @@ public void blmove() { } @Test + @SinceRedisVersion(value="7.0.0") public void lmpop() { String mylist1 = "mylist1"; String mylist2 = "mylist2"; @@ -982,6 +984,7 @@ public void lmpop() { } @Test + @SinceRedisVersion(value="7.0.0") public void blmpopSimple() { String mylist1 = "mylist1"; String mylist2 = "mylist2"; diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/PipelineCommandsTestBase.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/PipelineCommandsTestBase.java index 55dfec6e98..9744244616 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/PipelineCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/PipelineCommandsTestBase.java @@ -2,12 +2,13 @@ import java.util.Collection; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runners.Parameterized; -import redis.clients.jedis.JedisPooled; -import redis.clients.jedis.Pipeline; -import redis.clients.jedis.RedisProtocol; +import redis.clients.jedis.*; import redis.clients.jedis.commands.CommandsTestsParameters; import redis.clients.jedis.commands.unified.pooled.PooledCommandsTestHelper; @@ -29,6 +30,10 @@ public static Collection data() { protected final RedisProtocol protocol; + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); /** * The RESP protocol is to be injected by the subclasses, usually via JUnit * parameterized tests, because most of the subclassed tests are meant to be diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/SetPipelineCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/SetPipelineCommandsTest.java index 0dd0a18559..c311e1134c 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/SetPipelineCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/SetPipelineCommandsTest.java @@ -20,6 +20,7 @@ import java.util.List; import java.util.Set; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -378,6 +379,7 @@ public void sinterstore() { } @Test + @SinceRedisVersion(value="7.0.0") public void sintercard() { pipe.sadd("foo", "a"); pipe.sadd("foo", "b"); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/SortedSetPipelineCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/SortedSetPipelineCommandsTest.java index a6915ce3a7..dfd46c7ae8 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/SortedSetPipelineCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/SortedSetPipelineCommandsTest.java @@ -20,6 +20,7 @@ import java.util.Map; import java.util.stream.Collectors; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -542,6 +543,7 @@ public void zrank() { } @Test + @SinceRedisVersion(value="7.2.0", message = "Starting with Redis version 7.2.0: Added the optional WITHSCORE argument.") public void zrankWithScore() { pipe.zadd("foo", 1d, "a"); pipe.zadd("foo", 2d, "b"); @@ -1516,6 +1518,7 @@ public void zintertoreParams() { } @Test + @SinceRedisVersion(value="7.0.0") public void zintercard() { pipe.zadd("foo", 1, "a"); pipe.zadd("foo", 2, "b"); @@ -1840,6 +1843,7 @@ private Double getScoreFromByteMap(Map bhash, byte[] key) { } @Test + @SinceRedisVersion(value="7.0.0") public void zmpop() { pipe.zadd("foo", 1d, "a", ZAddParams.zAddParams().nx()); pipe.zadd("foo", 10d, "b", ZAddParams.zAddParams().nx()); @@ -1863,6 +1867,7 @@ public void zmpop() { } @Test + @SinceRedisVersion(value="7.0.0") public void bzmpopSimple() { pipe.zadd("foo", 1d, "a", ZAddParams.zAddParams().nx()); pipe.zadd("foo", 10d, "b", ZAddParams.zAddParams().nx()); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pipeline/StreamsPipelineCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pipeline/StreamsPipelineCommandsTest.java index af64b17576..6d52e88b1f 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pipeline/StreamsPipelineCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pipeline/StreamsPipelineCommandsTest.java @@ -27,6 +27,9 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; +import redis.clients.jedis.util.RedisVersionUtil; import org.hamcrest.Matchers; import org.junit.Test; import org.junit.runner.RunWith; @@ -251,6 +254,7 @@ public void xaddWithParamsMinId() { } @Test + @SinceRedisVersion(value = "7.0.0", message = "Added support for XADD ID auto sequence is introduced in 7.0.0") public void xaddParamsId() { String key = "kk"; Map map = singletonMap("ff", "vv"); @@ -1208,7 +1212,9 @@ public void xinfo() throws InterruptedException { assertEquals(MY_CONSUMER, consumersInfo.get(0).getName()); assertEquals(0L, consumersInfo.get(0).getPending()); assertThat(consumersInfo.get(0).getIdle(), Matchers.greaterThanOrEqualTo(0L)); - assertThat(consumersInfo.get(0).getInactive(), Matchers.any(Long.class)); + if (RedisVersionUtil.getRedisVersion(jedis).isGreaterThanOrEqualTo(RedisVersion.V7_0_0)) { + assertThat(consumersInfo.get(0).getInactive(), Matchers.any(Long.class)); + } // Consumer info test List consumerInfo = consumerInfoResponse.get(); @@ -1222,7 +1228,9 @@ public void xinfo() throws InterruptedException { assertEquals(MY_CONSUMER, consumerInfo.get(0).getName()); assertEquals(0L, consumerInfo.get(0).getPending()); assertThat(consumerInfo.get(0).getIdle(), Matchers.greaterThanOrEqualTo(0L)); - assertThat(consumerInfo.get(0).getInactive(), Matchers.any(Long.class)); + if (RedisVersionUtil.getRedisVersion(jedis).isGreaterThanOrEqualTo(RedisVersion.V7_0_0)) { + assertThat(consumerInfo.get(0).getInactive(), Matchers.any(Long.class)); + } // test with more groups and consumers pipe.xgroupCreate(STREAM_NAME, G2, StreamEntryID.XGROUP_LAST_ENTRY, false); @@ -1305,7 +1313,9 @@ public void xinfoStreamFullWithPending() { StreamConsumerFullInfo consumer = group.getConsumers().get(0); assertEquals("xreadGroup-consumer", consumer.getName()); assertThat(consumer.getSeenTime(), Matchers.greaterThanOrEqualTo(0L)); - assertThat(consumer.getActiveTime(), Matchers.greaterThanOrEqualTo(0L)); + if (RedisVersionUtil.getRedisVersion(jedis).isGreaterThanOrEqualTo(RedisVersion.V7_0_0)) { + assertThat(consumer.getActiveTime(), Matchers.greaterThanOrEqualTo(0L)); + } assertEquals(1, consumer.getPending().size()); List consumerPendingEntry = consumer.getPending().get(0); assertEquals(id1, consumerPendingEntry.get(0)); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledAllKindOfValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledAllKindOfValuesCommandsTest.java index a1b53de023..608034f9cc 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledAllKindOfValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledAllKindOfValuesCommandsTest.java @@ -2,15 +2,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.AllKindOfValuesCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledAllKindOfValuesCommandsTest extends AllKindOfValuesCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledAllKindOfValuesCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledBitCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledBitCommandsTest.java index 5764a1bbfa..e91b0ece06 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledBitCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledBitCommandsTest.java @@ -1,7 +1,10 @@ package redis.clients.jedis.commands.unified.pooled; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -11,6 +14,11 @@ @RunWith(Parameterized.class) public class PooledBitCommandsTest extends BitCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledBitCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java index ab69c57f4e..86e1f666de 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledCommandsTestHelper.java @@ -4,7 +4,7 @@ public class PooledCommandsTestHelper { - private static final EndpointConfig nodeInfo = HostAndPorts.getRedisEndpoint("standalone0"); + public static final EndpointConfig nodeInfo = HostAndPorts.getRedisEndpoint("standalone0"); public static JedisPooled getPooled(RedisProtocol redisProtocol) { return new JedisPooled(nodeInfo.getHostAndPort(), nodeInfo.getClientConfigBuilder() diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledHashesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledHashesCommandsTest.java index bb5741d967..07d7273b58 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledHashesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledHashesCommandsTest.java @@ -2,15 +2,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.HashesCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledHashesCommandsTest extends HashesCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledHashesCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledListCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledListCommandsTest.java index 5d38fe43d5..6d053fca74 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledListCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledListCommandsTest.java @@ -2,15 +2,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.ListCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledListCommandsTest extends ListCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledListCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java index d6feb05fa3..c1e3857bb6 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledMiscellaneousTest.java @@ -7,22 +7,32 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; + +import io.redis.test.annotations.SinceRedisVersion; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; - import org.junit.runner.RunWith; import org.junit.runners.Parameterized; + import redis.clients.jedis.AbstractPipeline; import redis.clients.jedis.AbstractTransaction; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.Response; import redis.clients.jedis.commands.unified.UnifiedJedisCommandsTestBase; import redis.clients.jedis.exceptions.JedisDataException; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledMiscellaneousTest extends UnifiedJedisCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledMiscellaneousTest(RedisProtocol protocol) { super(protocol); } @@ -148,6 +158,7 @@ public void broadcast() { } @Test + @SinceRedisVersion(value="7.0.0") public void broadcastWithError() { JedisDataException error = assertThrows(JedisDataException.class, () -> jedis.functionDelete("xyz")); diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSetCommandsTest.java index 2be9dbbf1c..07c8d9e983 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSetCommandsTest.java @@ -2,15 +2,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.SetCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledSetCommandsTest extends SetCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledSetCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSortedSetCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSortedSetCommandsTest.java index c3d0b76ece..7bd76c973d 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSortedSetCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledSortedSetCommandsTest.java @@ -2,15 +2,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.SortedSetCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledSortedSetCommandsTest extends SortedSetCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledSortedSetCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledStringValuesCommandsTest.java b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledStringValuesCommandsTest.java index c9a1c39ae1..c100e2a0fa 100644 --- a/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledStringValuesCommandsTest.java +++ b/src/test/java/redis/clients/jedis/commands/unified/pooled/PooledStringValuesCommandsTest.java @@ -2,15 +2,23 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import redis.clients.jedis.RedisProtocol; import redis.clients.jedis.commands.unified.StringValuesCommandsTestBase; +import redis.clients.jedis.util.EnabledOnCommandRule; +import redis.clients.jedis.util.RedisVersionRule; @RunWith(Parameterized.class) public class PooledStringValuesCommandsTest extends StringValuesCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(PooledCommandsTestHelper.nodeInfo); + @Rule + public EnabledOnCommandRule enabledOnCommandRule = new EnabledOnCommandRule(PooledCommandsTestHelper.nodeInfo); + public PooledStringValuesCommandsTest(RedisProtocol protocol) { super(protocol); } diff --git a/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java b/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java index d2032e5d23..7155a8d9ca 100644 --- a/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java +++ b/src/test/java/redis/clients/jedis/csc/ClientSideCacheFunctionalityTest.java @@ -1,5 +1,6 @@ package redis.clients.jedis.csc; +import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.aMapWithSize; import static org.hamcrest.Matchers.hasSize; @@ -8,21 +9,14 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collector; import java.util.stream.Collectors; import org.hamcrest.Matchers; @@ -508,7 +502,7 @@ public void run() { @Test public void testNullValue() throws InterruptedException { int MAX_SIZE = 20; - String nonExisting = "non-existing-key"; + String nonExisting = "non-existing-key-"+ UUID.randomUUID().toString(); control.del(nonExisting); try (JedisPooled jedis = new JedisPooled(hnp, clientConfig.get(), CacheConfig.builder().maxSize(MAX_SIZE).build())) { @@ -529,8 +523,10 @@ public void testNullValue() throws InterruptedException { assertEquals(1, stats.getMissCount()); control.set(nonExisting, "bar"); - val = jedis.get(nonExisting); - assertEquals("bar", val); + await() + .atMost(5, TimeUnit.SECONDS) + .pollInterval(10, TimeUnit.MILLISECONDS) + .untilAsserted(() -> assertEquals("bar", jedis.get(nonExisting))); assertEquals(1, cache.getSize()); assertEquals("bar", cache.getCacheEntries().iterator().next().getValue()); assertEquals(1, stats.getHitCount()); diff --git a/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java b/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java index db53b085be..5fd9c48e7a 100644 --- a/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java +++ b/src/test/java/redis/clients/jedis/csc/ClientSideCacheTestBase.java @@ -1,19 +1,17 @@ package redis.clients.jedis.csc; import java.util.function.Supplier; + +import io.redis.test.annotations.SinceRedisVersion; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.After; import org.junit.Before; +import org.junit.Rule; +import redis.clients.jedis.*; +import redis.clients.jedis.util.RedisVersionRule; -import redis.clients.jedis.Connection; -import redis.clients.jedis.ConnectionPoolConfig; -import redis.clients.jedis.EndpointConfig; -import redis.clients.jedis.HostAndPort; -import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisClientConfig; - -abstract class ClientSideCacheTestBase { +@SinceRedisVersion(value = "7.4.0", message = "Jedis client-side caching is only supported with Redis 7.4 or later.") +public abstract class ClientSideCacheTestBase { protected static final EndpointConfig endpoint = HostAndPorts.getRedisEndpoint("standalone1"); @@ -21,6 +19,9 @@ abstract class ClientSideCacheTestBase { protected Jedis control; + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(HostAndPorts.getRedisEndpoint("standalone1")); + @Before public void setUp() throws Exception { control = new Jedis(hnp, endpoint.getClientConfigBuilder().build()); diff --git a/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java index 89114d154f..16ab32577b 100644 --- a/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/JedisClusterClientSideCacheTest.java @@ -1,9 +1,10 @@ package redis.clients.jedis.csc; +import io.redis.test.annotations.SinceRedisVersion; import java.util.HashSet; import java.util.Set; import java.util.function.Supplier; - +import org.junit.ClassRule; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.Connection; @@ -13,7 +14,9 @@ import redis.clients.jedis.HostAndPorts; import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisCluster; +import redis.clients.jedis.util.RedisVersionRule; +@SinceRedisVersion(value = "7.4.0", message = "Jedis client-side caching is only supported with Redis 7.4 or later.") public class JedisClusterClientSideCacheTest extends UnifiedJedisClientSideCacheTestBase { private static final Set hnp = new HashSet<>(HostAndPorts.getStableClusterServers()); @@ -28,6 +31,9 @@ public class JedisClusterClientSideCacheTest extends UnifiedJedisClientSideCache return poolConfig; }; + @ClassRule + public static RedisVersionRule versionRule = new RedisVersionRule(hnp.iterator().next(), clientConfig.get()); + @Override protected JedisCluster createRegularJedis() { return new JedisCluster(hnp, clientConfig.get()); diff --git a/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java index d7b2bd4989..9950613bfc 100644 --- a/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/JedisPooledClientSideCacheTest.java @@ -1,13 +1,20 @@ package redis.clients.jedis.csc; +import io.redis.test.annotations.SinceRedisVersion; import org.junit.BeforeClass; +import org.junit.ClassRule; import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.util.RedisVersionRule; +@SinceRedisVersion(value = "7.4.0", message = "Jedis client-side caching is only supported with Redis 7.4 or later.") public class JedisPooledClientSideCacheTest extends JedisPooledClientSideCacheTestBase { + @ClassRule + public static RedisVersionRule versionRule = new RedisVersionRule( + HostAndPorts.getRedisEndpoint("standalone1")); + @BeforeClass public static void prepare() { endpoint = HostAndPorts.getRedisEndpoint("standalone1"); } - } diff --git a/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java index 82da0b14af..e2d2f3c853 100644 --- a/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/JedisSentineledClientSideCacheTest.java @@ -1,14 +1,19 @@ package redis.clients.jedis.csc; +import io.redis.test.utils.RedisVersion; import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import org.junit.Assume; +import org.junit.BeforeClass; import redis.clients.jedis.DefaultJedisClientConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.HostAndPorts; +import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisClientConfig; import redis.clients.jedis.JedisSentineled; +import redis.clients.jedis.util.RedisVersionUtil; public class JedisSentineledClientSideCacheTest extends UnifiedJedisClientSideCacheTestBase { @@ -33,4 +38,12 @@ protected JedisSentineled createCachedJedis(CacheConfig cacheConfig) { return new JedisSentineled(MASTER_NAME, masterClientConfig, cacheConfig, sentinels, sentinelClientConfig); } + @BeforeClass + public static void prepare() { + try (JedisSentineled sentinelClient = new JedisSentineled(MASTER_NAME, masterClientConfig, sentinels, sentinelClientConfig); + Jedis master = new Jedis(sentinelClient.getCurrentMaster(),masterClientConfig)) { + Assume.assumeTrue("Jedis Client side caching is only supported with 'Redis 7.4' or later.", + RedisVersionUtil.getRedisVersion(master).isGreaterThanOrEqualTo(RedisVersion.V7_4)); + } + } } diff --git a/src/test/java/redis/clients/jedis/csc/SSLJedisPooledClientSideCacheTest.java b/src/test/java/redis/clients/jedis/csc/SSLJedisPooledClientSideCacheTest.java index f59f248b7a..d04b19bc1f 100644 --- a/src/test/java/redis/clients/jedis/csc/SSLJedisPooledClientSideCacheTest.java +++ b/src/test/java/redis/clients/jedis/csc/SSLJedisPooledClientSideCacheTest.java @@ -1,22 +1,40 @@ package redis.clients.jedis.csc; +import io.redis.test.utils.RedisVersion; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + import org.junit.AfterClass; +import org.junit.Assume; import org.junit.BeforeClass; + import redis.clients.jedis.HostAndPorts; -import redis.clients.jedis.SSLJedisTest; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.util.RedisVersionUtil; +import redis.clients.jedis.util.TlsUtil; public class SSLJedisPooledClientSideCacheTest extends JedisPooledClientSideCacheTestBase { + private static final String trustStoreName = SSLJedisPooledClientSideCacheTest.class.getSimpleName(); + @BeforeClass public static void prepare() { - SSLJedisTest.setupTrustStore(); endpoint = HostAndPorts.getRedisEndpoint("standalone0-tls"); + + List trustedCertLocation = Collections.singletonList(endpoint.getCertificatesLocation()); + Path trustStorePath = TlsUtil.createAndSaveTestTruststore(trustStoreName, trustedCertLocation,"changeit"); + TlsUtil.setCustomTrustStore(trustStorePath, "changeit"); + + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), endpoint.getClientConfigBuilder().build())) { + Assume.assumeTrue("Jedis Client side caching is only supported with 'Redis 7.4' or later.", + RedisVersionUtil.getRedisVersion(jedis).isGreaterThanOrEqualTo(RedisVersion.V7_4)); + } } @AfterClass - public static void unprepare() { - SSLJedisTest.cleanupTrustStore(); + public static void teardownTrustStore() { + TlsUtil.restoreOriginalTrustStore(); } - } diff --git a/src/test/java/redis/clients/jedis/modules/RedisModuleCommandsTestBase.java b/src/test/java/redis/clients/jedis/modules/RedisModuleCommandsTestBase.java index 9e21fba23f..7e0e085c17 100644 --- a/src/test/java/redis/clients/jedis/modules/RedisModuleCommandsTestBase.java +++ b/src/test/java/redis/clients/jedis/modules/RedisModuleCommandsTestBase.java @@ -6,6 +6,7 @@ import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.runners.Parameterized.Parameters; import redis.clients.jedis.Connection; import redis.clients.jedis.DefaultJedisClientConfig; @@ -16,9 +17,13 @@ import redis.clients.jedis.UnifiedJedis; import redis.clients.jedis.commands.CommandsTestsParameters; import redis.clients.jedis.exceptions.JedisConnectionException; +import redis.clients.jedis.util.RedisVersionRule; public abstract class RedisModuleCommandsTestBase { + @Rule + public RedisVersionRule versionRule = new RedisVersionRule(hnp,DefaultJedisClientConfig.builder().build() ); + /** * Input data for parameterized tests. In principle all subclasses of this * class should be parameterized tests, to run with several versions of RESP. @@ -70,12 +75,5 @@ public void setUp() { public void tearDown() throws Exception { client.close(); } -// -// public static void tearDown() { -// client.close(); -// } -// -// protected static Connection createConnection() { -// return new Connection(hnp); -// } + } diff --git a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java index ad960209e3..61ad8cda61 100644 --- a/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/AggregationTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; +import io.redis.test.annotations.SinceRedisVersion; import org.hamcrest.Matchers; import org.junit.BeforeClass; import org.junit.Test; @@ -201,6 +202,7 @@ public void testAggregationBuilderVerbatim() { } @Test + @SinceRedisVersion(value="7.4.0", message="ADDSCORES") public void testAggregationBuilderAddScores() { Schema sc = new Schema(); sc.addSortableTextField("name", 1.0); diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java index 0776eabcd4..d6c1739371 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchTest.java @@ -4,6 +4,9 @@ import java.util.*; import java.util.stream.Collectors; + +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.hamcrest.Matchers; import org.junit.Assume; import org.junit.BeforeClass; @@ -17,13 +20,13 @@ import redis.clients.jedis.search.*; import redis.clients.jedis.search.Schema.*; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +import redis.clients.jedis.util.RedisVersionUtil; import redis.clients.jedis.util.SafeEncoder; @RunWith(Parameterized.class) public class SearchTest extends RedisModuleCommandsTestBase { private static final String index = "testindex"; - @BeforeClass public static void prepare() { RedisModuleCommandsTestBase.prepare(); @@ -413,8 +416,10 @@ public void testQueryParams() { Query query = new Query("@numval:[$min $max]").addParam("min", 1).addParam("max", 2).dialect(2); assertEquals(2, client.ftSearch(index, query).getTotalResults()); - query = new Query("@numval:[$eq]").addParam("eq", 2).dialect(4); - assertEquals(1, client.ftSearch(index, query).getTotalResults()); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4) ) { + query = new Query("@numval:[$eq]").addParam("eq", 2).dialect(4); + assertEquals(1, client.ftSearch(index, query).getTotalResults()); + } } @Test @@ -540,9 +545,11 @@ public void testJsonWithAlias() { assertEquals(1, res.getTotalResults()); assertEquals("king:1", res.getDocuments().get(0).getId()); - res = client.ftSearch(index, new Query("@num:[42]").dialect(4)); - assertEquals(1, res.getTotalResults()); - assertEquals("king:1", res.getDocuments().get(0).getId()); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4) ) { + res = client.ftSearch(index, new Query("@num:[42]").dialect(4)); + assertEquals(1, res.getTotalResults()); + assertEquals("king:1", res.getDocuments().get(0).getId()); + } } @Test diff --git a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java index 03d4dc62dd..8ab421809d 100644 --- a/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java +++ b/src/test/java/redis/clients/jedis/modules/search/SearchWithParamsTest.java @@ -7,6 +7,9 @@ import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; + +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisVersion; import org.hamcrest.Matchers; import org.junit.BeforeClass; import org.junit.Ignore; @@ -32,6 +35,7 @@ import redis.clients.jedis.search.schemafields.GeoShapeField.CoordinateSystem; import redis.clients.jedis.search.schemafields.VectorField.VectorAlgorithm; import redis.clients.jedis.modules.RedisModuleCommandsTestBase; +import redis.clients.jedis.util.RedisVersionUtil; @RunWith(Parameterized.class) public class SearchWithParamsTest extends RedisModuleCommandsTestBase { @@ -220,18 +224,29 @@ public void search() { @Test public void textFieldParams() { - assertOK(client.ftCreate("testindex", TextField.of("title").indexMissing().indexEmpty() + assertOK(client.ftCreate("testindex", TextField.of("title") .weight(2.5).noStem().phonetic("dm:en").withSuffixTrie().sortable())); - assertOK(client.ftCreate("testunfindex", TextField.of("title").indexMissing().indexEmpty() + assertOK(client.ftCreate("testunfindex", TextField.of("title") .weight(2.5).noStem().phonetic("dm:en").withSuffixTrie().sortableUNF())); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + assertOK(client.ftCreate("testindex-missing", + TextField.of("title").indexMissing().indexEmpty().weight(2.5).noStem().phonetic("dm:en") + .withSuffixTrie().sortable())); + + assertOK(client.ftCreate("testunfindex-missing", + TextField.of("title").indexMissing().indexEmpty().weight(2.5).noStem().phonetic("dm:en") + .withSuffixTrie().sortableUNF())); + } + assertOK(client.ftCreate("testnoindex", TextField.of("title").sortable().noIndex())); assertOK(client.ftCreate("testunfnoindex", TextField.of("title").sortableUNF().noIndex())); } @Test + @SinceRedisVersion(value = "7.4.0", message = "optional params since 7.4.0 are being tested") public void searchTextFieldsCondition() { assertOK(client.ftCreate(index, FTCreateParams.createParams(), TextField.of("title"), TextField.of("body").indexMissing().indexEmpty())); @@ -326,7 +341,12 @@ public void numericFilter() { @Test public void numericFieldParams() { assertOK(client.ftCreate("testindex", TextField.of("title"), - NumericField.of("price").as("px").indexMissing().sortable())); + NumericField.of("price").as("px").sortable())); + + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + assertOK(client.ftCreate("testindex-missing", TextField.of("title"), + NumericField.of("price").as("px").indexMissing().sortable())); + } assertOK(client.ftCreate("testnoindex", TextField.of("title"), NumericField.of("price").as("px").sortable().noIndex())); @@ -412,9 +432,16 @@ public void geoFilterAndGeoCoordinateObject() { @Test public void geoFieldParams() { - assertOK(client.ftCreate("testindex", TextField.of("title"), GeoField.of("location").as("loc").indexMissing().sortable())); + assertOK(client.ftCreate("testindex", TextField.of("title"), + GeoField.of("location").as("loc").sortable())); - assertOK(client.ftCreate("testnoindex", TextField.of("title"), GeoField.of("location").as("loc").sortable().noIndex())); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + assertOK(client.ftCreate("testindex-missing", TextField.of("title"), + GeoField.of("location").as("loc").indexMissing().sortable())); + } + + assertOK(client.ftCreate("testnoindex", TextField.of("title"), + GeoField.of("location").as("loc").sortable().noIndex())); } @Test @@ -502,20 +529,22 @@ public void geoShapeFilterFlat() throws ParseException { assertEquals(2, result.getDocuments().size()); // intersects and disjoint - final Polygon disjointersect = factory.createPolygon(new Coordinate[]{new Coordinate(150, 150), + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + final Polygon disjointersect = factory.createPolygon(new Coordinate[]{new Coordinate(150, 150), new Coordinate(150, 250), new Coordinate(250, 250), new Coordinate(250, 150), new Coordinate(150, 150)}); - result = client.ftSearch(index, "@geom:[intersects $poly]", - FTSearchParams.searchParams().addParam("poly", disjointersect).dialect(3)); - assertEquals(1, result.getTotalResults()); - assertEquals(1, result.getDocuments().size()); - assertEquals(large, reader.read(result.getDocuments().get(0).getString("geom"))); - - result = client.ftSearch(index, "@geom:[disjoint $poly]", - FTSearchParams.searchParams().addParam("poly", disjointersect).dialect(3)); - assertEquals(1, result.getTotalResults()); - assertEquals(1, result.getDocuments().size()); - assertEquals(small, reader.read(result.getDocuments().get(0).getString("geom"))); + result = client.ftSearch(index, "@geom:[intersects $poly]", + FTSearchParams.searchParams().addParam("poly", disjointersect).dialect(3)); + assertEquals(1, result.getTotalResults()); + assertEquals(1, result.getDocuments().size()); + assertEquals(large, reader.read(result.getDocuments().get(0).getString("geom"))); + + result = client.ftSearch(index, "@geom:[disjoint $poly]", + FTSearchParams.searchParams().addParam("poly", disjointersect).dialect(3)); + assertEquals(1, result.getTotalResults()); + assertEquals(1, result.getDocuments().size()); + assertEquals(small, reader.read(result.getDocuments().get(0).getString("geom"))); + } // point type final Point point = factory.createPoint(new Coordinate(30, 30)); @@ -529,9 +558,13 @@ public void geoShapeFilterFlat() throws ParseException { @Test public void geoShapeFieldParams() { - assertOK(client.ftCreate("testindex", GeoShapeField.of("geometry", CoordinateSystem.SPHERICAL).as("geom").indexMissing())); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + assertOK(client.ftCreate("testindex-missing", + GeoShapeField.of("geometry", CoordinateSystem.SPHERICAL).as("geom").indexMissing())); + } - assertOK(client.ftCreate("testnoindex", GeoShapeField.of("geometry", CoordinateSystem.SPHERICAL).as("geom").noIndex())); + assertOK(client.ftCreate("testnoindex", + GeoShapeField.of("geometry", CoordinateSystem.SPHERICAL).as("geom").noIndex())); } @Test @@ -609,8 +642,10 @@ public void testQueryParams() { FTSearchParams.searchParams().params(paramValues) .dialect(2)).getTotalResults()); - assertEquals(1, client.ftSearch(index, "@numval:[$eq]", - FTSearchParams.searchParams().addParam("eq", 2).dialect(4)).getTotalResults()); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4) ) { + assertEquals(1, client.ftSearch(index, "@numval:[$eq]", + FTSearchParams.searchParams().addParam("eq", 2).dialect(4)).getTotalResults()); + } } @Test @@ -673,9 +708,11 @@ public void testJsonWithAlias() { assertEquals(1, res.getTotalResults()); assertEquals("king:1", res.getDocuments().get(0).getId()); - res = client.ftSearch(index, "@num:[42]", FTSearchParams.searchParams().dialect(4)); - assertEquals(1, res.getTotalResults()); - assertEquals("king:1", res.getDocuments().get(0).getId()); + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + res = client.ftSearch(index, "@num:[42]", FTSearchParams.searchParams().dialect(4)); + assertEquals(1, res.getTotalResults()); + assertEquals("king:1", res.getDocuments().get(0).getId()); + } } @Test @@ -945,12 +982,22 @@ public void caseSensitiveTagField() { @Test public void tagFieldParams() { assertOK(client.ftCreate("testindex", TextField.of("title"), - TagField.of("category").as("cat").indexMissing().indexEmpty() - .separator(',').caseSensitive().withSuffixTrie().sortable())); + TagField.of("category").as("cat").separator(',') + .caseSensitive().withSuffixTrie().sortable())); assertOK(client.ftCreate("testunfindex", TextField.of("title"), - TagField.of("category").as("cat").indexMissing().indexEmpty() - .separator(',').caseSensitive().withSuffixTrie().sortableUNF())); + TagField.of("category").as("cat").separator(',') + .caseSensitive().withSuffixTrie().sortableUNF())); + + if (RedisVersionUtil.getRedisVersion(client).isGreaterThanOrEqualTo(RedisVersion.V7_4)) { + assertOK(client.ftCreate("testindex-missing", TextField.of("title"), + TagField.of("category").as("cat").indexMissing().indexEmpty().separator(',') + .caseSensitive().withSuffixTrie().sortable())); + + assertOK(client.ftCreate("testunfindex-missing", TextField.of("title"), + TagField.of("category").as("cat").indexMissing().indexEmpty().separator(',') + .caseSensitive().withSuffixTrie().sortableUNF())); + } assertOK(client.ftCreate("testnoindex", TextField.of("title"), TagField.of("category").as("cat").sortable().noIndex())); @@ -1207,19 +1254,21 @@ public void testFlatVectorSimilarity() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "no optional params before 7.4.0") public void vectorFieldParams() { Map attr = new HashMap<>(); attr.put("TYPE", "FLOAT32"); attr.put("DIM", 2); attr.put("DISTANCE_METRIC", "L2"); - assertOK(client.ftCreate("testindex", new VectorField("vector", VectorAlgorithm.HNSW, attr).as("vec").indexMissing())); + assertOK(client.ftCreate("testindex-missing", new VectorField("vector", VectorAlgorithm.HNSW, attr).as("vec").indexMissing())); // assertOK(client.ftCreate("testnoindex", new VectorField("vector", VectorAlgorithm.HNSW, attr).as("vec").noIndex())); // throws Field `NOINDEX` does not have a type } @Test + @SinceRedisVersion(value = "7.4.0", message = "FLOAT16") public void float16StorageType() { assertOK(client.ftCreate(index, VectorField.builder().fieldName("v") @@ -1231,6 +1280,7 @@ public void float16StorageType() { } @Test + @SinceRedisVersion(value = "7.4.0", message = "BFLOAT16") public void bfloat16StorageType() { assertOK(client.ftCreate(index, VectorField.builder().fieldName("v") diff --git a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java index 723e914d47..ab8d81160a 100644 --- a/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java +++ b/src/test/java/redis/clients/jedis/modules/timeseries/TimeSeriesTest.java @@ -373,20 +373,20 @@ public void testAddStar() throws InterruptedException { assertEquals("OK", client.tsCreate("seriesAdd2", TSCreateParams.createParams().retention(10000L).labels(labels))); long startTime = System.currentTimeMillis(); - Thread.sleep(1); + Thread.sleep(2); // long add1 = client.tsAdd("seriesAdd2", 1.1, 10000); long add1 = client.tsAdd("seriesAdd2", 1.1); assertTrue(add1 > startTime); - Thread.sleep(1); + Thread.sleep(2); long add2 = client.tsAdd("seriesAdd2", 3.2); assertTrue(add2 > add1); - Thread.sleep(1); + Thread.sleep(2); long add3 = client.tsAdd("seriesAdd2", 3.2); assertTrue(add3 > add2); - Thread.sleep(1); + Thread.sleep(2); long add4 = client.tsAdd("seriesAdd2", -1.2); assertTrue(add4 > add3); - Thread.sleep(1); + Thread.sleep(2); long endTime = System.currentTimeMillis(); assertTrue(endTime > add4); diff --git a/src/test/java/redis/clients/jedis/util/EnabledOnCommandRule.java b/src/test/java/redis/clients/jedis/util/EnabledOnCommandRule.java new file mode 100644 index 0000000000..0e0163cd4c --- /dev/null +++ b/src/test/java/redis/clients/jedis/util/EnabledOnCommandRule.java @@ -0,0 +1,123 @@ +package redis.clients.jedis.util; + +import io.redis.test.annotations.EnabledOnCommand; +import java.lang.reflect.Method; +import java.util.Map; + +import org.junit.Assume; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import redis.clients.jedis.*; +import redis.clients.jedis.resps.CommandInfo; + +public class EnabledOnCommandRule implements TestRule { + + private final HostAndPort hostPort; + private final JedisClientConfig config; + + public EnabledOnCommandRule(HostAndPort hostPort, JedisClientConfig config) { + this.hostPort = hostPort; + this.config = config; + } + + public EnabledOnCommandRule(EndpointConfig endpointConfig) { + this.hostPort = endpointConfig.getHostAndPort(); + this.config = endpointConfig.getClientConfigBuilder().build(); + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try (Jedis jedisClient = new Jedis(hostPort, config)) { + String[] command = getCommandFromAnnotations(description); + + if (command != null && !isCommandAvailable(jedisClient, command[0],command[1])) { + Assume.assumeTrue("Test requires Redis command '" + command[0] + " " + command[1] + "' to be available, but it was not found.", false); + } + + base.evaluate(); + } + } + + /** + * Retrieves the command from either class-level or method-level annotations. + * + * @param description The test description containing annotations. + * @return The Redis array containing command, subcommand from the annotations, or null if not found. + */ + private String[] getCommandFromAnnotations(Description description) { + // Retrieve class-level and method-level annotations + EnabledOnCommand descriptionCommandAnnotation = description.getAnnotation(EnabledOnCommand.class); + if (descriptionCommandAnnotation != null) { + return new String[] {descriptionCommandAnnotation.value(), descriptionCommandAnnotation.subCommand()}; + } + + EnabledOnCommand methodCommand = getMethodAnnotation(description); + if (methodCommand != null) { + return new String[] {methodCommand.value(), methodCommand.subCommand()}; + } + + EnabledOnCommand classCommand = description.getTestClass().getAnnotation(EnabledOnCommand.class); + if (classCommand != null) { + return new String[] {classCommand.value(), classCommand.subCommand()}; + } + + return null; + } + + private EnabledOnCommand getMethodAnnotation(Description description) { + try { + // description.getAnnotation() does not return anootaion when used + // with parametrised tests + String methodName = description.getMethodName(); + if (methodName != null) { + Class testClass = description.getTestClass(); + if (testClass != null) { + for (Method method : testClass.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method.getAnnotation(EnabledOnCommand.class); + } + } + } + } + } catch (Exception e) { + // Handle any potential exceptions here + throw new RuntimeException("Could not resolve EnabledOnCommand annotation",e); + } + return null; + } + + /** + * Checks if the specified Redis command is available. + */ + private boolean isCommandAvailable(Jedis jedisClient, String command, String subCommand) { + try { + Map commandInfoMap= jedisClient.commandInfo(command); + CommandInfo commandInfo = commandInfoMap.get(command.toLowerCase()); + if (commandInfo != null) { + // If a subCommand is provided, check for the subcommand under this command + if (subCommand != null && !subCommand.isEmpty()) { + // Check if this command supports the provided subcommand + String replySubCommandName = command + '|' + subCommand; + for (CommandInfo supportedSubCommand : commandInfo.getSubcommands().values()) { + if (replySubCommandName.equalsIgnoreCase(supportedSubCommand.getName())) { + return true; + } + } + return false; // Subcommand not found + } + return true; // Command found (no subcommand required) + } + return false; // Command not found + } catch (Exception e) { + String msg = String.format("Error found while EnableOnCommand for command '%s'", command); + throw new RuntimeException(msg, e); + } + } + }; + } +} diff --git a/src/test/java/redis/clients/jedis/util/GeoCoordinateMatcher.java b/src/test/java/redis/clients/jedis/util/GeoCoordinateMatcher.java index 5b21d3d427..0fb8f8c7cc 100644 --- a/src/test/java/redis/clients/jedis/util/GeoCoordinateMatcher.java +++ b/src/test/java/redis/clients/jedis/util/GeoCoordinateMatcher.java @@ -7,28 +7,37 @@ public class GeoCoordinateMatcher extends TypeSafeMatcher { public static GeoCoordinateMatcher atCoordinates(double longitude, double latitude) { - return new GeoCoordinateMatcher(longitude, latitude); + return atCoordinates(new GeoCoordinate(longitude, latitude)); + } + + static GeoCoordinateMatcher atCoordinates(GeoCoordinate expected) { + return new GeoCoordinateMatcher(expected); } private static final double EPSILON = 1e-5; - private final double longitude; - private final double latitude; + private final GeoCoordinate expected; - public GeoCoordinateMatcher(double longitude, double latitude) { - this.longitude = longitude; - this.latitude = latitude; + public GeoCoordinateMatcher(GeoCoordinate expected) { + this.expected = expected; } @Override - protected boolean matchesSafely(GeoCoordinate item) { - return item != null && - Math.abs(longitude - item.getLongitude()) < EPSILON && - Math.abs(latitude - item.getLatitude()) < EPSILON; + protected boolean matchesSafely(GeoCoordinate actual) { + return Math.abs(actual.getLatitude() - expected.getLatitude()) < EPSILON && + Math.abs(actual.getLongitude() - expected.getLongitude()) < EPSILON; } @Override public void describeTo(Description description) { - description.appendText("matches " + longitude + " longitude " + latitude + " latitude with precision " + EPSILON); + description.appendText("a GeoCoordinate within ") + .appendValue(EPSILON) + .appendText(" of ") + .appendValue(expected); + } + + @Override + protected void describeMismatchSafely(GeoCoordinate actual, Description mismatchDescription) { + mismatchDescription.appendText("was ").appendValue(actual); } } diff --git a/src/test/java/redis/clients/jedis/util/GeoRadiusResponseMatcher.java b/src/test/java/redis/clients/jedis/util/GeoRadiusResponseMatcher.java new file mode 100644 index 0000000000..a596a58de2 --- /dev/null +++ b/src/test/java/redis/clients/jedis/util/GeoRadiusResponseMatcher.java @@ -0,0 +1,55 @@ +package redis.clients.jedis.util; + +import java.util.Arrays; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeMatcher; +import redis.clients.jedis.resps.GeoRadiusResponse; + +public class GeoRadiusResponseMatcher extends TypeSafeMatcher { + + public static GeoRadiusResponseMatcher ofResponse(GeoRadiusResponse expected) { + return new GeoRadiusResponseMatcher(expected); + } + + private final GeoRadiusResponse expected; + + public GeoRadiusResponseMatcher(GeoRadiusResponse expected) { + this.expected = expected; + } + + @Override + protected boolean matchesSafely(GeoRadiusResponse actual) { + // Check if coordinates match within the tolerance + if (!GeoCoordinateMatcher.atCoordinates(expected.getCoordinate()) + .matches(actual.getCoordinate())) { + return false; + } + + // Check if other attributes match exactly + if (Double.compare(expected.getDistance(), actual.getDistance()) != 0) { + return false; + } + if (Long.compare(expected.getRawScore(), actual.getRawScore()) != 0) { + return false; + } + return Arrays.equals(expected.getMember(), actual.getMember()); + } + + @Override + public void describeTo(Description description) { + description.appendText("a GeoRadiusResponse with coordinate ") + .appendValue(expected.getCoordinate()) + .appendText(", distance ") + .appendValue(expected.getDistance()) + .appendText(", rawScore ") + .appendValue(expected.getRawScore()) + .appendText("and member ") + .appendValue(expected.getMemberByString()); + } + + @Override + protected void describeMismatchSafely(GeoRadiusResponse actual, Description mismatchDescription) { + mismatchDescription.appendText("was ").appendValue(actual); + } + +} \ No newline at end of file diff --git a/src/test/java/redis/clients/jedis/util/RedisVersionRule.java b/src/test/java/redis/clients/jedis/util/RedisVersionRule.java new file mode 100644 index 0000000000..0f3c471bae --- /dev/null +++ b/src/test/java/redis/clients/jedis/util/RedisVersionRule.java @@ -0,0 +1,104 @@ +package redis.clients.jedis.util; + +import io.redis.test.annotations.SinceRedisVersion; +import io.redis.test.utils.RedisInfo; +import io.redis.test.utils.RedisVersion; +import org.junit.Assume; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import redis.clients.jedis.EndpointConfig; +import redis.clients.jedis.HostAndPort; +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisClientConfig; + +import java.lang.reflect.Method; + +import static redis.clients.jedis.util.RedisVersionUtil.forcedVersion; + +public class RedisVersionRule implements TestRule { + private static final Logger logger = LoggerFactory.getLogger(RedisVersionRule.class); + + private final HostAndPort hostPort; + private final JedisClientConfig config; + + + public RedisVersionRule(EndpointConfig endpoint) { + this.hostPort = endpoint.getHostAndPort(); + this.config = endpoint.getClientConfigBuilder().build(); + } + + public RedisVersionRule(HostAndPort hostPort, JedisClientConfig config) { + this.hostPort = hostPort; + this.config = config; + } + + @Override + public Statement apply(Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try ( Jedis jedisClient = new Jedis(hostPort, config)) { + SinceRedisVersion descriptionVersionAnnotation = description.getAnnotation(SinceRedisVersion.class); + if (descriptionVersionAnnotation != null) { + checkRedisVersion(jedisClient, descriptionVersionAnnotation); + } + + SinceRedisVersion classVersionAnnotation = description.getTestClass().getAnnotation(SinceRedisVersion.class); + if (classVersionAnnotation != null) { + checkRedisVersion(jedisClient, classVersionAnnotation); + } + + SinceRedisVersion methodVersionAnnotation = getMethodAnnotation(description); + if (methodVersionAnnotation != null) { + checkRedisVersion(jedisClient, methodVersionAnnotation); + } + + // Return the base statement to execute the test + base.evaluate(); + } + } + private void checkRedisVersion(Jedis jedisClient, SinceRedisVersion versionAnnotation) { + + // Check if the environment variable is set + RedisVersion currentVersion; + + if (forcedVersion != null) { + logger.info("Using forced Redis server version from environment variable: " + forcedVersion); + currentVersion = forcedVersion; + } else { + RedisInfo info = RedisInfo.parseInfoServer(jedisClient.info("server")); + currentVersion = RedisVersion.of(info.getRedisVersion()); + } + + RedisVersion minRequiredVersion = RedisVersion.of(versionAnnotation.value()); + if (currentVersion.isLessThan(minRequiredVersion)) { + Assume.assumeTrue("Test requires Redis version " + minRequiredVersion + " or later, but found " + currentVersion, false); + } + } + + private SinceRedisVersion getMethodAnnotation(Description description) { + try { + // description.getAnnotation() does not return any method level annotation when used + // with parametrised tests + String methodName = description.getMethodName(); + if (methodName != null) { + Class testClass = description.getTestClass(); + if (testClass != null) { + for (Method method : testClass.getDeclaredMethods()) { + if (method.getName().equals(methodName)) { + return method.getAnnotation(SinceRedisVersion.class); + } + } + } + } + } catch (Exception e) { + throw new RuntimeException("Could not resolve EnabledOnCommand annotation", e); + } + return null; + } + }; + } +} diff --git a/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java b/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java index fed3055b4f..16b5a0bbb5 100644 --- a/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java +++ b/src/test/java/redis/clients/jedis/util/RedisVersionUtil.java @@ -1,32 +1,54 @@ package redis.clients.jedis.util; -import redis.clients.jedis.EndpointConfig; -import redis.clients.jedis.Jedis; +import io.redis.test.utils.RedisInfo; +import io.redis.test.utils.RedisVersion; +import redis.clients.jedis.*; public class RedisVersionUtil { - public static Integer getRedisMajorVersionNumber(EndpointConfig endpoint) { - String completeVersion = null; + static final String FORCE_REDIS_SERVER_VERSION_ENV = "forceRedisServerVersion"; - try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), - endpoint.getClientConfigBuilder().build())) { - String info = jedis.info("server"); - String[] splitted = info.split("\\s+|:"); - for (int i = 0; i < splitted.length; i++) { - if (splitted[i].equalsIgnoreCase("redis_version")) { - completeVersion = splitted[i + 1]; - break; - } - } + static final RedisVersion forcedVersion = System.getenv(FORCE_REDIS_SERVER_VERSION_ENV) != null + ? RedisVersion.of(System.getenv(FORCE_REDIS_SERVER_VERSION_ENV)) + : null; + + public static RedisVersion getRedisVersion(Connection conn) { + if (forcedVersion != null) { + return forcedVersion; + } + + try (Jedis jedis = new Jedis(conn)) { + return getRedisVersion(jedis); + } + } + + public static RedisVersion getRedisVersion(UnifiedJedis jedis) { + if (forcedVersion != null) { + return forcedVersion; } - if (completeVersion == null) { - return null; + Object response = SafeEncoder.encodeObject(jedis.sendCommand(Protocol.Command.INFO, "server")); + RedisInfo info = RedisInfo.parseInfoServer(response.toString()); + return RedisVersion.of(info.getRedisVersion()); + } + + public static RedisVersion getRedisVersion(Jedis jedis) { + if (forcedVersion != null) { + return forcedVersion; } - return Integer.parseInt(completeVersion.substring(0, completeVersion.indexOf("."))); + + RedisInfo info = RedisInfo.parseInfoServer(jedis.info("server")); + return RedisVersion.of(info.getRedisVersion()); } - public static boolean checkRedisMajorVersionNumber(int minVersion, EndpointConfig endpoint) { - return getRedisMajorVersionNumber(endpoint) >= minVersion; + public static RedisVersion getRedisVersion(EndpointConfig endpoint) { + if (forcedVersion != null) { + return forcedVersion; + } + + try (Jedis jedis = new Jedis(endpoint.getHostAndPort(), + endpoint.getClientConfigBuilder().build())) { + return getRedisVersion(jedis); + } } } diff --git a/src/test/java/redis/clients/jedis/util/TestEnvUtil.java b/src/test/java/redis/clients/jedis/util/TestEnvUtil.java new file mode 100644 index 0000000000..d7a4299d01 --- /dev/null +++ b/src/test/java/redis/clients/jedis/util/TestEnvUtil.java @@ -0,0 +1,23 @@ +package redis.clients.jedis.util; + +import java.util.Optional; + +public class TestEnvUtil { + // Redis servers running inside docker + public static final String ENV_DOCKER = "docker"; + + private static final String TEST_ENV_PROVIDER = System.getenv().getOrDefault("TEST_ENV_PROVIDER", ENV_DOCKER); + + private static final String TESTMODULE_SO_PATH = Optional.ofNullable(System.getenv("TESTMODULE_SO")) + .orElseGet(() -> isContainerEnv() + ? "/redis/work/modules/testmodule.so" + : "/tmp/testmodule.so"); + + public static boolean isContainerEnv() { + return TEST_ENV_PROVIDER.equals(ENV_DOCKER); + } + + public static String testModuleSoPath() { + return TESTMODULE_SO_PATH; + } +} diff --git a/src/test/java/redis/clients/jedis/util/TlsUtil.java b/src/test/java/redis/clients/jedis/util/TlsUtil.java new file mode 100644 index 0000000000..96005a60db --- /dev/null +++ b/src/test/java/redis/clients/jedis/util/TlsUtil.java @@ -0,0 +1,304 @@ +package redis.clients.jedis.util; + +import javax.net.ssl.*; +import java.io.*; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class TlsUtil { + + private static final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore"; + private static final String TRUST_STORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword"; + private static final String TRUST_STORE_TYPE_PROPERTY = "javax.net.ssl.trustStoreType"; + + private static String originalTrustStore; + private static String originalTrustStoreType; + private static String originalTrustStorePassword; + + private static final String TRUST_STORE_TYPE = "JCEKS"; + private static final String CERTIFICATE_TYPE = "X.509"; + + private static final String TEST_WORK_FOLDER = System.getenv().getOrDefault("TEST_WORK_FOLDER", "/tmp/redis-env-work"); + private static final String TEST_TRUSTSTORE = System.getenv().getOrDefault("TEST_TRUSTSTORE", "truststore.jceks"); + private static final String TEST_CA_CERT = System.getenv().getOrDefault("TEST_CA_CERT", "ca.crt"); + private static final String TEST_SERVER_CERT = System.getenv().getOrDefault("TEST_SERVER_CERT", "redis.crt"); + + public static void setCustomTrustStore(Path customTrustStorePath, String customTrustStorePassword) { + // Store original properties + originalTrustStore = System.getProperty(TRUST_STORE_PROPERTY); + originalTrustStorePassword = System.getProperty(TRUST_STORE_PASSWORD_PROPERTY); + originalTrustStoreType = System.getProperty(TRUST_STORE_TYPE_PROPERTY); + // Set new properties for the custom truststore + System.setProperty(TRUST_STORE_PROPERTY, customTrustStorePath.toAbsolutePath().toString()); + System.setProperty(TRUST_STORE_TYPE_PROPERTY, TRUST_STORE_TYPE); + if (customTrustStorePassword != null) { + System.setProperty(TRUST_STORE_PASSWORD_PROPERTY, customTrustStorePassword); + } else { + System.clearProperty(TRUST_STORE_PASSWORD_PROPERTY); + } + + reinitializeDefaultSSLContext(); + } + + public static void reinitializeDefaultSSLContext(){ + String trustStorePath = System.getProperty(TRUST_STORE_PROPERTY); + String trustStorePassword = System.getProperty(TRUST_STORE_PASSWORD_PROPERTY); + String trustStoreType = System.getProperty(TRUST_STORE_TYPE_PROPERTY, KeyStore.getDefaultType()); + // Load the new truststore + KeyStore trustStore = null; + try { + trustStore = KeyStore.getInstance(trustStoreType); + try (java.io.FileInputStream trustStoreStream = new java.io.FileInputStream(trustStorePath)) { + trustStore.load(trustStoreStream, trustStorePassword.toCharArray()); + } catch (CertificateException | IOException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(trustStore); + + SSLContext newSslContext = SSLContext.getInstance("TLS"); + newSslContext.init(null, tmf.getTrustManagers(), null); + SSLContext.setDefault(newSslContext); + } catch (KeyStoreException | KeyManagementException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + public static void restoreOriginalTrustStore() { + // Restore original properties + if (originalTrustStore != null) { + System.setProperty(TRUST_STORE_PROPERTY, originalTrustStore); + } else { + System.clearProperty(TRUST_STORE_PROPERTY); + } + + if ( originalTrustStoreType != null) { + System.setProperty(TRUST_STORE_TYPE_PROPERTY, originalTrustStoreType); + } else { + System.clearProperty(TRUST_STORE_TYPE_PROPERTY); + } + + if (originalTrustStorePassword != null) { + System.setProperty(TRUST_STORE_PASSWORD_PROPERTY, originalTrustStorePassword); + } else { + System.clearProperty(TRUST_STORE_PASSWORD_PROPERTY); + } + } + + private static Path envCa(Path certLocation) { + if (TestEnvUtil.isContainerEnv()) { + return Paths.get(TEST_WORK_FOLDER, certLocation.toString(), TEST_CA_CERT); + } else { + // Legacy test env uses same certificate & truststore for all tests + return Paths.get("src/test/resources/private.crt"); + } + } + + private static Path envServerCert(Path certLocation) { + if (TestEnvUtil.isContainerEnv()) { + return Paths.get(TEST_WORK_FOLDER, certLocation.toString(), TEST_SERVER_CERT); + } else { + // Legacy test env uses same certificate & truststore for all tests + return Paths.get("src/test/resources/private.crt"); + } + } + + public static Path testTruststorePath(String name) { + if (TestEnvUtil.isContainerEnv()) { + return Paths.get(TEST_WORK_FOLDER, name + '-' + TEST_TRUSTSTORE); + } else { + // Legacy test env uses same certificate & truststore for all tests + return Paths.get("src/test/resources/truststore.jceks"); + } + } + + public static Path createAndSaveTestTruststore(String trustStoreName, List certificateLocations, String truststorePassword) { + List trustedCertPaths = new ArrayList<>(); + + // Traverse each location in certificateLocations and add both CA and Server certificates + for (Path location : certificateLocations) { + trustedCertPaths.add(envCa(location).toAbsolutePath()); + trustedCertPaths.add(envServerCert(location).toAbsolutePath()); + } + + Path trustStorePath = testTruststorePath(trustStoreName).toAbsolutePath(); + + return createAndSaveTruststore(trustedCertPaths, trustStorePath, truststorePassword); + } + + /** + * Creates an empty truststore. + * + * @return An empty KeyStore object. + * @throws KeyStoreException If there's an error initializing the truststore. + * @throws IOException If there's an error loading the truststore. + * @throws NoSuchAlgorithmException If the algorithm used to check the integrity of the truststore cannot be found. + * @throws CertificateException If any of the certificates in the truststore could not be loaded. + */ + private static KeyStore createTruststore() throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { + KeyStore trustStore = KeyStore.getInstance(TRUST_STORE_TYPE); + trustStore.load(null, null); + return trustStore; + } + + /** + * Adds a trusted certificate to the given truststore. + * + * @param trustStore The KeyStore object. + * @param alias Alias for the certificate. + * @param certPath Path to the certificate file. + * @throws Exception If there's an error adding the certificate. + */ + private static void addTrustedCertificate(KeyStore trustStore, String alias, Path certPath) throws Exception { + X509Certificate cert = loadCertificate(certPath); + trustStore.setCertificateEntry(alias, cert); + } + + /** + * Loads an X.509 certificate from the given file path. + * + * @param certPath Path to the certificate file. + * @return An X509Certificate object. + * @throws Exception If there's an error loading the certificate. + */ + private static X509Certificate loadCertificate(Path certPath) throws Exception { + try (FileInputStream fis = new FileInputStream(certPath.toFile())) { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + return (X509Certificate) certFactory.generateCertificate(fis); + } + } + + /** + * Creates a truststore, adds multiple trusted certificates, and saves it to the specified path. + * + * @param trustedCertPaths List of certificate file paths to add to the truststore. + * @param truststorePath Path to save the generated truststore. + * @param truststorePassword Password for the truststore. + * @return Path to the saved truststore file. + */ + public static Path createAndSaveTruststore(List trustedCertPaths, Path truststorePath, String truststorePassword) { + try { + KeyStore trustStore = createTruststore(); + + for (Path certPath : trustedCertPaths) { + addTrustedCertificate(trustStore, "trusted-cert-" + UUID.randomUUID(), certPath); + } + + try (FileOutputStream fos = new FileOutputStream(truststorePath.toFile())) { + trustStore.store(fos, truststorePassword.toCharArray()); + } catch (IOException e) { + throw new RuntimeException("Failed to save truststore to " + truststorePath + ": " + e.getMessage(), e); + } + } catch (Exception e) { + throw new RuntimeException("Failed to create and save truststore: " + e.getMessage(), e); + } + + return truststorePath; + } + + + /** + * Creates an SSLSocketFactory that trusts all certificates in truststore.jceks. + * for given test environment + */ + public static SSLSocketFactory sslSocketFactoryForEnv(Path certLocations){ + return sslSocketFactory(envCa(certLocations)); + } + + /** + * Returns SSLSocketFactory configured with Truststore containing provided CA cert + */ + private static SSLSocketFactory sslSocketFactory(Path trustedCertPath) { + + KeyStore trustStore = null; + try { + trustStore = createTruststore(); + addTrustedCertificate(trustStore, "trusted-cert-" + UUID.randomUUID(), trustedCertPath.toAbsolutePath()); + + TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX"); + trustManagerFactory.init(trustStore); + TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); + + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, trustManagers, new SecureRandom()); + return sslContext.getSocketFactory(); + } catch (Exception e) { + throw new RuntimeException("Failed to initialise SslSocketFactory for " + trustedCertPath , e); + } + + } + + /** + * Creates an SSLSocketFactory with a trust manager that does not trust any certificates. + */ + public static SSLSocketFactory createTrustNoOneSslSocketFactory() throws Exception { + TrustManager[] unTrustManagers = new TrustManager[]{new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + throw new CertificateException("Using a trust manager that does not trust any certificates for test purposes!",new InvalidAlgorithmParameterException()); + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + throw new CertificateException("Using a trust manager that does not trust any certificates for test purposes!", new InvalidAlgorithmParameterException()); + } + }}; + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, unTrustManagers, new SecureRandom()); + return sslContext.getSocketFactory(); + } + + /** + * Very basic hostname verifier implementation for testing. NOT recommended for production. + */ + public static class BasicHostnameVerifier implements HostnameVerifier { + + private static final String COMMON_NAME_RDN_PREFIX = "CN="; + + @Override + public boolean verify(String hostname, SSLSession session) { + X509Certificate peerCertificate; + try { + peerCertificate = (X509Certificate) session.getPeerCertificates()[0]; + } catch (SSLPeerUnverifiedException e) { + throw new IllegalStateException("The session does not contain a peer X.509 certificate.", e); + } + String peerCertificateCN = getCommonName(peerCertificate); + return hostname.equals(peerCertificateCN); + } + + private String getCommonName(X509Certificate peerCertificate) { + String subjectDN = peerCertificate.getSubjectDN().getName(); + String[] dnComponents = subjectDN.split(","); + for (String dnComponent : dnComponents) { + dnComponent = dnComponent.trim(); + if (dnComponent.startsWith(COMMON_NAME_RDN_PREFIX)) { + return dnComponent.substring(COMMON_NAME_RDN_PREFIX.length()); + } + } + throw new IllegalArgumentException("The certificate has no common name."); + } + } + + public static class LocalhostVerifier extends BasicHostnameVerifier { + @Override + public boolean verify(String hostname, SSLSession session) { + if (hostname.equals("127.0.0.1")) { + hostname = "localhost"; + } + return super.verify(hostname, session); + } + } +} diff --git a/src/test/resources/endpoints.json b/src/test/resources/endpoints.json index c1d905bfb8..e637851717 100644 --- a/src/test/resources/endpoints.json +++ b/src/test/resources/endpoints.json @@ -10,6 +10,7 @@ "username": "default", "password": "foobared", "tls": true, + "certificatesLocation": "redis1-2-5-8-sentinel/work/tls", "endpoints": [ "rediss://localhost:6390" ] @@ -26,6 +27,7 @@ "username": "acljedis", "password": "fizzbuzz", "tls": true, + "certificatesLocation": "redis1-2-5-8-sentinel/work/tls", "endpoints": [ "rediss://localhost:6390" ] @@ -104,4 +106,4 @@ "redis://localhost:6479" ] } -} \ No newline at end of file +} diff --git a/src/test/resources/env/.env b/src/test/resources/env/.env new file mode 100644 index 0000000000..d33d5ab0fd --- /dev/null +++ b/src/test/resources/env/.env @@ -0,0 +1,7 @@ +REDIS_VERSION=8.0-M02 +CLIENT_LIBS_TEST_IMAGE=redislabs/client-libs-test +REDIS_ENV_CONF_DIR=./ +REDIS_MODULES_DIR=/tmp +REDIS_ENV_WORK_DIR=/tmp/redis-env-work + +ENABLE_MODULE_COMMAND_DIRECTIVE=--enable-module-command yes \ No newline at end of file diff --git a/src/test/resources/env/.env.v6.2.16 b/src/test/resources/env/.env.v6.2.16 new file mode 100644 index 0000000000..9e3cc90eaa --- /dev/null +++ b/src/test/resources/env/.env.v6.2.16 @@ -0,0 +1,5 @@ +REDIS_VERSION=6.2.16 +REDIS_STACK_VERSION=rs-6.2.6-v17 + +#REMOVE UNSUPPORTED DIRECTIVE +ENABLE_MODULE_COMMAND_DIRECTIVE= \ No newline at end of file diff --git a/src/test/resources/env/.env.v7.2.6 b/src/test/resources/env/.env.v7.2.6 new file mode 100644 index 0000000000..aab168b4a8 --- /dev/null +++ b/src/test/resources/env/.env.v7.2.6 @@ -0,0 +1,2 @@ +REDIS_VERSION=7.2.6 +REDIS_STACK_VERSION=rs-7.2.0-v13 \ No newline at end of file diff --git a/src/test/resources/env/.env.v7.4.1 b/src/test/resources/env/.env.v7.4.1 new file mode 100644 index 0000000000..f9ecc54b2c --- /dev/null +++ b/src/test/resources/env/.env.v7.4.1 @@ -0,0 +1,2 @@ +REDIS_VERSION=7.4.1 +REDIS_STACK_VERSION=rs-7.4.0-v1 \ No newline at end of file diff --git a/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf new file mode 100644 index 0000000000..03a685ca8b --- /dev/null +++ b/src/test/resources/env/cluster-unbound/config/node-7379-8379/redis.conf @@ -0,0 +1,9 @@ +bind 0.0.0.0 +port 7379 +tls-port 8379 +requirepass cluster +tls-auth-clients no +cluster-node-timeout 15000 +save "" +appendonly no +cluster-enabled yes \ No newline at end of file diff --git a/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf new file mode 100644 index 0000000000..7991ea74bd --- /dev/null +++ b/src/test/resources/env/cluster-unbound/config/node-7380-8380/redis.conf @@ -0,0 +1,8 @@ +bind 0.0.0.0 +requirepass cluster +port 7380 +tls-port 8380 +tls-auth-clients no +save "" +appendonly no +cluster-enabled yes \ No newline at end of file diff --git a/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf new file mode 100644 index 0000000000..27e5faa26d --- /dev/null +++ b/src/test/resources/env/cluster-unbound/config/node-7381-8381/redis.conf @@ -0,0 +1,9 @@ +bind 0.0.0.0 +port 7381 +tls-port 8381 +requirepass cluster +tls-auth-clients no +cluster-node-timeout 15000 +save "" +appendonly no +cluster-enabled yes \ No newline at end of file diff --git a/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf new file mode 100644 index 0000000000..dbe32b3b7d --- /dev/null +++ b/src/test/resources/env/cluster-unbound/config/node-7382-8382/redis.conf @@ -0,0 +1,9 @@ +bind 0.0.0.0 +requirepass cluster +port 7382 +tls-port 8382 +tls-auth-clients no +cluster-node-timeout 15000 +save "" +appendonly no +cluster-enabled yes \ No newline at end of file diff --git a/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf b/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf new file mode 100644 index 0000000000..6928409ec7 --- /dev/null +++ b/src/test/resources/env/cluster-unbound/config/node-7383-8383/redis.conf @@ -0,0 +1,9 @@ +bind 0.0.0.0 +port 7383 +tls-port 8383 +requirepass cluster +tls-auth-clients no +cluster-node-timeout 15000 +save "" +appendonly no +cluster-enabled yes \ No newline at end of file diff --git a/src/test/resources/env/config/redis6-7/node-sentinel-26381-36381/redis.conf b/src/test/resources/env/config/redis6-7/node-sentinel-26381-36381/redis.conf new file mode 100644 index 0000000000..4268f7b62d --- /dev/null +++ b/src/test/resources/env/config/redis6-7/node-sentinel-26381-36381/redis.conf @@ -0,0 +1,9 @@ +port 26380 +tls-port 36380 +tls-auth-clients no +user deploy on allcommands allkeys >verify +sentinel monitor mymaster 127.0.0.1 6381 1 +sentinel auth-pass mymaster foobared +sentinel down-after-milliseconds mymaster 2000 +sentinel parallel-syncs mymaster 1 +sentinel failover-timeout mymaster 120000 \ No newline at end of file diff --git a/src/test/resources/env/docker-compose.yml b/src/test/resources/env/docker-compose.yml new file mode 100644 index 0000000000..bcdeef5835 --- /dev/null +++ b/src/test/resources/env/docker-compose.yml @@ -0,0 +1,167 @@ +services: + redis1-2-5-8-sentinel: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: redis1-2-5-8-sentinel + #network_mode: host + environment: + - REDIS_CLUSTER=no + - REDIS_PASSWORD=foobared + - TLS_ENABLED=yes + ports: + - "6379:6379" + - "6380:6380" + - "6383:6383" + - "6386:6386" + - "6390:6390" + - "6391:6391" + - "26379:26379" # sentinel + - "36379:36379" # sentinel tls + command: ${ENABLE_MODULE_COMMAND_DIRECTIVE} + volumes: + - ${REDIS_ENV_CONF_DIR}/redis1-2-5-8-sentinel/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/redis1-2-5-8-sentinel/work:/redis/work:rw + redis3-4-sentinel: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: redis3-4-sentinel + #network_mode: host + environment: + - REDIS_CLUSTER=no + - TLS_ENABLED=yes + - REDIS_PASSWORD=foobared + ports: + - "6381:6381" + - "16381:16381" + - "6382:6382" + - "16382:16382" + - "26380:26380" # sentinel + - "36380:36380" # sentinel tls + - "26382:26382" # sentinel + - "36382:36382" # sentinel tls + volumes: + - ${REDIS_ENV_CONF_DIR}/redis3-4-sentinel/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/redis3-4-sentinel/work:/redis/work:rw + + redis6-7-sentinel: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: redis6-7-sentinel + #network_mode: host + environment: + - REDIS_CLUSTER=no + - REDIS_PASSWORD=foobared + ports: + - "6384:6384" + - "6385:6385" + - "26381:26381" # sentinel + - "36381:36381" # sentinel tls + volumes: + - ${REDIS_ENV_CONF_DIR}/redis6-7-sentinel/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/redis6-7-sentinel/work:/redis/work:rw + redis9-sentinel: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: redis9-sentinel + #network_mode: host + environment: + - REDIS_CLUSTER=no + - REDIS_CLIENT_USER=deploy + - REDIS_CLIENT_PASSWORD=verify + - TLS_ENABLED=yes + ports: + - "6387:6387" + - "16387:16387" + - "26383:26383" # sentinel + - "36383:36383" # sentinel tls + volumes: + - ${REDIS_ENV_CONF_DIR}/redis9-sentinel/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/redis9-sentinel/work:/redis/work:rw + + redis10-11: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: redis10-11 + #network_mode: host + environment: + - REDIS_CLUSTER=no + ports: + - "6388:6388" + - "6389:6389" + volumes: + - ${REDIS_ENV_CONF_DIR}/redis10-11/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/redis10-11/work:/redis/work:rw + redis-unavailable: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: redis-unavailable-1 + #network_mode: host + environment: + - REDIS_CLUSTER=no + - PORT=6400 + ports: + - "6400:6400" + volumes: + - ${REDIS_ENV_WORK_DIR}/redis-unavailable/work:/redis/work:rw + + cluster-unbound: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: cluster-unbound-1 + environment: + - TLS_ENABLED=yes + - REDIS_PASSWORD=cluster + ports: + - "7379-7383:7379-7383" + - "8379-8383:8379-8383" + volumes: + - ${REDIS_ENV_CONF_DIR}/cluster-unbound/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/cluster-unbound/work:/redis/work:rw + + cluster-stable: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_VERSION}" + container_name: cluster-stable-1 + #network_mode: host + command: --cluster-announce-ip 127.0.0.1 + environment: + - REDIS_CLUSTER=yes + - REDIS_PASSWORD=cluster + - PORT=7479 + - NODES=3 + - REPLICAS=0 + ports: + - "7479-7481:7479-7481" + volumes: + - ${REDIS_ENV_CONF_DIR}/cluster-stable/config:/redis/config:r + - ${REDIS_ENV_WORK_DIR}/cluster-stable/work:/redis/work:rw + + jedis-stack: + sysctls: + - net.ipv6.conf.all.disable_ipv6=1 + image: "${CLIENT_LIBS_TEST_IMAGE}:${REDIS_STACK_VERSION:-${REDIS_VERSION}}" + container_name: jedis-stack + environment: + - REDIS_CLUSTER=no + - PORT=6479 + ports: + - "6479:6479" + volumes: + - ${REDIS_ENV_WORK_DIR}/jedis-stack/work:/redis/work:rw +#todo find a way to connect from mac os host to exposed unix socket in container +# redis_uds: +# image: redis:${REDIS_VERSION} +# container_name: redis_uds +# #network_mode: host +# command: redis-server /etc/redis.conf +# volumes: +# - "./redis_uds/config/node-0/redis.conf:/etc/redis.conf" +# - "./work/redis_uds/work:/tmp/docker/" diff --git a/src/test/resources/env/redis-uds/config/node-0/redis.conf b/src/test/resources/env/redis-uds/config/node-0/redis.conf new file mode 100644 index 0000000000..dbcfd53b5f --- /dev/null +++ b/src/test/resources/env/redis-uds/config/node-0/redis.conf @@ -0,0 +1,2 @@ +unixsocket /tmp/docker/redis.sock +unixsocketperm 777 \ No newline at end of file diff --git a/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6379-6390/redis.conf b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6379-6390/redis.conf new file mode 100644 index 0000000000..d0b4944b89 --- /dev/null +++ b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6379-6390/redis.conf @@ -0,0 +1,11 @@ +port 6379 +tls-port 6390 +requirepass foobared +user deploy on allcommands allkeys >verify +user acljedis on allcommands allkeys >fizzbuzz +save "" +appendonly no +tls-auth-clients no + # Not supported on v6. provided as argument on node start +# enable-module-command yes +client-output-buffer-limit pubsub 256k 128k 5 \ No newline at end of file diff --git a/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6380/redis.conf b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6380/redis.conf new file mode 100644 index 0000000000..8c1e0b9873 --- /dev/null +++ b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6380/redis.conf @@ -0,0 +1,8 @@ +protected-mode no +port 6380 +user deploy on allcommands allkeys >verify +requirepass foobared +pidfile /tmp/redis2.pid +logfile /tmp/redis2.log +save "" +appendonly no \ No newline at end of file diff --git a/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6383-6391/redis.conf b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6383-6391/redis.conf new file mode 100644 index 0000000000..7ec2b09d49 --- /dev/null +++ b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6383-6391/redis.conf @@ -0,0 +1,9 @@ +port 6383 +tls-port 6391 +user deploy on allcommands allkeys >verify +requirepass foobared +masterauth foobared +tls-auth-clients no +save "" +appendonly no +slaveof localhost 6379 \ No newline at end of file diff --git a/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6386/redis.conf b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6386/redis.conf new file mode 100644 index 0000000000..df268e026c --- /dev/null +++ b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-6386/redis.conf @@ -0,0 +1,6 @@ +protected-mode no +port 6386 +user deploy on allcommands allkeys >verify +save "" +appendonly no +maxmemory-policy allkeys-lfu \ No newline at end of file diff --git a/src/test/resources/env/redis1-2-5-8-sentinel/config/node-sentinel-26379-36379/redis.conf b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-sentinel-26379-36379/redis.conf new file mode 100644 index 0000000000..8ff68c24cb --- /dev/null +++ b/src/test/resources/env/redis1-2-5-8-sentinel/config/node-sentinel-26379-36379/redis.conf @@ -0,0 +1,8 @@ +port 26379 +tls-port 36379 +tls-auth-clients no +sentinel monitor mymaster 127.0.0.1 6379 1 +sentinel auth-pass mymaster foobared +sentinel down-after-milliseconds mymaster 2000 +sentinel failover-timeout mymaster 120000 +sentinel parallel-syncs mymaster 1 \ No newline at end of file diff --git a/src/test/resources/env/redis10-11/config/node-6388/redis.conf b/src/test/resources/env/redis10-11/config/node-6388/redis.conf new file mode 100644 index 0000000000..deab0b333c --- /dev/null +++ b/src/test/resources/env/redis10-11/config/node-6388/redis.conf @@ -0,0 +1,3 @@ +port 6388 +save "" +appendonly no \ No newline at end of file diff --git a/src/test/resources/env/redis10-11/config/node-6389/redis.conf b/src/test/resources/env/redis10-11/config/node-6389/redis.conf new file mode 100644 index 0000000000..bff698c1bd --- /dev/null +++ b/src/test/resources/env/redis10-11/config/node-6389/redis.conf @@ -0,0 +1,4 @@ +port 6389 +save "" +appendonly no +replicaof localhost 6388 \ No newline at end of file diff --git a/src/test/resources/env/redis3-4-sentinel/config/node-6381-16381/redis.conf b/src/test/resources/env/redis3-4-sentinel/config/node-6381-16381/redis.conf new file mode 100644 index 0000000000..2a8295ba66 --- /dev/null +++ b/src/test/resources/env/redis3-4-sentinel/config/node-6381-16381/redis.conf @@ -0,0 +1,6 @@ +port 6381 +tls-port 16381 +requirepass foobared +masterauth foobared +save "" +appendonly no \ No newline at end of file diff --git a/src/test/resources/env/redis3-4-sentinel/config/node-6382-16382/redis.conf b/src/test/resources/env/redis3-4-sentinel/config/node-6382-16382/redis.conf new file mode 100644 index 0000000000..e0b7881f88 --- /dev/null +++ b/src/test/resources/env/redis3-4-sentinel/config/node-6382-16382/redis.conf @@ -0,0 +1,7 @@ +port 6382 +tls-port 16382 +requirepass foobared +masterauth foobared +save "" +appendonly no +slaveof localhost 6381 \ No newline at end of file diff --git a/src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26380-36380/redis.conf b/src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26380-36380/redis.conf new file mode 100644 index 0000000000..1f15e2bb71 --- /dev/null +++ b/src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26380-36380/redis.conf @@ -0,0 +1,8 @@ +port 26380 +tls-port 36380 +tls-auth-clients no +sentinel monitor mymaster 127.0.0.1 6381 1 +sentinel auth-pass mymaster foobared +sentinel down-after-milliseconds mymaster 2000 +sentinel parallel-syncs mymaster 1 +sentinel failover-timeout mymaster 120000 \ No newline at end of file diff --git a/src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26382-36382/redis.conf b/src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26382-36382/redis.conf new file mode 100644 index 0000000000..971b7115a5 --- /dev/null +++ b/src/test/resources/env/redis3-4-sentinel/config/node-sentinel-26382-36382/redis.conf @@ -0,0 +1,8 @@ +port 26382 +tls-port 36382 +tls-auth-clients no +sentinel monitor mymaster 127.0.0.1 6381 1 +sentinel auth-pass mymaster foobared +sentinel down-after-milliseconds mymaster 2000 +sentinel parallel-syncs mymaster 1 +sentinel failover-timeout mymaster 120000 \ No newline at end of file diff --git a/src/test/resources/env/redis6-7-sentinel/config/node-6384/redis.conf b/src/test/resources/env/redis6-7-sentinel/config/node-6384/redis.conf new file mode 100644 index 0000000000..6c9d2f611c --- /dev/null +++ b/src/test/resources/env/redis6-7-sentinel/config/node-6384/redis.conf @@ -0,0 +1,5 @@ +port 6384 +requirepass foobared +masterauth foobared +save "" +appendonly no \ No newline at end of file diff --git a/src/test/resources/env/redis6-7-sentinel/config/node-6385/redis.conf b/src/test/resources/env/redis6-7-sentinel/config/node-6385/redis.conf new file mode 100644 index 0000000000..b9820488cf --- /dev/null +++ b/src/test/resources/env/redis6-7-sentinel/config/node-6385/redis.conf @@ -0,0 +1,6 @@ +port 6385 +requirepass foobared +masterauth foobared +save "" +appendonly no +slaveof localhost 6384 \ No newline at end of file diff --git a/src/test/resources/env/redis6-7-sentinel/config/node-sentinel-26381-36381/redis.conf b/src/test/resources/env/redis6-7-sentinel/config/node-sentinel-26381-36381/redis.conf new file mode 100644 index 0000000000..e71d81bf5f --- /dev/null +++ b/src/test/resources/env/redis6-7-sentinel/config/node-sentinel-26381-36381/redis.conf @@ -0,0 +1,7 @@ +port 26381 +protected-mode no +sentinel monitor mymasterfailover 127.0.0.1 6384 1 +sentinel auth-pass mymasterfailover foobared +sentinel down-after-milliseconds mymasterfailover 2000 +sentinel failover-timeout mymasterfailover 120000 +sentinel parallel-syncs mymasterfailover 1 \ No newline at end of file diff --git a/src/test/resources/env/redis9-sentinel/config/node-6387-16387/redis.conf b/src/test/resources/env/redis9-sentinel/config/node-6387-16387/redis.conf new file mode 100644 index 0000000000..fae3fa276d --- /dev/null +++ b/src/test/resources/env/redis9-sentinel/config/node-6387-16387/redis.conf @@ -0,0 +1,9 @@ +port 6387 +tls-port 16387 +tls-auth-clients no +user default off +user deploy on allcommands allkeys >verify +user acljedis on allcommands allkeys >fizzbuzz +save "" +appendonly no +client-output-buffer-limit pubsub 256k 128k 5 \ No newline at end of file diff --git a/src/test/resources/env/redis9-sentinel/config/node-sentinel-26383-36383/redis.conf b/src/test/resources/env/redis9-sentinel/config/node-sentinel-26383-36383/redis.conf new file mode 100644 index 0000000000..c190c2c4f8 --- /dev/null +++ b/src/test/resources/env/redis9-sentinel/config/node-sentinel-26383-36383/redis.conf @@ -0,0 +1,12 @@ +port 26383 +tls-port 36383 +tls-auth-clients no +user default off +user deploy on allcommands allkeys >verify +user sentinel on allcommands allkeys allchannels >foobared +sentinel monitor aclmaster 127.0.0.1 6387 1 +sentinel auth-user aclmaster acljedis +sentinel auth-pass aclmaster fizzbuzz +sentinel down-after-milliseconds aclmaster 2000 +sentinel failover-timeout aclmaster 120000 +sentinel parallel-syncs aclmaster 1 \ No newline at end of file diff --git a/src/test/resources/private.crt b/src/test/resources/private.crt new file mode 100644 index 0000000000..4c560cfeae --- /dev/null +++ b/src/test/resources/private.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhzCCAm+gAwIBAgIJALGtKQQvKbGEMA0GCSqGSIb3DQEBCwUAMFoxCzAJBgNV +BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAG +A1UECgwJVHJ1U3BoZXJlMRIwEAYDVQQDDAlsb2NhbGhvc3QwHhcNMTYwMTA5MjEw +ODMyWhcNMjYwMTA2MjEwODMyWjBaMQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0Ex +FjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoMCVRydVNwaGVyZTESMBAG +A1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +4nb/9hXI5iFXIHh34gpvQMGTqTCf2im/FCvXYoDer/FTLKxdr3Bw0Cj9NarMpVZO +fBRykVdKir8v1+Gv0mUVwHkEJ2Mouxo6mqDQEKRt9G/gbzcC+AoMEUsnV4tKaptX +dWDLcZU9oer6wLicmAyV+4vlUJn+j6ADXBk4pJT+wbG/oawJ0op4vQNeVcJPr7Bc +fMLG60UOTABEPBM6YWqVe2pLPX4a4ec84kcFDLjRfU9ZTy+fD+BP5XQjIJyjyjTS +iOSy+qQM8Yk0CjJ/zfysChApCefP1/kOiIeStuE8jkmkVW6atprb9Vr+E5jnHKeh +SmZmXq9BRjF2OyUMG8m4DwIDAQABo1AwTjAdBgNVHQ4EFgQUSg+P0noapK2yuFoH +v9xe5HNYNiYwHwYDVR0jBBgwFoAUSg+P0noapK2yuFoHv9xe5HNYNiYwDAYDVR0T +BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAakaOSczmzRoPg3etzWiKTYht+CbA +/UtOdRxwTTHLauDUtGo6YTT+HG4tItwNxI9n3CZvcX68fNTi99fxzrHddiAwnCPv +DqEv2ASxed95/6QZIzPVFT7GZZDOUrwFkC01vawaVyl0f8UbeOWCly7eetu3mV2r +VFNPxPPT622cGn8uSqnpN1cQ4LdsDpVUR+YDAxIB8YbsWgtl79evwcnTWINy3CSc +QjAYQe1aC/kAs3VfIymdu9xEv2Er9NOidUx23RD54jrFCXNUYEBnSc2yi7YSTTzT +4cKnp7wuVdacd1noQRZFEEsVd6tmtiJKZhdllJ21Rb5g1q50dBlbq25hnw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/src/test/resources/private.key b/src/test/resources/private.key new file mode 100644 index 0000000000..0cf26fe000 --- /dev/null +++ b/src/test/resources/private.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDidv/2FcjmIVcg +eHfiCm9AwZOpMJ/aKb8UK9digN6v8VMsrF2vcHDQKP01qsylVk58FHKRV0qKvy/X +4a/SZRXAeQQnYyi7GjqaoNAQpG30b+BvNwL4CgwRSydXi0pqm1d1YMtxlT2h6vrA +uJyYDJX7i+VQmf6PoANcGTiklP7Bsb+hrAnSini9A15Vwk+vsFx8wsbrRQ5MAEQ8 +EzphapV7aks9fhrh5zziRwUMuNF9T1lPL58P4E/ldCMgnKPKNNKI5LL6pAzxiTQK +Mn/N/KwKECkJ58/X+Q6Ih5K24TyOSaRVbpq2mtv1Wv4TmOccp6FKZmZer0FGMXY7 +JQwbybgPAgMBAAECggEBANEPMfOm4LMxjBD5pRISt+l7yiiiLq9jYnXokwjoFqst +iK7w3/uZPUusyzPD3O+04PdCmRD7GGFFZZFRUtJTZuUr0l3Z+DvhVsBwPCNg5/CD +ZxjEHAWGoOVGD6eNesE3bmF5XdYZA7B6D8nhow3qcHqrBqKFxq4n9XIMBnJI6XU8 +OS0dG+xQouvjZ7bG4CXHPEa/B1EjVGRTjfGa+YcgQYkcnuQCCKB+twzt1wkYn16m +PWcxNddhI2FQEieULP5gkDvCFVsni8oM2hkkQuyVViW9iJ93yp0MCqhV/YlqEUGb +vmbUpKOSHPqzSITc1OMJxbt/PS1xM/xnvzJwV1AVV+ECgYEA8ulTuWR5CvTvs+dY +r5B71vJe9V6KWQhiDLE07hntWbxRm2e8FvUe3cxY6x5ao+gYdWoTOGDWmB0oZhbr +5axtQh+BlZDXe5V2wzsZJ66Uc6KeWUb2kysW3yb/yjmNvexLlf6NF+JEKYplUiWW +az5ugUzBzhcQ6BGYLNXSajWm2f0CgYEA7qrPzf6+9BneVbWXPpxSa6cmRK1Vc9ka +91Jd4w+K32T+Axbmkm2OO91tuHpYHeEEd/RIO+1YcbeGXvvRhm/pudPJ6pjqjCx1 +IiFY96Sgp9z6ONkyoPkWnzT6u+qVK/PXKTB/ZT4YX949KzFeMkao7q5b9tLJsF2Y +AIWRa0c4AfsCgYEAg60j642hZ+Uaw0UXeCQ0XXKJMy2KhXTb4dF1xdRcK5bADiQP +e8pobwdE9D9CFzPLfmp//MHR0ieMLLskKR5tI7j8f91CUgXVmUNCAZbLdluixvaG +14Q2I8V6R18njNq4ppiUV2waUwJopj0l6wCu2nyHWnZ6fbJ78WH/a/+lcOkCgYEA +nJRLySW8OYFPMIP2OglsuVvr61qcmWhyHJhZKEJmJbGoRHadxqtBiVz4QvNhJBkg +SWJmkYphYBm7ek1TZRO/Dz83VUYFevkfz8h5Cd9j1z1OnEVCxgElKkYjyW1ZeIB9 +RHSg39chPqQbFV9KIUniQtT5WLFpyN9efdkjUnJi+EkCgYEApJ43b2MnFAnR7AHt +GgICw+uxQltqkaopmtvAszMUXReoQd4PIp5SwqcZRZmFZQOEASVuC3uld1Wu762K +NFzPRxqAb3oZIIfemMa+PytYWI0I4G+Nq8XMPoL5Ms1TaB9e9VjtfaDBIbBNiZ8O +W7dFYnGv0nhO3eudyAlLVC/FFbU= +-----END PRIVATE KEY-----