diff --git a/java/client/build.gradle b/java/client/build.gradle index 0fb95b43ec..6c8bfe0d67 100644 --- a/java/client/build.gradle +++ b/java/client/build.gradle @@ -2,6 +2,7 @@ import java.nio.file.Paths plugins { id 'java-library' + id 'jacoco' } repositories { @@ -103,4 +104,15 @@ tasks.withType(Test) { showStandardStreams true } jvmArgs "-Djava.library.path=${projectDir}/../target/release:${projectDir}/../target/debug" + finalizedBy jacocoTestReport, jacocoTestCoverageVerification } + +jacocoTestReport { + afterEvaluate { + classDirectories.setFrom(files(classDirectories.files.collect { + fileTree(dir: it, exclude: ['**/connection_request/**', '**/response/**', '**/redis_request/**']) + })) + } +} + + diff --git a/java/client/src/main/java/glide/models/RequestBuilder.java b/java/client/src/main/java/glide/models/RequestBuilder.java deleted file mode 100644 index cd8e2dc1b6..0000000000 --- a/java/client/src/main/java/glide/models/RequestBuilder.java +++ /dev/null @@ -1,54 +0,0 @@ -package glide.models; - -import connection_request.ConnectionRequestOuterClass.ConnectionRequest; -import connection_request.ConnectionRequestOuterClass.NodeAddress; -import connection_request.ConnectionRequestOuterClass.ReadFrom; -import connection_request.ConnectionRequestOuterClass.TlsMode; -import glide.connectors.handlers.CallbackDispatcher; -import glide.managers.CommandManager; -import glide.managers.ConnectionManager; -import java.util.List; -import redis_request.RedisRequestOuterClass.Command; -import redis_request.RedisRequestOuterClass.Command.ArgsArray; -import redis_request.RedisRequestOuterClass.RedisRequest; -import redis_request.RedisRequestOuterClass.RequestType; -import redis_request.RedisRequestOuterClass.Routes; -import redis_request.RedisRequestOuterClass.SimpleRoutes; - -public class RequestBuilder { - - /** - * Build a protobuf connection request.
- * Used by {@link ConnectionManager#connectToRedis}. - */ - // TODO support more parameters and/or configuration object - public static ConnectionRequest createConnectionRequest( - String host, int port, boolean useSsl, boolean clusterMode) { - return ConnectionRequest.newBuilder() - .addAddresses(NodeAddress.newBuilder().setHost(host).setPort(port).build()) - .setTlsMode(useSsl ? TlsMode.SecureTls : TlsMode.NoTls) - .setClusterModeEnabled(clusterMode) - .setReadFrom(ReadFrom.Primary) - .setDatabaseId(0) - .build(); - } - - /** - * Build a protobuf command/transaction request draft.
- * Used by {@link CommandManager}. - * - * @return An uncompleted request. {@link CallbackDispatcher} is responsible to complete it by - * adding a callback id. - */ - public static RedisRequest.Builder prepareRedisRequest(RequestType command, List args) { - var commandArgs = ArgsArray.newBuilder(); - for (var arg : args) { - commandArgs.addArgs(arg); - } - - return RedisRequest.newBuilder() - .setSingleCommand( - Command.newBuilder().setRequestType(command).setArgsArray(commandArgs.build()).build()) - .setRoute(Routes.newBuilder().setSimpleRoutes(SimpleRoutes.AllNodes).build()); - } -} diff --git a/java/client/src/test/java/glide/api/ConfigurationTest.java b/java/client/src/test/java/glide/api/ConfigurationTest.java new file mode 100644 index 0000000000..f5cd7cdd2d --- /dev/null +++ b/java/client/src/test/java/glide/api/ConfigurationTest.java @@ -0,0 +1,138 @@ +package glide.api; + +import static glide.api.models.configuration.NodeAddress.DEFAULT_HOST; +import static glide.api.models.configuration.NodeAddress.DEFAULT_PORT; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNull; + +import glide.api.models.configuration.*; +import java.util.ArrayList; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class ConfigurationTest { + private static String HOST = "aws.com"; + private static int PORT = 9999; + + private static String USERNAME = "JohnDoe"; + private static String PASSWORD = "Password1"; + + private static int NUM_OF_RETRIES = 5; + private static int FACTOR = 10; + private static int EXPONENT_BASE = 50; + + private static int DATABASE_ID = 1; + + private static int REQUEST_TIMEOUT = 3; + + @Test + public void NodeAddress_DefaultConfig() { + NodeAddress nodeAddress = NodeAddress.builder().build(); + + assertEquals(DEFAULT_HOST, nodeAddress.getHost()); + assertEquals(DEFAULT_PORT, nodeAddress.getPort()); + } + + @Test + public void NodeAddress_CustomConfig() { + NodeAddress nodeAddress = NodeAddress.builder().host(HOST).port(PORT).build(); + + assertEquals(HOST, nodeAddress.getHost()); + assertEquals(PORT, nodeAddress.getPort()); + } + + @Test + public void BackoffStrategy_CustomConfig() { + BackoffStrategy backoffStrategy = + BackoffStrategy.builder() + .numOfRetries(NUM_OF_RETRIES) + .factor(FACTOR) + .exponentBase(EXPONENT_BASE) + .build(); + + assertEquals(NUM_OF_RETRIES, backoffStrategy.getNumOfRetries()); + assertEquals(FACTOR, backoffStrategy.getFactor()); + assertEquals(EXPONENT_BASE, backoffStrategy.getExponentBase()); + } + + @Test + public void RedisCredentials_CustomConfig() { + RedisCredentials redisCredentials = + RedisCredentials.builder().password(PASSWORD).username(USERNAME).build(); + + assertEquals(PASSWORD, redisCredentials.getPassword()); + assertEquals(USERNAME, redisCredentials.getUsername()); + } + + @Test + public void RedisClientConfiguration_DefaultConfig() { + RedisClientConfiguration redisClientConfiguration = RedisClientConfiguration.builder().build(); + + assertEquals(new ArrayList(), redisClientConfiguration.getAddresses()); + assertFalse(redisClientConfiguration.isUseTLS()); + assertEquals(ReadFrom.PRIMARY, redisClientConfiguration.getReadFrom()); + assertNull(redisClientConfiguration.getCredentials()); + assertNull(redisClientConfiguration.getRequestTimeout()); + assertNull(redisClientConfiguration.getDatabaseId()); + assertNull(redisClientConfiguration.getReconnectStrategy()); + } + + @Test + public void RedisClientConfiguration_CustomConfig() { + RedisClientConfiguration redisClientConfiguration = + RedisClientConfiguration.builder() + .address(NodeAddress.builder().host(HOST).port(PORT).build()) + .address(NodeAddress.builder().host(DEFAULT_HOST).port(DEFAULT_PORT).build()) + .useTLS(true) + .readFrom(ReadFrom.PREFER_REPLICA) + .credentials(RedisCredentials.builder().username(USERNAME).password(PASSWORD).build()) + .requestTimeout(REQUEST_TIMEOUT) + .reconnectStrategy( + BackoffStrategy.builder() + .numOfRetries(NUM_OF_RETRIES) + .exponentBase(EXPONENT_BASE) + .factor(FACTOR) + .build()) + .databaseId(DATABASE_ID) + .build(); + + List expectedAddresses = new ArrayList<>(); + NodeAddress address1 = NodeAddress.builder().host(HOST).port(PORT).build(); + NodeAddress address2 = NodeAddress.builder().host(DEFAULT_HOST).port(DEFAULT_PORT).build(); + expectedAddresses.add(address1); + expectedAddresses.add(address2); + + List actualAddresses = redisClientConfiguration.getAddresses(); + assertEquals( + expectedAddresses.size(), actualAddresses.size(), "Lists should be of the same size"); + for (int i = 0; i < actualAddresses.size(); i++) { + NodeAddress actualNodeAddress = actualAddresses.get(i); + NodeAddress expectedNodeAddress = expectedAddresses.get(i); + assertAll( + "Object fields should match", + () -> assertEquals(expectedNodeAddress.getHost(), actualNodeAddress.getHost()), + () -> assertEquals(expectedNodeAddress.getPort(), actualNodeAddress.getPort())); + } + assertTrue(redisClientConfiguration.isUseTLS()); + assertEquals(ReadFrom.PREFER_REPLICA, redisClientConfiguration.getReadFrom()); + assertEquals(PASSWORD, redisClientConfiguration.getCredentials().getPassword()); + assertEquals(USERNAME, redisClientConfiguration.getCredentials().getUsername()); + assertEquals(REQUEST_TIMEOUT, redisClientConfiguration.getRequestTimeout()); + assertEquals(NUM_OF_RETRIES, redisClientConfiguration.getReconnectStrategy().getNumOfRetries()); + assertEquals(FACTOR, redisClientConfiguration.getReconnectStrategy().getFactor()); + assertEquals(EXPONENT_BASE, redisClientConfiguration.getReconnectStrategy().getExponentBase()); + assertEquals(DATABASE_ID, redisClientConfiguration.getDatabaseId()); + } + + @Test + public void RedisClusterClientConfiguration_DefaultConfig() { + RedisClusterClientConfiguration redisClusterClientConfiguration = + RedisClusterClientConfiguration.builder().build(); + + assertEquals(new ArrayList(), redisClusterClientConfiguration.getAddresses()); + assertFalse(redisClusterClientConfiguration.isUseTLS()); + assertEquals(ReadFrom.PRIMARY, redisClusterClientConfiguration.getReadFrom()); + assertNull(redisClusterClientConfiguration.getCredentials()); + assertNull(redisClusterClientConfiguration.getRequestTimeout()); + } +} diff --git a/java/client/src/test/java/glide/handlers/ReadHandlerTest.java b/java/client/src/test/java/glide/handlers/ReadHandlerTest.java new file mode 100644 index 0000000000..198f9e2d7d --- /dev/null +++ b/java/client/src/test/java/glide/handlers/ReadHandlerTest.java @@ -0,0 +1,72 @@ +package glide.handlers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import glide.connectors.handlers.CallbackDispatcher; +import glide.connectors.handlers.ReadHandler; +import io.netty.channel.embedded.EmbeddedChannel; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import response.ResponseOuterClass; + +public class ReadHandlerTest { + + EmbeddedChannel embeddedChannel; + ReadHandler readHandler; + CallbackDispatcher dispatcher; + + @BeforeEach + public void init() { + dispatcher = mock(CallbackDispatcher.class); + readHandler = new ReadHandler(dispatcher); + embeddedChannel = new EmbeddedChannel(readHandler); + } + + @AfterEach + public void teardown() { + embeddedChannel.finishAndReleaseAll(); + } + + @Test + public void readHandlerRead_testInboundProtobufMessages() { + ResponseOuterClass.Response msg = + ResponseOuterClass.Response.newBuilder() + .setConstantResponse(ResponseOuterClass.ConstantResponse.OK) + .build(); + + assertTrue(embeddedChannel.writeInbound(msg, msg, msg)); + assertTrue(embeddedChannel.finish()); + + verify(dispatcher, times(3)).completeRequest(msg); + } + + @Test + public void readHandlerRead_testInboundProtobufMessages_invalidMessage() { + + String invalidMsg = "Invalid"; + + Exception e = + assertThrows( + Exception.class, + () -> embeddedChannel.writeInbound(invalidMsg, invalidMsg, invalidMsg)); + assertEquals("Unexpected message in socket", e.getMessage()); + + verify(dispatcher, times(0)).completeRequest(any()); + + ResponseOuterClass.Response msg = + ResponseOuterClass.Response.newBuilder() + .setConstantResponse(ResponseOuterClass.ConstantResponse.OK) + .build(); + assertTrue(embeddedChannel.writeInbound(msg)); + assertTrue(embeddedChannel.finish()); + + verify(dispatcher, times(1)).completeRequest(msg); + } +} diff --git a/java/lombok.config b/java/lombok.config new file mode 100644 index 0000000000..8f7e8aa1ac --- /dev/null +++ b/java/lombok.config @@ -0,0 +1 @@ +lombok.addLombokGeneratedAnnotation = true \ No newline at end of file