diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index a4cf018e7a..e1f23f92d0 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -64,11 +64,7 @@ jobs: with: redis-version: ${{ matrix.redis }} - - name: Build rust part - working-directory: java - run: cargo build --release - - - name: Build java part + - name: Build java client working-directory: java run: ./gradlew --continue build @@ -77,10 +73,11 @@ jobs: continue-on-error: true uses: actions/upload-artifact@v4 with: - name: test-reports-${{ matrix.java }} + name: test-reports-java-${{ matrix.java }}-redis-${{ matrix.redis }}-${{ matrix.os }} path: | java/client/build/reports/** java/integTest/build/reports/** + utils/clusters/** build-amazonlinux-latest: if: github.repository_owner == 'aws' diff --git a/java/client/build.gradle b/java/client/build.gradle index 6118a27984..07962a8b02 100644 --- a/java/client/build.gradle +++ b/java/client/build.gradle @@ -110,7 +110,7 @@ tasks.register('buildAll') { finalizedBy 'build' } -compileJava.dependsOn('protobuf', 'buildRustRelease') +compileJava.dependsOn('protobuf') clean.dependsOn('cleanProtobuf', 'cleanRust') test.dependsOn('buildRust') testFfi.dependsOn('buildRust') @@ -127,4 +127,3 @@ tasks.withType(Test) { } jvmArgs "-Djava.library.path=${projectDir}/../target/debug" } - diff --git a/java/integTest/build.gradle b/java/integTest/build.gradle index e69de29bb2..137fb6625c 100644 --- a/java/integTest/build.gradle +++ b/java/integTest/build.gradle @@ -0,0 +1,68 @@ +plugins { + id 'java-library' +} + +repositories { + mavenCentral() +} + +dependencies { + // client + implementation project(':client') + + // lombok + testCompileOnly 'org.projectlombok:lombok:1.18.30' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.30' + + // junit + testImplementation 'org.junit.jupiter:junit-jupiter:5.6.2' + testImplementation 'org.mockito:mockito-junit-jupiter:3.12.4' +} + +tasks.register('stopAllAfterTests', Exec) { + workingDir "${project.rootDir}/../utils" + commandLine 'python3', 'cluster_manager.py', 'stop', '--prefix', 'redis-cluster', '--keep-folder' +} + +// We need to call for stop before and after the test, but gradle doesn't support executing a task +// twice. So there are two identical tasks with different names. +// We need to call for stop in case if previous test run was interrupted/crashed and didn't stop. +tasks.register('stopAllBeforeTests', Exec) { + workingDir "${project.rootDir}/../utils" + commandLine 'python3', 'cluster_manager.py', 'stop', '--prefix', 'redis-cluster' + ignoreExitValue true // ignore fail if servers are stopped before +} + +// delete dirs if stop failed due to https://github.com/aws/glide-for-redis/issues/849 +tasks.register('clearDirs', Delete) { + delete "${project.rootDir}/../utils/clusters" +} + +tasks.register('startCluster', Exec) { + workingDir "${project.rootDir}/../utils" + commandLine 'python3', 'cluster_manager.py', 'start', '--cluster-mode', '-p', '7000', '7001', '7002', '7003', '7004', '7005' +} + +tasks.register('startStandalone', Exec) { + workingDir "${project.rootDir}/../utils" + commandLine 'python3', 'cluster_manager.py', 'start', '-p', '6380', '-r', '0' +} + +test.dependsOn 'stopAllBeforeTests' +stopAllBeforeTests.finalizedBy 'clearDirs' +clearDirs.finalizedBy 'startStandalone' +clearDirs.finalizedBy 'startCluster' +test.finalizedBy 'stopAllAfterTests' +test.dependsOn ':client:buildRustRelease' + +tasks.withType(Test) { + systemProperty 'test.redis.standalone.port', '6380' + systemProperty 'test.redis.cluster.port', '7000' + + testLogging { + exceptionFormat "full" + events "started", "skipped", "passed", "failed" + showStandardStreams true + } + jvmArgs "-Djava.library.path=${project.rootDir}/target/release" +} diff --git a/java/integTest/src/test/java/glide/CommandTests.java b/java/integTest/src/test/java/glide/CommandTests.java new file mode 100644 index 0000000000..0cf28e5387 --- /dev/null +++ b/java/integTest/src/test/java/glide/CommandTests.java @@ -0,0 +1,38 @@ +package glide; + +import glide.api.RedisClient; +import glide.api.models.configuration.NodeAddress; +import glide.api.models.configuration.RedisClientConfiguration; +import java.util.concurrent.TimeUnit; +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +public class CommandTests { + + private static RedisClient regularClient = null; + + @BeforeAll + @SneakyThrows + public static void init() { + regularClient = + RedisClient.CreateClient( + RedisClientConfiguration.builder() + .address(NodeAddress.builder().port(TestConfiguration.STANDALONE_PORT).build()) + .build()) + .get(10, TimeUnit.SECONDS); + } + + @AfterAll + @SneakyThrows + public static void deinit() { + regularClient.close(); + } + + @Test + @SneakyThrows + public void custom_command_info() { + regularClient.customCommand(new String[] {"info"}).get(10, TimeUnit.SECONDS); + } +} diff --git a/java/integTest/src/test/java/glide/ConnectionTests.java b/java/integTest/src/test/java/glide/ConnectionTests.java new file mode 100644 index 0000000000..c723e6d8d9 --- /dev/null +++ b/java/integTest/src/test/java/glide/ConnectionTests.java @@ -0,0 +1,25 @@ +package glide; + +import glide.api.RedisClient; +import glide.api.models.configuration.NodeAddress; +import glide.api.models.configuration.RedisClientConfiguration; +import java.util.concurrent.TimeUnit; +import lombok.SneakyThrows; +import org.junit.jupiter.api.Test; + +public class ConnectionTests { + + @Test + @SneakyThrows + public void basic_client() { + var regularClient = + RedisClient.CreateClient( + RedisClientConfiguration.builder() + .address(NodeAddress.builder().port(TestConfiguration.STANDALONE_PORT).build()) + .build()) + .get(10, TimeUnit.SECONDS); + regularClient.close(); + } + + // TODO cluster client once implemented +} diff --git a/java/integTest/src/test/java/glide/TestConfiguration.java b/java/integTest/src/test/java/glide/TestConfiguration.java new file mode 100644 index 0000000000..05b3ca785c --- /dev/null +++ b/java/integTest/src/test/java/glide/TestConfiguration.java @@ -0,0 +1,9 @@ +package glide; + +public class TestConfiguration { + // All redis servers are hosted on localhost + public static final int STANDALONE_PORT = + Integer.parseInt(System.getProperty("test.redis.standalone.port")); + public static final int CLUSTER_PORT = + Integer.parseInt(System.getProperty("test.redis.cluster.port")); +} diff --git a/java/integTest/src/test/resources/junit-platform.properties b/java/integTest/src/test/resources/junit-platform.properties new file mode 100644 index 0000000000..3249fb3c49 --- /dev/null +++ b/java/integTest/src/test/resources/junit-platform.properties @@ -0,0 +1,2 @@ +junit.jupiter.displayname.generator.default = \ + org.junit.jupiter.api.DisplayNameGenerator$ReplaceUnderscores diff --git a/utils/cluster_manager.py b/utils/cluster_manager.py index 0667ce38e3..4dac83d0e1 100644 --- a/utils/cluster_manager.py +++ b/utils/cluster_manager.py @@ -1,3 +1,5 @@ +#!/usr/bin/python3 + import argparse import logging import os @@ -258,7 +260,7 @@ def create_cluster_folder(path: str, prefix: str) -> str: str: The full path of the cluster folder """ time = datetime.now(timezone.utc) - time_str = time.strftime("%Y-%m-%dT%H:%M:%SZ") + time_str = time.strftime("%Y-%m-%dT%H-%M-%SZ") cluster_folder = f"{path}/{prefix}-{time_str}-{get_random_string(6)}" logging.debug(f"## Creating cluster folder in {cluster_folder}") Path(cluster_folder).mkdir(exist_ok=True)