Skip to content

Commit

Permalink
This change introduces a new test matrix based on Redis versions [8.0…
Browse files Browse the repository at this point in the history
….0-M1, 7.4.1, 7.2.6, 6.2.16]

We use docker composer for bringing up test env using redislabs/client-libs-test image.

When run against older Redis version it appears that some tests are using commands available only in newer Redis server versions.
To resolve this we are introducing two new annotation/rules

 - Introduce SinceRedisVersion annotation/Rule - for conditionally running test based on Redis server version contacted
 - Introduce EnableOnCommad annotation/Rule -  for conditionally running test 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

 Same approach used to mark CSC tests
 - Disabled client side caching tests for versions below  7.4

Fix in Jedis Client against Redis server 6.x
 - Fix NPE in CommandInfo command when used against Redis 6
   Starting with Redis version 7.2.0: Added entry ID, timestamp created, and timestamp last updated fields.
   Client will throw NPE if those are missing in the response (e.g when connected against 6.2)
   Fix is to safe check if (entry ID, timestamp created, and timestamp last) exists in the response before converting them.

Fix Tests failures  against 6.x
 - Fix JedisPooledClientSideCacheTest
 - Fix AccessControlListCommandsTest.aclLogTest:372 » NullPointer
 - Fix AccessControlListCommandsTest.aclLogWithEntryID:473 » NullPointer
 - Fix StreamsCommandsTest
 - Fix StreamsPipelineCommandsTest
   xadd - Starting with Redis version 7.0.0: Added support for the <ms>-* explicit ID form.

- Test env migrated to use native Redis server TLS instead of  using stunnel

Not all test were migrated
 - Disable Modules test in containerised test env
   ModuleTest is using custtom  test module to test load/unload/sendCommand.
   Need to prebuild the test module on same os like test container to avoid erros

 - Disable UDS tests in containerised test env
   No easy way to make unix sockets on MAC with docker

docker-compose to deploy required IT test envs.
  • Loading branch information
ggivo committed Nov 10, 2024
1 parent 9b88636 commit eb4bb8c
Show file tree
Hide file tree
Showing 136 changed files with 2,688 additions and 667 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ jobs:
- name: System setup
run: |
sudo apt update
sudo apt install -y stunnel make
make system-setup
sudo apt install -y make
make compile-module
- name: Cache dependencies
uses: actions/cache@v2
with:
Expand Down
128 changes: 128 additions & 0 deletions .github/workflows/test-on-docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---

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-M01"
- "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 CLIENT_LIBS_TEST_IMAGE="${CLIENT_LIBS_IMAGE_PREFIX}:${{ matrix.redis_version }}"
export COMPOSE_ENV_FILES="src/test/resources/env/.env"
if [[ "${{ matrix.redis_version }}" == "6.2.16" ]]; then
COMPOSE_ENV_FILES+=",src/test/resources/env/.env.v${{ matrix.redis_version }}"
fi
docker compose -f src/test/resources/env/docker-compose.yml up -d
- 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=$SPECIFIC_TEST 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@v3
with:
name: redis-env-work-logs
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 }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ build/
bin/
tags
.idea
.run
*.aof
*.rdb
redis-git
appendonlydir/
.DS_Store
23 changes: 23 additions & 0 deletions .run/redis in jedis.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="redis in jedis" type="JUnit" factoryName="JUnit" nameIsGenerated="true">
<module name="jedis" />
<extension name="net.ashald.envfile">
<option name="IS_ENABLED" value="false" />
<option name="IS_SUBST" value="false" />
<option name="IS_PATH_MACRO_SUPPORTED" value="false" />
<option name="IS_IGNORE_MISSING_FILES" value="false" />
<option name="IS_ENABLE_EXPERIMENTAL_INTEGRATIONS" value="false" />
<ENTRIES>
<ENTRY IS_ENABLED="true" PARSER="runconfig" IS_EXECUTABLE="false" />
</ENTRIES>
</extension>
<option name="MAIN_CLASS_NAME" value="" />
<option name="METHOD_NAME" value="" />
<option name="TEST_OBJECT" value="directory" />
<option name="VM_PARAMETERS" value="-ea -Djava.net.preferIPv4Stack=true " />
<dir value="$PROJECT_DIR$/src/test/java/redis" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ protected-mode no
port 6379
requirepass foobared
user acljedis on allcommands allkeys >fizzbuzz
user deploy on allcommands allkeys >verify
pidfile /tmp/redis1.pid
logfile /tmp/redis1.log
save ""
Expand Down Expand Up @@ -189,6 +190,7 @@ endef

define REDIS_SENTINEL5
port 26383
tlsport 36383
daemonize yes
protected-mode no
user default off
Expand Down Expand Up @@ -525,8 +527,14 @@ mvn-release:
mvn release:prepare
mvn release:perform -DskipTests

system-setup:
sudo apt install -y gcc g++
install-gcc:
@if [ "$(shell uname)" = "Darwin" ]; then \
brew install gcc; \
else \
sudo apt install -y gcc g++; \
fi

system-setup: install-gcc
[ ! -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
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5-fluent</artifactId>
<version>5.4.1</version>
<version>5.4</version>
<scope>test</scope>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ public class AccessControlLogEntry implements Serializable {
private final long timestampCreated;
private final long timestampLastUpdated;

/*
* Starting with Redis version 7.2.0: Added entry ID, timestamp created, and timestamp last updated.
* @see https://redis.io/docs/latest/commands/acl-log/
*/
public AccessControlLogEntry(Map<String, Object> map) {
count = (long) map.get(COUNT);
reason = (String) map.get(REASON);
Expand All @@ -47,9 +51,9 @@ public AccessControlLogEntry(Map<String, Object> map) {
ageSeconds = (Double) map.get(AGE_SECONDS);
clientInfo = getMapFromRawClientInfo((String) map.get(CLIENT_INFO));
logEntry = map;
entryId = (long) map.get(ENTRY_ID);
timestampCreated = (long) map.get(TIMESTAMP_CREATED);
timestampLastUpdated = (long) map.get(TIMESTAMP_LAST_UPDATED);
entryId = map.get(ENTRY_ID) == null ? 0L : (long) map.get(ENTRY_ID);
timestampCreated = map.get(TIMESTAMP_CREATED) == null ? 0L : (long) map.get(TIMESTAMP_CREATED);
timestampLastUpdated = map.get(TIMESTAMP_LAST_UPDATED) == null ? 0L : (long) map.get(TIMESTAMP_LAST_UPDATED);
}

public long getCount() {
Expand Down
11 changes: 8 additions & 3 deletions src/main/java/redis/clients/jedis/resps/CommandInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import redis.clients.jedis.Builder;

import java.util.Collections;
import java.util.List;

import static redis.clients.jedis.BuilderFactory.STRING_LIST;
Expand Down Expand Up @@ -103,9 +104,13 @@ public CommandInfo build(Object data) {
long firstKey = LONG.build(commandData.get(3));
long lastKey = LONG.build(commandData.get(4));
long step = LONG.build(commandData.get(5));
List<String> aclCategories = STRING_LIST.build(commandData.get(6));
List<String> tips = STRING_LIST.build(commandData.get(7));
List<String> subcommands = STRING_LIST.build(commandData.get(9));

// (as of Redis 6.0)
List<String> aclCategories = commandData.size()>=6?STRING_LIST.build(commandData.get(6)):Collections.emptyList();

// (as of Redis 7.0)
List<String> tips = commandData.size()>=8?STRING_LIST.build(commandData.get(7)):Collections.emptyList();
List<String> subcommands = commandData.size()>=10?STRING_LIST.build(commandData.get(9)): Collections.emptyList();

return new CommandInfo(arity, flags, firstKey, lastKey, step, aclCategories, tips, subcommands);
}
Expand Down
11 changes: 11 additions & 0 deletions src/test/java/io/redis/test/annotations/EnabledOnCommand.java
Original file line number Diff line number Diff line change
@@ -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 "";
}
11 changes: 11 additions & 0 deletions src/test/java/io/redis/test/annotations/SinceRedisVersion.java
Original file line number Diff line number Diff line change
@@ -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 "";
}
Loading

0 comments on commit eb4bb8c

Please sign in to comment.