From f9523e3fcbb35d1dd7910b72a466b3ba49a2c467 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Mon, 4 Mar 2024 18:13:57 -0800 Subject: [PATCH 1/9] Added Shared Client Tests. --- .../test/java/glide/cluster/ClientTests.java | 269 ++++++++++++++++-- .../java/glide/standalone/ClientTests.java | 258 ++++++++++++++++- 2 files changed, 496 insertions(+), 31 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClientTests.java b/java/integTest/src/test/java/glide/cluster/ClientTests.java index 3924747391..347faa885b 100644 --- a/java/integTest/src/test/java/glide/cluster/ClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClientTests.java @@ -2,47 +2,284 @@ package glide.cluster; import static glide.TestConfiguration.CLUSTER_PORTS; +import static glide.api.BaseClient.OK; +import static glide.api.models.commands.InfoOptions.Section.SERVER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import glide.api.RedisClusterClient; +import glide.api.models.ClusterValue; +import glide.api.models.commands.InfoOptions; import glide.api.models.configuration.NodeAddress; import glide.api.models.configuration.RedisClusterClientConfiguration; +import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; +import glide.api.models.exceptions.RequestException; +import java.lang.module.ModuleDescriptor; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class ClientTests { + private RedisClusterClientConfiguration.RedisClusterClientConfigurationBuilder + commonClusterClientConfig() { + return RedisClusterClientConfiguration.builder() + .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()); + } + + private static Map parseInfoResponse(ClusterValue infoResponse) { + String value; + if (infoResponse.hasSingleData()) { + value = infoResponse.getSingleValue(); + } else { + value = infoResponse.getMultiValue().entrySet().iterator().next().getValue(); + } + + return value + .lines() + .filter(line -> line.contains(":")) + .map(line -> line.split(":", 2)) + .collect( + Collectors.toMap( + parts -> parts[0], + parts -> parts[1], + (existingValue, newValue) -> newValue, + HashMap::new)); + } + + private static String getRandomString(int length) { + String asciiLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + SecureRandom random = new SecureRandom(); + StringBuilder sb = new StringBuilder(length); + + for (int i = 0; i < length; i++) { + int index = random.nextInt(asciiLetters.length()); + char randomChar = asciiLetters.charAt(index); + sb.append(randomChar); + } + + return sb.toString(); + } + + @SneakyThrows + private Boolean check_if_server_version_gte(RedisClusterClient client, String minVersion) { + ClusterValue infoStr = client.info(InfoOptions.builder().section(SERVER).build()).get(); + String redisVersion = parseInfoResponse(infoStr).get("redis_version"); + assertNotNull(redisVersion); + return ModuleDescriptor.Version.parse(redisVersion) + .compareTo(ModuleDescriptor.Version.parse(minVersion)) + >= 0; + } + + @SneakyThrows @Test + public void register_client_name_and_version() { + RedisClusterClient client = + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + + String minVersion = "7.2.0"; + assumeTrue( + check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); + String info = + (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); + assertTrue(info.contains("lib-name=GlideJava")); + assertTrue(info.contains("lib-ver=unknown")); + + client.close(); + } + @SneakyThrows - public void custom_command_info() { + @Test + public void send_and_receive_large_values() { RedisClusterClient client = - RedisClusterClient.CreateClient( - RedisClusterClientConfiguration.builder() - .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()) - .clientName("TEST_CLIENT_NAME") - .build()) - .get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - String clientInfo = - (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); - assertTrue(clientInfo.contains("name=TEST_CLIENT_NAME")); + int length = 2 ^ 16; + String key = getRandomString(length); + String value = getRandomString(length); + + assertEquals(length, key.length()); + assertEquals(length, value.length()); + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + + client.close(); + } + + @SneakyThrows + @Test + public void send_and_receive_non_ascii_unicode() { + RedisClusterClient client = + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + + String key = "foo"; + String value = "שלום hello 汉字"; + + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + + client.close(); + } + + @SneakyThrows + @ParameterizedTest + @ValueSource(ints = {100, 2 ^ 16}) + public void client_can_handle_concurrent_workload(int valueSize) { + ExecutorService executorService = Executors.newFixedThreadPool(8); + RedisClusterClient client = + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + CompletableFuture[] futures = new CompletableFuture[100]; + + for (int i = 0; i < 100; i++) { + futures[i] = + CompletableFuture.runAsync( + () -> { + String key = getRandomString(valueSize); + String value = getRandomString(valueSize); + try { + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }, + executorService); + } + + CompletableFuture.allOf(futures).join(); + + client.close(); + executorService.shutdown(); + } + + @SneakyThrows + @Test + public void can_connect_with_auth_requirepass() { + RedisClusterClient client = + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + + String password = "TEST_AUTH"; + client.customCommand(new String[] {"CONFIG", "SET", "requirepass", password}).get(); + + // Creation of a new client without a password should fail + ExecutionException exception = + assertThrows( + ExecutionException.class, + () -> RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()); + assertTrue(exception.getCause() instanceof ClosingException); + + // Creation of a new client with credentials + RedisClusterClient auth_client = + RedisClusterClient.CreateClient( + commonClusterClientConfig() + .credentials(RedisCredentials.builder().password(password).build()) + .build()) + .get(); + + String key = getRandomString(10); + String value = getRandomString(10); + + assertEquals(OK, auth_client.set(key, value).get()); + assertEquals(value, auth_client.get(key).get()); + + // Reset password + client.customCommand(new String[] {"CONFIG", "SET", "requirepass", ""}).get(); + + auth_client.close(); + client.close(); + } + + @SneakyThrows + @Test + public void can_connect_with_auth_acl() { + RedisClusterClient client = + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + + String username = "testuser"; + String password = "TEST_AUTH"; + assertEquals( + OK, + client + .customCommand( + new String[] { + "ACL", + "SETUSER", + username, + "on", + "allkeys", + "+get", + "+cluster", + "+ping", + "+info", + "+client", + ">" + password, + }) + .get() + .getSingleValue()); + + String key = getRandomString(10); + String value = getRandomString(10); + + assertEquals(OK, client.set(key, value).get()); + + // Creation of a new cluster client with credentials + RedisClusterClient testUserClient = + RedisClusterClient.CreateClient( + commonClusterClientConfig() + .credentials( + RedisCredentials.builder().username(username).password(password).build()) + .build()) + .get(); + + assertEquals(value, testUserClient.get(key).get()); + + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> testUserClient.set("foo", "bar").get()); + assertTrue(executionException.getCause() instanceof RequestException); + + client.customCommand(new String[] {"ACL", "DELUSER", username}).get(); + + testUserClient.close(); + client.close(); } @Test @SneakyThrows public void close_client_throws_ExecutionException_with_ClosingException_cause() { RedisClusterClient client = - RedisClusterClient.CreateClient( - RedisClusterClientConfiguration.builder() - .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()) - .build()) - .get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()) + .get(); client.close(); ExecutionException executionException = - assertThrows(ExecutionException.class, () -> client.set("foo", "bar").get()); + assertThrows(ExecutionException.class, () -> client.set("foo", "bar").get()); assertTrue(executionException.getCause() instanceof ClosingException); } + + @SneakyThrows + @Test + public void custom_command_info() { + RedisClusterClient client = + RedisClusterClient.CreateClient( + commonClusterClientConfig().clientName("TEST_CLIENT_NAME").build()) + .get(); + + String clientInfo = + (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); + assertTrue(clientInfo.contains("name=TEST_CLIENT_NAME")); + + client.close(); + } } diff --git a/java/integTest/src/test/java/glide/standalone/ClientTests.java b/java/integTest/src/test/java/glide/standalone/ClientTests.java index 960696b06e..32b06f9d43 100644 --- a/java/integTest/src/test/java/glide/standalone/ClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/ClientTests.java @@ -2,46 +2,274 @@ package glide.standalone; import static glide.TestConfiguration.STANDALONE_PORTS; +import static glide.api.BaseClient.OK; +import static glide.api.models.commands.InfoOptions.Section.SERVER; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import glide.api.RedisClient; +import glide.api.models.commands.InfoOptions; import glide.api.models.configuration.NodeAddress; import glide.api.models.configuration.RedisClientConfiguration; +import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; +import glide.api.models.exceptions.RequestException; +import java.lang.module.ModuleDescriptor.Version; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; public class ClientTests { + + private RedisClientConfiguration.RedisClientConfigurationBuilder commonClientConfig() { + return RedisClientConfiguration.builder() + .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()); + } + + private static Map parseInfoResponse(String serverInfo) { + return serverInfo + .lines() + .filter(line -> line.contains(":")) + .map(line -> line.split(":", 2)) + .collect( + Collectors.toMap( + parts -> parts[0], + parts -> parts[1], + (existingValue, newValue) -> newValue, + HashMap::new)); + } + + private static String getRandomString(int length) { + String asciiLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + SecureRandom random = new SecureRandom(); + StringBuilder sb = new StringBuilder(length); + + for (int i = 0; i < length; i++) { + int index = random.nextInt(asciiLetters.length()); + char randomChar = asciiLetters.charAt(index); + sb.append(randomChar); + } + + return sb.toString(); + } + + @SneakyThrows + private Boolean check_if_server_version_gte(RedisClient client, String minVersion) { + String infoStr = client.info(InfoOptions.builder().section(SERVER).build()).get(); + String redisVersion = parseInfoResponse(infoStr).get("redis_version"); + assertNotNull(redisVersion); + return Version.parse(redisVersion).compareTo(Version.parse(minVersion)) >= 0; + } + + @SneakyThrows @Test + public void register_client_name_and_version() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + + String minVersion = "7.2.0"; + assumeTrue( + check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); + String info = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get(); + assertTrue(info.contains("lib-name=GlideJava")); + assertTrue(info.contains("lib-ver=unknown")); + + client.close(); + } + @SneakyThrows - public void custom_command_info() { - RedisClient client = - RedisClient.CreateClient( - RedisClientConfiguration.builder() - .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()) - .clientName("TEST_CLIENT_NAME") - .build()) - .get(); + @Test + public void send_and_receive_large_values() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + + int length = 2 ^ 16; + String key = getRandomString(length); + String value = getRandomString(length); + + assertEquals(length, key.length()); + assertEquals(length, value.length()); + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + + client.close(); + } + + @SneakyThrows + @Test + public void send_and_receive_non_ascii_unicode() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + + String key = "foo"; + String value = "שלום hello 汉字"; + + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + + client.close(); + } + + @SneakyThrows + @ParameterizedTest + @ValueSource(ints = {100, 2 ^ 16}) + public void client_can_handle_concurrent_workload(int valueSize) { + ExecutorService executorService = Executors.newFixedThreadPool(8); + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + CompletableFuture[] futures = new CompletableFuture[100]; + + for (int i = 0; i < 100; i++) { + futures[i] = + CompletableFuture.runAsync( + () -> { + String key = getRandomString(valueSize); + String value = getRandomString(valueSize); + try { + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }, + executorService); + } + + CompletableFuture.allOf(futures).join(); + + client.close(); + executorService.shutdown(); + } + + @SneakyThrows + @Test + public void can_connect_with_auth_require_pass() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + + String password = "TEST_AUTH"; + client.customCommand(new String[] {"CONFIG", "SET", "requirepass", password}).get(); + + // Creation of a new client without a password should fail + ExecutionException exception = + assertThrows( + ExecutionException.class, + () -> RedisClient.CreateClient(commonClientConfig().build()).get()); + assertTrue(exception.getCause() instanceof ClosingException); + + // Creation of a new client with credentials + RedisClient auth_client = + RedisClient.CreateClient( + commonClientConfig() + .credentials(RedisCredentials.builder().password(password).build()) + .build()) + .get(); + + String key = getRandomString(10); + String value = getRandomString(10); + + assertEquals(OK, auth_client.set(key, value).get()); + assertEquals(value, auth_client.get(key).get()); + + // Reset password + client.customCommand(new String[] {"CONFIG", "SET", "requirepass", ""}).get(); + + auth_client.close(); + client.close(); + } + + @SneakyThrows + @Test + public void can_connect_with_auth_acl() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + + String username = "testuser"; + String password = "TEST_AUTH"; + assertEquals( + OK, + client + .customCommand( + new String[] { + "ACL", + "SETUSER", + username, + "on", + "allkeys", + "+get", + "+cluster", + "+ping", + "+info", + "+client", + ">" + password, + }) + .get()); + + String key = getRandomString(10); + String value = getRandomString(10); + + assertEquals(OK, client.set(key, value).get()); + + // Creation of a new client with credentials + RedisClient testUserClient = + RedisClient.CreateClient( + commonClientConfig() + .credentials( + RedisCredentials.builder().username(username).password(password).build()) + .build()) + .get(); + + assertEquals(value, testUserClient.get(key).get()); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> testUserClient.set("foo", "bar").get()); + assertTrue(executionException.getCause() instanceof RequestException); + + client.customCommand(new String[] {"ACL", "DELUSER", username}).get(); + + testUserClient.close(); + client.close(); + } + + @SneakyThrows + @Test + public void select_standalone_database_id() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().databaseId(4).build()).get(); String clientInfo = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get(); - assertTrue(clientInfo.contains("name=TEST_CLIENT_NAME")); + assertTrue(clientInfo.contains("db=4")); + + client.close(); } @Test @SneakyThrows public void close_client_throws_ExecutionException_with_ClosingException_cause() { RedisClient client = - RedisClient.CreateClient( - RedisClientConfiguration.builder() - .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()) - .build()) - .get(); + RedisClient.CreateClient( + commonClientConfig().build()) + .get(); client.close(); ExecutionException executionException = - assertThrows(ExecutionException.class, () -> client.set("key", "value").get()); + assertThrows(ExecutionException.class, () -> client.set("key", "value").get()); assertTrue(executionException.getCause() instanceof ClosingException); } + + @SneakyThrows + @Test + public void custom_command_info() { + RedisClient client = + RedisClient.CreateClient(commonClientConfig().clientName("TEST_CLIENT_NAME").build()).get(); + + String clientInfo = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get(); + assertTrue(clientInfo.contains("name=TEST_CLIENT_NAME")); + + client.close(); + } } From a497fcfb6e50e6667dfbc63c1ccc1d68a1ef847d Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Wed, 6 Mar 2024 14:29:15 -0800 Subject: [PATCH 2/9] Renamed tests, migrated some functions to TestUtilities, minor refactor to imports. --- .../src/test/java/glide/TestUtilities.java | 36 ++++ ...ientTests.java => ClusterClientTests.java} | 185 ++++++++---------- ...tTests.java => StandaloneClientTests.java} | 140 ++++++------- 3 files changed, 170 insertions(+), 191 deletions(-) rename java/integTest/src/test/java/glide/cluster/{ClientTests.java => ClusterClientTests.java} (53%) rename java/integTest/src/test/java/glide/standalone/{ClientTests.java => StandaloneClientTests.java} (64%) diff --git a/java/integTest/src/test/java/glide/TestUtilities.java b/java/integTest/src/test/java/glide/TestUtilities.java index 8c18e8b98f..cb97e00a9b 100644 --- a/java/integTest/src/test/java/glide/TestUtilities.java +++ b/java/integTest/src/test/java/glide/TestUtilities.java @@ -4,6 +4,10 @@ import static org.junit.jupiter.api.Assertions.fail; import glide.api.models.ClusterValue; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; import lombok.experimental.UtilityClass; @UtilityClass @@ -23,4 +27,36 @@ public static int getValueFromInfo(String data, String value) { public static T getFirstEntryFromMultiValue(ClusterValue data) { return data.getMultiValue().get(data.getMultiValue().keySet().toArray(String[]::new)[0]); } + + /** Generates a random string of a specified length using ASCII letters. */ + public static String getRandomString(int length) { + String asciiLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + SecureRandom random = new SecureRandom(); + StringBuilder sb = new StringBuilder(length); + + for (int i = 0; i < length; i++) { + int index = random.nextInt(asciiLetters.length()); + char randomChar = asciiLetters.charAt(index); + sb.append(randomChar); + } + + return sb.toString(); + } + + /** + * Transforms server info string into a Map, using lines with ":" to create key-value pairs, + * replacing duplicates with the last encountered value. + */ + public static Map parseInfoResponseToMap(String serverInfo) { + return serverInfo + .lines() + .filter(line -> line.contains(":")) + .map(line -> line.split(":", 2)) + .collect( + Collectors.toMap( + parts -> parts[0], + parts -> parts[1], + (existingValue, newValue) -> newValue, + HashMap::new)); + } } diff --git a/java/integTest/src/test/java/glide/cluster/ClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java similarity index 53% rename from java/integTest/src/test/java/glide/cluster/ClientTests.java rename to java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index 347faa885b..007f543b1e 100644 --- a/java/integTest/src/test/java/glide/cluster/ClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -2,6 +2,8 @@ package glide.cluster; import static glide.TestConfiguration.CLUSTER_PORTS; +import static glide.TestUtilities.getRandomString; +import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; import static glide.api.models.commands.InfoOptions.Section.SERVER; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -18,82 +20,54 @@ import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.RequestException; -import java.lang.module.ModuleDescriptor; -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.Map; +import java.lang.module.ModuleDescriptor.Version; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.stream.Collectors; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -public class ClientTests { +@Timeout(10) +public class ClusterClientTests { + private RedisClusterClientConfiguration.RedisClusterClientConfigurationBuilder - commonClusterClientConfig() { + commonClusterClientConfig() { return RedisClusterClientConfiguration.builder() - .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()); + .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()); } - private static Map parseInfoResponse(ClusterValue infoResponse) { - String value; - if (infoResponse.hasSingleData()) { - value = infoResponse.getSingleValue(); - } else { - value = infoResponse.getMultiValue().entrySet().iterator().next().getValue(); - } - - return value - .lines() - .filter(line -> line.contains(":")) - .map(line -> line.split(":", 2)) - .collect( - Collectors.toMap( - parts -> parts[0], - parts -> parts[1], - (existingValue, newValue) -> newValue, - HashMap::new)); - } - - private static String getRandomString(int length) { - String asciiLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - SecureRandom random = new SecureRandom(); - StringBuilder sb = new StringBuilder(length); + @SneakyThrows + private Boolean check_if_server_version_gte(RedisClusterClient client, String minVersion) { + ClusterValue infoClusterValue = + client.info(InfoOptions.builder().section(SERVER).build()).get(); - for (int i = 0; i < length; i++) { - int index = random.nextInt(asciiLetters.length()); - char randomChar = asciiLetters.charAt(index); - sb.append(randomChar); + String infoStr; + if (infoClusterValue.hasSingleData()) { + infoStr = infoClusterValue.getSingleValue(); + } else { + infoStr = infoClusterValue.getMultiValue().entrySet().iterator().next().getValue(); } - return sb.toString(); - } - - @SneakyThrows - private Boolean check_if_server_version_gte(RedisClusterClient client, String minVersion) { - ClusterValue infoStr = client.info(InfoOptions.builder().section(SERVER).build()).get(); - String redisVersion = parseInfoResponse(infoStr).get("redis_version"); + String redisVersion = parseInfoResponseToMap(infoStr).get("redis_version"); assertNotNull(redisVersion); - return ModuleDescriptor.Version.parse(redisVersion) - .compareTo(ModuleDescriptor.Version.parse(minVersion)) - >= 0; + return Version.parse(redisVersion).compareTo(Version.parse(minVersion)) >= 0; } @SneakyThrows @Test public void register_client_name_and_version() { RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); String minVersion = "7.2.0"; assumeTrue( - check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); + check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); String info = - (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); + (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); assertTrue(info.contains("lib-name=GlideJava")); assertTrue(info.contains("lib-ver=unknown")); @@ -104,7 +78,7 @@ public void register_client_name_and_version() { @Test public void send_and_receive_large_values() { RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); int length = 2 ^ 16; String key = getRandomString(length); @@ -122,7 +96,7 @@ public void send_and_receive_large_values() { @Test public void send_and_receive_non_ascii_unicode() { RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); String key = "foo"; String value = "שלום hello 汉字"; @@ -139,23 +113,23 @@ public void send_and_receive_non_ascii_unicode() { public void client_can_handle_concurrent_workload(int valueSize) { ExecutorService executorService = Executors.newFixedThreadPool(8); RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); CompletableFuture[] futures = new CompletableFuture[100]; for (int i = 0; i < 100; i++) { futures[i] = - CompletableFuture.runAsync( - () -> { - String key = getRandomString(valueSize); - String value = getRandomString(valueSize); - try { - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - }, - executorService); + CompletableFuture.runAsync( + () -> { + String key = getRandomString(valueSize); + String value = getRandomString(valueSize); + try { + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }, + executorService); } CompletableFuture.allOf(futures).join(); @@ -168,25 +142,25 @@ public void client_can_handle_concurrent_workload(int valueSize) { @Test public void can_connect_with_auth_requirepass() { RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); String password = "TEST_AUTH"; client.customCommand(new String[] {"CONFIG", "SET", "requirepass", password}).get(); // Creation of a new client without a password should fail ExecutionException exception = - assertThrows( - ExecutionException.class, - () -> RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()); + assertThrows( + ExecutionException.class, + () -> RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get()); assertTrue(exception.getCause() instanceof ClosingException); // Creation of a new client with credentials RedisClusterClient auth_client = - RedisClusterClient.CreateClient( - commonClusterClientConfig() - .credentials(RedisCredentials.builder().password(password).build()) - .build()) - .get(); + RedisClusterClient.CreateClient( + commonClusterClientConfig() + .credentials(RedisCredentials.builder().password(password).build()) + .build()) + .get(); String key = getRandomString(10); String value = getRandomString(10); @@ -205,29 +179,29 @@ public void can_connect_with_auth_requirepass() { @Test public void can_connect_with_auth_acl() { RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); String username = "testuser"; String password = "TEST_AUTH"; assertEquals( - OK, - client - .customCommand( - new String[] { - "ACL", - "SETUSER", - username, - "on", - "allkeys", - "+get", - "+cluster", - "+ping", - "+info", - "+client", - ">" + password, - }) - .get() - .getSingleValue()); + OK, + client + .customCommand( + new String[] { + "ACL", + "SETUSER", + username, + "on", + "allkeys", + "+get", + "+cluster", + "+ping", + "+info", + "+client", + ">" + password, + }) + .get() + .getSingleValue()); String key = getRandomString(10); String value = getRandomString(10); @@ -236,17 +210,17 @@ public void can_connect_with_auth_acl() { // Creation of a new cluster client with credentials RedisClusterClient testUserClient = - RedisClusterClient.CreateClient( - commonClusterClientConfig() - .credentials( - RedisCredentials.builder().username(username).password(password).build()) - .build()) - .get(); + RedisClusterClient.CreateClient( + commonClusterClientConfig() + .credentials( + RedisCredentials.builder().username(username).password(password).build()) + .build()) + .get(); assertEquals(value, testUserClient.get(key).get()); ExecutionException executionException = - assertThrows(ExecutionException.class, () -> testUserClient.set("foo", "bar").get()); + assertThrows(ExecutionException.class, () -> testUserClient.set("foo", "bar").get()); assertTrue(executionException.getCause() instanceof RequestException); client.customCommand(new String[] {"ACL", "DELUSER", username}).get(); @@ -259,12 +233,11 @@ public void can_connect_with_auth_acl() { @SneakyThrows public void close_client_throws_ExecutionException_with_ClosingException_cause() { RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()) - .get(); + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); client.close(); ExecutionException executionException = - assertThrows(ExecutionException.class, () -> client.set("foo", "bar").get()); + assertThrows(ExecutionException.class, () -> client.set("foo", "bar").get()); assertTrue(executionException.getCause() instanceof ClosingException); } @@ -272,12 +245,12 @@ public void close_client_throws_ExecutionException_with_ClosingException_cause() @Test public void custom_command_info() { RedisClusterClient client = - RedisClusterClient.CreateClient( - commonClusterClientConfig().clientName("TEST_CLIENT_NAME").build()) - .get(); + RedisClusterClient.CreateClient( + commonClusterClientConfig().clientName("TEST_CLIENT_NAME").build()) + .get(); String clientInfo = - (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); + (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); assertTrue(clientInfo.contains("name=TEST_CLIENT_NAME")); client.close(); diff --git a/java/integTest/src/test/java/glide/standalone/ClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java similarity index 64% rename from java/integTest/src/test/java/glide/standalone/ClientTests.java rename to java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index 32b06f9d43..3877067556 100644 --- a/java/integTest/src/test/java/glide/standalone/ClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -2,6 +2,8 @@ package glide.standalone; import static glide.TestConfiguration.STANDALONE_PORTS; +import static glide.TestUtilities.getRandomString; +import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; import static glide.api.models.commands.InfoOptions.Section.SERVER; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -18,57 +20,28 @@ import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.RequestException; import java.lang.module.ModuleDescriptor.Version; -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.stream.Collectors; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -public class ClientTests { +@Timeout(10) +public class StandaloneClientTests { private RedisClientConfiguration.RedisClientConfigurationBuilder commonClientConfig() { return RedisClientConfiguration.builder() - .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()); - } - - private static Map parseInfoResponse(String serverInfo) { - return serverInfo - .lines() - .filter(line -> line.contains(":")) - .map(line -> line.split(":", 2)) - .collect( - Collectors.toMap( - parts -> parts[0], - parts -> parts[1], - (existingValue, newValue) -> newValue, - HashMap::new)); - } - - private static String getRandomString(int length) { - String asciiLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - SecureRandom random = new SecureRandom(); - StringBuilder sb = new StringBuilder(length); - - for (int i = 0; i < length; i++) { - int index = random.nextInt(asciiLetters.length()); - char randomChar = asciiLetters.charAt(index); - sb.append(randomChar); - } - - return sb.toString(); + .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()); } @SneakyThrows private Boolean check_if_server_version_gte(RedisClient client, String minVersion) { String infoStr = client.info(InfoOptions.builder().section(SERVER).build()).get(); - String redisVersion = parseInfoResponse(infoStr).get("redis_version"); + String redisVersion = parseInfoResponseToMap(infoStr).get("redis_version"); assertNotNull(redisVersion); return Version.parse(redisVersion).compareTo(Version.parse(minVersion)) >= 0; } @@ -80,7 +53,7 @@ public void register_client_name_and_version() { String minVersion = "7.2.0"; assumeTrue( - check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); + check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); String info = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get(); assertTrue(info.contains("lib-name=GlideJava")); assertTrue(info.contains("lib-ver=unknown")); @@ -129,18 +102,18 @@ public void client_can_handle_concurrent_workload(int valueSize) { for (int i = 0; i < 100; i++) { futures[i] = - CompletableFuture.runAsync( - () -> { - String key = getRandomString(valueSize); - String value = getRandomString(valueSize); - try { - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - }, - executorService); + CompletableFuture.runAsync( + () -> { + String key = getRandomString(valueSize); + String value = getRandomString(valueSize); + try { + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }, + executorService); } CompletableFuture.allOf(futures).join(); @@ -159,18 +132,18 @@ public void can_connect_with_auth_require_pass() { // Creation of a new client without a password should fail ExecutionException exception = - assertThrows( - ExecutionException.class, - () -> RedisClient.CreateClient(commonClientConfig().build()).get()); + assertThrows( + ExecutionException.class, + () -> RedisClient.CreateClient(commonClientConfig().build()).get()); assertTrue(exception.getCause() instanceof ClosingException); // Creation of a new client with credentials RedisClient auth_client = - RedisClient.CreateClient( - commonClientConfig() - .credentials(RedisCredentials.builder().password(password).build()) - .build()) - .get(); + RedisClient.CreateClient( + commonClientConfig() + .credentials(RedisCredentials.builder().password(password).build()) + .build()) + .get(); String key = getRandomString(10); String value = getRandomString(10); @@ -193,23 +166,23 @@ public void can_connect_with_auth_acl() { String username = "testuser"; String password = "TEST_AUTH"; assertEquals( - OK, - client - .customCommand( - new String[] { - "ACL", - "SETUSER", - username, - "on", - "allkeys", - "+get", - "+cluster", - "+ping", - "+info", - "+client", - ">" + password, - }) - .get()); + OK, + client + .customCommand( + new String[] { + "ACL", + "SETUSER", + username, + "on", + "allkeys", + "+get", + "+cluster", + "+ping", + "+info", + "+client", + ">" + password, + }) + .get()); String key = getRandomString(10); String value = getRandomString(10); @@ -218,16 +191,16 @@ public void can_connect_with_auth_acl() { // Creation of a new client with credentials RedisClient testUserClient = - RedisClient.CreateClient( - commonClientConfig() - .credentials( - RedisCredentials.builder().username(username).password(password).build()) - .build()) - .get(); + RedisClient.CreateClient( + commonClientConfig() + .credentials( + RedisCredentials.builder().username(username).password(password).build()) + .build()) + .get(); assertEquals(value, testUserClient.get(key).get()); ExecutionException executionException = - assertThrows(ExecutionException.class, () -> testUserClient.set("foo", "bar").get()); + assertThrows(ExecutionException.class, () -> testUserClient.set("foo", "bar").get()); assertTrue(executionException.getCause() instanceof RequestException); client.customCommand(new String[] {"ACL", "DELUSER", username}).get(); @@ -250,14 +223,11 @@ public void select_standalone_database_id() { @Test @SneakyThrows public void close_client_throws_ExecutionException_with_ClosingException_cause() { - RedisClient client = - RedisClient.CreateClient( - commonClientConfig().build()) - .get(); + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); client.close(); ExecutionException executionException = - assertThrows(ExecutionException.class, () -> client.set("key", "value").get()); + assertThrows(ExecutionException.class, () -> client.set("key", "value").get()); assertTrue(executionException.getCause() instanceof ClosingException); } @@ -265,7 +235,7 @@ public void close_client_throws_ExecutionException_with_ClosingException_cause() @Test public void custom_command_info() { RedisClient client = - RedisClient.CreateClient(commonClientConfig().clientName("TEST_CLIENT_NAME").build()).get(); + RedisClient.CreateClient(commonClientConfig().clientName("TEST_CLIENT_NAME").build()).get(); String clientInfo = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get(); assertTrue(clientInfo.contains("name=TEST_CLIENT_NAME")); From 7c6e51dfa2bf45882c71a1a031d8bf303b26455e Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Wed, 6 Mar 2024 14:39:02 -0800 Subject: [PATCH 3/9] For concurrent handling test changed executor from fixed size to cached thread pool. --- .../src/test/java/glide/cluster/ClusterClientTests.java | 2 +- .../src/test/java/glide/standalone/StandaloneClientTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index 007f543b1e..fe8ae0e061 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -111,7 +111,7 @@ public void send_and_receive_non_ascii_unicode() { @ParameterizedTest @ValueSource(ints = {100, 2 ^ 16}) public void client_can_handle_concurrent_workload(int valueSize) { - ExecutorService executorService = Executors.newFixedThreadPool(8); + ExecutorService executorService = Executors.newCachedThreadPool(); RedisClusterClient client = RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); CompletableFuture[] futures = new CompletableFuture[100]; diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index 3877067556..e1927059eb 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -96,7 +96,7 @@ public void send_and_receive_non_ascii_unicode() { @ParameterizedTest @ValueSource(ints = {100, 2 ^ 16}) public void client_can_handle_concurrent_workload(int valueSize) { - ExecutorService executorService = Executors.newFixedThreadPool(8); + ExecutorService executorService = Executors.newCachedThreadPool(); RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); CompletableFuture[] futures = new CompletableFuture[100]; From f9cbb19dcf71bdc5806a8626710ad96a46e93cb4 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Thu, 7 Mar 2024 11:48:18 -0800 Subject: [PATCH 4/9] Minor update to test name and ordering. --- .../glide/cluster/ClusterClientTests.java | 26 +++++++++---------- .../standalone/StandaloneClientTests.java | 24 ++++++++--------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index fe8ae0e061..2846eace63 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -229,21 +229,9 @@ public void can_connect_with_auth_acl() { client.close(); } - @Test - @SneakyThrows - public void close_client_throws_ExecutionException_with_ClosingException_cause() { - RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - - client.close(); - ExecutionException executionException = - assertThrows(ExecutionException.class, () -> client.set("foo", "bar").get()); - assertTrue(executionException.getCause() instanceof ClosingException); - } - @SneakyThrows @Test - public void custom_command_info() { + public void client_name() { RedisClusterClient client = RedisClusterClient.CreateClient( commonClusterClientConfig().clientName("TEST_CLIENT_NAME").build()) @@ -255,4 +243,16 @@ public void custom_command_info() { client.close(); } + + @Test + @SneakyThrows + public void close_client_throws_ExecutionException_with_ClosingException_cause() { + RedisClusterClient client = + RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); + + client.close(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.set("foo", "bar").get()); + assertTrue(executionException.getCause() instanceof ClosingException); + } } diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index e1927059eb..3d3eaa4e19 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -220,20 +220,9 @@ public void select_standalone_database_id() { client.close(); } - @Test - @SneakyThrows - public void close_client_throws_ExecutionException_with_ClosingException_cause() { - RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); - - client.close(); - ExecutionException executionException = - assertThrows(ExecutionException.class, () -> client.set("key", "value").get()); - assertTrue(executionException.getCause() instanceof ClosingException); - } - @SneakyThrows @Test - public void custom_command_info() { + public void client_name() { RedisClient client = RedisClient.CreateClient(commonClientConfig().clientName("TEST_CLIENT_NAME").build()).get(); @@ -242,4 +231,15 @@ public void custom_command_info() { client.close(); } + + @Test + @SneakyThrows + public void close_client_throws_ExecutionException_with_ClosingException_cause() { + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + + client.close(); + ExecutionException executionException = + assertThrows(ExecutionException.class, () -> client.set("key", "value").get()); + assertTrue(executionException.getCause() instanceof ClosingException); + } } From cb3389c95e77529515b61a21d51ee9aae3f47b30 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Fri, 8 Mar 2024 16:07:52 -0800 Subject: [PATCH 5/9] Fixed functionality of the power function. --- .../src/test/java/glide/cluster/ClusterClientTests.java | 4 ++-- .../src/test/java/glide/standalone/StandaloneClientTests.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index 2846eace63..cdd1eba245 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -80,7 +80,7 @@ public void send_and_receive_large_values() { RedisClusterClient client = RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - int length = 2 ^ 16; + int length = 65536; String key = getRandomString(length); String value = getRandomString(length); @@ -109,7 +109,7 @@ public void send_and_receive_non_ascii_unicode() { @SneakyThrows @ParameterizedTest - @ValueSource(ints = {100, 2 ^ 16}) + @ValueSource(ints = {100, 65536}) public void client_can_handle_concurrent_workload(int valueSize) { ExecutorService executorService = Executors.newCachedThreadPool(); RedisClusterClient client = diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index 3d3eaa4e19..084521fb5c 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -66,7 +66,7 @@ public void register_client_name_and_version() { public void send_and_receive_large_values() { RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); - int length = 2 ^ 16; + int length = 65536; String key = getRandomString(length); String value = getRandomString(length); @@ -94,7 +94,7 @@ public void send_and_receive_non_ascii_unicode() { @SneakyThrows @ParameterizedTest - @ValueSource(ints = {100, 2 ^ 16}) + @ValueSource(ints = {100, 65536}) public void client_can_handle_concurrent_workload(int valueSize) { ExecutorService executorService = Executors.newCachedThreadPool(); RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); From 0793cfb749f3aee0ec3369f20630b1069a816551 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Mon, 11 Mar 2024 13:26:32 -0700 Subject: [PATCH 6/9] Refactored shared commands in to a shared tests file. --- .../test/java/glide/SharedClientTests.java | 113 ++++++++++++++++++ .../src/test/java/glide/TestUtilities.java | 17 +++ .../glide/cluster/ClusterClientTests.java | 79 +----------- .../standalone/StandaloneClientTests.java | 75 +----------- 4 files changed, 132 insertions(+), 152 deletions(-) create mode 100644 java/integTest/src/test/java/glide/SharedClientTests.java diff --git a/java/integTest/src/test/java/glide/SharedClientTests.java b/java/integTest/src/test/java/glide/SharedClientTests.java new file mode 100644 index 0000000000..79d5f29f17 --- /dev/null +++ b/java/integTest/src/test/java/glide/SharedClientTests.java @@ -0,0 +1,113 @@ +/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ +package glide; + +import static glide.TestUtilities.commonClientConfig; +import static glide.TestUtilities.commonClusterClientConfig; +import static glide.TestUtilities.getRandomString; +import static glide.api.BaseClient.OK; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import glide.api.BaseClient; +import glide.api.RedisClient; +import glide.api.RedisClusterClient; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Stream; +import lombok.Getter; +import lombok.SneakyThrows; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Timeout; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +@Timeout(25) +public class SharedClientTests { + + private static RedisClient standaloneClient = null; + private static RedisClusterClient clusterClient = null; + + @Getter private static List clients; + + @BeforeAll + @SneakyThrows + public static void init() { + standaloneClient = RedisClient.CreateClient(commonClientConfig().build()).get(); + clusterClient = + RedisClusterClient.CreateClient(commonClusterClientConfig().requestTimeout(5000).build()) + .get(); + + clients = List.of(Arguments.of(standaloneClient), Arguments.of(clusterClient)); + } + + @AfterAll + @SneakyThrows + public static void teardown() { + standaloneClient.close(); + clusterClient.close(); + } + + @SneakyThrows + @ParameterizedTest + @MethodSource("getClients") + public void send_and_receive_large_values(BaseClient client) { + int length = 1 << 16; + String key = getRandomString(length); + String value = getRandomString(length); + + assertEquals(length, key.length()); + assertEquals(length, value.length()); + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } + + @SneakyThrows + @ParameterizedTest + @MethodSource("getClients") + public void send_and_receive_non_ascii_unicode(BaseClient client) { + String key = "foo"; + String value = "שלום hello 汉字"; + + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } + + private static Stream clientAndDataSize() { + return Stream.of( + Arguments.of(standaloneClient, 100), + Arguments.of(standaloneClient, 1 << 16), + Arguments.of(clusterClient, 100), + Arguments.of(clusterClient, 1 << 16)); + } + + @ParameterizedTest + @MethodSource("clientAndDataSize") + public void client_can_handle_concurrent_workload(BaseClient client, int valueSize) { + ExecutorService executorService = Executors.newCachedThreadPool(); + CompletableFuture[] futures = new CompletableFuture[100]; + + for (int i = 0; i < 100; i++) { + futures[i] = + CompletableFuture.runAsync( + () -> { + String key = getRandomString(valueSize); + String value = getRandomString(valueSize); + try { + assertEquals(OK, client.set(key, value).get()); + assertEquals(value, client.get(key).get()); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } + }, + executorService); + } + + CompletableFuture.allOf(futures).join(); + + executorService.shutdown(); + } +} diff --git a/java/integTest/src/test/java/glide/TestUtilities.java b/java/integTest/src/test/java/glide/TestUtilities.java index cb97e00a9b..a50d4542f5 100644 --- a/java/integTest/src/test/java/glide/TestUtilities.java +++ b/java/integTest/src/test/java/glide/TestUtilities.java @@ -1,9 +1,14 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide; +import static glide.TestConfiguration.CLUSTER_PORTS; +import static glide.TestConfiguration.STANDALONE_PORTS; import static org.junit.jupiter.api.Assertions.fail; import glide.api.models.ClusterValue; +import glide.api.models.configuration.NodeAddress; +import glide.api.models.configuration.RedisClientConfiguration; +import glide.api.models.configuration.RedisClusterClientConfiguration; import java.security.SecureRandom; import java.util.HashMap; import java.util.Map; @@ -59,4 +64,16 @@ public static Map parseInfoResponseToMap(String serverInfo) { (existingValue, newValue) -> newValue, HashMap::new)); } + + public static RedisClientConfiguration.RedisClientConfigurationBuilder + commonClientConfig() { + return RedisClientConfiguration.builder() + .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()); + } + + public static RedisClusterClientConfiguration.RedisClusterClientConfigurationBuilder + commonClusterClientConfig() { + return RedisClusterClientConfiguration.builder() + .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()); + } } diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index cdd1eba245..847ce2f124 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -1,7 +1,7 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.cluster; -import static glide.TestConfiguration.CLUSTER_PORTS; +import static glide.TestUtilities.commonClusterClientConfig; import static glide.TestUtilities.getRandomString; import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; @@ -15,31 +15,18 @@ import glide.api.RedisClusterClient; import glide.api.models.ClusterValue; import glide.api.models.commands.InfoOptions; -import glide.api.models.configuration.NodeAddress; -import glide.api.models.configuration.RedisClusterClientConfiguration; import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.RequestException; import java.lang.module.ModuleDescriptor.Version; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; @Timeout(10) public class ClusterClientTests { - private RedisClusterClientConfiguration.RedisClusterClientConfigurationBuilder - commonClusterClientConfig() { - return RedisClusterClientConfiguration.builder() - .address(NodeAddress.builder().port(CLUSTER_PORTS[0]).build()); - } - @SneakyThrows private Boolean check_if_server_version_gte(RedisClusterClient client, String minVersion) { ClusterValue infoClusterValue = @@ -74,70 +61,6 @@ public void register_client_name_and_version() { client.close(); } - @SneakyThrows - @Test - public void send_and_receive_large_values() { - RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - - int length = 65536; - String key = getRandomString(length); - String value = getRandomString(length); - - assertEquals(length, key.length()); - assertEquals(length, value.length()); - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - - client.close(); - } - - @SneakyThrows - @Test - public void send_and_receive_non_ascii_unicode() { - RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - - String key = "foo"; - String value = "שלום hello 汉字"; - - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - - client.close(); - } - - @SneakyThrows - @ParameterizedTest - @ValueSource(ints = {100, 65536}) - public void client_can_handle_concurrent_workload(int valueSize) { - ExecutorService executorService = Executors.newCachedThreadPool(); - RedisClusterClient client = - RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - CompletableFuture[] futures = new CompletableFuture[100]; - - for (int i = 0; i < 100; i++) { - futures[i] = - CompletableFuture.runAsync( - () -> { - String key = getRandomString(valueSize); - String value = getRandomString(valueSize); - try { - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - }, - executorService); - } - - CompletableFuture.allOf(futures).join(); - - client.close(); - executorService.shutdown(); - } - @SneakyThrows @Test public void can_connect_with_auth_requirepass() { diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index 084521fb5c..888a339557 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -1,7 +1,7 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.standalone; -import static glide.TestConfiguration.STANDALONE_PORTS; +import static glide.TestUtilities.commonClientConfig; import static glide.TestUtilities.getRandomString; import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; @@ -14,30 +14,18 @@ import glide.api.RedisClient; import glide.api.models.commands.InfoOptions; -import glide.api.models.configuration.NodeAddress; -import glide.api.models.configuration.RedisClientConfiguration; import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.RequestException; import java.lang.module.ModuleDescriptor.Version; -import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Timeout; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; @Timeout(10) public class StandaloneClientTests { - private RedisClientConfiguration.RedisClientConfigurationBuilder commonClientConfig() { - return RedisClientConfiguration.builder() - .address(NodeAddress.builder().port(STANDALONE_PORTS[0]).build()); - } - @SneakyThrows private Boolean check_if_server_version_gte(RedisClient client, String minVersion) { String infoStr = client.info(InfoOptions.builder().section(SERVER).build()).get(); @@ -61,67 +49,6 @@ public void register_client_name_and_version() { client.close(); } - @SneakyThrows - @Test - public void send_and_receive_large_values() { - RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); - - int length = 65536; - String key = getRandomString(length); - String value = getRandomString(length); - - assertEquals(length, key.length()); - assertEquals(length, value.length()); - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - - client.close(); - } - - @SneakyThrows - @Test - public void send_and_receive_non_ascii_unicode() { - RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); - - String key = "foo"; - String value = "שלום hello 汉字"; - - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - - client.close(); - } - - @SneakyThrows - @ParameterizedTest - @ValueSource(ints = {100, 65536}) - public void client_can_handle_concurrent_workload(int valueSize) { - ExecutorService executorService = Executors.newCachedThreadPool(); - RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); - CompletableFuture[] futures = new CompletableFuture[100]; - - for (int i = 0; i < 100; i++) { - futures[i] = - CompletableFuture.runAsync( - () -> { - String key = getRandomString(valueSize); - String value = getRandomString(valueSize); - try { - assertEquals(OK, client.set(key, value).get()); - assertEquals(value, client.get(key).get()); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - }, - executorService); - } - - CompletableFuture.allOf(futures).join(); - - client.close(); - executorService.shutdown(); - } - @SneakyThrows @Test public void can_connect_with_auth_require_pass() { From 106698a02678e82d6102e3dcc86cabe4a21e311c Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Tue, 12 Mar 2024 15:00:02 -0700 Subject: [PATCH 7/9] Minor update to IT tests based on PR comments. --- .../glide/cluster/ClusterClientTests.java | 31 +++---------------- .../standalone/StandaloneClientTests.java | 21 +++---------- 2 files changed, 10 insertions(+), 42 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index 847ce2f124..365d3267a6 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -1,24 +1,19 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.cluster; +import static glide.TestConfiguration.REDIS_VERSION; import static glide.TestUtilities.commonClusterClientConfig; import static glide.TestUtilities.getRandomString; -import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; -import static glide.api.models.commands.InfoOptions.Section.SERVER; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue; import glide.api.RedisClusterClient; -import glide.api.models.ClusterValue; -import glide.api.models.commands.InfoOptions; import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.RequestException; -import java.lang.module.ModuleDescriptor.Version; import java.util.concurrent.ExecutionException; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; @@ -27,32 +22,16 @@ @Timeout(10) public class ClusterClientTests { - @SneakyThrows - private Boolean check_if_server_version_gte(RedisClusterClient client, String minVersion) { - ClusterValue infoClusterValue = - client.info(InfoOptions.builder().section(SERVER).build()).get(); - - String infoStr; - if (infoClusterValue.hasSingleData()) { - infoStr = infoClusterValue.getSingleValue(); - } else { - infoStr = infoClusterValue.getMultiValue().entrySet().iterator().next().getValue(); - } - - String redisVersion = parseInfoResponseToMap(infoStr).get("redis_version"); - assertNotNull(redisVersion); - return Version.parse(redisVersion).compareTo(Version.parse(minVersion)) >= 0; - } - @SneakyThrows @Test public void register_client_name_and_version() { + String minVersion = "7.2.0"; + assumeTrue( + REDIS_VERSION.isGreaterThanOrEqualTo("7.2.0"), "Redis version required >= " + minVersion); + RedisClusterClient client = RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); - String minVersion = "7.2.0"; - assumeTrue( - check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); String info = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get().getSingleValue(); assertTrue(info.contains("lib-name=GlideJava")); diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index 888a339557..4fefbf8b3f 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -1,23 +1,19 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.standalone; +import static glide.TestConfiguration.REDIS_VERSION; import static glide.TestUtilities.commonClientConfig; import static glide.TestUtilities.getRandomString; -import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; -import static glide.api.models.commands.InfoOptions.Section.SERVER; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeTrue; import glide.api.RedisClient; -import glide.api.models.commands.InfoOptions; import glide.api.models.configuration.RedisCredentials; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.RequestException; -import java.lang.module.ModuleDescriptor.Version; import java.util.concurrent.ExecutionException; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; @@ -26,22 +22,15 @@ @Timeout(10) public class StandaloneClientTests { - @SneakyThrows - private Boolean check_if_server_version_gte(RedisClient client, String minVersion) { - String infoStr = client.info(InfoOptions.builder().section(SERVER).build()).get(); - String redisVersion = parseInfoResponseToMap(infoStr).get("redis_version"); - assertNotNull(redisVersion); - return Version.parse(redisVersion).compareTo(Version.parse(minVersion)) >= 0; - } - @SneakyThrows @Test public void register_client_name_and_version() { - RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); - String minVersion = "7.2.0"; assumeTrue( - check_if_server_version_gte(client, minVersion), "Redis version required >= " + minVersion); + REDIS_VERSION.isGreaterThanOrEqualTo("7.2.0"), "Redis version required >= " + minVersion); + + RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); + String info = (String) client.customCommand(new String[] {"CLIENT", "INFO"}).get(); assertTrue(info.contains("lib-name=GlideJava")); assertTrue(info.contains("lib-ver=unknown")); From 6a09e0f981103b611c5f4d090d1a7308eb074f84 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Wed, 13 Mar 2024 11:26:20 -0700 Subject: [PATCH 8/9] Minor update. --- .../src/test/java/glide/cluster/ClusterClientTests.java | 4 ++-- .../src/test/java/glide/standalone/StandaloneClientTests.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index 365d3267a6..dccae10eb3 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -27,7 +27,7 @@ public class ClusterClientTests { public void register_client_name_and_version() { String minVersion = "7.2.0"; assumeTrue( - REDIS_VERSION.isGreaterThanOrEqualTo("7.2.0"), "Redis version required >= " + minVersion); + REDIS_VERSION.isGreaterThanOrEqualTo(minVersion), "Redis version required >= " + minVersion); RedisClusterClient client = RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); @@ -148,7 +148,7 @@ public void client_name() { @Test @SneakyThrows - public void close_client_throws_ExecutionException_with_ClosingException_cause() { + public void closed_client_throws_ExecutionException_with_ClosingException_as_cause() { RedisClusterClient client = RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index 4fefbf8b3f..e57b80ef83 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -27,7 +27,7 @@ public class StandaloneClientTests { public void register_client_name_and_version() { String minVersion = "7.2.0"; assumeTrue( - REDIS_VERSION.isGreaterThanOrEqualTo("7.2.0"), "Redis version required >= " + minVersion); + REDIS_VERSION.isGreaterThanOrEqualTo(minVersion), "Redis version required >= " + minVersion); RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); @@ -150,7 +150,7 @@ public void client_name() { @Test @SneakyThrows - public void close_client_throws_ExecutionException_with_ClosingException_cause() { + public void closed_client_throws_ExecutionException_with_ClosingException_as_cause() { RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get(); client.close(); From 26472f9f8a6b23d4c4365d6cb84a10c43f4f0785 Mon Sep 17 00:00:00 2001 From: SanHalacogluImproving Date: Wed, 13 Mar 2024 11:26:38 -0700 Subject: [PATCH 9/9] Spotless. --- .../src/test/java/glide/cluster/ClusterClientTests.java | 3 ++- .../src/test/java/glide/standalone/StandaloneClientTests.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java index dccae10eb3..aefeb36ad3 100644 --- a/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java +++ b/java/integTest/src/test/java/glide/cluster/ClusterClientTests.java @@ -27,7 +27,8 @@ public class ClusterClientTests { public void register_client_name_and_version() { String minVersion = "7.2.0"; assumeTrue( - REDIS_VERSION.isGreaterThanOrEqualTo(minVersion), "Redis version required >= " + minVersion); + REDIS_VERSION.isGreaterThanOrEqualTo(minVersion), + "Redis version required >= " + minVersion); RedisClusterClient client = RedisClusterClient.CreateClient(commonClusterClientConfig().build()).get(); diff --git a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java index e57b80ef83..4356f1e333 100644 --- a/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java +++ b/java/integTest/src/test/java/glide/standalone/StandaloneClientTests.java @@ -27,7 +27,8 @@ public class StandaloneClientTests { public void register_client_name_and_version() { String minVersion = "7.2.0"; assumeTrue( - REDIS_VERSION.isGreaterThanOrEqualTo(minVersion), "Redis version required >= " + minVersion); + REDIS_VERSION.isGreaterThanOrEqualTo(minVersion), + "Redis version required >= " + minVersion); RedisClient client = RedisClient.CreateClient(commonClientConfig().build()).get();