From d5cb19dc651ec00c2ed09ce3d4f654ea8e390f12 Mon Sep 17 00:00:00 2001 From: yulazariy Date: Thu, 27 Jun 2024 13:56:43 +0300 Subject: [PATCH] Support of GlideString interface for echo command (#1668) * Add support of GlideString interface for echo command for both standalone and cluster clients. In addition added handleGlideStringResponse to return a GlideString from a non nullable response. --------- Co-authored-by: Yulazari --- .../src/main/java/glide/api/BaseClient.java | 4 ++ .../src/main/java/glide/api/RedisClient.java | 6 +++ .../java/glide/api/RedisClusterClient.java | 19 ++++++++ .../ConnectionManagementClusterCommands.java | 39 +++++++++++++++ .../ConnectionManagementCommands.java | 15 ++++++ .../test/java/glide/api/RedisClientTest.java | 22 +++++++++ .../glide/api/RedisClusterClientTest.java | 48 +++++++++++++++++++ .../test/java/glide/cluster/CommandTests.java | 20 ++++++++ .../java/glide/standalone/CommandTests.java | 12 +++++ 9 files changed, 185 insertions(+) diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 5586003928..c777e40c30 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -399,6 +399,10 @@ protected GlideString handleGlideStringOrNullResponse(Response response) throws return handleRedisResponse(GlideString.class, EnumSet.of(ResponseFlags.IS_NULLABLE), response); } + protected GlideString handleGlideStringResponse(Response response) throws RedisException { + return handleRedisResponse(GlideString.class, EnumSet.noneOf(ResponseFlags.class), response); + } + protected Boolean handleBooleanResponse(Response response) throws RedisException { return handleRedisResponse(Boolean.class, EnumSet.noneOf(ResponseFlags.class), response); } diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java index 412294f7dc..0f8607afb7 100644 --- a/java/client/src/main/java/glide/api/RedisClient.java +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -165,6 +165,12 @@ public CompletableFuture echo(@NonNull String message) { Echo, new String[] {message}, this::handleStringResponse); } + @Override + public CompletableFuture echo(@NonNull GlideString message) { + return commandManager.submitNewCommand( + Echo, new GlideString[] {message}, this::handleGlideStringResponse); + } + @Override public CompletableFuture time() { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index e6ff24b9b5..26fc3e86e7 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -285,6 +285,12 @@ public CompletableFuture echo(@NonNull String message) { Echo, new String[] {message}, this::handleStringResponse); } + @Override + public CompletableFuture echo(@NonNull GlideString message) { + return commandManager.submitNewCommand( + Echo, new GlideString[] {message}, this::handleGlideStringResponse); + } + @Override public CompletableFuture> echo( @NonNull String message, @NonNull Route route) { @@ -298,6 +304,19 @@ public CompletableFuture> echo( : ClusterValue.ofMultiValue(handleMapResponse(response))); } + @Override + public CompletableFuture> echo( + @NonNull GlideString message, @NonNull Route route) { + return commandManager.submitNewCommand( + Echo, + new GlideString[] {message}, + route, + response -> + route instanceof SingleNodeRoute + ? ClusterValue.ofSingleValue(handleGlideStringResponse(response)) + : ClusterValue.ofMultiValueBinary(handleBinaryStringMapResponse(response))); + } + @Override public CompletableFuture time() { return commandManager.submitNewCommand( diff --git a/java/client/src/main/java/glide/api/commands/ConnectionManagementClusterCommands.java b/java/client/src/main/java/glide/api/commands/ConnectionManagementClusterCommands.java index ac04fa8b9a..6da4f51d91 100644 --- a/java/client/src/main/java/glide/api/commands/ConnectionManagementClusterCommands.java +++ b/java/client/src/main/java/glide/api/commands/ConnectionManagementClusterCommands.java @@ -2,6 +2,7 @@ package glide.api.commands; import glide.api.models.ClusterValue; +import glide.api.models.GlideString; import glide.api.models.configuration.RequestRoutingConfiguration.Route; import java.util.concurrent.CompletableFuture; @@ -157,6 +158,21 @@ public interface ConnectionManagementClusterCommands { */ CompletableFuture echo(String message); + /** + * Echoes the provided message back.
+ * The command will be routed a random node. + * + * @see redis.io for details. + * @param message The message to be echoed back. + * @return The provided message. + * @example + *
{@code
+     * GlideString payload = client.echo(gs("GLIDE")).get();
+     * assert payload.equals(gs("GLIDE"));
+     * }
+ */ + CompletableFuture echo(GlideString message); + /** * Echoes the provided message back. * @@ -179,4 +195,27 @@ public interface ConnectionManagementClusterCommands { * } */ CompletableFuture> echo(String message, Route route); + + /** + * Echoes the provided message back. + * + * @see redis.io for details. + * @param message The message to be echoed back. + * @param route Specifies the routing configuration for the command. The client will route the + * command to the nodes defined by route. + * @return The provided message. + * @example + *
{@code
+     * // Command sent to a single random node via RANDOM route, expecting a SingleValue result.
+     * GlideString message = client.echo(gs("GLIDE"), RANDOM).get().getSingleValue();
+     * assert message.equals(gs("GLIDE"));
+     *
+     * // Command sent to all nodes via ALL_NODES route, expecting a MultiValue result.
+     * Map msgForAllNodes = client.echo(gs("GLIDE"), ALL_NODES).get().getMultiValue();
+     * for(var msgPerNode : msgForAllNodes.entrySet()) {
+     *     assert msgPerNode.equals(gs("GLIDE"));
+     * }
+     * }
+ */ + CompletableFuture> echo(GlideString message, Route route); } diff --git a/java/client/src/main/java/glide/api/commands/ConnectionManagementCommands.java b/java/client/src/main/java/glide/api/commands/ConnectionManagementCommands.java index 5333e81398..c737cf24ef 100644 --- a/java/client/src/main/java/glide/api/commands/ConnectionManagementCommands.java +++ b/java/client/src/main/java/glide/api/commands/ConnectionManagementCommands.java @@ -1,6 +1,7 @@ /** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.api.commands; +import glide.api.models.GlideString; import java.util.concurrent.CompletableFuture; /** @@ -77,4 +78,18 @@ public interface ConnectionManagementCommands { * } */ CompletableFuture echo(String message); + + /** + * Echoes the provided message back. + * + * @see + */ + CompletableFuture echo(GlideString message); } diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index cdb28f7b16..e254d364ba 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -411,6 +411,28 @@ public void echo_returns_success() { assertEquals(message, echo); } + @SneakyThrows + @Test + public void echo_binary_returns_success() { + // setup + GlideString message = gs("GLIDE FOR REDIS"); + GlideString[] arguments = new GlideString[] {message}; + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(message); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(Echo), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.echo(message); + GlideString echo = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(message, echo); + } + @SneakyThrows @Test public void ping_returns_success() { diff --git a/java/client/src/test/java/glide/api/RedisClusterClientTest.java b/java/client/src/test/java/glide/api/RedisClusterClientTest.java index ffdbf2c3b9..7a82ff5e35 100644 --- a/java/client/src/test/java/glide/api/RedisClusterClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClusterClientTest.java @@ -6,7 +6,10 @@ import static glide.api.models.GlideString.gs; import static glide.api.models.commands.FlushMode.ASYNC; import static glide.api.models.commands.FlushMode.SYNC; +import static glide.api.models.commands.SortBaseOptions.ALPHA_COMMAND_STRING; +import static glide.api.models.commands.SortBaseOptions.LIMIT_COMMAND_STRING; import static glide.api.models.commands.SortBaseOptions.OrderBy.DESC; +import static glide.api.models.commands.SortBaseOptions.STORE_COMMAND_STRING; import static glide.api.models.commands.SortOptions.ALPHA_COMMAND_STRING; import static glide.api.models.commands.SortOptions.LIMIT_COMMAND_STRING; import static glide.api.models.commands.SortOptions.STORE_COMMAND_STRING; @@ -353,6 +356,28 @@ public void echo_returns_success() { assertEquals(message, echo); } + @SneakyThrows + @Test + public void echo_binary_returns_success() { + // setup + GlideString message = gs("GLIDE FOR REDIS"); + GlideString[] arguments = new GlideString[] {message}; + CompletableFuture testResponse = new CompletableFuture<>(); + testResponse.complete(message); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(Echo), eq(arguments), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture response = service.echo(message); + GlideString echo = response.get(); + + // verify + assertEquals(testResponse, response); + assertEquals(message, echo); + } + @SneakyThrows @Test public void echo_with_route_returns_success() { @@ -376,6 +401,29 @@ public void echo_with_route_returns_success() { assertEquals(message, echo); } + @SneakyThrows + @Test + public void echo_binary_with_route_returns_success() { + // setup + GlideString message = gs("GLIDE FOR REDIS"); + GlideString[] arguments = new GlideString[] {message}; + CompletableFuture> testResponse = new CompletableFuture<>(); + testResponse.complete(ClusterValue.ofSingleValue(message)); + + // match on protobuf request + when(commandManager.>submitNewCommand( + eq(Echo), eq(arguments), eq(RANDOM), any())) + .thenReturn(testResponse); + + // exercise + CompletableFuture> response = service.echo(message, RANDOM); + GlideString echo = response.get().getSingleValue(); + + // verify + assertEquals(testResponse, response); + assertEquals(message, echo); + } + @SneakyThrows @Test public void info_returns_string() { diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index 4f9184412e..c8793d33b4 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -563,6 +563,26 @@ public void echo_with_route() { multiPayload.forEach((key, value) -> assertEquals(message, value)); } + @SneakyThrows + @Test + public void echo_gs() { + byte[] message = {(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x02}; + GlideString response = clusterClient.echo(gs(message)).get(); + assertEquals(gs(message), response); + } + + @SneakyThrows + @Test + public void echo_gs_with_route() { + byte[] message = {(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x02}; + GlideString singlePayload = clusterClient.echo(gs(message), RANDOM).get().getSingleValue(); + assertEquals(gs(message), singlePayload); + + Map multiPayload = + clusterClient.echo(gs(message), ALL_NODES).get().getMultiValue(); + multiPayload.forEach((key, value) -> assertEquals(gs(message), value)); + } + @Test @SneakyThrows public void time() { diff --git a/java/integTest/src/test/java/glide/standalone/CommandTests.java b/java/integTest/src/test/java/glide/standalone/CommandTests.java index 736284375c..d69cb817e8 100644 --- a/java/integTest/src/test/java/glide/standalone/CommandTests.java +++ b/java/integTest/src/test/java/glide/standalone/CommandTests.java @@ -11,6 +11,7 @@ import static glide.TestUtilities.getValueFromInfo; import static glide.TestUtilities.parseInfoResponseToMap; import static glide.api.BaseClient.OK; +import static glide.api.models.GlideString.gs; import static glide.api.models.commands.FlushMode.ASYNC; import static glide.api.models.commands.FlushMode.SYNC; import static glide.api.models.commands.InfoOptions.Section.CLUSTER; @@ -335,6 +336,17 @@ public void echo() { String message = "GLIDE"; String response = regularClient.echo(message).get(); assertEquals(message, response); + message = ""; + response = regularClient.echo(message).get(); + assertEquals(message, response); + } + + @SneakyThrows + @Test + public void echo_gs() { + byte[] message = {(byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x02}; + GlideString response = regularClient.echo(gs(message)).get(); + assertEquals(gs(message), response); } @Test