CommandArgumentsTest.java
package redis.clients.jedis;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.args.Rawable;
import redis.clients.jedis.commands.ProtocolCommand;
import redis.clients.jedis.util.JedisClusterCRC16;
public class CommandArgumentsTest {
private enum TestCommand implements ProtocolCommand {
MSET, HSET;
@Override
public byte[] getRaw() {
return name().getBytes(StandardCharsets.US_ASCII);
}
}
private static List<Object> asList(CommandArguments args) {
List<Object> values = new ArrayList<>();
for (Rawable raw : args) {
values.add(raw.toString());
}
return values;
}
@Test
public void ensureCapacityMatchesDefaultBehavior() {
CommandArguments expected = new CommandArguments(TestCommand.MSET);
CommandArguments hinted = new CommandArguments(TestCommand.MSET).ensureCapacity(9);
for (int i = 0; i < 8; i++) {
String value = "value" + i;
expected.add(value);
hinted.add(value);
}
assertEquals(asList(expected), asList(hinted));
assertEquals(expected.getCommand(), hinted.getCommand());
}
@Test
public void ensureCapacityIsChainableMidBuild() {
CommandArguments args = new CommandArguments(TestCommand.HSET).key("key");
assertSame(args, args.ensureCapacity(args.size() + 4));
args.add("f1").add("v1").add("f2").add("v2");
assertEquals(6, args.size()); // command + key + 4 arguments
}
@Test
public void underEstimatedCapacityGrowsBeyondExpectation() {
CommandArguments args = new CommandArguments(TestCommand.HSET).ensureCapacity(2);
for (int i = 0; i < 100; i++) {
args.add("value" + i);
}
assertEquals(101, asList(args).size()); // command + 100 arguments
}
@Test
public void nonPositiveCapacityHasNoEffect() {
CommandArguments args = new CommandArguments(TestCommand.MSET).ensureCapacity(-5);
args.add("a");
args.add("b");
assertEquals(3, asList(args).size()); // command + 2 arguments
}
@Test
public void collectionCommandsHonorCommandArgumentsOverride() {
List<ProtocolCommand> created = new ArrayList<>();
CommandObjects objects = new CommandObjects(RedisProtocol.RESP3) {
@Override
protected CommandArguments commandArguments(ProtocolCommand command) {
created.add(command);
return super.commandArguments(command);
}
};
Map<String, String> hash = new HashMap<>();
hash.put("field", "value");
// CommandObjects field initialization (cached PING/FLUSHALL/INFO) already invoked
// the overridden factory; only assert on invocations from the collection commands.
created.clear();
objects.hset("key", hash);
objects.hmset("key", hash);
// the capacity-aware collection path must still go through the overridable factory
assertTrue(created.contains(Protocol.Command.HSET));
assertTrue(created.contains(Protocol.Command.HMSET));
}
@Test
public void addObjectsFromCollectionPreservesAllArguments() {
CommandArguments args = new CommandArguments(TestCommand.MSET);
List<String> values = new ArrayList<>();
for (int i = 0; i < 50; i++) {
values.add("value" + i);
}
args.addObjects(values);
assertEquals(51, asList(args).size()); // command + 50 arguments
}
@Test
public void keysVarargsPreservesAllKeysAndArguments() {
Object[] keys = new Object[50];
for (int i = 0; i < 50; i++) {
keys[i] = "key" + i;
}
CommandArguments args = new CommandArguments(TestCommand.MSET).keys(keys);
assertEquals(51, args.size()); // command + 50 keys
assertEquals(50, args.getKeys().size());
}
@Test
public void keysCollectionPreservesAllKeysAndArguments() {
List<String> keys = new ArrayList<>();
for (int i = 0; i < 50; i++) {
keys.add("key" + i);
}
CommandArguments args = new CommandArguments(TestCommand.MSET).keys(keys);
assertEquals(51, args.size()); // command + 50 keys
assertEquals(50, args.getKeys().size());
}
@Test
public void addObjectsVarargsPreservesAllArguments() {
CommandArguments args = new CommandArguments(TestCommand.MSET);
Object[] values = new Object[50];
for (int i = 0; i < 50; i++) {
values[i] = "value" + i;
}
args.addObjects(values);
assertEquals(51, asList(args).size()); // command + 50 arguments
}
@Test
public void binaryKeyIsNotAliasedToTheCallerArray() {
byte[] key = "foo".getBytes(StandardCharsets.UTF_8);
CommandArguments args = new CommandArguments(TestCommand.HSET).key(key);
key[0] = 'b'; // caller reuses its buffer for the next command
assertArrayEquals("foo".getBytes(StandardCharsets.UTF_8), args.get(1).getRaw());
assertArrayEquals("foo".getBytes(StandardCharsets.UTF_8), (byte[]) args.getKeys().get(0));
assertEquals(JedisClusterCRC16.getSlot("foo"), args.getKeyHashSlots().iterator().next().intValue());
}
@Test
public void routingOnlyBinaryKeyIsNotAliasedToTheCallerArray() {
byte[] sampleKey = "foo".getBytes(StandardCharsets.UTF_8);
CommandArguments args = new CommandArguments(TestCommand.HSET).addHashSlotKey(sampleKey);
sampleKey[0] = 'b'; // caller reuses its buffer for the next command
assertArrayEquals("foo".getBytes(StandardCharsets.UTF_8), (byte[]) args.getKeys().get(0));
assertEquals(JedisClusterCRC16.getSlot("foo"), args.getKeyHashSlots().iterator().next().intValue());
}
}