Skip to content

Commit

Permalink
Add extensive tests for UnifiedJedis (#3788)
Browse files Browse the repository at this point in the history
* Align Pipelined commands with UnifiedJedis

Add some Pipelined commands that are available in UnifiedJedis but are
missing the pipelined version.

* Add extensive tests for UnifiedJedis

Add mocked tests for UnifiedJedis. Most of the code is covered, except
the constructors and some iterator methods. Those are left for later.

Take the opportunity to split PipeliningTests into smaller test classes.
The idea is to have one superclass (MockCommandObjectsTest) that exposes
a variety of mocked CommandObjects. From there we branch in two
directions: towards PipeliningBase and towards UnifiedJedis. Each has a
test superclass that prepares mocked instances, and a set of concrete
test classes that contain the actual tests.

The tests are grouped in categories. The names of the categories are the
same as used on the redis.io website in the commands documentation page.
Inside each section (i.e. test class), the tested commands are ordered
alphabetically. The tests run in pairs, one for the string-based
command, and one for the equivalent byte-array-based command. Hopefully
this gives a good structure for following the code.

A new public constructor is needed in UnifiedJedis, in order to inject
the mocks.

Also, due to method visibility, one test class for UnifiedJedis must
reside in the same package as the class itself.

* Rename to subject under test to jedis

* Undo script commands changes

* Remove tests for removed code

* Mark new constructor as visible for testing

* React to code review

Rename classes as suggested. Move some tests into better suited classed.
Remove everything Graph related.

* Fix unit tests

And add two tests for recently added code.

---------

Co-authored-by: Gabriel Erzse <[email protected]>
Co-authored-by: M Sazzadul Hoque <[email protected]>
  • Loading branch information
3 people authored Apr 3, 2024
1 parent fac0ae9 commit c7a1687
Show file tree
Hide file tree
Showing 51 changed files with 27,158 additions and 10,503 deletions.
4 changes: 3 additions & 1 deletion src/main/java/redis/clients/jedis/UnifiedJedis.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.json.JSONArray;

import redis.clients.jedis.annots.Experimental;
import redis.clients.jedis.annots.VisibleForTesting;
import redis.clients.jedis.args.*;
import redis.clients.jedis.bloom.*;
import redis.clients.jedis.commands.JedisCommands;
Expand Down Expand Up @@ -213,7 +214,8 @@ private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider) {
}

// Uses a fetched connection to process protocol. Should be avoided if possible.
private UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects) {
@VisibleForTesting
public UnifiedJedis(CommandExecutor executor, ConnectionProvider provider, CommandObjects commandObjects) {
this(executor, provider, commandObjects, null);
if (this.provider != null) {
try (Connection conn = this.provider.getConnection()) {
Expand Down
10,502 changes: 0 additions & 10,502 deletions src/test/java/redis/clients/jedis/PipeliningBaseTest.java

This file was deleted.

263 changes: 263 additions & 0 deletions src/test/java/redis/clients/jedis/UnifiedJedisCustomCommandsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
package redis.clients.jedis;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.sameInstance;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.mockito.ArgumentCaptor;
import redis.clients.jedis.commands.ProtocolCommand;
import redis.clients.jedis.mocked.unified.UnifiedJedisMockedTestBase;

/**
* These tests are part of the mocked tests for {@link UnifiedJedis}, but, due to {@code protected}
* visibility of some methods, they must reside in the same package as the tested class.
*/
public class UnifiedJedisCustomCommandsTest extends UnifiedJedisMockedTestBase {

@Test
public void testSendCommandWithProtocolCommand() {
ProtocolCommand cmd = mock(ProtocolCommand.class);
CommandArguments commandArguments = mock(CommandArguments.class);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendCommand(cmd);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArguments));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendCommandWithProtocolCommandAndByteArrayArgs() {
ProtocolCommand cmd = mock(ProtocolCommand.class);
byte[][] args = { "arg1".getBytes(), "arg2".getBytes() };
CommandArguments commandArguments = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendCommand(cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsWithArgs));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendBlockingCommandWithProtocolCommandAndByteArrayArgs() {
ProtocolCommand cmd = mock(ProtocolCommand.class);
byte[][] args = { "arg1".getBytes(), "arg2".getBytes() };
CommandArguments commandArguments = mock(CommandArguments.class);

CommandArguments commandArgumentsBlocking = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
when(commandArgumentsWithArgs.blocking()).thenReturn(commandArgumentsBlocking);

when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendBlockingCommand(cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsBlocking));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendCommandWithProtocolCommandAndStringArgs() {
ProtocolCommand cmd = mock(ProtocolCommand.class);
String[] args = { "arg1", "arg2" };
CommandArguments commandArguments = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendCommand(cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsWithArgs));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendBlockingCommandWithProtocolCommandAndStringArgs() {
ProtocolCommand cmd = mock(ProtocolCommand.class);
String[] args = { "arg1", "arg2" };
CommandArguments commandArguments = mock(CommandArguments.class);

CommandArguments commandArgumentsBlocking = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
when(commandArgumentsWithArgs.blocking()).thenReturn(commandArgumentsBlocking);

when(commandArguments.addObjects(args)).thenReturn(commandArgumentsWithArgs);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendBlockingCommand(cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsBlocking));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendCommandWithSampleKeyProtocolCommandAndByteArrayArgs() {
byte[] sampleKey = "key".getBytes();
ProtocolCommand cmd = mock(ProtocolCommand.class);
byte[][] args = { "arg1".getBytes(), "arg2".getBytes() };
CommandArguments commandArguments = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
CommandArguments commandArgumentsWithKey = mock(CommandArguments.class);

when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs);
when(commandArgumentsWithArgs.processKey(sampleKey)).thenReturn(commandArgumentsWithKey);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendCommand(sampleKey, cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsWithKey));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendBlockingCommandWithSampleKeyProtocolCommandAndByteArrayArgs() {
byte[] sampleKey = "key".getBytes();
ProtocolCommand cmd = mock(ProtocolCommand.class);
byte[][] args = { "arg1".getBytes(), "arg2".getBytes() };
CommandArguments commandArguments = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
CommandArguments commandArgumentsBlocking = mock(CommandArguments.class);
CommandArguments commandArgumentsWithKey = mock(CommandArguments.class);

when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs);
when(commandArgumentsWithArgs.blocking()).thenReturn(commandArgumentsBlocking);
when(commandArgumentsBlocking.processKey(sampleKey)).thenReturn(commandArgumentsWithKey);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendBlockingCommand(sampleKey, cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsWithKey));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendCommandWithStringSampleKeyProtocolCommandAndStringArgs() {
String sampleKey = "key";
ProtocolCommand cmd = mock(ProtocolCommand.class);
String[] args = { "arg1", "arg2" };
CommandArguments commandArguments = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
CommandArguments commandArgumentsWithKey = mock(CommandArguments.class);

when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs);
when(commandArgumentsWithArgs.processKey(sampleKey)).thenReturn(commandArgumentsWithKey);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendCommand(sampleKey, cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsWithKey));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

@Test
public void testSendBlockingCommandWithStringSampleKeyProtocolCommandAndStringArgs() {
String sampleKey = "key";
ProtocolCommand cmd = mock(ProtocolCommand.class);
String[] args = { "arg1", "arg2" };
CommandArguments commandArguments = mock(CommandArguments.class);
CommandArguments commandArgumentsWithArgs = mock(CommandArguments.class);
CommandArguments commandArgumentsBlocking = mock(CommandArguments.class);
CommandArguments commandArgumentsWithKey = mock(CommandArguments.class);

when(commandArguments.addObjects((Object[]) args)).thenReturn(commandArgumentsWithArgs);
when(commandArgumentsWithArgs.blocking()).thenReturn(commandArgumentsBlocking);
when(commandArgumentsBlocking.processKey(sampleKey)).thenReturn(commandArgumentsWithKey);

when(commandObjects.commandArguments(cmd)).thenReturn(commandArguments);
when(commandExecutor.executeCommand(any())).thenReturn("OK");

Object result = jedis.sendBlockingCommand(sampleKey, cmd, args);

ArgumentCaptor<CommandObject<Object>> argumentCaptor = ArgumentCaptor.forClass(CommandObject.class);
verify(commandExecutor).executeCommand(argumentCaptor.capture());

CommandObject<Object> commandObject = argumentCaptor.getValue();
assertThat(commandObject.getArguments(), sameInstance(commandArgumentsWithKey));

assertThat(result, equalTo("OK"));

verify(commandObjects).commandArguments(cmd);
}

}
Loading

0 comments on commit c7a1687

Please sign in to comment.