diff --git a/java/client/src/main/java/glide/api/BaseClient.java b/java/client/src/main/java/glide/api/BaseClient.java index 042ab91354..8c61c2908b 100644 --- a/java/client/src/main/java/glide/api/BaseClient.java +++ b/java/client/src/main/java/glide/api/BaseClient.java @@ -26,18 +26,6 @@ public abstract class BaseClient implements AutoCloseable { protected final ConnectionManager connectionManager; protected final CommandManager commandManager; - /** - * Extracts the response from the Protobuf response and either throws an exception or returns the - * appropriate response as an Object - * - * @param response Redis protobuf message - * @return Response Object - */ - protected Object handleObjectResponse(Response response) { - // convert protobuf response into Object and then Object into T - return new BaseCommandResponseResolver(RedisValueResolver::valueFromPointer).apply(response); - } - /** * Async request for an async (non-blocking) Redis client. * @@ -74,8 +62,8 @@ protected static CompletableFuture CreateClient( * Closes this resource, relinquishing any underlying resources. This method is invoked * automatically on objects managed by the try-with-resources statement. * - *

see: AutoCloseable::close() + * @see AutoCloseable::close() */ @Override public void close() throws ExecutionException { @@ -100,4 +88,16 @@ protected static ConnectionManager buildConnectionManager(ChannelHandler channel protected static CommandManager buildCommandManager(ChannelHandler channelHandler) { return new CommandManager(channelHandler); } + + /** + * Extracts the response from the Protobuf response and either throws an exception or returns the + * appropriate response as an Object. + * + * @param response Redis protobuf message + * @return Response Object + */ + protected Object handleObjectResponse(Response response) { + // convert protobuf response into Object + return new BaseCommandResponseResolver(RedisValueResolver::valueFromPointer).apply(response); + } } diff --git a/java/client/src/main/java/glide/api/RedisClient.java b/java/client/src/main/java/glide/api/RedisClient.java index c39ebfb753..a253095558 100644 --- a/java/client/src/main/java/glide/api/RedisClient.java +++ b/java/client/src/main/java/glide/api/RedisClient.java @@ -1,11 +1,12 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.api; +import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand; + import glide.api.commands.BaseCommands; import glide.api.models.configuration.RedisClientConfiguration; import glide.managers.CommandManager; import glide.managers.ConnectionManager; -import glide.managers.models.Command; import java.util.concurrent.CompletableFuture; /** @@ -30,8 +31,6 @@ public static CompletableFuture CreateClient(RedisClientConfigurati @Override public CompletableFuture customCommand(String[] args) { - Command command = - Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).arguments(args).build(); - return commandManager.submitNewCommand(command, this::handleObjectResponse); + return commandManager.submitNewCommand(CustomCommand, args, this::handleObjectResponse); } } diff --git a/java/client/src/main/java/glide/api/RedisClusterClient.java b/java/client/src/main/java/glide/api/RedisClusterClient.java index 948ee7240b..427c21cbb4 100644 --- a/java/client/src/main/java/glide/api/RedisClusterClient.java +++ b/java/client/src/main/java/glide/api/RedisClusterClient.java @@ -1,13 +1,14 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.api; +import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand; + import glide.api.commands.ClusterBaseCommands; import glide.api.models.ClusterValue; import glide.api.models.configuration.RedisClusterClientConfiguration; import glide.api.models.configuration.RequestRoutingConfiguration.Route; import glide.managers.CommandManager; import glide.managers.ConnectionManager; -import glide.managers.models.Command; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -34,25 +35,18 @@ public static CompletableFuture CreateClient( @Override public CompletableFuture> customCommand(String[] args) { - Command command = - Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).arguments(args).build(); // TODO if a command returns a map as a single value, ClusterValue misleads user return commandManager.submitNewCommand( - command, response -> ClusterValue.of(handleObjectResponse(response))); + CustomCommand, args, response -> ClusterValue.of(handleObjectResponse(response))); } @Override @SuppressWarnings("unchecked") public CompletableFuture> customCommand(String[] args, Route route) { - Command command = - Command.builder() - .requestType(Command.RequestType.CUSTOM_COMMAND) - .arguments(args) - .route(route) - .build(); - return commandManager.submitNewCommand( - command, + CustomCommand, + args, + route, response -> route.isSingleNodeRoute() ? ClusterValue.ofSingleValue(handleObjectResponse(response)) diff --git a/java/client/src/main/java/glide/managers/CommandManager.java b/java/client/src/main/java/glide/managers/CommandManager.java index 36663893d1..6e1ca7cc1c 100644 --- a/java/client/src/main/java/glide/managers/CommandManager.java +++ b/java/client/src/main/java/glide/managers/CommandManager.java @@ -8,11 +8,10 @@ import glide.api.models.exceptions.ClosingException; import glide.connectors.handlers.CallbackDispatcher; import glide.connectors.handlers.ChannelHandler; -import glide.managers.models.Command; -import java.util.Optional; import java.util.concurrent.CompletableFuture; import lombok.RequiredArgsConstructor; import redis_request.RedisRequestOuterClass; +import redis_request.RedisRequestOuterClass.Command; import redis_request.RedisRequestOuterClass.Command.ArgsArray; import redis_request.RedisRequestOuterClass.RedisRequest; import redis_request.RedisRequestOuterClass.RequestType; @@ -34,135 +33,151 @@ public class CommandManager { /** * Build a command and send. * - * @param command The command to execute + * @param requestType Redis command type + * @param arguments Redis command arguments * @param responseHandler The handler for the response object * @return A result promise of type T */ public CompletableFuture submitNewCommand( - Command command, RedisExceptionCheckedFunction responseHandler) { - // write command request to channel - // when complete, convert the response to our expected type T using the given responseHandler - return channel - .write( - prepareRedisRequest( - command.getRequestType(), - command.getArguments(), - Optional.ofNullable(command.getRoute())), - true) - .exceptionally(this::exceptionHandler) - .thenApplyAsync(responseHandler::apply); + RedisRequestOuterClass.RequestType requestType, + String[] arguments, + RedisExceptionCheckedFunction responseHandler) { + + RedisRequest.Builder command = prepareRedisRequest(requestType, arguments); + return submitCommandToChannel(command, responseHandler); } /** - * Exception handler for future pipeline. + * Build a command and send. * - * @param e An exception thrown in the pipeline before - * @return Nothing, it rethrows the exception + * @param requestType Redis command type + * @param arguments Redis command arguments + * @param route Command routing parameters + * @param responseHandler The handler for the response object + * @return A result promise of type T */ - private Response exceptionHandler(Throwable e) { - if (e instanceof ClosingException) { - channel.close(); - } - if (e instanceof RuntimeException) { - // RedisException also goes here - throw (RuntimeException) e; - } - throw new RuntimeException(e); + public CompletableFuture submitNewCommand( + RequestType requestType, + String[] arguments, + Route route, + RedisExceptionCheckedFunction responseHandler) { + + RedisRequest.Builder command = prepareRedisRequest(requestType, arguments, route); + return submitCommandToChannel(command, responseHandler); + } + + /** + * Take a redis request and send to channel. + * + * @param command The Redis command request as a builder to execute + * @param responseHandler The handler for the response object + * @return A result promise of type T + */ + protected CompletableFuture submitCommandToChannel( + RedisRequest.Builder command, RedisExceptionCheckedFunction responseHandler) { + // write command request to channel + // when complete, convert the response to our expected type T using the given responseHandler + return channel + .write(command, true) + .exceptionally(this::exceptionHandler) + .thenApplyAsync(responseHandler::apply); } /** - * Build a protobuf command/transaction request object.
- * Used by {@link CommandManager}. + * Build a protobuf command request object with routing options. * - * @param command - Redis command - * @param args - Redis command arguments as string array - * @return An uncompleted request. CallbackDispatcher is responsible to complete it by adding a - * callback id. + * @param requestType Redis command type + * @param arguments Redis command arguments + * @param route Command routing parameters + * @return An incomplete request. {@link CallbackDispatcher} is responsible to complete it by + * adding a callback id. */ - private RedisRequestOuterClass.RedisRequest.Builder prepareRedisRequest( - Command.RequestType command, String[] args) { - RedisRequestOuterClass.Command.ArgsArray.Builder commandArgs = - RedisRequestOuterClass.Command.ArgsArray.newBuilder(); - for (var arg : args) { + protected RedisRequest.Builder prepareRedisRequest( + RequestType requestType, String[] arguments, Route route) { + ArgsArray.Builder commandArgs = ArgsArray.newBuilder(); + for (var arg : arguments) { commandArgs.addArgs(arg); } - // TODO: set route properly when no RouteOptions given - return RedisRequestOuterClass.RedisRequest.newBuilder() - .setSingleCommand( - RedisRequestOuterClass.Command.newBuilder() - .setRequestType(mapRequestTypes(command)) - .setArgsArray(commandArgs.build()) - .build()) - .setRoute( - RedisRequestOuterClass.Routes.newBuilder() - .setSimpleRoutes(RedisRequestOuterClass.SimpleRoutes.AllNodes) - .build()); - } + var builder = + RedisRequest.newBuilder() + .setSingleCommand( + Command.newBuilder() + .setRequestType(requestType) + .setArgsArray(commandArgs.build()) + .build()); - private RequestType mapRequestTypes(Command.RequestType inType) { - switch (inType) { - case CUSTOM_COMMAND: - return RequestType.CustomCommand; - } - throw new RuntimeException("Unsupported request type"); + return prepareRedisRequestRoute(builder, route); } /** - * Build a protobuf command/transaction request object with routing options.
- * Used by {@link CommandManager}. + * Build a protobuf command request object. * - * @param command Redis command type - * @param args Redis command arguments - * @param route Command routing parameters + * @param requestType Redis command type + * @param arguments Redis command arguments * @return An uncompleted request. {@link CallbackDispatcher} is responsible to complete it by * adding a callback id. */ - private RedisRequest.Builder prepareRedisRequest( - Command.RequestType command, String[] args, Optional route) { + protected RedisRequest.Builder prepareRedisRequest(RequestType requestType, String[] arguments) { ArgsArray.Builder commandArgs = ArgsArray.newBuilder(); - for (var arg : args) { + for (var arg : arguments) { commandArgs.addArgs(arg); } var builder = RedisRequest.newBuilder() .setSingleCommand( - RedisRequestOuterClass.Command.newBuilder() - .setRequestType(mapRequestTypes(command)) + Command.newBuilder() + .setRequestType(requestType) .setArgsArray(commandArgs.build()) .build()); - if (route.isEmpty()) { - return builder; - } + return builder; + } + + private RedisRequest.Builder prepareRedisRequestRoute(RedisRequest.Builder builder, Route route) { - if (route.get() instanceof SimpleRoute) { + if (route instanceof SimpleRoute) { builder.setRoute( Routes.newBuilder() - .setSimpleRoutes(SimpleRoutes.forNumber(((SimpleRoute) route.get()).ordinal())) + .setSimpleRoutes(SimpleRoutes.forNumber(((SimpleRoute) route).ordinal())) .build()); - } else if (route.get() instanceof SlotIdRoute) { + } else if (route instanceof SlotIdRoute) { builder.setRoute( Routes.newBuilder() .setSlotIdRoute( RedisRequestOuterClass.SlotIdRoute.newBuilder() - .setSlotId(((SlotIdRoute) route.get()).getSlotId()) + .setSlotId(((SlotIdRoute) route).getSlotId()) .setSlotType( - SlotTypes.forNumber( - ((SlotIdRoute) route.get()).getSlotType().ordinal())))); - } else if (route.get() instanceof SlotKeyRoute) { + SlotTypes.forNumber(((SlotIdRoute) route).getSlotType().ordinal())))); + } else if (route instanceof SlotKeyRoute) { builder.setRoute( Routes.newBuilder() .setSlotKeyRoute( RedisRequestOuterClass.SlotKeyRoute.newBuilder() - .setSlotKey(((SlotKeyRoute) route.get()).getSlotKey()) + .setSlotKey(((SlotKeyRoute) route).getSlotKey()) .setSlotType( - SlotTypes.forNumber( - ((SlotKeyRoute) route.get()).getSlotType().ordinal())))); + SlotTypes.forNumber(((SlotKeyRoute) route).getSlotType().ordinal())))); } else { throw new IllegalArgumentException("Unknown type of route"); } return builder; } + + /** + * Exception handler for future pipeline. + * + * @param e An exception thrown in the pipeline before + * @return Nothing, it rethrows the exception + */ + private Response exceptionHandler(Throwable e) { + if (e instanceof ClosingException) { + channel.close(); + } + if (e instanceof RuntimeException) { + // RedisException also goes here + throw (RuntimeException) e; + } + throw new RuntimeException(e); + } } diff --git a/java/client/src/main/java/glide/managers/models/Command.java b/java/client/src/main/java/glide/managers/models/Command.java deleted file mode 100644 index 4b45f38593..0000000000 --- a/java/client/src/main/java/glide/managers/models/Command.java +++ /dev/null @@ -1,29 +0,0 @@ -/** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ -package glide.managers.models; - -import glide.api.models.configuration.RequestRoutingConfiguration.Route; -import lombok.Builder; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NonNull; - -/** Base Command class to send a single request to Redis. */ -@Builder -@Getter -@EqualsAndHashCode -public class Command { - - /** Redis command request type */ - @NonNull final RequestType requestType; - - /** Request routing configuration */ - final Route route; - - /** List of Arguments for the Redis command request */ - @Builder.Default final String[] arguments = new String[] {}; - - public enum RequestType { - /** Call a custom command with list of string arguments */ - CUSTOM_COMMAND, - } -} diff --git a/java/client/src/test/java/glide/ExceptionHandlingTests.java b/java/client/src/test/java/glide/ExceptionHandlingTests.java index a4a534c5d6..43bdb224d0 100644 --- a/java/client/src/test/java/glide/ExceptionHandlingTests.java +++ b/java/client/src/test/java/glide/ExceptionHandlingTests.java @@ -6,6 +6,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand; import static response.ResponseOuterClass.RequestErrorType.Disconnect; import static response.ResponseOuterClass.RequestErrorType.ExecAbort; import static response.ResponseOuterClass.RequestErrorType.Timeout; @@ -26,8 +27,6 @@ import glide.managers.BaseCommandResponseResolver; import glide.managers.CommandManager; import glide.managers.ConnectionManager; -import glide.managers.models.Command; -import glide.managers.models.Command.RequestType; import io.netty.channel.ChannelFuture; import java.io.IOException; import java.util.concurrent.CancellationException; @@ -95,7 +94,7 @@ public void channel_is_closed_when_disconnected_on_command() { var channelHandler = new TestChannelHandler(callbackDispatcher); var commandManager = new CommandManager(channelHandler); - var future = commandManager.submitNewCommand(createDummyCommand(), r -> null); + var future = commandManager.submitNewCommand(CustomCommand, new String[0], r -> null); callbackDispatcher.completeRequest(null); var exception = assertThrows(ExecutionException.class, future::get); // a ClosingException thrown from CallbackDispatcher::completeRequest and then @@ -112,7 +111,7 @@ public void channel_is_not_closed_when_error_was_in_command_pipeline() { var channelHandler = new TestChannelHandler(callbackDispatcher); var commandManager = new CommandManager(channelHandler); - var future = commandManager.submitNewCommand(createDummyCommand(), r -> null); + var future = commandManager.submitNewCommand(CustomCommand, new String[0], r -> null); callbackDispatcher.completeRequest(null); var exception = assertThrows(ExecutionException.class, future::get); // a RequestException thrown from CallbackDispatcher::completeRequest and then @@ -129,7 +128,7 @@ public void command_manager_rethrows_non_RedisException_too() { var channelHandler = new TestChannelHandler(callbackDispatcher); var commandManager = new CommandManager(channelHandler); - var future = commandManager.submitNewCommand(createDummyCommand(), r -> null); + var future = commandManager.submitNewCommand(CustomCommand, new String[0], r -> null); callbackDispatcher.completeRequest(null); var exception = assertThrows(ExecutionException.class, future::get); // a IOException thrown from CallbackDispatcher::completeRequest and then wrapped @@ -210,7 +209,7 @@ public void dont_close_connection_when_callback_dispatcher_receives_response_wit var channelHandler = new TestChannelHandler(callbackDispatcher); var commandManager = new CommandManager(channelHandler); - var future = commandManager.submitNewCommand(createDummyCommand(), r -> null); + var future = commandManager.submitNewCommand(CustomCommand, new String[0], r -> null); var response = Response.newBuilder() .setCallbackIdx(0) @@ -280,10 +279,6 @@ private static RedisClientConfiguration createDummyConfig() { return RedisClientConfiguration.builder().build(); } - private static Command createDummyCommand() { - return Command.builder().requestType(RequestType.CUSTOM_COMMAND).build(); - } - /** Test ChannelHandler extension which allows to validate whether the channel was closed. */ private static class TestChannelHandler extends ChannelHandler { diff --git a/java/client/src/test/java/glide/api/RedisClientTest.java b/java/client/src/test/java/glide/api/RedisClientTest.java index ff8c356cff..2eab3d6497 100644 --- a/java/client/src/test/java/glide/api/RedisClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClientTest.java @@ -2,15 +2,16 @@ package glide.api; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand; import glide.managers.CommandManager; import glide.managers.ConnectionManager; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; +import lombok.SneakyThrows; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -29,46 +30,27 @@ public void setUp() { service = new RedisClient(connectionManager, commandManager); } + @SneakyThrows @Test - public void customCommand_success() throws ExecutionException, InterruptedException { + public void customCommand_returns_success() { // setup String key = "testKey"; Object value = "testValue"; String cmd = "GETSTRING"; + String[] arguments = new String[] {cmd, key}; CompletableFuture testResponse = mock(CompletableFuture.class); when(testResponse.get()).thenReturn(value); - when(commandManager.submitNewCommand(any(), any())).thenReturn(testResponse); + + // match on protobuf request + when(commandManager.submitNewCommand(eq(CustomCommand), eq(arguments), any())) + .thenReturn(testResponse); // exercise - CompletableFuture response = service.customCommand(new String[] {cmd, key}); + CompletableFuture response = service.customCommand(arguments); String payload = (String) response.get(); // verify assertEquals(testResponse, response); assertEquals(value, payload); } - - @Test - public void customCommand_interruptedException() throws ExecutionException, InterruptedException { - // setup - String key = "testKey"; - Object value = "testValue"; - String cmd = "GETSTRING"; - CompletableFuture testResponse = mock(CompletableFuture.class); - InterruptedException interruptedException = new InterruptedException(); - when(testResponse.get()).thenThrow(interruptedException); - when(commandManager.submitNewCommand(any(), any())).thenReturn(testResponse); - - // exercise - InterruptedException exception = - assertThrows( - InterruptedException.class, - () -> { - CompletableFuture response = service.customCommand(new String[] {cmd, key}); - response.get(); - }); - - // verify - assertEquals(interruptedException, exception); - } } diff --git a/java/client/src/test/java/glide/api/RedisClusterClientTest.java b/java/client/src/test/java/glide/api/RedisClusterClientTest.java index 32c459cafa..d8c86b71e1 100644 --- a/java/client/src/test/java/glide/api/RedisClusterClientTest.java +++ b/java/client/src/test/java/glide/api/RedisClusterClientTest.java @@ -1,22 +1,25 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.api; +import static glide.api.models.configuration.RequestRoutingConfiguration.SimpleRoute.ALL_NODES; +import static glide.api.models.configuration.RequestRoutingConfiguration.SimpleRoute.RANDOM; import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import glide.api.models.configuration.RequestRoutingConfiguration.SimpleRoute; import glide.managers.CommandManager; import glide.managers.RedisExceptionCheckedFunction; -import glide.managers.models.Command; import java.util.Map; import java.util.concurrent.CompletableFuture; import lombok.SneakyThrows; import org.junit.jupiter.api.Test; +import redis_request.RedisRequestOuterClass.RedisRequest; import response.ResponseOuterClass.Response; public class RedisClusterClientTest { + private final String[] TEST_ARGS = new String[0]; + @Test @SneakyThrows public void custom_command_returns_single_value() { @@ -24,7 +27,7 @@ public void custom_command_returns_single_value() { var client = new TestClient(commandManager, "TEST"); - var value = client.customCommand(new String[0]).get(); + var value = client.customCommand(TEST_ARGS).get(); assertAll( () -> assertTrue(value.hasSingleData()), () -> assertEquals("TEST", value.getSingleValue())); @@ -38,7 +41,7 @@ public void custom_command_returns_multi_value() { var data = Map.of("key1", "value1", "key2", "value2"); var client = new TestClient(commandManager, data); - var value = client.customCommand(new String[0]).get(); + var value = client.customCommand(TEST_ARGS).get(); assertAll( () -> assertTrue(value.hasMultiData()), () -> assertEquals(data, value.getMultiValue())); } @@ -52,7 +55,7 @@ public void custom_command_with_single_node_route_returns_single_value() { var data = Map.of("key1", "value1", "key2", "value2"); var client = new TestClient(commandManager, data); - var value = client.customCommand(new String[0], SimpleRoute.RANDOM).get(); + var value = client.customCommand(TEST_ARGS, RANDOM).get(); assertAll( () -> assertTrue(value.hasSingleData()), () -> assertEquals(data, value.getSingleValue())); } @@ -65,7 +68,7 @@ public void custom_command_with_multi_node_route_returns_multi_value() { var data = Map.of("key1", "value1", "key2", "value2"); var client = new TestClient(commandManager, data); - var value = client.customCommand(new String[0], SimpleRoute.ALL_NODES).get(); + var value = client.customCommand(TEST_ARGS, ALL_NODES).get(); assertAll( () -> assertTrue(value.hasMultiData()), () -> assertEquals(data, value.getMultiValue())); } @@ -95,8 +98,8 @@ public TestCommandManager(Response responseToReturn) { } @Override - public CompletableFuture submitNewCommand( - Command command, RedisExceptionCheckedFunction responseHandler) { + public CompletableFuture submitCommandToChannel( + RedisRequest.Builder command, RedisExceptionCheckedFunction responseHandler) { return CompletableFuture.supplyAsync(() -> responseHandler.apply(response)); } } diff --git a/java/client/src/test/java/glide/managers/CommandManagerTest.java b/java/client/src/test/java/glide/managers/CommandManagerTest.java index 8e5010a905..9f239a7fa5 100644 --- a/java/client/src/test/java/glide/managers/CommandManagerTest.java +++ b/java/client/src/test/java/glide/managers/CommandManagerTest.java @@ -12,13 +12,13 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static redis_request.RedisRequestOuterClass.RequestType.CustomCommand; import glide.api.models.configuration.RequestRoutingConfiguration.SimpleRoute; import glide.api.models.configuration.RequestRoutingConfiguration.SlotIdRoute; import glide.api.models.configuration.RequestRoutingConfiguration.SlotKeyRoute; import glide.api.models.configuration.RequestRoutingConfiguration.SlotType; import glide.connectors.handlers.ChannelHandler; -import glide.managers.models.Command; import java.util.Map; import java.util.concurrent.CompletableFuture; import lombok.SneakyThrows; @@ -38,12 +38,8 @@ public class CommandManagerTest { CommandManager service; - Command command; - @BeforeEach void init() { - command = Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).build(); - channelHandler = mock(ChannelHandler.class); service = new CommandManager(channelHandler); } @@ -64,7 +60,9 @@ public void submitNewCommand_return_Object_result() { // exercise CompletableFuture result = service.submitNewCommand( - command, new BaseCommandResponseResolver((ptr) -> ptr == pointer ? respObject : null)); + CustomCommand, + new String[0], + new BaseCommandResponseResolver((ptr) -> ptr == pointer ? respObject : null)); Object respPointer = result.get(); // verify @@ -83,7 +81,9 @@ public void submitNewCommand_return_Null_result() { // exercise CompletableFuture result = service.submitNewCommand( - command, new BaseCommandResponseResolver((p) -> new RuntimeException(""))); + CustomCommand, + new String[0], + new BaseCommandResponseResolver((p) -> new RuntimeException(""))); Object respPointer = result.get(); // verify @@ -107,7 +107,9 @@ public void submitNewCommand_return_String_result() { // exercise CompletableFuture result = service.submitNewCommand( - command, new BaseCommandResponseResolver((p) -> p == pointer ? testString : null)); + CustomCommand, + new String[0], + new BaseCommandResponseResolver((p) -> p == pointer ? testString : null)); Object respPointer = result.get(); // verify @@ -120,22 +122,20 @@ public void submitNewCommand_return_String_result() { public void prepare_request_with_simple_routes(SimpleRoute routeType) { CompletableFuture future = new CompletableFuture<>(); when(channelHandler.write(any(), anyBoolean())).thenReturn(future); - var command = - Command.builder().requestType(Command.RequestType.CUSTOM_COMMAND).route(routeType).build(); ArgumentCaptor captor = ArgumentCaptor.forClass(RedisRequest.Builder.class); + service.submitNewCommand(CustomCommand, new String[0], routeType, r -> null); + verify(channelHandler).write(captor.capture(), anyBoolean()); + var requestBuilder = captor.getValue(); + var protobufToClientRouteMapping = Map.of( SimpleRoutes.AllNodes, SimpleRoute.ALL_NODES, SimpleRoutes.AllPrimaries, SimpleRoute.ALL_PRIMARIES, SimpleRoutes.Random, SimpleRoute.RANDOM); - service.submitNewCommand(command, r -> null); - verify(channelHandler).write(captor.capture(), anyBoolean()); - var requestBuilder = captor.getValue(); - assertAll( () -> assertTrue(requestBuilder.hasRoute()), () -> assertTrue(requestBuilder.getRoute().hasSimpleRoutes()), @@ -152,16 +152,12 @@ public void prepare_request_with_simple_routes(SimpleRoute routeType) { public void prepare_request_with_slot_id_routes(SlotType slotType) { CompletableFuture future = new CompletableFuture<>(); when(channelHandler.write(any(), anyBoolean())).thenReturn(future); - var command = - Command.builder() - .requestType(Command.RequestType.CUSTOM_COMMAND) - .route(new SlotIdRoute(42, slotType)) - .build(); ArgumentCaptor captor = ArgumentCaptor.forClass(RedisRequest.Builder.class); - service.submitNewCommand(command, r -> null); + service.submitNewCommand( + CustomCommand, new String[0], new SlotIdRoute(42, slotType), r -> null); verify(channelHandler).write(captor.capture(), anyBoolean()); var requestBuilder = captor.getValue(); @@ -188,16 +184,12 @@ public void prepare_request_with_slot_id_routes(SlotType slotType) { public void prepare_request_with_slot_key_routes(SlotType slotType) { CompletableFuture future = new CompletableFuture<>(); when(channelHandler.write(any(), anyBoolean())).thenReturn(future); - var command = - Command.builder() - .requestType(Command.RequestType.CUSTOM_COMMAND) - .route(new SlotKeyRoute("TEST", slotType)) - .build(); ArgumentCaptor captor = ArgumentCaptor.forClass(RedisRequest.Builder.class); - service.submitNewCommand(command, r -> null); + service.submitNewCommand( + CustomCommand, new String[0], new SlotKeyRoute("TEST", slotType), r -> null); verify(channelHandler).write(captor.capture(), anyBoolean()); var requestBuilder = captor.getValue(); @@ -223,15 +215,11 @@ public void prepare_request_with_slot_key_routes(SlotType slotType) { public void prepare_request_with_unknown_route_type() { CompletableFuture future = new CompletableFuture<>(); when(channelHandler.write(any(), anyBoolean())).thenReturn(future); - var command = - Command.builder() - .requestType(Command.RequestType.CUSTOM_COMMAND) - .route(() -> false) - .build(); var exception = assertThrows( - IllegalArgumentException.class, () -> service.submitNewCommand(command, r -> null)); + IllegalArgumentException.class, + () -> service.submitNewCommand(CustomCommand, new String[0], () -> false, r -> null)); assertEquals("Unknown type of route", exception.getMessage()); } } diff --git a/java/integTest/src/test/java/glide/cluster/CommandTests.java b/java/integTest/src/test/java/glide/cluster/CommandTests.java index 4ad99b552f..96d85a8a1f 100644 --- a/java/integTest/src/test/java/glide/cluster/CommandTests.java +++ b/java/integTest/src/test/java/glide/cluster/CommandTests.java @@ -1,11 +1,13 @@ /** Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 */ package glide.cluster; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import glide.TestConfiguration; import glide.api.RedisClusterClient; +import glide.api.models.ClusterValue; import glide.api.models.configuration.NodeAddress; import glide.api.models.configuration.RedisClusterClientConfiguration; import java.util.concurrent.TimeUnit; @@ -32,14 +34,15 @@ public static void init() { @AfterAll @SneakyThrows - public static void deinit() { + public static void teardown() { clusterClient.close(); } @Test @SneakyThrows public void custom_command_info() { - var data = clusterClient.customCommand(new String[] {"info"}).get(10, TimeUnit.SECONDS); + ClusterValue data = clusterClient.customCommand(new String[] {"info"}).get(10, SECONDS); + assertTrue(data.hasMultiData()); for (var info : data.getMultiValue().values()) { assertTrue(((String) info).contains("# Stats")); }